This commit was manufactured by cvs2svn to create branch 'captive'.
[reactos.git] / lib / user32 / controls / static.c
diff --git a/lib/user32/controls/static.c b/lib/user32/controls/static.c
new file mode 100644 (file)
index 0000000..6035170
--- /dev/null
@@ -0,0 +1,565 @@
+/* $Id$
+ *
+ * COPYRIGHT:        See COPYING in the top level directory
+ * PROJECT:          ReactOS User32
+ * PURPOSE:          Static control
+ * FILE:             lib/user32/controls/static.c
+ * PROGRAMER:        Ge van Geldorp (ge@gse.nl)
+ * REVISION HISTORY: 2003/05/28 GvG Created
+ * NOTES:            Adapted from Wine
+ */
+
+#include "windows.h"
+#include "user32/regcontrol.h"
+
+static void STATIC_PaintOwnerDrawfn( HWND hwnd, HDC hdc, DWORD style );
+static void STATIC_PaintTextfn( HWND hwnd, HDC hdc, DWORD style );
+static void STATIC_PaintRectfn( HWND hwnd, HDC hdc, DWORD style );
+static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style );
+static void STATIC_PaintBitmapfn( HWND hwnd, HDC hdc, DWORD style );
+static void STATIC_PaintEtchedfn( HWND hwnd, HDC hdc, DWORD style );
+//static LRESULT CALLBACK StaticWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
+static LRESULT CALLBACK StaticWndProcW( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
+
+static COLORREF color_black, color_gray, color_white;
+
+/* offsets for GetWindowLong for static private information */
+#define HFONT_GWL_OFFSET    0
+#define HICON_GWL_OFFSET    (sizeof(HFONT))
+#define STATIC_EXTRA_BYTES  (HICON_GWL_OFFSET + sizeof(HICON))
+
+typedef void (*pfPaint)( HWND hwnd, HDC hdc, DWORD style );
+
+static pfPaint staticPaintFunc[SS_TYPEMASK+1] =
+{
+    STATIC_PaintTextfn,      /* SS_LEFT */
+    STATIC_PaintTextfn,      /* SS_CENTER */
+    STATIC_PaintTextfn,      /* SS_RIGHT */
+    STATIC_PaintIconfn,      /* SS_ICON */
+    STATIC_PaintRectfn,      /* SS_BLACKRECT */
+    STATIC_PaintRectfn,      /* SS_GRAYRECT */
+    STATIC_PaintRectfn,      /* SS_WHITERECT */
+    STATIC_PaintRectfn,      /* SS_BLACKFRAME */
+    STATIC_PaintRectfn,      /* SS_GRAYFRAME */
+    STATIC_PaintRectfn,      /* SS_WHITEFRAME */
+    NULL,                    /* SS_USERITEM */
+    STATIC_PaintTextfn,      /* SS_SIMPLE */
+    STATIC_PaintTextfn,      /* SS_LEFTNOWORDWRAP */
+    STATIC_PaintOwnerDrawfn, /* SS_OWNERDRAW */
+    STATIC_PaintBitmapfn,    /* SS_BITMAP */
+    NULL,                    /* SS_ENHMETAFILE */
+    STATIC_PaintEtchedfn,    /* SS_ETCHEDHORIZ */
+    STATIC_PaintEtchedfn,    /* SS_ETCHEDVERT */
+    STATIC_PaintEtchedfn,    /* SS_ETCHEDFRAME */
+};
+
+
+/*********************************************************************
+ * static class descriptor
+ */
+const struct builtin_class_descr STATIC_builtin_class =
+{
+    L"Static",            /* name */
+    CS_GLOBALCLASS | CS_DBLCLKS, /* style  */
+    (WNDPROC) StaticWndProcW,                  /* procW */
+    STATIC_EXTRA_BYTES,                        /* extra */
+    (LPCWSTR) IDC_ARROW,                        /* cursor */ /* FIXME Wine uses IDC_ARROWA */
+    0                                          /* brush */
+};
+
+
+/***********************************************************************
+ *           STATIC_SetIcon
+ *
+ * Set the icon for an SS_ICON control.
+ */
+static HICON STATIC_SetIcon( HWND hwnd, HICON hicon, DWORD style )
+{
+#if 0 /* FIXME */
+    HICON prevIcon;
+    CURSORICONINFO *info = hicon?(CURSORICONINFO *) GlobalLock16(HICON_16(hicon)):NULL;
+
+    if ((style & SS_TYPEMASK) != SS_ICON) return 0;
+    if (hicon && !info) {
+       ERR("huh? hicon!=0, but info=0???\n");
+       return 0;
+    }
+    prevIcon = (HICON)SetWindowLongA( hwnd, HICON_GWL_OFFSET, (LONG)hicon );
+    if (hicon)
+    {
+        SetWindowPos( hwnd, 0, 0, 0, info->nWidth, info->nHeight,
+                        SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
+        GlobalUnlock16(HICON_16(hicon));
+    }
+    return prevIcon;
+#else
+    OutputDebugStringA("STATIC_SetIcon not implemented\n");
+    return NULL;
+#endif
+}
+
+/***********************************************************************
+ *           STATIC_SetBitmap
+ *
+ * Set the bitmap for an SS_BITMAP control.
+ */
+static HBITMAP STATIC_SetBitmap( HWND hwnd, HBITMAP hBitmap, DWORD style )
+{
+    HBITMAP hOldBitmap;
+
+    if ((style & SS_TYPEMASK) != SS_BITMAP) return 0;
+    if (hBitmap && GetObjectType(hBitmap) != OBJ_BITMAP) {
+       OutputDebugStringA("huh? hBitmap!=0, but not bitmap\n");
+       return 0;
+    }
+    hOldBitmap = (HBITMAP)SetWindowLongA( hwnd, HICON_GWL_OFFSET, (LONG)hBitmap );
+    if (hBitmap)
+    {
+        BITMAP bm;
+        GetObjectW(hBitmap, sizeof(bm), &bm);
+        SetWindowPos( hwnd, 0, 0, 0, bm.bmWidth, bm.bmHeight,
+                     SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
+    }
+    return hOldBitmap;
+}
+
+/***********************************************************************
+ *           STATIC_LoadIconW
+ *
+ * Load the icon for an SS_ICON control.
+ */
+static HICON STATIC_LoadIconW( HWND hwnd, LPCWSTR name )
+{
+    HINSTANCE hInstance = (HINSTANCE)GetWindowLongA( hwnd, GWL_HINSTANCE );
+    HICON hicon = LoadIconW( hInstance, name );
+    if (!hicon) hicon = LoadIconW( 0, name );
+    return hicon;
+}
+
+/***********************************************************************
+ *           STATIC_LoadBitmapW
+ *
+ * Load the bitmap for an SS_BITMAP control.
+ */
+static HBITMAP STATIC_LoadBitmapW( HWND hwnd, LPCWSTR name )
+{
+    HINSTANCE hInstance = (HINSTANCE)GetWindowLongA( hwnd, GWL_HINSTANCE );
+    HBITMAP hbitmap = LoadBitmapW( hInstance, name );
+    if (!hbitmap)  /* Try OEM icon (FIXME: is this right?) */
+        hbitmap = LoadBitmapW( 0, name );
+    return hbitmap;
+}
+
+/***********************************************************************
+ *           STATIC_TryPaintFcn
+ *
+ * Try to immediately paint the control.
+ */
+static VOID STATIC_TryPaintFcn(HWND hwnd, LONG full_style)
+{
+    LONG style = full_style & SS_TYPEMASK;
+    RECT rc;
+
+    GetClientRect( hwnd, &rc );
+    if (!IsRectEmpty(&rc) && IsWindowVisible(hwnd) && staticPaintFunc[style])
+    {
+       HDC hdc;
+       hdc = GetDC( hwnd );
+       (staticPaintFunc[style])( hwnd, hdc, full_style );
+       ReleaseDC( hwnd, hdc );
+    }
+}
+
+/***********************************************************************
+ *           StaticWndProcW
+ */
+static LRESULT CALLBACK StaticWndProcW( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+    LRESULT lResult = 0;
+    LONG full_style = GetWindowLongA( hwnd, GWL_STYLE );
+    LONG style = full_style & SS_TYPEMASK;
+
+    if (!IsWindow( hwnd )) return 0;
+    switch (uMsg)
+    {
+    case WM_CREATE:
+        if (style < 0L || style > SS_TYPEMASK)
+        {
+            OutputDebugStringA("Unknown style\n");
+            return -1;
+        }
+        /* initialise colours */
+        color_black = GetSysColor(COLOR_3DDKSHADOW);
+        color_gray = GetSysColor(COLOR_3DSHADOW);
+        color_white  = GetSysColor(COLOR_3DHILIGHT);
+        break;
+
+    case WM_NCDESTROY:
+        if (style == SS_ICON) {
+/*
+ * FIXME
+ *           DestroyIcon32( STATIC_SetIcon( wndPtr, 0 ) );
+ *
+ * We don't want to do this yet because DestroyIcon32 is broken. If the icon
+ * had already been loaded by the application the last thing we want to do is
+ * GlobalFree16 the handle.
+ */
+            break;
+        }
+        else return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+
+    case WM_PAINT:
+        {
+            PAINTSTRUCT ps;
+            BeginPaint(hwnd, &ps);
+            if (staticPaintFunc[style])
+                (staticPaintFunc[style])( hwnd, ps.hdc, full_style );
+            EndPaint(hwnd, &ps);
+        }
+        break;
+
+    case WM_ENABLE:
+        InvalidateRect(hwnd, NULL, TRUE);
+        break;
+
+    case WM_SYSCOLORCHANGE:
+        color_black = GetSysColor(COLOR_3DDKSHADOW);
+        color_gray = GetSysColor(COLOR_3DSHADOW);
+        color_white  = GetSysColor(COLOR_3DHILIGHT);
+        InvalidateRect(hwnd, NULL, TRUE);
+        break;
+
+    case WM_NCCREATE:
+       if (full_style & SS_SUNKEN)
+            SetWindowLongA( hwnd, GWL_EXSTYLE,
+                            GetWindowLongA( hwnd, GWL_EXSTYLE ) | WS_EX_STATICEDGE );
+
+       lParam = (LPARAM)(((LPCREATESTRUCTW)lParam)->lpszName);
+       /* fall through */
+    case WM_SETTEXT:
+       switch (style) {
+       case SS_ICON:
+       {
+           HICON hIcon;
+           hIcon = STATIC_LoadIconW(hwnd, (LPCWSTR)lParam);
+            /* FIXME : should we also return the previous hIcon here ??? */
+            STATIC_SetIcon(hwnd, hIcon, style);
+           break;
+       }
+        case SS_BITMAP:
+       {
+           HBITMAP hBitmap;
+           hBitmap = STATIC_LoadBitmapW(hwnd, (LPCWSTR)lParam);
+            STATIC_SetBitmap(hwnd, hBitmap, style);
+           break;
+       }
+       case SS_LEFT:
+       case SS_CENTER:
+       case SS_RIGHT:
+       case SS_SIMPLE:
+       case SS_LEFTNOWORDWRAP:
+        {
+           if (HIWORD(lParam))
+           {
+               lResult = DefWindowProcW( hwnd, WM_SETTEXT, wParam, lParam );
+           }
+           if (uMsg == WM_SETTEXT)
+               STATIC_TryPaintFcn( hwnd, full_style );
+           break;
+       }
+       default:
+           if (HIWORD(lParam))
+           {
+               lResult = DefWindowProcW( hwnd, WM_SETTEXT, wParam, lParam );
+           }
+           if(uMsg == WM_SETTEXT)
+               InvalidateRect(hwnd, NULL, TRUE);
+       }
+        return 1; /* success. FIXME: check text length */
+
+    case WM_SETFONT:
+        if ((style == SS_ICON) || (style == SS_BITMAP)) return 0;
+        SetWindowLongA( hwnd, HFONT_GWL_OFFSET, wParam );
+        if (LOWORD(lParam))
+            InvalidateRect( hwnd, NULL, TRUE );
+        break;
+
+    case WM_GETFONT:
+        return GetWindowLongA( hwnd, HFONT_GWL_OFFSET );
+
+    case WM_NCHITTEST:
+        if (full_style & SS_NOTIFY)
+           return HTCLIENT;
+        else
+           return HTTRANSPARENT;
+
+    case WM_GETDLGCODE:
+        return DLGC_STATIC;
+
+    case WM_LBUTTONDOWN:
+       if (! (full_style & SS_NOTIFY)) return 0;
+       SendMessageW(GetParent(hwnd), WM_COMMAND,
+                    MAKEWPARAM((WORD) GetWindowLongW(hwnd, GWL_ID), STN_CLICKED), (LPARAM) hwnd);
+       return 0;
+
+    case WM_LBUTTONDBLCLK:
+       if (! (full_style & SS_NOTIFY)) return 0;
+       SendMessageW(GetParent(hwnd), WM_COMMAND,
+                    MAKEWPARAM((WORD) GetWindowLongW(hwnd, GWL_ID), STN_DBLCLK), (LPARAM) hwnd);
+       return 0;
+
+    case STM_GETIMAGE:
+    case STM_GETICON:
+        return GetWindowLongA( hwnd, HICON_GWL_OFFSET );
+
+    case STM_SETIMAGE:
+        switch(wParam) {
+       case IMAGE_BITMAP:
+           lResult = (LRESULT)STATIC_SetBitmap( hwnd, (HBITMAP)lParam, style );
+           break;
+       case IMAGE_ICON:
+           lResult = (LRESULT)STATIC_SetIcon( hwnd, (HICON)lParam, style );
+           break;
+       default:
+           OutputDebugStringA("STM_SETIMAGE: Unhandled type\n");
+           break;
+       }
+        InvalidateRect( hwnd, NULL, TRUE );
+       break;
+
+    case STM_SETICON:
+        lResult = (LRESULT)STATIC_SetIcon( hwnd, (HICON)wParam, style );
+        InvalidateRect( hwnd, NULL, TRUE );
+        break;
+
+    default:
+        return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+    }
+    return lResult;
+}
+
+static void STATIC_PaintOwnerDrawfn( HWND hwnd, HDC hdc, DWORD style )
+{
+  DRAWITEMSTRUCT dis;
+  LONG id = GetWindowLongA( hwnd, GWL_ID );
+
+  dis.CtlType    = ODT_STATIC;
+  dis.CtlID      = id;
+  dis.itemID     = 0;
+  dis.itemAction = ODA_DRAWENTIRE;
+  dis.itemState  = 0;
+  dis.hwndItem   = hwnd;
+  dis.hDC        = hdc;
+  dis.itemData   = 0;
+  GetClientRect( hwnd, &dis.rcItem );
+
+  SendMessageW( GetParent(hwnd), WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd );
+  SendMessageW( GetParent(hwnd), WM_DRAWITEM, id, (LPARAM)&dis );
+}
+
+static void STATIC_PaintTextfn( HWND hwnd, HDC hdc, DWORD style )
+{
+    RECT rc;
+    HBRUSH hBrush;
+    HFONT hFont;
+    UINT wFormat;
+    INT len;
+    WCHAR *text;
+    HPEN ShadowPen, HighlightPen;
+
+    GetClientRect( hwnd, &rc);
+
+    switch (style & SS_TYPEMASK)
+    {
+    case SS_LEFT:
+       wFormat = DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP;
+       break;
+
+    case SS_CENTER:
+       wFormat = DT_CENTER | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP;
+       break;
+
+    case SS_RIGHT:
+       wFormat = DT_RIGHT | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP;
+       break;
+
+    case SS_SIMPLE:
+       wFormat = DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_NOCLIP;
+       break;
+
+    case SS_LEFTNOWORDWRAP:
+       wFormat = DT_LEFT | DT_EXPANDTABS | DT_VCENTER;
+       break;
+
+    default:
+        return;
+    }
+
+    if (style & SS_NOPREFIX)
+       wFormat |= DT_NOPREFIX;
+    switch(style & SS_ELLIPSISMASK)
+    {
+    case SS_WORDELLIPSIS:
+       wFormat |= DT_WORD_ELLIPSIS | DT_SINGLELINE;
+       break;
+    case SS_ENDELLIPSIS:
+       wFormat |= DT_END_ELLIPSIS;
+       wFormat &= ~DT_WORDBREAK;
+       break;
+    case SS_PATHELLIPSIS:
+       wFormat |= DT_PATH_ELLIPSIS;
+       wFormat &= ~DT_WORDBREAK;
+       break;
+    }
+
+    if ((hFont = (HFONT)GetWindowLongA( hwnd, HFONT_GWL_OFFSET ))) SelectObject( hdc, hFont );
+
+    if ((style & SS_NOPREFIX) || ((style & SS_TYPEMASK) != SS_SIMPLE))
+    {
+        hBrush = (HBRUSH)SendMessageW( GetParent(hwnd), WM_CTLCOLORSTATIC,
+                                      (WPARAM)hdc, (LPARAM)hwnd );
+        if (!hBrush) /* did the app forget to call defwindowproc ? */
+            hBrush = (HBRUSH)DefWindowProcW(GetParent(hwnd), WM_CTLCOLORSTATIC,
+                                           (WPARAM)hdc, (LPARAM)hwnd);
+        FillRect( hdc, &rc, hBrush );
+    }
+    if (!IsWindowEnabled(hwnd)) SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
+    SetBkMode(hdc, TRANSPARENT);
+
+    if (style & SS_SUNKEN)
+    {
+       ShadowPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
+       SelectObject(hdc, ShadowPen);
+       MoveToEx(hdc, 0, rc.bottom - 2, NULL);
+       LineTo(hdc, 0, 0);
+       LineTo(hdc, rc.right - 1, 0);
+       HighlightPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNHIGHLIGHT));
+       SelectObject(hdc, HighlightPen);
+       LineTo(hdc, rc.right - 1, rc.bottom - 1);
+       LineTo(hdc, -1, rc.bottom - 1);
+       SelectObject(hdc, GetStockObject(WHITE_PEN));
+       DeleteObject(HighlightPen);
+       DeleteObject(ShadowPen);
+       rc.left++;
+       rc.right--;
+       rc.top++;
+       rc.bottom--;
+    }
+
+    if (!(len = SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 ))) return;
+    if (!(text = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return;
+    SendMessageW( hwnd, WM_GETTEXT, len + 1, (LPARAM)text );
+    DrawTextW( hdc, text, -1, &rc, wFormat );
+    HeapFree( GetProcessHeap(), 0, text );
+}
+
+static void STATIC_PaintRectfn( HWND hwnd, HDC hdc, DWORD style )
+{
+    RECT rc;
+    HBRUSH hBrush;
+
+    GetClientRect( hwnd, &rc);
+
+    switch (style & SS_TYPEMASK)
+    {
+    case SS_BLACKRECT:
+       hBrush = CreateSolidBrush(color_black);
+        FillRect( hdc, &rc, hBrush );
+       break;
+    case SS_GRAYRECT:
+       hBrush = CreateSolidBrush(color_gray);
+        FillRect( hdc, &rc, hBrush );
+       break;
+    case SS_WHITERECT:
+       hBrush = CreateSolidBrush(color_white);
+        FillRect( hdc, &rc, hBrush );
+       break;
+    case SS_BLACKFRAME:
+       hBrush = CreateSolidBrush(color_black);
+        FrameRect( hdc, &rc, hBrush );
+       break;
+    case SS_GRAYFRAME:
+       hBrush = CreateSolidBrush(color_gray);
+        FrameRect( hdc, &rc, hBrush );
+       break;
+    case SS_WHITEFRAME:
+       hBrush = CreateSolidBrush(color_white);
+        FrameRect( hdc, &rc, hBrush );
+       break;
+    default:
+        return;
+    }
+    DeleteObject( hBrush );
+}
+
+
+static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style )
+{
+    RECT rc;
+    HBRUSH hbrush;
+    HICON hIcon;
+
+    GetClientRect( hwnd, &rc );
+    hbrush = (HBRUSH)SendMessageW( GetParent(hwnd), WM_CTLCOLORSTATIC,
+                                  (WPARAM)hdc, (LPARAM)hwnd );
+    FillRect( hdc, &rc, hbrush );
+    if ((hIcon = (HICON)GetWindowLongA( hwnd, HICON_GWL_OFFSET )))
+        DrawIcon( hdc, rc.left, rc.top, hIcon );
+}
+
+static void STATIC_PaintBitmapfn(HWND hwnd, HDC hdc, DWORD style )
+{
+    RECT rc;
+    HBRUSH hbrush;
+    HDC hMemDC;
+    HBITMAP hBitmap, oldbitmap;
+
+    GetClientRect( hwnd, &rc );
+    hbrush = (HBRUSH)SendMessageW( GetParent(hwnd), WM_CTLCOLORSTATIC,
+                                  (WPARAM)hdc, (LPARAM)hwnd );
+    FillRect( hdc, &rc, hbrush );
+
+    if ((hBitmap = (HBITMAP)GetWindowLongA( hwnd, HICON_GWL_OFFSET )))
+    {
+        BITMAP bm;
+       SIZE sz;
+
+        if(GetObjectType(hBitmap) != OBJ_BITMAP) return;
+        if (!(hMemDC = CreateCompatibleDC( hdc ))) return;
+       GetObjectW(hBitmap, sizeof(bm), &bm);
+       GetBitmapDimensionEx(hBitmap, &sz);
+       oldbitmap = SelectObject(hMemDC, hBitmap);
+       BitBlt(hdc, sz.cx, sz.cy, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0,
+              SRCCOPY);
+       SelectObject(hMemDC, oldbitmap);
+       DeleteDC(hMemDC);
+    }
+}
+
+
+static void STATIC_PaintEtchedfn( HWND hwnd, HDC hdc, DWORD style )
+{
+    RECT rc;
+
+    GetClientRect( hwnd, &rc );
+    switch (style & SS_TYPEMASK)
+    {
+       case SS_ETCHEDHORZ:
+#if 0 /* This is what seems logical */
+           DrawEdge(hdc,&rc,EDGE_ETCHED,BF_TOP|BF_BOTTOM);
+#else /* But this is what NT, Win2k and WinXP actually do */
+           DrawEdge(hdc,&rc,EDGE_ETCHED,BF_TOP);
+#endif
+           break;
+       case SS_ETCHEDVERT:
+#if 0 /* This is what seems logical */
+           DrawEdge(hdc,&rc,EDGE_ETCHED,BF_LEFT|BF_RIGHT);
+#else /* But this is what NT, Win2k and WinXP actually do */
+           DrawEdge(hdc,&rc,EDGE_ETCHED,BF_LEFT);
+#endif
+           break;
+       case SS_ETCHEDFRAME:
+           DrawEdge (hdc, &rc, EDGE_ETCHED, BF_RECT);
+           break;
+    }
+}