/*
 * Icontitle window class.
 *
 * Copyright 1997 Alex Korobka
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "windows.h"
#include "sysmetrics.h"
#include "syscolor.h"
#include "win.h"
#include "desktop.h"
#include "graphics.h"
#include "heap.h"

static  LPCSTR	emptyTitleText = "<...>";

	BOOL32	bMultiLineTitle;
	HFONT32	hIconTitleFont;

/***********************************************************************
 *           ICONTITLE_Init
 */
BOOL32 ICONTITLE_Init(void)
{
    LOGFONT16 logFont;

    SystemParametersInfo16( SPI_GETICONTITLELOGFONT, 0, &logFont, 0 );
    SystemParametersInfo16( SPI_GETICONTITLEWRAP, 0, &bMultiLineTitle, 0 );
    hIconTitleFont = CreateFontIndirect16( &logFont );
    return (hIconTitleFont) ? TRUE : FALSE;
}

/***********************************************************************
 *           ICONTITLE_Create
 */
HWND32 ICONTITLE_Create( WND* wnd )
{
    WND* wndPtr;
    HWND32 hWnd;

    if( wnd->dwStyle & WS_CHILD )
	hWnd = CreateWindowEx32A( 0, ICONTITLE_CLASS_ATOM, NULL,
				  WS_CHILD | WS_CLIPSIBLINGS, 0, 0, 1, 1,
				  wnd->parent->hwndSelf, 0, wnd->hInstance, NULL );
    else
	hWnd = CreateWindowEx32A( 0, ICONTITLE_CLASS_ATOM, NULL,
				  WS_CLIPSIBLINGS, 0, 0, 1, 1,
				  wnd->hwndSelf, 0, wnd->hInstance, NULL );
    wndPtr = WIN_FindWndPtr( hWnd );
    if( wndPtr )
    {
	wndPtr->owner = wnd;	/* MDI depends on this */
	wndPtr->dwStyle &= ~(WS_CAPTION | WS_BORDER);
	if( wnd->dwStyle & WS_DISABLED ) wndPtr->dwStyle |= WS_DISABLED;
	return hWnd;
    }
    return 0;
}

/***********************************************************************
 *           ICONTITLE_GetTitlePos
 */
static BOOL32 ICONTITLE_GetTitlePos( WND* wnd, LPRECT32 lpRect )
{
    LPSTR str;
    int length = lstrlen32A( wnd->owner->text );

    if( length )
    {
	str = HeapAlloc( GetProcessHeap(), 0, length + 1 );
	lstrcpy32A( str, wnd->owner->text );
	while( str[length - 1] == ' ' ) /* remove trailing spaces */
	{ 
	    str[--length] = '\0';
	    if( !length )
	    {
		HeapFree( GetProcessHeap(), 0, str );
		break;
	    }
	}
    }
    if( !length ) 
    {
	str = (LPSTR)emptyTitleText;
	length = lstrlen32A( str );
    }

    if( str )
    {
	HDC32 hDC = GetDC32( wnd->hwndSelf );
	if( hDC )
	{
	    HFONT32 hPrevFont = SelectObject32( hDC, hIconTitleFont );

	    SetRect32( lpRect, 0, 0, sysMetrics[SM_CXICONSPACING] -
		       SYSMETRICS_CXBORDER * 2, SYSMETRICS_CYBORDER * 2 );

	    DrawText32A( hDC, str, length, lpRect, DT_CALCRECT |
			 DT_CENTER | DT_NOPREFIX | DT_WORDBREAK |
			 (( bMultiLineTitle ) ? 0 : DT_SINGLELINE) );

	    SelectObject32( hDC, hPrevFont );
	    ReleaseDC32( wnd->hwndSelf, hDC );

	    lpRect->right += 4 * SYSMETRICS_CXBORDER - lpRect->left;
	    lpRect->left = wnd->owner->rectWindow.left + SYSMETRICS_CXICON / 2 -
				      (lpRect->right - lpRect->left) / 2;
	    lpRect->bottom -= lpRect->top;
	    lpRect->top = wnd->owner->rectWindow.top + SYSMETRICS_CYICON;
	}
	if( str != emptyTitleText ) HeapFree( GetProcessHeap(), 0, str );
	return ( hDC ) ? TRUE : FALSE;
    }
    return FALSE;
}

/***********************************************************************
 *           ICONTITLE_Paint
 */
