/*
 * 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 WINAPI 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 );
}