static BOOL32 ICONTITLE_Paint( WND* wnd, HDC32 hDC, BOOL32 bActive )
{
    HFONT32 hPrevFont;
    HBRUSH32 hBrush = 0;
    COLORREF textColor = 0;

    if( bActive )
    {
	hBrush = sysColorObjects.hbrushActiveCaption;
	textColor = GetSysColor32(COLOR_CAPTIONTEXT);
    }
    else 
    {
	if( wnd->dwStyle & WS_CHILD ) 
	{ 
	    hBrush = wnd->parent->class->hbrBackground;
	    if( hBrush )
	    {
		INT32 level;
		LOGBRUSH32 logBrush;
		GetObject32A( hBrush, sizeof(logBrush), &logBrush );
		level = GetRValue(logBrush.lbColor) +
			   GetGValue(logBrush.lbColor) +
			      GetBValue(logBrush.lbColor);
		if( level < (0x7F * 3) )
		    textColor = RGB( 0xFF, 0xFF, 0xFF );
	    }
	    else
		hBrush = GetStockObject32( WHITE_BRUSH );
	}
	else
	{
	    hBrush = GetStockObject32( BLACK_BRUSH );
	    textColor = RGB( 0xFF, 0xFF, 0xFF );    
	}
    }

    FillWindow( wnd->parent->hwndSelf, wnd->hwndSelf, hDC, hBrush );

    hPrevFont = SelectObject32( hDC, hIconTitleFont );
    if( hPrevFont )
    {
        RECT16  rect;
	INT32	length;
	char	buffer[80];

	rect.left = rect.top = 0;
	rect.right = wnd->rectWindow.right - wnd->rectWindow.left;
	rect.bottom = wnd->rectWindow.bottom - wnd->rectWindow.top;

	length = GetWindowText32A( wnd->owner->hwndSelf, buffer, 80 );
        SetTextColor32( hDC, textColor );
        SetBkMode32( hDC, TRANSPARENT );
	
	DrawText16( hDC, buffer, length, &rect, DT_CENTER | DT_NOPREFIX |
		    DT_WORDBREAK | ((bMultiLineTitle) ? 0 : DT_SINGLELINE) ); 

	SelectObject32( hDC, hPrevFont );
    }
    return ( hPrevFont ) ? TRUE : FALSE;
}

/***********************************************************************
 *           IconTitleWndProc
 */
LRESULT IconTitleWndProc( HWND32 hWnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam )
{
    WND *wnd = WIN_FindWndPtr( hWnd );

    switch( msg )
    {
	case WM_NCHITTEST:
	     return HTCAPTION;

	case WM_NCMOUSEMOVE:
	case WM_NCLBUTTONDBLCLK:
	     return SendMessage32A( wnd->owner->hwndSelf, msg, wParam, lParam );	

	case WM_ACTIVATE:
	     if( wParam ) SetActiveWindow32( wnd->owner->hwndSelf );
	     /* fall through */

	case WM_CLOSE:
	     return 0;

	case WM_SHOWWINDOW:
	     if( wnd && wParam )
	     {
		 RECT32 titleRect;

		 ICONTITLE_GetTitlePos( wnd, &titleRect );
		 if( wnd->owner->next != wnd )	/* keep icon title behind the owner */
		     SetWindowPos32( hWnd, wnd->owner->hwndSelf, 
				     titleRect.left, titleRect.top,
				     titleRect.right, titleRect.bottom, SWP_NOACTIVATE );
		 else
		     SetWindowPos32( hWnd, 0, titleRect.left, titleRect.top,
				     titleRect.right, titleRect.bottom, 
				     SWP_NOACTIVATE | SWP_NOZORDER );
	     }
	     return 0;

	case WM_ERASEBKGND:
	     if( wnd )
	     {
		 WND* iconWnd = wnd->owner;

		 if( iconWnd->dwStyle & WS_CHILD )
		     lParam = SendMessage32A( iconWnd->hwndSelf, WM_ISACTIVEICON, 0, 0 );
		 else
		     lParam = (iconWnd->hwndSelf == GetActiveWindow16());

		 if( ICONTITLE_Paint( wnd, (HDC32)wParam, (BOOL32)lParam ) )
		     ValidateRect32( hWnd, NULL );
	         return 1;
	     }
    }

    return DefWindowProc32A( hWnd, msg, wParam, lParam );
}


