https://git.reactos.org/?p=reactos.git;a=commitdiff;h=b3fb8555bf9abcc04eeac…
commit b3fb8555bf9abcc04eeac31c7153d33e2f027fc0
Author: Giannis Adamopoulos <gadamopoulos(a)reactos.org>
AuthorDate: Wed Apr 4 16:39:21 2018 +0300
Commit: David Quintana <gigaherz(a)gmail.com>
CommitDate: Fri Apr 20 16:27:17 2018 +0200
[COMCTL32] Sync with Wine Staging 3.3. CORE-14434
---
dll/win32/comctl32/CMakeLists.txt | 15 +-
dll/win32/comctl32/animate.c | 86 +-
dll/win32/comctl32/button.c | 1743 ++++---
dll/win32/comctl32/combo.c | 2160 +++++++++
dll/win32/comctl32/comboex.c | 58 +-
dll/win32/comctl32/comctl32.h | 173 +-
dll/win32/comctl32/comctl32undoc.c | 25 +-
dll/win32/comctl32/commctrl.c | 62 +-
dll/win32/comctl32/datetime.c | 36 +-
dll/win32/comctl32/dpa.c | 12 +
dll/win32/comctl32/draglist.c | 9 +
dll/win32/comctl32/dsa.c | 8 +
dll/win32/comctl32/edit.c | 5041 ++++++++++++++++++++
dll/win32/comctl32/flatsb.c | 8 +
dll/win32/comctl32/header.c | 60 +-
dll/win32/comctl32/hotkey.c | 14 +-
dll/win32/comctl32/imagelist.c | 81 +-
dll/win32/comctl32/ipaddress.c | 32 +-
dll/win32/comctl32/listbox.c | 3083 ++++++++++++
dll/win32/comctl32/listview.c | 63 +-
dll/win32/comctl32/monthcal.c | 83 +-
dll/win32/comctl32/nativefont.c | 8 +
dll/win32/comctl32/pager.c | 14 +-
dll/win32/comctl32/precomp.h | 28 +
dll/win32/comctl32/progress.c | 35 +-
dll/win32/comctl32/propsheet.c | 26 +-
dll/win32/comctl32/rebar.c | 17 +-
dll/win32/comctl32/rsrc.rc | 5 +-
dll/win32/comctl32/smoothscroll.c | 9 +-
dll/win32/comctl32/static.c | 793 +++
dll/win32/comctl32/status.c | 22 +-
dll/win32/comctl32/string.c | 16 +
dll/win32/comctl32/syslink.c | 28 +-
dll/win32/comctl32/tab.c | 14 +
dll/win32/comctl32/taskdialog.c | 20 +-
dll/win32/comctl32/theme_button.c | 4 +
dll/win32/comctl32/theme_dialog.c | 14 +-
dll/win32/comctl32/theme_scrollbar.c | 15 +-
dll/win32/comctl32/theming.c | 42 +-
dll/win32/comctl32/toolbar.c | 31 +-
dll/win32/comctl32/tooltips.c | 46 +-
dll/win32/comctl32/trackbar.c | 30 +-
dll/win32/comctl32/treeview.c | 83 +-
dll/win32/comctl32/updown.c | 80 +-
...144ccf1df_5.82.2600.2982_none_deadbeef.manifest | 1 +
...4144ccf1df_6.0.2600.2982_none_deadbeef.manifest | 1 +
46 files changed, 12986 insertions(+), 1248 deletions(-)
diff --git a/dll/win32/comctl32/CMakeLists.txt b/dll/win32/comctl32/CMakeLists.txt
index 9285001478..4a1151bd98 100644
--- a/dll/win32/comctl32/CMakeLists.txt
+++ b/dll/win32/comctl32/CMakeLists.txt
@@ -13,6 +13,7 @@ spec2def(comctl32.dll comctl32.spec ADD_IMPORTLIB)
list(APPEND SOURCE
animate.c
button.c
+ combo.c
comboex.c
comctl32undoc.c
commctrl.c
@@ -20,11 +21,13 @@ list(APPEND SOURCE
dpa.c
draglist.c
dsa.c
+ edit.c
flatsb.c
header.c
hotkey.c
imagelist.c
ipaddress.c
+ listbox.c
listview.c
monthcal.c
nativefont.c
@@ -33,16 +36,12 @@ list(APPEND SOURCE
propsheet.c
rebar.c
smoothscroll.c
+ static.c
status.c
string.c
syslink.c
tab.c
taskdialog.c
- theme_button.c
- theme_combo.c
- theme_dialog.c
- theme_edit.c
- theme_listbox.c
theme_scrollbar.c
theming.c
toolbar.c
@@ -50,7 +49,7 @@ list(APPEND SOURCE
trackbar.c
treeview.c
updown.c
- comctl32.h)
+ precomp.h)
add_library(comctl32 SHARED
${SOURCE}
@@ -61,8 +60,8 @@ add_library(comctl32 SHARED
set_module_type(comctl32 win32dll UNICODE)
target_link_libraries(comctl32 uuid wine ${PSEH_LIB})
add_delay_importlibs(comctl32 winmm uxtheme)
-add_importlibs(comctl32 user32 gdi32 advapi32 msvcrt kernel32 ntdll)
-add_pch(comctl32 comctl32.h SOURCE)
+add_importlibs(comctl32 user32 gdi32 advapi32 usp10 imm32 msvcrt kernel32 ntdll)
+add_pch(comctl32 precomp.h SOURCE)
add_cd_file(TARGET comctl32 DESTINATION reactos/system32 FOR all)
add_cd_file(TARGET comctl32 DESTINATION
reactos/winsxs/x86_microsoft.windows.common-controls_6595b64144ccf1df_5.82.2600.2982_none_deadbeef
FOR all)
add_cd_file(TARGET comctl32 DESTINATION
reactos/winsxs/x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.2600.2982_none_deadbeef
FOR all)
diff --git a/dll/win32/comctl32/animate.c b/dll/win32/comctl32/animate.c
index 594a227568..f8ba159779 100644
--- a/dll/win32/comctl32/animate.c
+++ b/dll/win32/comctl32/animate.c
@@ -20,22 +20,23 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
- * NOTES
- *
- * This code was audited for completeness against the documented features
- * of Comctl32.dll version 6.0 on Mar. 15, 2005, by Dimitrie O. Paun.
- *
- * Unless otherwise noted, we believe this code to be complete, as per
- * the specification mentioned above.
- * If you discover missing features, or bugs, please note them below.
- *
* TODO:
* - check for the 'rec ' list in some AVI files
*/
+#include <stdarg.h>
+#include <string.h>
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "commctrl.h"
+#include "vfw.h"
+#include "mmsystem.h"
#include "comctl32.h"
-
-#include <vfw.h>
+#include "wine/debug.h"
+#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(animate);
@@ -179,36 +180,39 @@ static BOOL ANIMATE_DoStop(ANIMATE_INFO *infoPtr)
static void ANIMATE_Free(ANIMATE_INFO *infoPtr)
{
- if (infoPtr->hMMio) {
- ANIMATE_DoStop(infoPtr);
- mmioClose(infoPtr->hMMio, 0);
- if (infoPtr->hRes) {
- FreeResource(infoPtr->hRes);
- infoPtr->hRes = 0;
- }
- Free (infoPtr->lpIndex);
+ if (infoPtr->hMMio)
+ {
+ ANIMATE_DoStop(infoPtr);
+ mmioClose(infoPtr->hMMio, 0);
+ if (infoPtr->hRes)
+ {
+ FreeResource(infoPtr->hRes);
+ infoPtr->hRes = 0;
+ }
+ heap_free (infoPtr->lpIndex);
infoPtr->lpIndex = NULL;
- if (infoPtr->hic) {
- fnIC.fnICClose(infoPtr->hic);
- infoPtr->hic = 0;
- }
- Free (infoPtr->inbih);
+ if (infoPtr->hic)
+ {
+ fnIC.fnICClose(infoPtr->hic);
+ infoPtr->hic = 0;
+ }
+ heap_free (infoPtr->inbih);
infoPtr->inbih = NULL;
- Free (infoPtr->outbih);
+ heap_free (infoPtr->outbih);
infoPtr->outbih = NULL;
- Free (infoPtr->indata);
+ heap_free (infoPtr->indata);
infoPtr->indata = NULL;
- Free (infoPtr->outdata);
+ heap_free (infoPtr->outdata);
infoPtr->outdata = NULL;
- if( infoPtr->hbmPrevFrame )
+ if (infoPtr->hbmPrevFrame)
{
- DeleteObject(infoPtr->hbmPrevFrame);
+ DeleteObject(infoPtr->hbmPrevFrame);
infoPtr->hbmPrevFrame = 0;
}
- memset(&infoPtr->mah, 0, sizeof(infoPtr->mah));
- memset(&infoPtr->ash, 0, sizeof(infoPtr->ash));
- infoPtr->nFromFrame = infoPtr->nToFrame = infoPtr->nLoop =
infoPtr->currFrame = 0;
+ memset(&infoPtr->mah, 0, sizeof(infoPtr->mah));
+ memset(&infoPtr->ash, 0, sizeof(infoPtr->ash));
+ infoPtr->nFromFrame = infoPtr->nToFrame = infoPtr->nLoop =
infoPtr->currFrame = 0;
}
infoPtr->transparentColor = ANIMATE_COLOR_NONE;
}
@@ -562,7 +566,7 @@ static BOOL ANIMATE_GetAviInfo(ANIMATE_INFO *infoPtr)
return FALSE;
}
- infoPtr->inbih = Alloc(mmckInfo.cksize);
+ infoPtr->inbih = heap_alloc_zero(mmckInfo.cksize);
if (!infoPtr->inbih) {
WARN("Can't alloc input BIH\n");
return FALSE;
@@ -609,7 +613,7 @@ static BOOL ANIMATE_GetAviInfo(ANIMATE_INFO *infoPtr)
/* FIXME: should handle the 'rec ' LIST when present */
- infoPtr->lpIndex = Alloc(infoPtr->mah.dwTotalFrames * sizeof(DWORD));
+ infoPtr->lpIndex = heap_alloc_zero(infoPtr->mah.dwTotalFrames *
sizeof(DWORD));
if (!infoPtr->lpIndex)
return FALSE;
@@ -631,7 +635,7 @@ static BOOL ANIMATE_GetAviInfo(ANIMATE_INFO *infoPtr)
infoPtr->ash.dwSuggestedBufferSize = insize;
}
- infoPtr->indata = Alloc(infoPtr->ash.dwSuggestedBufferSize);
+ infoPtr->indata = heap_alloc_zero(infoPtr->ash.dwSuggestedBufferSize);
if (!infoPtr->indata)
return FALSE;
@@ -662,7 +666,7 @@ static BOOL ANIMATE_GetAviCodec(ANIMATE_INFO *infoPtr)
outSize = fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT,
(DWORD_PTR)infoPtr->inbih, 0L);
- infoPtr->outbih = Alloc(outSize);
+ infoPtr->outbih = heap_alloc_zero(outSize);
if (!infoPtr->outbih)
return FALSE;
@@ -673,7 +677,7 @@ static BOOL ANIMATE_GetAviCodec(ANIMATE_INFO *infoPtr)
return FALSE;
}
- infoPtr->outdata = Alloc(infoPtr->outbih->biSizeImage);
+ infoPtr->outdata = heap_alloc_zero(infoPtr->outbih->biSizeImage);
if (!infoPtr->outdata)
return FALSE;
@@ -767,12 +771,12 @@ static BOOL ANIMATE_OpenA(ANIMATE_INFO *infoPtr, HINSTANCE
hInstance, LPSTR lpsz
return ANIMATE_OpenW(infoPtr, hInstance, (LPWSTR)lpszName);
len = MultiByteToWideChar(CP_ACP, 0, lpszName, -1, NULL, 0);
- lpwszName = Alloc(len * sizeof(WCHAR));
+ lpwszName = heap_alloc(len * sizeof(WCHAR));
if (!lpwszName) return FALSE;
MultiByteToWideChar(CP_ACP, 0, lpszName, -1, lpwszName, len);
result = ANIMATE_OpenW(infoPtr, hInstance, lpwszName);
- Free (lpwszName);
+ heap_free (lpwszName);
return result;
}
@@ -805,7 +809,7 @@ static BOOL ANIMATE_Create(HWND hWnd, const CREATESTRUCTW *lpcs)
}
/* allocate memory for info structure */
- infoPtr = Alloc(sizeof(ANIMATE_INFO));
+ infoPtr = heap_alloc_zero(sizeof(*infoPtr));
if (!infoPtr) return FALSE;
/* store crossref hWnd <-> info structure */
@@ -835,7 +839,7 @@ static LRESULT ANIMATE_Destroy(ANIMATE_INFO *infoPtr)
infoPtr->cs.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&infoPtr->cs);
- Free(infoPtr);
+ heap_free(infoPtr);
return 0;
}
diff --git a/dll/win32/comctl32/button.c b/dll/win32/comctl32/button.c
index bdc91840d5..c313aa81e8 100644
--- a/dll/win32/comctl32/button.c
+++ b/dll/win32/comctl32/button.c
@@ -1,8 +1,8 @@
-/* File: button.c -- Button type widgets
- *
+/*
* Copyright (C) 1993 Johannes Ruscheinski
* Copyright (C) 1993 David Metcalfe
* Copyright (C) 1994 Alexandre Julliard
+ * Copyright (C) 2008 by Reece H. Dunn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -18,15 +18,6 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
- * NOTES
- *
- * This code was audited for completeness against the documented features
- * of Comctl32.dll version 6.0 on Oct. 3, 2004, by Dimitrie O. Paun.
- *
- * Unless otherwise noted, we believe this code to be complete, as per
- * the specification mentioned above.
- * If you discover missing features, or bugs, please note them below.
- *
* TODO
* Styles
* - BS_NOTIFY: is it complete?
@@ -42,7 +33,7 @@
* - BCM_GETTEXTMARGIN
* - BCM_SETIMAGELIST
* - BCM_SETTEXTMARGIN
- *
+ *
* Notifications
* - BCN_HOTITEMCHANGE
* - BN_DISABLE
@@ -62,18 +53,26 @@
* - Button_SetImageList
* - Button_SetTextMargin
*/
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define OEMRESOURCE
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "uxtheme.h"
+#include "vssym32.h"
+#include "wine/debug.h"
+#include "wine/heap.h"
+
#include "comctl32.h"
-#include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(button);
-/* GetWindowLong offsets for window extra information */
-#define STATE_GWL_OFFSET 0
-#define HFONT_GWL_OFFSET (sizeof(LONG))
-#define HIMAGE_GWL_OFFSET (HFONT_GWL_OFFSET+sizeof(HFONT))
-#define UISTATE_GWL_OFFSET (HIMAGE_GWL_OFFSET+sizeof(HFONT))
-#define NB_EXTRA_BYTES (UISTATE_GWL_OFFSET+sizeof(LONG))
-
/* undocumented flags */
#define BUTTON_NSTATES 0x0F
#define BUTTON_BTNPRESSED 0x40
@@ -91,12 +90,31 @@ WINE_DEFAULT_DEBUG_CHANNEL(button);
(LPARAM)(hWnd)); \
} while(0)
-static UINT BUTTON_CalcLabelRect( HWND hwnd, HDC hdc, RECT *rc );
-static void PB_Paint( HWND hwnd, HDC hDC, UINT action );
-static void CB_Paint( HWND hwnd, HDC hDC, UINT action );
-static void GB_Paint( HWND hwnd, HDC hDC, UINT action );
-static void UB_Paint( HWND hwnd, HDC hDC, UINT action );
-static void OB_Paint( HWND hwnd, HDC hDC, UINT action );
+typedef struct _BUTTON_INFO
+{
+ HWND hwnd;
+ LONG state;
+ HFONT font;
+ union
+ {
+ HICON icon;
+ HBITMAP bitmap;
+ HANDLE image;
+ } u;
+
+#ifdef __REACTOS__
+ DWORD ui_state;
+ RECT rcTextMargin;
+ BUTTON_IMAGELIST imlData;
+#endif
+} BUTTON_INFO;
+
+static UINT BUTTON_CalcLabelRect( const BUTTON_INFO *infoPtr, HDC hdc, RECT *rc );
+static void PB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
+static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
+static void GB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
+static void UB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
+static void OB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
static void BUTTON_CheckAutoRadioButton( HWND hwnd );
#define MAX_BTN_TYPE 16
@@ -114,10 +132,24 @@ static const WORD maxCheckState[MAX_BTN_TYPE] =
BST_UNCHECKED, /* BS_USERBUTTON */
BST_CHECKED, /* BS_AUTORADIOBUTTON */
BST_UNCHECKED, /* BS_PUSHBOX */
- BST_UNCHECKED /* BS_OWNERDRAW */
+ BST_UNCHECKED, /* BS_OWNERDRAW */
+ BST_UNCHECKED, /* BS_SPLITBUTTON */
+ BST_UNCHECKED, /* BS_DEFSPLITBUTTON */
+ BST_UNCHECKED, /* BS_COMMANDLINK */
+ BST_UNCHECKED /* BS_DEFCOMMANDLINK */
};
-typedef void (*pfPaint)( HWND hwnd, HDC hdc, UINT action );
+/* These are indices into a states array to determine the theme state for a given theme
part. */
+typedef enum
+{
+ STATE_NORMAL,
+ STATE_DISABLED,
+ STATE_HOT,
+ STATE_PRESSED,
+ STATE_DEFAULTED
+} ButtonState;
+
+typedef void (*pfPaint)( const BUTTON_INFO *infoPtr, HDC hdc, UINT action );
static const pfPaint btnPaintFunc[MAX_BTN_TYPE] =
{
@@ -132,88 +164,76 @@ static const pfPaint btnPaintFunc[MAX_BTN_TYPE] =
UB_Paint, /* BS_USERBUTTON */
CB_Paint, /* BS_AUTORADIOBUTTON */
NULL, /* BS_PUSHBOX */
- OB_Paint /* BS_OWNERDRAW */
+ OB_Paint, /* BS_OWNERDRAW */
+ PB_Paint, /* BS_SPLITBUTTON */
+ PB_Paint, /* BS_DEFSPLITBUTTON */
+ PB_Paint, /* BS_COMMANDLINK */
+ PB_Paint /* BS_DEFCOMMANDLINK */
};
-/* The original code from user32 was kept in order to make it easier to bring changes
from user32 */
-#ifdef _USER32_
-/*********************************************************************
- * button class descriptor
- */
-static const WCHAR buttonW[] =
{'B','u','t','t','o','n',0};
-const struct builtin_class_descr BUTTON_builtin_class =
-{
- buttonW, /* name */
- CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC, /* style */
-#ifdef __REACTOS__
- ButtonWndProcA, /* procA */
- ButtonWndProcW, /* procW */
-#else
- WINPROC_BUTTON, /* proc */
-#endif
- NB_EXTRA_BYTES, /* extra */
- IDC_ARROW, /* cursor */
- 0 /* brush */
-};
-
-
-static inline LONG get_button_state( HWND hwnd )
-{
- return GetWindowLongPtrW( hwnd, STATE_GWL_OFFSET );
-}
-static inline void set_button_state( HWND hwnd, LONG state )
-{
- SetWindowLongPtrW( hwnd, STATE_GWL_OFFSET, state );
-}
+#ifdef __REACTOS__ /* r73885 */
+typedef void (*pfThemedPaint)( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc,
ButtonState drawState, UINT dtflags, BOOL focused, LPARAM prfFlag);
-#ifdef __REACTOS__
+static void PB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc,
ButtonState drawState, UINT dtflags, BOOL focused, LPARAM prfFlag);
+static void CB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc,
ButtonState drawState, UINT dtflags, BOOL focused, LPARAM prfFlag);
+static void GB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc,
ButtonState drawState, UINT dtflags, BOOL focused, LPARAM prfFlag);
-static __inline void set_ui_state( HWND hwnd, LONG flags )
-{
- SetWindowLongPtrW( hwnd, UISTATE_GWL_OFFSET, flags );
-}
-
-static __inline LONG get_ui_state( HWND hwnd )
-{
- return GetWindowLongPtrW( hwnd, UISTATE_GWL_OFFSET );
-}
+#else
+typedef void (*pfThemedPaint)( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc,
ButtonState drawState, UINT dtflags, BOOL focused);
-#endif /* __REACTOS__ */
+static void PB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc,
ButtonState drawState, UINT dtflags, BOOL focused);
+static void CB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc,
ButtonState drawState, UINT dtflags, BOOL focused);
+static void GB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc,
ButtonState drawState, UINT dtflags, BOOL focused);
-static inline HFONT get_button_font( HWND hwnd )
-{
- return (HFONT)GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET );
-}
+#endif
-static inline void set_button_font( HWND hwnd, HFONT font )
+static const pfThemedPaint btnThemedPaintFunc[MAX_BTN_TYPE] =
{
- SetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET, (LONG_PTR)font );
-}
+ PB_ThemedPaint, /* BS_PUSHBUTTON */
+ PB_ThemedPaint, /* BS_DEFPUSHBUTTON */
+ CB_ThemedPaint, /* BS_CHECKBOX */
+ CB_ThemedPaint, /* BS_AUTOCHECKBOX */
+ CB_ThemedPaint, /* BS_RADIOBUTTON */
+ CB_ThemedPaint, /* BS_3STATE */
+ CB_ThemedPaint, /* BS_AUTO3STATE */
+ GB_ThemedPaint, /* BS_GROUPBOX */
+ NULL, /* BS_USERBUTTON */
+ CB_ThemedPaint, /* BS_AUTORADIOBUTTON */
+ NULL, /* BS_PUSHBOX */
+ NULL, /* BS_OWNERDRAW */
+ NULL, /* BS_SPLITBUTTON */
+ NULL, /* BS_DEFSPLITBUTTON */
+ NULL, /* BS_COMMANDLINK */
+ NULL, /* BS_DEFCOMMANDLINK */
+};
static inline UINT get_button_type( LONG window_style )
{
return (window_style & BS_TYPEMASK);
}
+#ifndef __REACTOS__
/* paint a button of any type */
-static inline void paint_button( HWND hwnd, LONG style, UINT action )
+static inline void paint_button( BUTTON_INFO *infoPtr, LONG style, UINT action )
{
- if (btnPaintFunc[style] && IsWindowVisible(hwnd))
+ if (btnPaintFunc[style] && IsWindowVisible(infoPtr->hwnd))
{
- HDC hdc = GetDC( hwnd );
- btnPaintFunc[style]( hwnd, hdc, action );
- ReleaseDC( hwnd, hdc );
+ HDC hdc = GetDC( infoPtr->hwnd );
+ btnPaintFunc[style]( infoPtr, hdc, action );
+ ReleaseDC( infoPtr->hwnd, hdc );
}
}
+#endif
-#else
-
-#define NtUserAlterWindowStyle SetWindowLongPtrW
-
-static inline void _SetButtonData(HWND hwnd, PBUTTON_DATA data)
+/* retrieve the button text; returned buffer must be freed by caller */
+static inline WCHAR *get_button_text( const BUTTON_INFO *infoPtr )
{
- SetWindowLongPtrW( hwnd, 0, (LONG)data );
+ INT len = GetWindowTextLengthW( infoPtr->hwnd );
+ WCHAR *buffer = heap_alloc( (len + 1) * sizeof(WCHAR) );
+ if (buffer)
+ GetWindowTextW( infoPtr->hwnd, buffer, len + 1 );
+ return buffer;
}
HRGN set_control_clipping( HDC hdc, const RECT *rect )
@@ -236,81 +256,153 @@ HRGN set_control_clipping( HDC hdc, const RECT *rect )
return hrgn;
}
-BOOL BUTTON_PaintWithTheme(HTHEME theme, HWND hwnd, HDC hParamDC, LPARAM prfFlag);
-WCHAR *get_button_text( HWND hwnd );
-
-static inline LONG_PTR get_button_image(HWND hwnd)
+/**********************************************************************
+ * Convert button styles to flags used by DrawText.
+ */
+static UINT BUTTON_BStoDT( DWORD style, DWORD ex_style )
{
- return _GetButtonData(hwnd)->image;
-}
+ UINT dtStyle = DT_NOCLIP; /* We use SelectClipRgn to limit output */
-static inline LONG_PTR set_button_image(HWND hwnd, LONG_PTR image)
-{
- PBUTTON_DATA data = _GetButtonData(hwnd);
- LONG_PTR ret = data->image;
- data->image = image;
- return ret;
-}
+ /* "Convert" pushlike buttons to pushbuttons */
+ if (style & BS_PUSHLIKE)
+ style &= ~BS_TYPEMASK;
-static inline LONG get_button_state( HWND hwnd )
-{
- return _GetButtonData(hwnd)->state;
-}
+ if (!(style & BS_MULTILINE))
+ dtStyle |= DT_SINGLELINE;
+ else
+ dtStyle |= DT_WORDBREAK;
-static inline void set_button_state( HWND hwnd, LONG state )
-{
- _GetButtonData(hwnd)->state = state;
-}
+ switch (style & BS_CENTER)
+ {
+ case BS_LEFT: /* DT_LEFT is 0 */ break;
+ case BS_RIGHT: dtStyle |= DT_RIGHT; break;
+ case BS_CENTER: dtStyle |= DT_CENTER; break;
+ default:
+ /* Pushbutton's text is centered by default */
+ if (get_button_type(style) <= BS_DEFPUSHBUTTON) dtStyle |= DT_CENTER;
+ /* all other flavours have left aligned text */
+ }
-static __inline void set_ui_state( HWND hwnd, LONG flags )
-{
- _GetButtonData(hwnd)->ui_state = flags;
-}
+ if (ex_style & WS_EX_RIGHT) dtStyle = DT_RIGHT | (dtStyle & ~(DT_LEFT |
DT_CENTER));
-static __inline LONG get_ui_state( HWND hwnd )
-{
- return _GetButtonData(hwnd)->ui_state;
-}
+ /* DrawText ignores vertical alignment for multiline text,
+ * but we use these flags to align label manually.
+ */
+ if (get_button_type(style) != BS_GROUPBOX)
+ {
+ switch (style & BS_VCENTER)
+ {
+ case BS_TOP: /* DT_TOP is 0 */ break;
+ case BS_BOTTOM: dtStyle |= DT_BOTTOM; break;
+ case BS_VCENTER: /* fall through */
+ default: dtStyle |= DT_VCENTER; break;
+ }
+ }
+ else
+ /* GroupBox's text is always single line and is top aligned. */
+ dtStyle |= DT_SINGLELINE;
-static inline HFONT get_button_font( HWND hwnd )
-{
- return (HFONT)_GetButtonData(hwnd)->font;
+ return dtStyle;
}
-static inline void set_button_font( HWND hwnd, HFONT font )
-{
- _GetButtonData(hwnd)->font = font;
-}
-static inline UINT get_button_type( LONG window_style )
+#ifdef __REACTOS__
+BOOL BUTTON_PaintWithTheme(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hParamDC, LPARAM
prfFlag)
{
- return (window_style & BS_TYPEMASK);
+ DWORD dwStyle;
+ DWORD dwStyleEx;
+ DWORD type;
+ UINT dtFlags;
+ ButtonState drawState;
+ pfThemedPaint paint;
+
+ /* Don't draw with themes on a button with BS_ICON or BS_BITMAP */
+ if (infoPtr->u.image != 0)
+ return FALSE;
+
+ dwStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
+ type = get_button_type(dwStyle);
+
+ if (type != BS_PUSHBUTTON && type != BS_DEFPUSHBUTTON && (dwStyle
& BS_PUSHLIKE))
+ type = BS_PUSHBUTTON;
+
+ paint = btnThemedPaintFunc[type];
+ if (!paint)
+ return FALSE;
+
+ dwStyleEx = GetWindowLongW(infoPtr->hwnd, GWL_EXSTYLE);
+ dtFlags = BUTTON_BStoDT(dwStyle, dwStyleEx);
+
+ if(dwStyle & WS_DISABLED)
+ drawState = STATE_DISABLED;
+ else if(infoPtr->state & BST_PUSHED)
+ drawState = STATE_PRESSED;
+ else if ((dwStyle & BS_PUSHLIKE) && (infoPtr->state &
(BST_CHECKED|BST_INDETERMINATE)))
+ drawState = STATE_PRESSED;
+ else if(infoPtr->state & BST_HOT)
+ drawState = STATE_HOT;
+ else if((infoPtr->state & BST_FOCUS) || (dwStyle & BS_DEFPUSHBUTTON))
+ drawState = STATE_DEFAULTED;
+ else
+ drawState = STATE_NORMAL;
+
+ if (paint == PB_ThemedPaint || paint == CB_ThemedPaint)
+ {
+ HDC hdc;
+ HBITMAP hbmp;
+ RECT rc;
+
+ GetClientRect(infoPtr->hwnd, &rc);
+ hdc = CreateCompatibleDC(hParamDC);
+ hbmp = CreateCompatibleBitmap(hParamDC, rc.right, rc.bottom);
+ if (hdc && hbmp)
+ {
+ SelectObject(hdc, hbmp);
+
+ paint(theme, infoPtr, hdc, drawState, dtFlags, infoPtr->state &
BST_FOCUS, prfFlag);
+
+ BitBlt(hParamDC, 0, 0, rc.right, rc.bottom, hdc, 0, 0, SRCCOPY);
+ DeleteObject(hbmp);
+ DeleteDC(hdc);
+ return TRUE;
+ }
+ else
+ {
+ ERR("Failed to create DC and bitmap for double buffering\n");
+ if (hbmp)
+ DeleteObject(hbmp);
+ if (hdc)
+ DeleteDC(hdc);
+ }
+ }
+
+ paint(theme, infoPtr, hParamDC, drawState, dtFlags, infoPtr->state &
BST_FOCUS, prfFlag);
+ return TRUE;
}
/* paint a button of any type */
-static inline void paint_button( HWND hwnd, LONG style, UINT action )
+static inline void paint_button( BUTTON_INFO *infoPtr, LONG style, UINT action )
{
- HTHEME theme = GetWindowTheme(hwnd);
+ HTHEME theme = GetWindowTheme(infoPtr->hwnd);
RECT rc;
- HDC hdc = GetDC( hwnd );
+ HDC hdc = GetDC( infoPtr->hwnd );
/* GetDC appears to give a dc with a clip rect that includes the whoe parent, not
sure if it is correct or not. */
- GetClientRect(hwnd, &rc);
+ GetClientRect(infoPtr->hwnd, &rc);
IntersectClipRect (hdc, rc.left, rc. top, rc.right, rc.bottom);
- if (theme && BUTTON_PaintWithTheme(theme, hwnd, hdc, 0))
+ if (theme && BUTTON_PaintWithTheme(theme, infoPtr, hdc, 0))
{
- ReleaseDC( hwnd, hdc );
+ ReleaseDC( infoPtr->hwnd, hdc );
return;
}
- if (btnPaintFunc[style] && IsWindowVisible(hwnd))
+ if (btnPaintFunc[style] && IsWindowVisible(infoPtr->hwnd))
{
- btnPaintFunc[style]( hwnd, hdc, action );
+ btnPaintFunc[style]( infoPtr, hdc, action );
}
- ReleaseDC( hwnd, hdc );
+ ReleaseDC( infoPtr->hwnd, hdc );
}
-BOOL BUTTON_GetIdealSize(HTHEME theme, HWND hwnd, SIZE* psize)
+BOOL BUTTON_GetIdealSize(BUTTON_INFO *infoPtr, HTHEME theme, SIZE* psize)
{
- PBUTTON_DATA pdata;
HDC hdc;
WCHAR *text;
HFONT hFont = 0, hPrevFont = 0;
@@ -318,10 +410,9 @@ BOOL BUTTON_GetIdealSize(HTHEME theme, HWND hwnd, SIZE* psize)
BOOL ret = FALSE;
LOGFONTW logfont = {0};
- pdata = _GetButtonData(hwnd);
- text = get_button_text( hwnd );
- hdc = GetDC(hwnd);
- if (!pdata || !text || !hdc || !text[0])
+ text = get_button_text(infoPtr);
+ hdc = GetDC(infoPtr->hwnd);
+ if (!text || !hdc || !text[0])
goto cleanup;
/* FIXME : Should use GetThemeTextExtent but unfortunately uses DrawTextW which is
broken */
@@ -337,8 +428,8 @@ BOOL BUTTON_GetIdealSize(HTHEME theme, HWND hwnd, SIZE* psize)
}
else
{
- if (pdata->font)
- hPrevFont = SelectObject( hdc, pdata->font );
+ if (infoPtr->font)
+ hPrevFont = SelectObject( hdc, infoPtr->font );
}
GetTextExtentPoint32W(hdc, text, wcslen(text), &TextSize);
@@ -352,13 +443,13 @@ BOOL BUTTON_GetIdealSize(HTHEME theme, HWND hwnd, SIZE* psize)
if (hPrevFont)
SelectObject( hdc, hPrevFont );
- TextSize.cy += pdata->rcTextMargin.top + pdata->rcTextMargin.bottom;
- TextSize.cx += pdata->rcTextMargin.left + pdata->rcTextMargin.right;
+ TextSize.cy += infoPtr->rcTextMargin.top + infoPtr->rcTextMargin.bottom;
+ TextSize.cx += infoPtr->rcTextMargin.left + infoPtr->rcTextMargin.right;
- if (pdata->imlData.himl && ImageList_GetIconSize(pdata->imlData.himl,
&ImageSize.cx, &ImageSize.cy))
+ if (infoPtr->imlData.himl &&
ImageList_GetIconSize(infoPtr->imlData.himl, &ImageSize.cx, &ImageSize.cy))
{
- ImageSize.cx += pdata->imlData.margin.left + pdata->imlData.margin.right;
- ImageSize.cy += pdata->imlData.margin.top + pdata->imlData.margin.bottom;
+ ImageSize.cx += infoPtr->imlData.margin.left +
infoPtr->imlData.margin.right;
+ ImageSize.cy += infoPtr->imlData.margin.top +
infoPtr->imlData.margin.bottom;
}
else
{
@@ -390,12 +481,12 @@ cleanup:
if (text)
HeapFree( GetProcessHeap(), 0, text );
if (hdc)
- ReleaseDC(hwnd, hdc);
+ ReleaseDC(infoPtr->hwnd, hdc);
return ret;
}
-BOOL BUTTON_DrawIml(HDC hDC, BUTTON_IMAGELIST *pimlData, RECT *prc, BOOL bOnlyCalc, int
index)
+BOOL BUTTON_DrawIml(HDC hDC, const BUTTON_IMAGELIST *pimlData, RECT *prc, BOOL bOnlyCalc,
int index)
{
SIZE ImageSize;
int left, top, count;
@@ -451,13 +542,12 @@ BOOL BUTTON_DrawIml(HDC hDC, BUTTON_IMAGELIST *pimlData, RECT *prc,
BOOL bOnlyCa
return TRUE;
}
-DWORD BUTTON_SendCustomDraw(HWND hwnd, HDC hDC, DWORD dwDrawStage, RECT* prc)
+DWORD BUTTON_SendCustomDraw(const BUTTON_INFO *infoPtr, HDC hDC, DWORD dwDrawStage, RECT*
prc)
{
NMCUSTOMDRAW nmcs;
- LONG state = get_button_state( hwnd );
- nmcs.hdr.hwndFrom = hwnd;
- nmcs.hdr.idFrom = GetWindowLongPtrW (hwnd, GWLP_ID);
+ nmcs.hdr.hwndFrom = infoPtr->hwnd;
+ nmcs.hdr.idFrom = GetWindowLongPtrW (infoPtr->hwnd, GWLP_ID);
nmcs.hdr.code = NM_CUSTOMDRAW ;
nmcs.dwDrawStage = dwDrawStage;
nmcs.hdc = hDC;
@@ -465,48 +555,28 @@ DWORD BUTTON_SendCustomDraw(HWND hwnd, HDC hDC, DWORD dwDrawStage,
RECT* prc)
nmcs.dwItemSpec = 0;
nmcs.uItemState = 0;
nmcs.lItemlParam = 0;
- if(!IsWindowEnabled(hwnd))
+ if(!IsWindowEnabled(infoPtr->hwnd))
nmcs.uItemState |= CDIS_DISABLED;
- if (state & (BST_CHECKED | BST_INDETERMINATE))
+ if (infoPtr->state & (BST_CHECKED | BST_INDETERMINATE))
nmcs.uItemState |= CDIS_CHECKED;
- if (state & BST_FOCUS)
+ if (infoPtr->state & BST_FOCUS)
nmcs.uItemState |= CDIS_FOCUS;
- if (state & BST_PUSHED)
+ if (infoPtr->state & BST_PUSHED)
nmcs.uItemState |= CDIS_SELECTED;
- if (!(get_ui_state(hwnd) & UISF_HIDEACCEL))
+ if (!(infoPtr->ui_state & UISF_HIDEACCEL))
nmcs.uItemState |= CDIS_SHOWKEYBOARDCUES;
- return SendMessageW(GetParent(hwnd), WM_NOTIFY, nmcs.hdr.idFrom, (LPARAM)&nmcs);
+ return SendMessageW(GetParent(infoPtr->hwnd), WM_NOTIFY, nmcs.hdr.idFrom,
(LPARAM)&nmcs);
}
-#endif
-
-
-/* retrieve the button text; returned buffer must be freed by caller */
-inline WCHAR *get_button_text( HWND hwnd )
-{
- INT len = 512;
- WCHAR *buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
- if (buffer) InternalGetWindowText( hwnd, buffer, len + 1 );
- return buffer;
-}
-
-#ifdef __REACTOS__
/* Retrieve the UI state for the control */
-static BOOL button_update_uistate(HWND hwnd, BOOL unicode)
+static BOOL button_update_uistate(BUTTON_INFO *infoPtr)
{
- LONG flags, prevflags;
-
- if (unicode)
- flags = DefWindowProcW(hwnd, WM_QUERYUISTATE, 0, 0);
- else
- flags = DefWindowProcA(hwnd, WM_QUERYUISTATE, 0, 0);
-
- prevflags = get_ui_state(hwnd);
+ LONG flags = DefWindowProcW(infoPtr->hwnd, WM_QUERYUISTATE, 0, 0);
- if (prevflags != flags)
+ if (infoPtr->ui_state != flags)
{
- set_ui_state(hwnd, flags);
+ infoPtr->ui_state = flags;
return TRUE;
}
@@ -514,222 +584,65 @@ static BOOL button_update_uistate(HWND hwnd, BOOL unicode)
}
#endif
-/***********************************************************************
- * ButtonWndProc_common
- */
-LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
- WPARAM wParam, LPARAM lParam, BOOL unicode )
+static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
lParam)
{
+ BUTTON_INFO *infoPtr = (BUTTON_INFO *)GetWindowLongPtrW(hWnd, 0);
RECT rect;
POINT pt;
- LONG style = GetWindowLongPtrW( hWnd, GWL_STYLE );
+ LONG style = GetWindowLongW( hWnd, GWL_STYLE );
UINT btn_type = get_button_type( style );
- LONG state;
+ LONG state, new_state;
HANDLE oldHbitmap;
-#if defined(__REACTOS__) && defined(_USER32_)
- PWND pWnd;
+ HTHEME theme;
- pWnd = ValidateHwnd(hWnd);
- if (pWnd)
- {
- if (!pWnd->fnid)
- {
- NtUserSetWindowFNID(hWnd, FNID_BUTTON);
- }
- else
- {
- if (pWnd->fnid != FNID_BUTTON)
- {
- ERR("Wrong window class for Button! fnId 0x%x\n",pWnd->fnid);
- return 0;
- }
- }
- }
- else
- return 0;
-#else
if (!IsWindow( hWnd )) return 0;
-#endif
+
+ if (!infoPtr && (uMsg != WM_NCCREATE))
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
pt.x = (short)LOWORD(lParam);
pt.y = (short)HIWORD(lParam);
-#ifndef _USER32_
- switch (uMsg)
- {
- case WM_NCCREATE:
- {
- PBUTTON_DATA data = HeapAlloc( GetProcessHeap(), 0, sizeof(BUTTON_DATA) );
- if (!data)
- {
- ERR("Failed to alloc internal button data\n");
- return -1;
- }
-
- memset(data, 0, sizeof(BUTTON_DATA));
- SetRect(&data->rcTextMargin, 1,1,1,1);
-
- _SetButtonData(hWnd, data);
- break;
- }
- case WM_NCDESTROY:
- {
- PBUTTON_DATA data = _GetButtonData(hWnd);
- if (!data)
- {
- ERR("No data");
- return 0;
- }
- HeapFree( GetProcessHeap(), 0, data );
- _SetButtonData(hWnd, NULL);
- }
- case WM_CREATE:
- OpenThemeData(hWnd, WC_BUTTONW);
- break;
- case WM_DESTROY:
- CloseThemeData (GetWindowTheme(hWnd));
- break;
- case WM_THEMECHANGED:
- CloseThemeData (GetWindowTheme(hWnd));
- OpenThemeData(hWnd, WC_BUTTONW);
- InvalidateRect(hWnd, NULL, TRUE);
- break;
- case WM_MOUSELEAVE:
- {
- state = get_button_state( hWnd );
- if (state & BST_HOT)
- {
- NMBCHOTITEM nmhotitem;
-
- state &= ~BST_HOT;
- set_button_state(hWnd, state);
-
- nmhotitem.hdr.hwndFrom = hWnd;
- nmhotitem.hdr.idFrom = GetWindowLongPtrW (hWnd, GWLP_ID);
- nmhotitem.hdr.code = BCN_HOTITEMCHANGE;
- nmhotitem.dwFlags = HICF_LEAVING;
- SendMessageW(GetParent(hWnd), WM_NOTIFY, nmhotitem.hdr.idFrom,
(LPARAM)&nmhotitem);
-
- InvalidateRect(hWnd, NULL, TRUE);
- }
- break;
- }
- case WM_MOUSEMOVE:
- {
- TRACKMOUSEEVENT mouse_event;
- state = get_button_state( hWnd );
- if ((state & BST_HOT) == 0)
- {
- NMBCHOTITEM nmhotitem;
-
- state |= BST_HOT;
- set_button_state(hWnd, state);
-
- nmhotitem.hdr.hwndFrom = hWnd;
- nmhotitem.hdr.idFrom = GetWindowLongPtrW (hWnd, GWLP_ID);
- nmhotitem.hdr.code = BCN_HOTITEMCHANGE;
- nmhotitem.dwFlags = HICF_ENTERING;
- SendMessageW(GetParent(hWnd), WM_NOTIFY, nmhotitem.hdr.idFrom,
(LPARAM)&nmhotitem);
-
- InvalidateRect(hWnd, NULL, TRUE);
- }
-
- mouse_event.cbSize = sizeof(TRACKMOUSEEVENT);
- mouse_event.dwFlags = TME_QUERY;
- if(!TrackMouseEvent(&mouse_event) ||
!(mouse_event.dwFlags&TME_LEAVE))
- {
- mouse_event.dwFlags = TME_LEAVE;
- mouse_event.hwndTrack = hWnd;
- mouse_event.dwHoverTime = 1;
- TrackMouseEvent(&mouse_event);
- }
- break;
- }
- case BCM_GETTEXTMARGIN:
- {
- RECT* prc = (RECT*)lParam;
- PBUTTON_DATA data = _GetButtonData(hWnd);
- if (!prc || !data)
- return FALSE;
- *prc = data->rcTextMargin;
- return TRUE;
- }
- case BCM_SETTEXTMARGIN:
- {
- RECT* prc = (RECT*)lParam;
- PBUTTON_DATA data = _GetButtonData(hWnd);
- if (!prc || !data)
- return FALSE;
- data->rcTextMargin = *prc;
- return TRUE;
- }
- case BCM_SETIMAGELIST:
- {
- BUTTON_IMAGELIST * pimldata = (BUTTON_IMAGELIST *)lParam;
- PBUTTON_DATA data = _GetButtonData(hWnd);
- if (!data || !pimldata || !pimldata->himl)
- return FALSE;
- data->imlData = *pimldata;
- return TRUE;
- }
- case BCM_GETIMAGELIST:
- {
- BUTTON_IMAGELIST * pimldata = (BUTTON_IMAGELIST *)lParam;
- PBUTTON_DATA data = _GetButtonData(hWnd);
- if (!data|| !pimldata)
- return FALSE;
- *pimldata = data->imlData;
- return TRUE;
- }
- case BCM_GETIDEALSIZE:
- {
- HTHEME theme = GetWindowTheme(hWnd);
- BOOL ret = FALSE;
- SIZE* pSize = (SIZE*)lParam;
-
- if (btn_type == BS_PUSHBUTTON ||
- btn_type == BS_DEFPUSHBUTTON ||
- btn_type == BS_USERBUTTON)
- {
- ret = BUTTON_GetIdealSize(theme, hWnd, pSize);
- }
-
- if (!ret)
- {
- GetClientRect(hWnd, &rect);
- pSize->cx = rect.right;
- pSize->cy = rect.bottom;
- }
-
- return TRUE;
- }
- }
-
- if (!_GetButtonData(hWnd))
- {
- ERR("no data!\n");
- return unicode ? DefWindowProcW(hWnd, uMsg, wParam, lParam) :
- DefWindowProcA(hWnd, uMsg, wParam, lParam);
- }
-
-#endif
-
switch (uMsg)
{
case WM_GETDLGCODE:
switch(btn_type)
{
+ case BS_COMMANDLINK:
case BS_USERBUTTON:
case BS_PUSHBUTTON: return DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON;
+ case BS_DEFCOMMANDLINK:
case BS_DEFPUSHBUTTON: return DLGC_BUTTON | DLGC_DEFPUSHBUTTON;
case BS_RADIOBUTTON:
case BS_AUTORADIOBUTTON: return DLGC_BUTTON | DLGC_RADIOBUTTON;
case BS_GROUPBOX: return DLGC_STATIC;
+ case BS_SPLITBUTTON: return DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON |
DLGC_WANTARROWS;
+ case BS_DEFSPLITBUTTON: return DLGC_BUTTON | DLGC_DEFPUSHBUTTON |
DLGC_WANTARROWS;
default: return DLGC_BUTTON;
}
case WM_ENABLE:
- paint_button( hWnd, btn_type, ODA_DRAWENTIRE );
+#ifndef __REACTOS__
+ theme = GetWindowTheme( hWnd );
+ if (theme)
+ RedrawWindow( hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW
);
+ else
+#endif
+ paint_button( infoPtr, btn_type, ODA_DRAWENTIRE );
+ break;
+
+ case WM_NCCREATE:
+ infoPtr = heap_alloc_zero( sizeof(*infoPtr) );
+ SetWindowLongPtrW( hWnd, 0, (LONG_PTR)infoPtr );
+ infoPtr->hwnd = hWnd;
+#ifdef __REACTOS__
+ SetRect(&infoPtr->rcTextMargin, 1,1,1,1);
+#endif
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+
+ case WM_NCDESTROY:
+ SetWindowLongPtrW( hWnd, 0, 0 );
+ heap_free(infoPtr);
break;
case WM_CREATE:
@@ -740,24 +653,26 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
if (btn_type == BS_USERBUTTON )
{
style = (style & ~BS_TYPEMASK) | BS_PUSHBUTTON;
-#ifdef __REACTOS__
- NtUserAlterWindowStyle(hWnd, GWL_STYLE, style );
-#else
- WIN_SetStyle( hWnd, style, BS_TYPEMASK & ~style );
-#endif
+ SetWindowLongW( hWnd, GWL_STYLE, style );
}
- set_button_state( hWnd, BST_UNCHECKED );
-#ifdef __REACTOS__
- button_update_uistate( hWnd, unicode );
-#endif
+ infoPtr->state = BST_UNCHECKED;
+ OpenThemeData( hWnd, WC_BUTTONW );
return 0;
-#if defined(__REACTOS__) && defined(_USER32_)
- case WM_NCDESTROY:
- NtUserSetWindowFNID(hWnd, FNID_DESTROY);
case WM_DESTROY:
+ theme = GetWindowTheme( hWnd );
+ CloseThemeData( theme );
break;
+
+ case WM_THEMECHANGED:
+ theme = GetWindowTheme( hWnd );
+ CloseThemeData( theme );
+ OpenThemeData( hWnd, WC_BUTTONW );
+#ifdef __REACTOS__
+ InvalidateRect(hWnd, NULL, TRUE);
#endif
+ break;
+
case WM_ERASEBKGND:
if (btn_type == BS_OWNERDRAW)
{
@@ -766,14 +681,10 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
HBRUSH hBrush;
HWND parent = GetParent(hWnd);
if (!parent) parent = hWnd;
-#if defined(__REACTOS__) && defined(_USER32_)
- hBrush = GetControlColor( parent, hWnd, hdc, WM_CTLCOLORBTN);
-#else
hBrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORBTN, (WPARAM)hdc,
(LPARAM)hWnd);
if (!hBrush) /* did the app forget to call defwindowproc ? */
hBrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORBTN,
(WPARAM)hdc, (LPARAM)hWnd);
-#endif
GetClientRect(hWnd, &rc);
FillRect(hdc, &rc, hBrush);
}
@@ -783,21 +694,44 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
case WM_PAINT:
{
PAINTSTRUCT ps;
- HDC hdc = wParam ? (HDC)wParam : BeginPaint( hWnd, &ps );
-#ifndef _USER32_
- HTHEME theme = GetWindowTheme(hWnd);
- if (theme && BUTTON_PaintWithTheme(theme, hWnd, hdc, uMsg ==
WM_PRINTCLIENT ? lParam : 0))
+ HDC hdc;
+
+ theme = GetWindowTheme( hWnd );
+ hdc = wParam ? (HDC)wParam : BeginPaint( hWnd, &ps );
+
+#ifdef __REACTOS__
+ if (theme && BUTTON_PaintWithTheme(theme, infoPtr, hdc, uMsg ==
WM_PRINTCLIENT ? lParam : 0))
{
if ( !wParam ) EndPaint( hWnd, &ps );
return 0;
}
+#else
+ if (theme && btnThemedPaintFunc[btn_type])
+ {
+ ButtonState drawState;
+ UINT dtflags;
+
+ if (IsWindowEnabled( hWnd ))
+ {
+ if (infoPtr->state & BST_PUSHED) drawState = STATE_PRESSED;
+ else if (infoPtr->state & BST_HOT) drawState = STATE_HOT;
+ else if (infoPtr->state & BST_FOCUS) drawState = STATE_DEFAULTED;
+ else drawState = STATE_NORMAL;
+ }
+ else
+ drawState = STATE_DISABLED;
+
+ dtflags = BUTTON_BStoDT(style, GetWindowLongW(hWnd, GWL_EXSTYLE));
+ btnThemedPaintFunc[btn_type](theme, infoPtr, hdc, drawState, dtflags,
infoPtr->state & BST_FOCUS);
+ }
#endif
- if (btnPaintFunc[btn_type])
+ else if (btnPaintFunc[btn_type])
{
int nOldMode = SetBkMode( hdc, OPAQUE );
- (btnPaintFunc[btn_type])( hWnd, hdc, ODA_DRAWENTIRE );
+ btnPaintFunc[btn_type]( infoPtr, hdc, ODA_DRAWENTIRE );
SetBkMode(hdc, nOldMode); /* reset painting mode */
}
+
if ( !wParam ) EndPaint( hWnd, &ps );
break;
}
@@ -806,7 +740,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
if (wParam == VK_SPACE)
{
SendMessageW( hWnd, BM_SETSTATE, TRUE, 0 );
- set_button_state( hWnd, get_button_state( hWnd ) | BUTTON_BTNPRESSED );
+ infoPtr->state |= BUTTON_BTNPRESSED;
SetCapture( hWnd );
}
break;
@@ -824,7 +758,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
case WM_LBUTTONDOWN:
SetCapture( hWnd );
SetFocus( hWnd );
- set_button_state( hWnd, get_button_state( hWnd ) | BUTTON_BTNPRESSED );
+ infoPtr->state |= BUTTON_BTNPRESSED;
SendMessageW( hWnd, BM_SETSTATE, TRUE, 0 );
break;
@@ -833,13 +767,9 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
break;
/* fall through */
case WM_LBUTTONUP:
-#ifdef _REACTOS_
- BOOL TellParent = FALSE; //// ReactOS see note below.
-#endif
- state = get_button_state( hWnd );
+ state = infoPtr->state;
if (!(state & BUTTON_BTNPRESSED)) break;
- state &= BUTTON_NSTATES;
- set_button_state( hWnd, state );
+ infoPtr->state &= BUTTON_NSTATES;
if (!(state & BST_PUSHED))
{
ReleaseCapture();
@@ -849,68 +779,196 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
GetClientRect( hWnd, &rect );
if (uMsg == WM_KEYUP || PtInRect( &rect, pt ))
{
- state = get_button_state( hWnd );
switch(btn_type)
{
case BS_AUTOCHECKBOX:
- SendMessageW( hWnd, BM_SETCHECK, !(state & BST_CHECKED), 0 );
+ SendMessageW( hWnd, BM_SETCHECK, !(infoPtr->state & BST_CHECKED),
0 );
break;
case BS_AUTORADIOBUTTON:
SendMessageW( hWnd, BM_SETCHECK, TRUE, 0 );
break;
case BS_AUTO3STATE:
- SendMessageW( hWnd, BM_SETCHECK,
- (state & BST_INDETERMINATE) ? 0 : ((state & 3) +
1), 0 );
+ SendMessageW( hWnd, BM_SETCHECK, (infoPtr->state &
BST_INDETERMINATE) ? 0 :
+ ((infoPtr->state & 3) + 1), 0 );
break;
}
-#ifdef _REACTOS_
- TellParent = TRUE; // <---- Fix CORE-10194, Notify parent after capture is
released.
-#else
+#ifdef __REACTOS__
+ // Fix CORE-10194, Notify parent after capture is released.
ReleaseCapture();
BUTTON_NOTIFY_PARENT(hWnd, BN_CLICKED);
+#else
+ BUTTON_NOTIFY_PARENT(hWnd, BN_CLICKED);
+ ReleaseCapture();
#endif
}
-#ifdef _REACTOS_
- ReleaseCapture();
- if (TellParent) BUTTON_NOTIFY_PARENT(hWnd, BN_CLICKED);
-#else
else
{
ReleaseCapture();
}
-#endif
+
break;
case WM_CAPTURECHANGED:
TRACE("WM_CAPTURECHANGED %p\n", hWnd);
if (hWnd == (HWND)lParam) break;
- state = get_button_state( hWnd );
- if (state & BUTTON_BTNPRESSED)
+ if (infoPtr->state & BUTTON_BTNPRESSED)
{
- state &= BUTTON_NSTATES;
- set_button_state( hWnd, state );
- if (state & BST_PUSHED) SendMessageW( hWnd, BM_SETSTATE, FALSE, 0 );
+ infoPtr->state &= BUTTON_NSTATES;
+ if (infoPtr->state & BST_PUSHED)
+ SendMessageW( hWnd, BM_SETSTATE, FALSE, 0 );
}
break;
case WM_MOUSEMOVE:
+ {
+ TRACKMOUSEEVENT mouse_event;
+ mouse_event.cbSize = sizeof(TRACKMOUSEEVENT);
+ mouse_event.dwFlags = TME_QUERY;
+
+#ifdef __REACTOS__
+ if ((infoPtr->state & BST_HOT) == 0)
+ {
+ NMBCHOTITEM nmhotitem;
+
+ infoPtr->state |= BST_HOT;
+
+ nmhotitem.hdr.hwndFrom = hWnd;
+ nmhotitem.hdr.idFrom = GetWindowLongPtrW (hWnd, GWLP_ID);
+ nmhotitem.hdr.code = BCN_HOTITEMCHANGE;
+ nmhotitem.dwFlags = HICF_ENTERING;
+ SendMessageW(GetParent(hWnd), WM_NOTIFY, nmhotitem.hdr.idFrom,
(LPARAM)&nmhotitem);
+
+ InvalidateRect(hWnd, NULL, TRUE);
+ }
+
+ if(!TrackMouseEvent(&mouse_event) || !(mouse_event.dwFlags&TME_LEAVE))
+ {
+ mouse_event.dwFlags = TME_LEAVE;
+ mouse_event.hwndTrack = hWnd;
+ mouse_event.dwHoverTime = 1;
+ TrackMouseEvent(&mouse_event);
+ }
+ break;
+#else
+
+ if (!TrackMouseEvent(&mouse_event) || !(mouse_event.dwFlags & (TME_HOVER
| TME_LEAVE)))
+ {
+ mouse_event.dwFlags = TME_HOVER | TME_LEAVE;
+ mouse_event.hwndTrack = hWnd;
+ mouse_event.dwHoverTime = 1;
+ TrackMouseEvent(&mouse_event);
+ }
+
if ((wParam & MK_LBUTTON) && GetCapture() == hWnd)
{
GetClientRect( hWnd, &rect );
SendMessageW( hWnd, BM_SETSTATE, PtInRect(&rect, pt), 0 );
}
break;
+#endif
+ }
+
+#ifndef __REACTOS__
+ case WM_MOUSEHOVER:
+ {
+ infoPtr->state |= BST_HOT;
+ InvalidateRect( hWnd, NULL, FALSE );
+ break;
+ }
+#endif
+
+ case WM_MOUSELEAVE:
+ {
+#ifdef __REACTOS__
+ if (infoPtr->state & BST_HOT)
+ {
+ NMBCHOTITEM nmhotitem;
+
+ infoPtr->state &= ~BST_HOT;
+
+ nmhotitem.hdr.hwndFrom = hWnd;
+ nmhotitem.hdr.idFrom = GetWindowLongPtrW (hWnd, GWLP_ID);
+ nmhotitem.hdr.code = BCN_HOTITEMCHANGE;
+ nmhotitem.dwFlags = HICF_LEAVING;
+ SendMessageW(GetParent(hWnd), WM_NOTIFY, nmhotitem.hdr.idFrom,
(LPARAM)&nmhotitem);
+
+ InvalidateRect(hWnd, NULL, TRUE);
+ }
+ break;
+#else
+ infoPtr->state &= ~BST_HOT;
+ InvalidateRect( hWnd, NULL, FALSE );
+ break;
+#endif
+ }
+
+#ifdef __REACTOS__
+ case BCM_GETTEXTMARGIN:
+ {
+ RECT* prc = (RECT*)lParam;
+ if (!prc)
+ return FALSE;
+ *prc = infoPtr->rcTextMargin;
+ return TRUE;
+ }
+ case BCM_SETTEXTMARGIN:
+ {
+ RECT* prc = (RECT*)lParam;
+ if (!prc)
+ return FALSE;
+ infoPtr->rcTextMargin = *prc;
+ return TRUE;
+ }
+ case BCM_SETIMAGELIST:
+ {
+ BUTTON_IMAGELIST * pimldata = (BUTTON_IMAGELIST *)lParam;
+ if (!pimldata || !pimldata->himl)
+ return FALSE;
+ infoPtr->imlData = *pimldata;
+ return TRUE;
+ }
+ case BCM_GETIMAGELIST:
+ {
+ BUTTON_IMAGELIST * pimldata = (BUTTON_IMAGELIST *)lParam;
+ if (!pimldata)
+ return FALSE;
+ *pimldata = infoPtr->imlData;
+ return TRUE;
+ }
+ case BCM_GETIDEALSIZE:
+ {
+ HTHEME theme = GetWindowTheme(hWnd);
+ BOOL ret = FALSE;
+ SIZE* pSize = (SIZE*)lParam;
+
+ if (btn_type == BS_PUSHBUTTON ||
+ btn_type == BS_DEFPUSHBUTTON ||
+ btn_type == BS_USERBUTTON)
+ {
+ ret = BUTTON_GetIdealSize(infoPtr, theme, pSize);
+ }
+
+ if (!ret)
+ {
+ GetClientRect(hWnd, &rect);
+ pSize->cx = rect.right;
+ pSize->cy = rect.bottom;
+ }
+
+ return TRUE;
+ }
+#endif
case WM_SETTEXT:
{
/* Clear an old text here as Windows does */
+#ifdef __REACTOS__
//
// ReactOS Note :
// wine Bug:
http://bugs.winehq.org/show_bug.cgi?id=25790
// Patch:
http://source.winehq.org/patches/data/70889
// By: Alexander LAW, Replicate Windows behavior of WM_SETTEXT handler regarding
WM_CTLCOLOR*
//
-#ifdef __REACTOS__
if (style & WS_VISIBLE)
#else
if (IsWindowVisible(hWnd))
@@ -922,28 +980,23 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
HWND parent = GetParent(hWnd);
UINT message = (btn_type == BS_PUSHBUTTON ||
btn_type == BS_DEFPUSHBUTTON ||
- btn_type == BS_PUSHLIKE ||
btn_type == BS_USERBUTTON ||
btn_type == BS_OWNERDRAW) ?
WM_CTLCOLORBTN : WM_CTLCOLORSTATIC;
if (!parent) parent = hWnd;
-#if defined(__REACTOS__) && defined(_USER32_)
- hbrush = GetControlColor(parent, hWnd, hdc, message);
-#else
hbrush = (HBRUSH)SendMessageW(parent, message,
(WPARAM)hdc, (LPARAM)hWnd);
if (!hbrush) /* did the app forget to call DefWindowProc ? */
hbrush = (HBRUSH)DefWindowProcW(parent, message,
(WPARAM)hdc, (LPARAM)hWnd);
-#endif
GetClientRect(hWnd, &client);
rc = client;
/* FIXME: check other BS_* handlers */
if (btn_type == BS_GROUPBOX)
InflateRect(&rc, -7, 1); /* GB_Paint does this */
- BUTTON_CalcLabelRect(hWnd, hdc, &rc);
+ BUTTON_CalcLabelRect(infoPtr, hdc, &rc);
/* Clip by client rect bounds */
if (rc.right > client.right) rc.right = client.right;
if (rc.bottom > client.bottom) rc.bottom = client.bottom;
@@ -951,45 +1004,43 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
ReleaseDC(hWnd, hdc);
}
- if (unicode) DefWindowProcW( hWnd, WM_SETTEXT, wParam, lParam );
- else DefWindowProcA( hWnd, WM_SETTEXT, wParam, lParam );
+ DefWindowProcW( hWnd, WM_SETTEXT, wParam, lParam );
if (btn_type == BS_GROUPBOX) /* Yes, only for BS_GROUPBOX */
InvalidateRect( hWnd, NULL, TRUE );
else
- paint_button( hWnd, btn_type, ODA_DRAWENTIRE );
+ paint_button( infoPtr, btn_type, ODA_DRAWENTIRE );
return 1; /* success. FIXME: check text length */
}
case WM_SETFONT:
- set_button_font( hWnd, (HFONT)wParam );
+ infoPtr->font = (HFONT)wParam;
if (lParam) InvalidateRect(hWnd, NULL, TRUE);
break;
case WM_GETFONT:
- return (LRESULT)get_button_font( hWnd );
+ return (LRESULT)infoPtr->font;
case WM_SETFOCUS:
TRACE("WM_SETFOCUS %p\n",hWnd);
- set_button_state( hWnd, get_button_state(hWnd) | BST_FOCUS );
-#ifndef _USER32_
+ infoPtr->state |= BST_FOCUS;
+#ifdef __REACTOS__
if (btn_type != BS_OWNERDRAW)
InvalidateRect(hWnd, NULL, FALSE);
else
#endif
- paint_button( hWnd, btn_type, ODA_FOCUS );
+ paint_button( infoPtr, btn_type, ODA_FOCUS );
if (style & BS_NOTIFY)
BUTTON_NOTIFY_PARENT(hWnd, BN_SETFOCUS);
break;
case WM_KILLFOCUS:
TRACE("WM_KILLFOCUS %p\n",hWnd);
- state = get_button_state( hWnd );
- set_button_state( hWnd, state & ~BST_FOCUS );
-#ifdef _USER32_
- paint_button( hWnd, btn_type, ODA_FOCUS );
+ infoPtr->state &= ~BST_FOCUS;
+#ifndef __REACTOS__
+ paint_button( infoPtr, btn_type, ODA_FOCUS );
#endif
- if ((state & BUTTON_BTNPRESSED) && GetCapture() == hWnd)
+ if ((infoPtr->state & BUTTON_BTNPRESSED) && GetCapture() == hWnd)
ReleaseCapture();
if (style & BS_NOTIFY)
BUTTON_NOTIFY_PARENT(hWnd, BN_KILLFOCUS);
@@ -1004,11 +1055,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
case BM_SETSTYLE:
btn_type = wParam & BS_TYPEMASK;
style = (style & ~BS_TYPEMASK) | btn_type;
-#ifdef __REACTOS__
- NtUserAlterWindowStyle(hWnd, GWL_STYLE, style);
-#else
- WIN_SetStyle( hWnd, style, BS_TYPEMASK & ~style );
-#endif
+ SetWindowLongW( hWnd, GWL_STYLE, style );
/* Only redraw if lParam flag is set.*/
if (lParam)
@@ -1018,18 +1065,15 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
case BM_CLICK:
#ifdef __REACTOS__
- state = get_button_state(hWnd);
- if (state & BUTTON_BMCLICK)
- break;
- set_button_state(hWnd, state | BUTTON_BMCLICK); // Tracked in STATE_GWL_OFFSET.
+ /* Fix for core CORE-6024 */
+ if (infoPtr->state & BUTTON_BMCLICK)
+ break;
+ infoPtr->state |= BUTTON_BMCLICK;
#endif
SendMessageW( hWnd, WM_LBUTTONDOWN, 0, 0 );
SendMessageW( hWnd, WM_LBUTTONUP, 0, 0 );
#ifdef __REACTOS__
- state = get_button_state(hWnd);
- if (!(state & BUTTON_BMCLICK)) break;
- state &= ~BUTTON_BMCLICK;
- set_button_state(hWnd, state);
+ infoPtr->state &= ~BUTTON_BMCLICK;
#endif
break;
@@ -1046,77 +1090,61 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
default:
return 0;
}
-#ifdef _USER32_
- oldHbitmap = (HBITMAP)SetWindowLongPtrW( hWnd, HIMAGE_GWL_OFFSET, lParam );
-#else
- oldHbitmap = (HBITMAP)set_button_image(hWnd, lParam );
-#endif
+ oldHbitmap = infoPtr->u.image;
+ infoPtr->u.image = (HANDLE)lParam;
InvalidateRect( hWnd, NULL, FALSE );
return (LRESULT)oldHbitmap;
case BM_GETIMAGE:
-#ifdef _USER32_
- return GetWindowLongPtrW( hWnd, HIMAGE_GWL_OFFSET );
-#else
- return get_button_image(hWnd);
-#endif
+ return (LRESULT)infoPtr->u.image;
case BM_GETCHECK:
- return get_button_state( hWnd ) & 3;
+ return infoPtr->state & 3;
case BM_SETCHECK:
if (wParam > maxCheckState[btn_type]) wParam = maxCheckState[btn_type];
- state = get_button_state( hWnd );
- if ((btn_type == BS_RADIOBUTTON) || (btn_type == BS_AUTORADIOBUTTON))
- {
-#ifdef __REACTOS__
- if (wParam) style |= WS_TABSTOP;
- else style &= ~WS_TABSTOP;
- NtUserAlterWindowStyle(hWnd, GWL_STYLE, style);
-#else
- if (wParam) WIN_SetStyle( hWnd, WS_TABSTOP, 0 );
- else WIN_SetStyle( hWnd, 0, WS_TABSTOP );
-#endif
+ if ((btn_type == BS_RADIOBUTTON) || (btn_type == BS_AUTORADIOBUTTON))
+ {
+ style = wParam ? style | WS_TABSTOP : style & ~WS_TABSTOP;
+ SetWindowLongW( hWnd, GWL_STYLE, style );
}
- if ((state & 3) != wParam)
+ if ((infoPtr->state & 3) != wParam)
{
- set_button_state( hWnd, (state & ~3) | wParam );
-#ifdef _USER32
- paint_button( hWnd, btn_type, ODA_SELECT );
-#else
- InvalidateRect(hWnd, NULL, FALSE);
-#endif
+ infoPtr->state = (infoPtr->state & ~3) | wParam;
+ InvalidateRect( hWnd, NULL, FALSE );
}
if ((btn_type == BS_AUTORADIOBUTTON) && (wParam == BST_CHECKED)
&& (style & WS_CHILD))
BUTTON_CheckAutoRadioButton( hWnd );
break;
case BM_GETSTATE:
- return get_button_state( hWnd );
+ return infoPtr->state;
case BM_SETSTATE:
- state = get_button_state( hWnd );
- if (wParam)
- set_button_state( hWnd, state | BST_PUSHED );
- else
- set_button_state( hWnd, state & ~BST_PUSHED );
+ state = infoPtr->state;
+ new_state = wParam ? BST_PUSHED : 0;
-#ifdef _USER32_
- paint_button( hWnd, btn_type, ODA_SELECT );
-#else
- InvalidateRect(hWnd, NULL, FALSE);
-#endif
+ if ((state ^ new_state) & BST_PUSHED)
+ {
+ if (wParam)
+ state |= BST_PUSHED;
+ else
+ state &= ~BST_PUSHED;
+
+ if (btn_type == BS_USERBUTTON)
+ BUTTON_NOTIFY_PARENT( hWnd, (state & BST_PUSHED) ? BN_HILITE :
BN_UNHILITE );
+ infoPtr->state = state;
+
+ InvalidateRect( hWnd, NULL, FALSE );
+ }
break;
#ifdef __REACTOS__
case WM_UPDATEUISTATE:
- if (unicode)
- DefWindowProcW(hWnd, uMsg, wParam, lParam);
- else
- DefWindowProcA(hWnd, uMsg, wParam, lParam);
+ DefWindowProcW(hWnd, uMsg, wParam, lParam);
- if (button_update_uistate(hWnd, unicode))
- paint_button( hWnd, btn_type, ODA_DRAWENTIRE );
+ if (button_update_uistate(infoPtr))
+ paint_button( infoPtr, btn_type, ODA_DRAWENTIRE );
break;
#endif
@@ -1124,86 +1152,11 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg,
if(btn_type == BS_GROUPBOX) return HTTRANSPARENT;
/* fall through */
default:
- return unicode ? DefWindowProcW(hWnd, uMsg, wParam, lParam) :
- DefWindowProcA(hWnd, uMsg, wParam, lParam);
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
return 0;
}
-#ifdef __REACTOS__
-
-/***********************************************************************
- * ButtonWndProcW
- * The button window procedure. This is just a wrapper which locks
- * the passed HWND and calls the real window procedure (with a WND*
- * pointer pointing to the locked windowstructure).
- */
-LRESULT WINAPI ButtonWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- if (!IsWindow(hWnd)) return 0;
- return ButtonWndProc_common(hWnd, uMsg, wParam, lParam, TRUE);
-}
-
-/***********************************************************************
- * ButtonWndProcA
- */
-LRESULT WINAPI ButtonWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- if (!IsWindow(hWnd)) return 0;
- return ButtonWndProc_common(hWnd, uMsg, wParam, lParam, FALSE);
-}
-
-#endif /* __REACTOS__ */
-
-/**********************************************************************
- * Convert button styles to flags used by DrawText.
- */
-static UINT BUTTON_BStoDT( DWORD style, DWORD ex_style )
-{
- UINT dtStyle = DT_NOCLIP; /* We use SelectClipRgn to limit output */
-
- /* "Convert" pushlike buttons to pushbuttons */
- if (style & BS_PUSHLIKE)
- style &= ~BS_TYPEMASK;
-
- if (!(style & BS_MULTILINE))
- dtStyle |= DT_SINGLELINE;
- else
- dtStyle |= DT_WORDBREAK;
-
- switch (style & BS_CENTER)
- {
- case BS_LEFT: /* DT_LEFT is 0 */ break;
- case BS_RIGHT: dtStyle |= DT_RIGHT; break;
- case BS_CENTER: dtStyle |= DT_CENTER; break;
- default:
- /* Pushbutton's text is centered by default */
- if (get_button_type(style) <= BS_DEFPUSHBUTTON) dtStyle |= DT_CENTER;
- /* all other flavours have left aligned text */
- }
-
- if (ex_style & WS_EX_RIGHT) dtStyle = DT_RIGHT | (dtStyle & ~(DT_LEFT |
DT_CENTER));
-
- /* DrawText ignores vertical alignment for multiline text,
- * but we use these flags to align label manually.
- */
- if (get_button_type(style) != BS_GROUPBOX)
- {
- switch (style & BS_VCENTER)
- {
- case BS_TOP: /* DT_TOP is 0 */ break;
- case BS_BOTTOM: dtStyle |= DT_BOTTOM; break;
- case BS_VCENTER: /* fall through */
- default: dtStyle |= DT_VCENTER; break;
- }
- }
- else
- /* GroupBox's text is always single line and is top aligned. */
- dtStyle |= DT_SINGLELINE;
-
- return dtStyle;
-}
-
/**********************************************************************
* BUTTON_CalcLabelRect
*
@@ -1214,10 +1167,10 @@ static UINT BUTTON_BStoDT( DWORD style, DWORD ex_style )
* (pushed, etc.). If there is nothing to draw (no text/image) output
* rectangle is empty, and return value is (UINT)-1.
*/
-static UINT BUTTON_CalcLabelRect(HWND hwnd, HDC hdc, RECT *rc)
+static UINT BUTTON_CalcLabelRect(const BUTTON_INFO *infoPtr, HDC hdc, RECT *rc)
{
- LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE );
- LONG ex_style = GetWindowLongPtrW( hwnd, GWL_EXSTYLE );
+ LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE );
+ LONG ex_style = GetWindowLongW( infoPtr->hwnd, GWL_EXSTYLE );
WCHAR *text;
ICONINFO iconInfo;
BITMAP bm;
@@ -1225,11 +1178,7 @@ static UINT BUTTON_CalcLabelRect(HWND hwnd, HDC hdc, RECT *rc)
RECT r = *rc;
INT n;
#ifdef __REACTOS__
- PBUTTON_DATA pdata = _GetButtonData(hwnd);
-#endif
-
-#ifndef _USER32_
- BOOL bHasIml = BUTTON_DrawIml(hdc, &pdata->imlData, &r, TRUE, 0);
+ BOOL bHasIml = BUTTON_DrawIml(hdc, &infoPtr->imlData, &r, TRUE, 0);
#endif
/* Calculate label rectangle according to label type */
@@ -1239,30 +1188,26 @@ static UINT BUTTON_CalcLabelRect(HWND hwnd, HDC hdc, RECT *rc)
{
HFONT hFont, hPrevFont = 0;
- if (!(text = get_button_text( hwnd ))) goto empty_rect;
+ if (!(text = get_button_text( infoPtr ))) goto empty_rect;
if (!text[0])
{
- HeapFree( GetProcessHeap(), 0, text );
+ heap_free( text );
goto empty_rect;
}
- if ((hFont = get_button_font( hwnd ))) hPrevFont = SelectObject( hdc, hFont );
+ if ((hFont = infoPtr->font)) hPrevFont = SelectObject( hdc, hFont );
DrawTextW(hdc, text, -1, &r, dtStyle | DT_CALCRECT);
if (hPrevFont) SelectObject( hdc, hPrevFont );
- HeapFree( GetProcessHeap(), 0, text );
+ heap_free( text );
#ifdef __REACTOS__
- if (get_ui_state(hwnd) & UISF_HIDEACCEL)
+ if (infoPtr->ui_state & UISF_HIDEACCEL)
dtStyle |= DT_HIDEPREFIX;
#endif
break;
}
case BS_ICON:
-#ifdef _USER32_
- if (!GetIconInfo((HICON)GetWindowLongPtrW( hwnd, HIMAGE_GWL_OFFSET ),
&iconInfo))
-#else
- if (!GetIconInfo((HICON)get_button_image(hwnd), &iconInfo))
-#endif
+ if (!GetIconInfo(infoPtr->u.icon, &iconInfo))
goto empty_rect;
GetObjectW (iconInfo.hbmColor, sizeof(BITMAP), &bm);
@@ -1275,11 +1220,7 @@ static UINT BUTTON_CalcLabelRect(HWND hwnd, HDC hdc, RECT *rc)
break;
case BS_BITMAP:
-#ifdef _USER32_
- if (!GetObjectW( (HANDLE)GetWindowLongPtrW( hwnd, HIMAGE_GWL_OFFSET ),
sizeof(BITMAP), &bm))
-#else
- if (!GetObjectW( (HANDLE)get_button_image(hwnd), sizeof(BITMAP), &bm))
-#endif
+ if (!GetObjectW( infoPtr->u.bitmap, sizeof(BITMAP), &bm))
goto empty_rect;
r.right = r.left + bm.bmWidth;
@@ -1288,26 +1229,22 @@ static UINT BUTTON_CalcLabelRect(HWND hwnd, HDC hdc, RECT *rc)
default:
empty_rect:
-#ifndef _USER32_
- if (bHasIml)
- break;
-#endif
rc->right = r.left;
rc->bottom = r.top;
return (UINT)-1;
}
-#ifndef _USER32_
+#ifdef __REACTOS__
if (bHasIml)
{
- if (pdata->imlData.uAlign == BUTTON_IMAGELIST_ALIGN_LEFT)
- r.left = pdata->imlData.margin.left;
- else if (pdata->imlData.uAlign == BUTTON_IMAGELIST_ALIGN_RIGHT)
- r.right = pdata->imlData.margin.right;
- else if (pdata->imlData.uAlign == BUTTON_IMAGELIST_ALIGN_TOP)
- r.top = pdata->imlData.margin.top;
- else if (pdata->imlData.uAlign == BUTTON_IMAGELIST_ALIGN_BOTTOM)
- r.bottom = pdata->imlData.margin.bottom;
+ if (infoPtr->imlData.uAlign == BUTTON_IMAGELIST_ALIGN_LEFT)
+ r.left = infoPtr->imlData.margin.left;
+ else if (infoPtr->imlData.uAlign == BUTTON_IMAGELIST_ALIGN_RIGHT)
+ r.right = infoPtr->imlData.margin.right;
+ else if (infoPtr->imlData.uAlign == BUTTON_IMAGELIST_ALIGN_TOP)
+ r.top = infoPtr->imlData.margin.top;
+ else if (infoPtr->imlData.uAlign == BUTTON_IMAGELIST_ALIGN_BOTTOM)
+ r.bottom = infoPtr->imlData.margin.bottom;
}
#endif
@@ -1365,19 +1302,15 @@ static BOOL CALLBACK BUTTON_DrawTextCallback(HDC hdc, LPARAM lp,
WPARAM wp, int
*
* Common function for drawing button label.
*/
- #if defined(_USER32_)
-static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, const RECT *rc)
-#else
-static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, RECT *rc)
-#endif
+static void BUTTON_DrawLabel(const BUTTON_INFO *infoPtr, HDC hdc, UINT dtFlags, const
RECT *rc)
{
DRAWSTATEPROC lpOutputProc = NULL;
LPARAM lp;
WPARAM wp = 0;
HBRUSH hbr = 0;
- UINT flags = IsWindowEnabled(hwnd) ? DSS_NORMAL : DSS_DISABLED;
- LONG state = get_button_state( hwnd );
- LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE );
+ UINT flags = IsWindowEnabled(infoPtr->hwnd) ? DSS_NORMAL : DSS_DISABLED;
+ LONG state = infoPtr->state;
+ LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE );
WCHAR *text = NULL;
/* FIXME: To draw disabled label in Win31 look-and-feel, we probably
@@ -1385,9 +1318,9 @@ static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, RECT
*rc)
* I don't have Win31 on hand to verify that, so I leave it as is.
*/
-#ifndef _USER32_
- PBUTTON_DATA pdata = _GetButtonData(hwnd);
- BUTTON_DrawIml(hdc, &pdata->imlData, rc, FALSE, 0);
+#ifdef __REACTOS__
+ RECT rcText = *rc;
+ BUTTON_DrawIml(hdc, &infoPtr->imlData, &rcText, FALSE, 0);
#endif
if ((style & BS_PUSHLIKE) && (state & BST_INDETERMINATE))
@@ -1401,10 +1334,9 @@ static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, RECT
*rc)
case BS_TEXT:
/* DST_COMPLEX -- is 0 */
lpOutputProc = BUTTON_DrawTextCallback;
- if (!(text = get_button_text( hwnd ))) return;
+ if (!(text = get_button_text( infoPtr ))) return;
lp = (LPARAM)text;
- wp = (WPARAM)dtFlags;
-
+ wp = dtFlags;
#ifdef __REACTOS__
if (dtFlags & DT_HIDEPREFIX)
flags |= DSS_HIDEPREFIX;
@@ -1413,79 +1345,66 @@ static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags,
RECT *rc)
case BS_ICON:
flags |= DST_ICON;
-#ifdef _USER32_
- lp = GetWindowLongPtrW( hwnd, HIMAGE_GWL_OFFSET );
-#else
- lp = get_button_image(hwnd);
-#endif
+ lp = (LPARAM)infoPtr->u.icon;
break;
case BS_BITMAP:
flags |= DST_BITMAP;
-#ifdef _USER32_
- lp = GetWindowLongPtrW( hwnd, HIMAGE_GWL_OFFSET );
-#else
- lp = get_button_image(hwnd);
-#endif
+ lp = (LPARAM)infoPtr->u.bitmap;
break;
default:
return;
}
+#ifdef __REACTOS__
+ DrawStateW(hdc, hbr, lpOutputProc, lp, wp, rcText.left, rcText.top,
+ rcText.right - rcText.left, rcText.bottom - rcText.top, flags);
+#else
DrawStateW(hdc, hbr, lpOutputProc, lp, wp, rc->left, rc->top,
rc->right - rc->left, rc->bottom - rc->top, flags);
- HeapFree( GetProcessHeap(), 0, text );
+#endif
+ heap_free( text );
}
/**********************************************************************
* Push Button Functions
*/
-static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
+static void PB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
{
RECT rc, r;
UINT dtFlags, uState;
- HPEN hOldPen;
+ HPEN hOldPen, hpen;
HBRUSH hOldBrush;
INT oldBkMode;
COLORREF oldTxtColor;
HFONT hFont;
- LONG state = get_button_state( hwnd );
- LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE );
+ LONG state = infoPtr->state;
+ LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE );
BOOL pushedState = (state & BST_PUSHED);
HWND parent;
HRGN hrgn;
-#ifndef _USER32_
+#ifdef __REACTOS__
DWORD cdrf;
#endif
- GetClientRect( hwnd, &rc );
+ GetClientRect( infoPtr->hwnd, &rc );
/* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
- if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont );
- parent = GetParent(hwnd);
- if (!parent) parent = hwnd;
-#if defined(__REACTOS__) && defined(_USER32_)
- GetControlColor( parent, hwnd, hDC, WM_CTLCOLORBTN);
-#else
- SendMessageW( parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)hwnd );
-#endif
+ if ((hFont = infoPtr->font)) SelectObject( hDC, hFont );
+ parent = GetParent(infoPtr->hwnd);
+ if (!parent) parent = infoPtr->hwnd;
+ SendMessageW( parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)infoPtr->hwnd );
hrgn = set_control_clipping( hDC, &rc );
-#ifdef __REACTOS__
- hOldPen = SelectObject(hDC, GetStockObject(DC_PEN));
- SetDCPenColor(hDC, GetSysColor(COLOR_WINDOWFRAME));
-#else
- hOldPen = SelectObject(hDC, SYSCOLOR_GetPen(COLOR_WINDOWFRAME));
-#endif
+
+ hpen = CreatePen( PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME));
+ hOldPen = SelectObject(hDC, hpen);
hOldBrush = SelectObject(hDC,GetSysColorBrush(COLOR_BTNFACE));
oldBkMode = SetBkMode(hDC, TRANSPARENT);
- /* completely skip the drawing if only focus has changed */
- if (action == ODA_FOCUS) goto draw_focus;
-
-#ifndef _USER32_
- cdrf = BUTTON_SendCustomDraw(hwnd, hDC, CDDS_PREERASE, &rc);
+#ifdef __REACTOS__
+ cdrf = BUTTON_SendCustomDraw(infoPtr, hDC, CDDS_PREERASE, &rc);
if (cdrf == CDRF_SKIPDEFAULT)
goto cleanup;
#endif
@@ -1497,6 +1416,9 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
InflateRect( &rc, -1, -1 );
}
+ /* completely skip the drawing if only focus has changed */
+ if (action == ODA_FOCUS) goto draw_focus;
+
uState = DFCS_BUTTONPUSH;
if (style & BS_FLAT)
@@ -1514,18 +1436,18 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
DrawFrameControl( hDC, &rc, DFC_BUTTON, uState );
-#ifndef _USER32_
+#ifdef __REACTOS__
if (cdrf == CDRF_NOTIFYPOSTERASE)
- BUTTON_SendCustomDraw(hwnd, hDC, CDDS_POSTERASE, &rc);
+ BUTTON_SendCustomDraw(infoPtr, hDC, CDDS_POSTERASE, &rc);
- cdrf = BUTTON_SendCustomDraw(hwnd, hDC, CDDS_PREPAINT, &rc);
+ cdrf = BUTTON_SendCustomDraw(infoPtr, hDC, CDDS_PREPAINT, &rc);
if (cdrf == CDRF_SKIPDEFAULT)
goto cleanup;
#endif
/* draw button label */
r = rc;
- dtFlags = BUTTON_CalcLabelRect(hwnd, hDC, &r);
+ dtFlags = BUTTON_CalcLabelRect(infoPtr, hDC, &r);
if (dtFlags == (UINT)-1L)
goto cleanup;
@@ -1535,20 +1457,20 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
oldTxtColor = SetTextColor( hDC, GetSysColor(COLOR_BTNTEXT) );
- BUTTON_DrawLabel(hwnd, hDC, dtFlags, &r);
+ BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &r);
SetTextColor( hDC, oldTxtColor );
-#ifndef _USER32_
+#ifdef __REACTOS__
if (cdrf == CDRF_NOTIFYPOSTPAINT)
- BUTTON_SendCustomDraw(hwnd, hDC, CDDS_POSTPAINT, &rc);
+ BUTTON_SendCustomDraw(infoPtr, hDC, CDDS_POSTPAINT, &rc);
#endif
draw_focus:
if (action == ODA_FOCUS || (state & BST_FOCUS))
{
#ifdef __REACTOS__
- if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS))
+ if (!(infoPtr->ui_state & UISF_HIDEFOCUS))
{
#endif
InflateRect( &rc, -2, -2 );
@@ -1564,64 +1486,57 @@ draw_focus:
SetBkMode(hDC, oldBkMode);
SelectClipRgn( hDC, hrgn );
if (hrgn) DeleteObject( hrgn );
+ DeleteObject( hpen );
}
/**********************************************************************
* Check Box & Radio Button Functions
*/
-static void CB_Paint( HWND hwnd, HDC hDC, UINT action )
+static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
{
RECT rbox, rtext, client;
HBRUSH hBrush;
int delta, text_offset, checkBoxWidth, checkBoxHeight;
UINT dtFlags;
HFONT hFont;
- LONG state = get_button_state( hwnd );
- LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE );
- LONG ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
+ LONG state = infoPtr->state;
+ LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE );
+ LONG ex_style = GetWindowLongW( infoPtr->hwnd, GWL_EXSTYLE );
HWND parent;
HRGN hrgn;
if (style & BS_PUSHLIKE)
{
- PB_Paint( hwnd, hDC, action );
+ PB_Paint( infoPtr, hDC, action );
return;
}
- GetClientRect(hwnd, &client);
+ GetClientRect(infoPtr->hwnd, &client);
rbox = rtext = client;
checkBoxWidth = 12 * GetDeviceCaps( hDC, LOGPIXELSX ) / 96 + 1;
checkBoxHeight = 12 * GetDeviceCaps( hDC, LOGPIXELSY ) / 96 + 1;
- if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont );
+ if ((hFont = infoPtr->font)) SelectObject( hDC, hFont );
GetCharWidthW( hDC, '0', '0', &text_offset );
text_offset /= 2;
- parent = GetParent(hwnd);
- if (!parent) parent = hwnd;
-#if defined(__REACTOS__) && defined(_USER32_)
- hBrush = GetControlColor(parent, hwnd, hDC, WM_CTLCOLORSTATIC);
-#else
- hBrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC,
- (WPARAM)hDC, (LPARAM)hwnd);
+ parent = GetParent(infoPtr->hwnd);
+ if (!parent) parent = infoPtr->hwnd;
+ hBrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC, (WPARAM)hDC,
(LPARAM)infoPtr->hwnd);
if (!hBrush) /* did the app forget to call defwindowproc ? */
- hBrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC,
- (WPARAM)hDC, (LPARAM)hwnd );
-#endif
+ hBrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC, (WPARAM)hDC,
(LPARAM)infoPtr->hwnd);
hrgn = set_control_clipping( hDC, &client );
if (style & BS_LEFTTEXT || ex_style & WS_EX_RIGHT)
{
- /* magic +4 is what CTL3D expects */
-
- rtext.right -= checkBoxWidth + text_offset;;
+ rtext.right -= checkBoxWidth + text_offset;
rbox.left = rbox.right - checkBoxWidth;
}
else
{
- rtext.left += checkBoxWidth + text_offset;;
+ rtext.left += checkBoxWidth + text_offset;
rbox.right = checkBoxWidth;
}
@@ -1631,8 +1546,8 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action )
/* Draw label */
client = rtext;
- dtFlags = BUTTON_CalcLabelRect(hwnd, hDC, &rtext);
-
+ dtFlags = BUTTON_CalcLabelRect(infoPtr, hDC, &rtext);
+
/* Only adjust rbox when rtext is valid */
if (dtFlags != (UINT)-1L)
{
@@ -1657,11 +1572,11 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action )
/* rbox must have the correct height */
delta = rbox.bottom - rbox.top - checkBoxHeight;
-
+
if (style & BS_TOP) {
if (delta > 0) {
rbox.bottom = rbox.top + checkBoxHeight;
- } else {
+ } else {
rbox.top -= -delta/2 + 1;
rbox.bottom = rbox.top + checkBoxHeight;
}
@@ -1691,22 +1606,15 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action )
return;
if (action == ODA_DRAWENTIRE)
- BUTTON_DrawLabel(hwnd, hDC, dtFlags, &rtext);
+ BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &rtext);
/* ... and focus */
if (action == ODA_FOCUS || (state & BST_FOCUS))
{
-#ifdef __REACTOS__
- if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS))
- {
-#endif
- rtext.left--;
- rtext.right++;
- IntersectRect(&rtext, &rtext, &client);
- DrawFocusRect( hDC, &rtext );
-#ifdef __REACTOS__
- }
-#endif
+ rtext.left--;
+ rtext.right++;
+ IntersectRect(&rtext, &rtext, &client);
+ DrawFocusRect( hDC, &rtext );
}
SelectClipRgn( hDC, hrgn );
if (hrgn) DeleteObject( hrgn );
@@ -1729,7 +1637,7 @@ static void BUTTON_CheckAutoRadioButton( HWND hwnd )
{
if (!sibling) break;
if ((hwnd != sibling) &&
- ((GetWindowLongPtrW( sibling, GWL_STYLE) & BS_TYPEMASK) ==
BS_AUTORADIOBUTTON))
+ ((GetWindowLongW( sibling, GWL_STYLE) & BS_TYPEMASK) ==
BS_AUTORADIOBUTTON))
SendMessageW( sibling, BM_SETCHECK, BST_UNCHECKED, 0 );
sibling = GetNextDlgGroupItem( parent, sibling, FALSE );
} while (sibling != start);
@@ -1740,30 +1648,25 @@ static void BUTTON_CheckAutoRadioButton( HWND hwnd )
* Group Box Functions
*/
-static void GB_Paint( HWND hwnd, HDC hDC, UINT action )
+static void GB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
{
RECT rc, rcFrame;
HBRUSH hbr;
HFONT hFont;
UINT dtFlags;
TEXTMETRICW tm;
- LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE );
+ LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE );
HWND parent;
HRGN hrgn;
- if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont );
+ if ((hFont = infoPtr->font)) SelectObject( hDC, hFont );
/* GroupBox acts like static control, so it sends CTLCOLORSTATIC */
- parent = GetParent(hwnd);
- if (!parent) parent = hwnd;
-#if defined(__REACTOS__) && defined(_USER32_)
- hbr = GetControlColor(parent, hwnd, hDC, WM_CTLCOLORSTATIC);
-#else
- hbr = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC, (WPARAM)hDC, (LPARAM)hwnd);
+ parent = GetParent(infoPtr->hwnd);
+ if (!parent) parent = infoPtr->hwnd;
+ hbr = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC, (WPARAM)hDC,
(LPARAM)infoPtr->hwnd);
if (!hbr) /* did the app forget to call defwindowproc ? */
- hbr = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC,
- (WPARAM)hDC, (LPARAM)hwnd);
-#endif
- GetClientRect( hwnd, &rc);
+ hbr = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC, (WPARAM)hDC,
(LPARAM)infoPtr->hwnd);
+ GetClientRect( infoPtr->hwnd, &rc);
rcFrame = rc;
hrgn = set_control_clipping( hDC, &rc );
@@ -1772,9 +1675,9 @@ static void GB_Paint( HWND hwnd, HDC hDC, UINT action )
DrawEdge (hDC, &rcFrame, EDGE_ETCHED, BF_RECT | ((style & BS_FLAT) ? BF_FLAT
: 0));
InflateRect(&rc, -7, 1);
- dtFlags = BUTTON_CalcLabelRect(hwnd, hDC, &rc);
+ dtFlags = BUTTON_CalcLabelRect(infoPtr, hDC, &rc);
- if (dtFlags != (UINT)-1L)
+ if (dtFlags != (UINT)-1)
{
/* Because buttons have CS_PARENTDC class style, there is a chance
* that label will be drawn out of client rect.
@@ -1786,7 +1689,7 @@ static void GB_Paint( HWND hwnd, HDC hDC, UINT action )
FillRect(hDC, &rc, hbr);
rc.left++; rc.right--; rc.bottom--;
- BUTTON_DrawLabel(hwnd, hDC, dtFlags, &rc);
+ BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &rc);
}
SelectClipRgn( hDC, hrgn );
if (hrgn) DeleteObject( hrgn );
@@ -1797,52 +1700,39 @@ static void GB_Paint( HWND hwnd, HDC hDC, UINT action )
* User Button Functions
*/
-static void UB_Paint( HWND hwnd, HDC hDC, UINT action )
+static void UB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
{
RECT rc;
HBRUSH hBrush;
HFONT hFont;
- LONG state = get_button_state( hwnd );
+ LONG state = infoPtr->state;
HWND parent;
- GetClientRect( hwnd, &rc);
+ GetClientRect( infoPtr->hwnd, &rc);
- if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont );
+ if ((hFont = infoPtr->font)) SelectObject( hDC, hFont );
- parent = GetParent(hwnd);
- if (!parent) parent = hwnd;
-#if defined(__REACTOS__) && defined(_USER32_)
- hBrush = GetControlColor( parent, hwnd, hDC, WM_CTLCOLORBTN);
-#else
- hBrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)hwnd);
+ parent = GetParent(infoPtr->hwnd);
+ if (!parent) parent = infoPtr->hwnd;
+ hBrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORBTN, (WPARAM)hDC,
(LPARAM)infoPtr->hwnd);
if (!hBrush) /* did the app forget to call defwindowproc ? */
- hBrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORBTN,
- (WPARAM)hDC, (LPARAM)hwnd);
-#endif
+ hBrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORBTN, (WPARAM)hDC,
(LPARAM)infoPtr->hwnd);
FillRect( hDC, &rc, hBrush );
if (action == ODA_FOCUS || (state & BST_FOCUS))
-#ifdef __REACTOS__
- {
- if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS))
-#endif
- DrawFocusRect( hDC, &rc );
-#ifdef __REACTOS__
- }
-#endif
+ DrawFocusRect( hDC, &rc );
switch (action)
{
case ODA_FOCUS:
- BUTTON_NOTIFY_PARENT( hwnd, (state & BST_FOCUS) ? BN_SETFOCUS : BN_KILLFOCUS
);
+ BUTTON_NOTIFY_PARENT( infoPtr->hwnd, (state & BST_FOCUS) ? BN_SETFOCUS :
BN_KILLFOCUS );
break;
case ODA_SELECT:
- BUTTON_NOTIFY_PARENT( hwnd, (state & BST_PUSHED) ? BN_HILITE : BN_UNHILITE
);
+ BUTTON_NOTIFY_PARENT( infoPtr->hwnd, (state & BST_PUSHED) ? BN_HILITE :
BN_UNHILITE );
break;
default:
- BUTTON_NOTIFY_PARENT( hwnd, BN_PAINT );
break;
}
}
@@ -1852,13 +1742,13 @@ static void UB_Paint( HWND hwnd, HDC hDC, UINT action )
* Ownerdrawn Button Functions
*/
-static void OB_Paint( HWND hwnd, HDC hDC, UINT action )
+static void OB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
{
- LONG state = get_button_state( hwnd );
+ LONG state = infoPtr->state;
DRAWITEMSTRUCT dis;
- LONG_PTR id = GetWindowLongPtrW( hwnd, GWLP_ID );
+ LONG_PTR id = GetWindowLongPtrW( infoPtr->hwnd, GWLP_ID );
HWND parent;
- HFONT hFont, hPrevFont = 0;
+ HFONT hFont;
HRGN hrgn;
dis.CtlType = ODT_BUTTON;
@@ -1867,46 +1757,349 @@ static void OB_Paint( HWND hwnd, HDC hDC, UINT action )
dis.itemAction = action;
dis.itemState = ((state & BST_FOCUS) ? ODS_FOCUS : 0) |
((state & BST_PUSHED) ? ODS_SELECTED : 0) |
- (IsWindowEnabled(hwnd) ? 0: ODS_DISABLED);
- dis.hwndItem = hwnd;
+ (IsWindowEnabled(infoPtr->hwnd) ? 0: ODS_DISABLED);
+ dis.hwndItem = infoPtr->hwnd;
dis.hDC = hDC;
dis.itemData = 0;
- GetClientRect( hwnd, &dis.rcItem );
+ GetClientRect( infoPtr->hwnd, &dis.rcItem );
- if ((hFont = get_button_font( hwnd ))) hPrevFont = SelectObject( hDC, hFont );
- parent = GetParent(hwnd);
- if (!parent) parent = hwnd;
-#if defined(__REACTOS__) && defined(_USER32_)
- GetControlColor( parent, hwnd, hDC, WM_CTLCOLORBTN);
-#else
- SendMessageW( parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)hwnd );
-#endif
+ if ((hFont = infoPtr->font)) SelectObject( hDC, hFont );
+ parent = GetParent(infoPtr->hwnd);
+ if (!parent) parent = infoPtr->hwnd;
+ SendMessageW( parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)infoPtr->hwnd );
hrgn = set_control_clipping( hDC, &dis.rcItem );
- SendMessageW( GetParent(hwnd), WM_DRAWITEM, id, (LPARAM)&dis );
- if (hPrevFont) SelectObject(hDC, hPrevFont);
+ SendMessageW( GetParent(infoPtr->hwnd), WM_DRAWITEM, id, (LPARAM)&dis );
SelectClipRgn( hDC, hrgn );
if (hrgn) DeleteObject( hrgn );
}
-#ifndef _USER32_
-void BUTTON_Register()
+#ifdef __REACTOS__ /* r73885 */
+static void PB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC,
ButtonState drawState, UINT dtFlags, BOOL focused, LPARAM prfFlag)
+#else
+static void PB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, ButtonState
drawState, UINT dtFlags, BOOL focused)
+#endif
+{
+ static const int states[] = { PBS_NORMAL, PBS_DISABLED, PBS_HOT, PBS_PRESSED,
PBS_DEFAULTED };
+
+ RECT bgRect, textRect;
+ HFONT font = infoPtr->font;
+ HFONT hPrevFont = font ? SelectObject(hDC, font) : NULL;
+ int state = states[ drawState ];
+ WCHAR *text = get_button_text(infoPtr);
+#ifdef __REACTOS__
+ HWND parent;
+ DWORD cdrf;
+
+ GetClientRect(infoPtr->hwnd, &bgRect);
+ GetThemeBackgroundContentRect(theme, hDC, BP_PUSHBUTTON, state, &bgRect,
&textRect);
+
+ if (prfFlag == 0)
+ {
+ if (IsThemeBackgroundPartiallyTransparent(theme, BP_PUSHBUTTON, state))
+ DrawThemeParentBackground(infoPtr->hwnd, hDC, NULL);
+ }
+
+ parent = GetParent(infoPtr->hwnd);
+ if (!parent) parent = infoPtr->hwnd;
+ SendMessageW( parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)infoPtr->hwnd );
+
+ cdrf = BUTTON_SendCustomDraw(infoPtr, hDC, CDDS_PREERASE, &bgRect);
+ if (cdrf == CDRF_SKIPDEFAULT)
+ goto cleanup;
+
+ DrawThemeBackground(theme, hDC, BP_PUSHBUTTON, state, &bgRect, NULL);
+
+ if (cdrf == CDRF_NOTIFYPOSTERASE)
+ BUTTON_SendCustomDraw(infoPtr, hDC, CDDS_POSTERASE, &bgRect);
+
+ cdrf = BUTTON_SendCustomDraw(infoPtr, hDC, CDDS_PREPAINT, &bgRect);
+ if (cdrf == CDRF_SKIPDEFAULT)
+ goto cleanup;
+
+ BUTTON_DrawIml(hDC, &infoPtr->imlData, &textRect, FALSE, drawState);
+#else
+ GetClientRect(infoPtr->hwnd, &bgRect);
+ GetThemeBackgroundContentRect(theme, hDC, BP_PUSHBUTTON, state, &bgRect,
&textRect);
+
+ if (IsThemeBackgroundPartiallyTransparent(theme, BP_PUSHBUTTON, state))
+ DrawThemeParentBackground(infoPtr->hwnd, hDC, NULL);
+
+ DrawThemeBackground(theme, hDC, BP_PUSHBUTTON, state, &bgRect, NULL);
+#endif
+
+ if (text)
+ {
+ DrawThemeText(theme, hDC, BP_PUSHBUTTON, state, text, lstrlenW(text), dtFlags, 0,
&textRect);
+ heap_free(text);
+ }
+
+ if (focused)
+ {
+ MARGINS margins;
+ RECT focusRect = bgRect;
+
+ GetThemeMargins(theme, hDC, BP_PUSHBUTTON, state, TMT_CONTENTMARGINS, NULL,
&margins);
+
+ focusRect.left += margins.cxLeftWidth;
+ focusRect.top += margins.cyTopHeight;
+ focusRect.right -= margins.cxRightWidth;
+ focusRect.bottom -= margins.cyBottomHeight;
+
+ DrawFocusRect( hDC, &focusRect );
+ }
+
+#ifdef __REACTOS__
+ if (cdrf == CDRF_NOTIFYPOSTPAINT)
+ BUTTON_SendCustomDraw(infoPtr, hDC, CDDS_POSTPAINT, &bgRect);
+cleanup:
+#endif
+ if (hPrevFont) SelectObject(hDC, hPrevFont);
+}
+
+#ifdef __REACTOS__ /* r73885 */
+static void CB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, ButtonState
drawState, UINT dtFlags, BOOL focused, LPARAM prfFlag)
+#else
+static void CB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, ButtonState
drawState, UINT dtFlags, BOOL focused)
+#endif
+{
+ static const int cb_states[3][5] =
+ {
+ { CBS_UNCHECKEDNORMAL, CBS_UNCHECKEDHOT, CBS_UNCHECKEDPRESSED,
CBS_UNCHECKEDDISABLED, CBS_UNCHECKEDNORMAL },
+ { CBS_CHECKEDNORMAL, CBS_CHECKEDHOT, CBS_CHECKEDPRESSED, CBS_CHECKEDDISABLED,
CBS_CHECKEDNORMAL },
+ { CBS_MIXEDNORMAL, CBS_MIXEDHOT, CBS_MIXEDPRESSED, CBS_MIXEDDISABLED,
CBS_MIXEDNORMAL }
+ };
+
+ static const int rb_states[2][5] =
+ {
+ { RBS_UNCHECKEDNORMAL, RBS_UNCHECKEDHOT, RBS_UNCHECKEDPRESSED,
RBS_UNCHECKEDDISABLED, RBS_UNCHECKEDNORMAL },
+ { RBS_CHECKEDNORMAL, RBS_CHECKEDHOT, RBS_CHECKEDPRESSED, RBS_CHECKEDDISABLED,
RBS_CHECKEDNORMAL }
+ };
+
+ SIZE sz;
+ RECT bgRect, textRect;
+ HFONT font, hPrevFont = NULL;
+ int checkState = infoPtr->state & 3;
+ DWORD dwStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
+ UINT btn_type = get_button_type( dwStyle );
+ int part = (btn_type == BS_RADIOBUTTON) || (btn_type == BS_AUTORADIOBUTTON) ?
BP_RADIOBUTTON : BP_CHECKBOX;
+ int state = (part == BP_CHECKBOX)
+ ? cb_states[ checkState ][ drawState ]
+ : rb_states[ checkState ][ drawState ];
+ WCHAR *text = get_button_text(infoPtr);
+ LOGFONTW lf;
+ BOOL created_font = FALSE;
+#ifdef __REACTOS__
+ HWND parent;
+ HBRUSH hBrush;
+ DWORD cdrf;
+#endif
+
+ HRESULT hr = GetThemeFont(theme, hDC, part, state, TMT_FONT, &lf);
+ if (SUCCEEDED(hr)) {
+ font = CreateFontIndirectW(&lf);
+ if (!font)
+ TRACE("Failed to create font\n");
+ else {
+ TRACE("font = %s\n", debugstr_w(lf.lfFaceName));
+ hPrevFont = SelectObject(hDC, font);
+ created_font = TRUE;
+ }
+ } else {
+#ifdef __REACTOS__ /* r73885 */
+ font = infoPtr->font;
+#else
+ font = (HFONT)SendMessageW(infoPtr->hwnd, WM_GETFONT, 0, 0);
+#endif
+ hPrevFont = SelectObject(hDC, font);
+ }
+
+ if (FAILED(GetThemePartSize(theme, hDC, part, state, NULL, TS_DRAW, &sz)))
+ sz.cx = sz.cy = 13;
+
+ GetClientRect(infoPtr->hwnd, &bgRect);
+
+#ifdef __REACTOS__
+ if (prfFlag == 0)
+ {
+ DrawThemeParentBackground(infoPtr->hwnd, hDC, NULL);
+ }
+
+ parent = GetParent(infoPtr->hwnd);
+ if (!parent) parent = infoPtr->hwnd;
+ hBrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC,
+ (WPARAM)hDC, (LPARAM)infoPtr->hwnd);
+ if (!hBrush) /* did the app forget to call defwindowproc ? */
+ hBrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC,
+ (WPARAM)hDC, (LPARAM)infoPtr->hwnd );
+ FillRect( hDC, &bgRect, hBrush );
+
+ cdrf = BUTTON_SendCustomDraw(infoPtr, hDC, CDDS_PREERASE, &bgRect);
+ if (cdrf == CDRF_SKIPDEFAULT)
+ goto cleanup;
+#endif
+
+ GetThemeBackgroundContentRect(theme, hDC, part, state, &bgRect, &textRect);
+
+ if (dtFlags & DT_SINGLELINE) /* Center the checkbox / radio button to the text.
*/
+ bgRect.top = bgRect.top + (textRect.bottom - textRect.top - sz.cy) / 2;
+
+ /* adjust for the check/radio marker */
+ bgRect.bottom = bgRect.top + sz.cy;
+ bgRect.right = bgRect.left + sz.cx;
+ textRect.left = bgRect.right + 6;
+
+#ifdef __REACTOS__
+ DrawThemeBackground(theme, hDC, part, state, &bgRect, NULL);
+
+ if (cdrf == CDRF_NOTIFYPOSTERASE)
+ BUTTON_SendCustomDraw(infoPtr, hDC, CDDS_POSTERASE, &bgRect);
+
+ cdrf = BUTTON_SendCustomDraw(infoPtr, hDC, CDDS_PREPAINT, &bgRect);
+ if (cdrf == CDRF_SKIPDEFAULT)
+ goto cleanup;
+
+#else
+ DrawThemeParentBackground(infoPtr->hwnd, hDC, NULL);
+ DrawThemeBackground(theme, hDC, part, state, &bgRect, NULL);
+#endif
+ if (text)
+ {
+ DrawThemeText(theme, hDC, part, state, text, lstrlenW(text), dtFlags, 0,
&textRect);
+
+ if (focused)
+ {
+ RECT focusRect;
+
+ focusRect = textRect;
+
+ DrawTextW(hDC, text, lstrlenW(text), &focusRect, dtFlags | DT_CALCRECT);
+
+ if (focusRect.right < textRect.right) focusRect.right++;
+ focusRect.bottom = textRect.bottom;
+
+ DrawFocusRect( hDC, &focusRect );
+ }
+
+ heap_free(text);
+ }
+
+#ifdef __REACTOS__
+ if (cdrf == CDRF_NOTIFYPOSTPAINT)
+ BUTTON_SendCustomDraw(infoPtr, hDC, CDDS_POSTPAINT, &bgRect);
+cleanup:
+#endif
+ if (created_font) DeleteObject(font);
+ if (hPrevFont) SelectObject(hDC, hPrevFont);
+}
+
+#ifdef __REACTOS__ /* r73885 */
+static void GB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, ButtonState
drawState, UINT dtFlags, BOOL focused, LPARAM prfFlag)
+#else
+static void GB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, ButtonState
drawState, UINT dtFlags, BOOL focused)
+#endif
+{
+ static const int states[] = { GBS_NORMAL, GBS_DISABLED, GBS_NORMAL, GBS_NORMAL,
GBS_NORMAL };
+
+ RECT bgRect, textRect, contentRect;
+ int state = states[ drawState ];
+ WCHAR *text = get_button_text(infoPtr);
+ LOGFONTW lf;
+ HFONT font, hPrevFont = NULL;
+ BOOL created_font = FALSE;
+#ifdef __REACTOS__ /* r74406 */
+ HWND parent;
+ HBRUSH hBrush;
+ RECT clientRect;
+#endif
+
+ HRESULT hr = GetThemeFont(theme, hDC, BP_GROUPBOX, state, TMT_FONT, &lf);
+ if (SUCCEEDED(hr)) {
+ font = CreateFontIndirectW(&lf);
+ if (!font)
+ TRACE("Failed to create font\n");
+ else {
+ hPrevFont = SelectObject(hDC, font);
+ created_font = TRUE;
+ }
+ } else {
+#ifdef __REACTOS__ /* r73885 */
+ font = infoPtr->font;
+#else
+ font = (HFONT)SendMessageW(infoPtr->hwnd, WM_GETFONT, 0, 0);
+#endif
+ hPrevFont = SelectObject(hDC, font);
+ }
+
+ GetClientRect(infoPtr->hwnd, &bgRect);
+ textRect = bgRect;
+
+ if (text)
+ {
+ SIZE textExtent;
+ GetTextExtentPoint32W(hDC, text, lstrlenW(text), &textExtent);
+ bgRect.top += (textExtent.cy / 2);
+ textRect.left += 10;
+ textRect.bottom = textRect.top + textExtent.cy;
+ textRect.right = textRect.left + textExtent.cx + 4;
+
+ ExcludeClipRect(hDC, textRect.left, textRect.top, textRect.right,
textRect.bottom);
+ }
+
+ GetThemeBackgroundContentRect(theme, hDC, BP_GROUPBOX, state, &bgRect,
&contentRect);
+ ExcludeClipRect(hDC, contentRect.left, contentRect.top, contentRect.right,
contentRect.bottom);
+
+#ifdef __REACTOS__ /* r73885 & r74149 */
+ if (prfFlag == 0)
+#endif
+ if (IsThemeBackgroundPartiallyTransparent(theme, BP_GROUPBOX, state))
+ DrawThemeParentBackground(infoPtr->hwnd, hDC, NULL);
+
+#ifdef __REACTOS__ /* r74406 */
+ parent = GetParent(infoPtr->hwnd);
+ if (!parent) parent = infoPtr->hwnd;
+ hBrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC,
+ (WPARAM)hDC, (LPARAM)infoPtr->hwnd);
+ if (!hBrush) /* did the app forget to call defwindowproc ? */
+ hBrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC,
+ (WPARAM)hDC, (LPARAM)infoPtr->hwnd );
+ GetClientRect(infoPtr->hwnd, &clientRect);
+ FillRect( hDC, &clientRect, hBrush );
+#endif
+
+ DrawThemeBackground(theme, hDC, BP_GROUPBOX, state, &bgRect, NULL);
+
+ SelectClipRgn(hDC, NULL);
+
+ if (text)
+ {
+ InflateRect(&textRect, -2, 0);
+ DrawThemeText(theme, hDC, BP_GROUPBOX, state, text, lstrlenW(text), 0, 0,
&textRect);
+ heap_free(text);
+ }
+
+ if (created_font) DeleteObject(font);
+ if (hPrevFont) SelectObject(hDC, hPrevFont);
+}
+
+void BUTTON_Register(void)
{
WNDCLASSW wndClass;
- ZeroMemory(&wndClass, sizeof(WNDCLASSW));
- wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW |
CS_PARENTDC;
- wndClass.lpfnWndProc = ButtonWndProcW;
- wndClass.cbClsExtra = 0;
- wndClass.cbWndExtra = sizeof(PBUTTON_DATA);
- wndClass.hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
- wndClass.hbrBackground = 0;
+ memset(&wndClass, 0, sizeof(wndClass));
+ wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW |
CS_PARENTDC;
+ wndClass.lpfnWndProc = BUTTON_WindowProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = sizeof(BUTTON_INFO *);
+ wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
+ wndClass.hbrBackground = NULL;
wndClass.lpszClassName = WC_BUTTONW;
-
RegisterClassW(&wndClass);
}
+
+#ifdef __REACTOS__
void BUTTON_Unregister()
{
UnregisterClassW(WC_BUTTONW, NULL);
diff --git a/dll/win32/comctl32/combo.c b/dll/win32/comctl32/combo.c
new file mode 100644
index 0000000000..712e27276a
--- /dev/null
+++ b/dll/win32/comctl32/combo.c
@@ -0,0 +1,2160 @@
+/*
+ * Combo controls
+ *
+ * Copyright 1997 Alex Korobka
+ * Copyright (c) 2005 by Frank Richter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * TODO:
+ * - ComboBox_[GS]etMinVisible()
+ * - CB_GETMINVISIBLE, CB_SETMINVISIBLE
+ * - CB_SETTOPINDEX
+ */
+
+#include <stdarg.h>
+#include <string.h>
+
+#define OEMRESOURCE
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "uxtheme.h"
+#include "vssym32.h"
+#include "commctrl.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+#include "wine/heap.h"
+
+#include "comctl32.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(combo);
+
+ /* bits in the dwKeyData */
+#define KEYDATA_ALT 0x2000
+#define KEYDATA_PREVSTATE 0x4000
+
+/*
+ * Additional combo box definitions
+ */
+
+#define CB_NOTIFY( lphc, code ) \
+ (SendMessageW((lphc)->owner, WM_COMMAND, \
+ MAKEWPARAM(GetWindowLongPtrW((lphc)->self,GWLP_ID), (code)),
(LPARAM)(lphc)->self))
+
+#define CB_DISABLED( lphc ) (!IsWindowEnabled((lphc)->self))
+#define CB_OWNERDRAWN( lphc ) ((lphc)->dwStyle & (CBS_OWNERDRAWFIXED |
CBS_OWNERDRAWVARIABLE))
+#define CB_HASSTRINGS( lphc ) ((lphc)->dwStyle & CBS_HASSTRINGS)
+#define CB_HWND( lphc ) ((lphc)->self)
+#define CB_GETTYPE( lphc ) ((lphc)->dwStyle & (CBS_DROPDOWNLIST))
+
+#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
+
+/*
+ * Drawing globals
+ */
+static HBITMAP hComboBmp = 0;
+static UINT CBitHeight, CBitWidth;
+
+/*
+ * Look and feel dependent "constants"
+ */
+
+#define COMBO_YBORDERGAP 5
+#define COMBO_XBORDERSIZE() 2
+#define COMBO_YBORDERSIZE() 2
+#define COMBO_EDITBUTTONSPACE() 0
+#define EDIT_CONTROL_PADDING() 1
+
+#define ID_CB_LISTBOX 1000
+#define ID_CB_EDIT 1001
+
+/***********************************************************************
+ * COMBO_Init
+ *
+ * Load combo button bitmap.
+ */
+static BOOL COMBO_Init(void)
+{
+ HDC hDC;
+
+ if( hComboBmp ) return TRUE;
+ if( (hDC = CreateCompatibleDC(0)) )
+ {
+ BOOL bRet = FALSE;
+ if( (hComboBmp = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_COMBO))) )
+ {
+ BITMAP bm;
+ HBITMAP hPrevB;
+ RECT r;
+
+ GetObjectW( hComboBmp, sizeof(bm), &bm );
+ CBitHeight = bm.bmHeight;
+ CBitWidth = bm.bmWidth;
+
+ TRACE("combo bitmap [%i,%i]\n", CBitWidth, CBitHeight );
+
+ hPrevB = SelectObject( hDC, hComboBmp);
+ SetRect( &r, 0, 0, CBitWidth, CBitHeight );
+ InvertRect( hDC, &r );
+ SelectObject( hDC, hPrevB );
+ bRet = TRUE;
+ }
+ DeleteDC( hDC );
+ return bRet;
+ }
+ return FALSE;
+}
+
+/***********************************************************************
+ * COMBO_NCCreate
+ */
+static LRESULT COMBO_NCCreate(HWND hwnd, LONG style)
+{
+ HEADCOMBO *lphc;
+
+ if (COMBO_Init() && (lphc = heap_alloc_zero(sizeof(*lphc))))
+ {
+ lphc->self = hwnd;
+ SetWindowLongPtrW( hwnd, 0, (LONG_PTR)lphc );
+
+ /* some braindead apps do try to use scrollbar/border flags */
+
+ lphc->dwStyle = style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL);
+ SetWindowLongW( hwnd, GWL_STYLE, style & ~(WS_BORDER | WS_HSCROLL |
WS_VSCROLL) );
+
+ /*
+ * We also have to remove the client edge style to make sure
+ * we don't end-up with a non client area.
+ */
+ SetWindowLongW( hwnd, GWL_EXSTYLE,
+ GetWindowLongW( hwnd, GWL_EXSTYLE ) & ~WS_EX_CLIENTEDGE );
+
+ if( !(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
+ lphc->dwStyle |= CBS_HASSTRINGS;
+ if( !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) )
+ lphc->wState |= CBF_NOTIFY;
+
+ TRACE("[%p], style = %08x\n", lphc, lphc->dwStyle );
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/***********************************************************************
+ * COMBO_NCDestroy
+ */
+static LRESULT COMBO_NCDestroy( HEADCOMBO *lphc )
+{
+ if (lphc)
+ {
+ TRACE("[%p]: freeing storage\n", lphc->self);
+
+ if ( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox )
+ DestroyWindow( lphc->hWndLBox );
+
+ SetWindowLongPtrW( lphc->self, 0, 0 );
+ heap_free( lphc );
+ }
+
+ return 0;
+}
+
+/***********************************************************************
+ * CBGetTextAreaHeight
+ *
+ * This method will calculate the height of the text area of the
+ * combobox.
+ * The height of the text area is set in two ways.
+ * It can be set explicitly through a combobox message or through a
+ * WM_MEASUREITEM callback.
+ * If this is not the case, the height is set to font height + 4px
+ * This height was determined through experimentation.
+ * CBCalcPlacement will add 2*COMBO_YBORDERSIZE pixels for the border
+ */
+static INT CBGetTextAreaHeight(
+ HWND hwnd,
+ LPHEADCOMBO lphc)
+{
+ INT iTextItemHeight;
+
+ if( lphc->editHeight ) /* explicitly set height */
+ {
+ iTextItemHeight = lphc->editHeight;
+ }
+ else
+ {
+ TEXTMETRICW tm;
+ HDC hDC = GetDC(hwnd);
+ HFONT hPrevFont = 0;
+ INT baseUnitY;
+
+ if (lphc->hFont)
+ hPrevFont = SelectObject( hDC, lphc->hFont );
+
+ GetTextMetricsW(hDC, &tm);
+
+ baseUnitY = tm.tmHeight;
+
+ if( hPrevFont )
+ SelectObject( hDC, hPrevFont );
+
+ ReleaseDC(hwnd, hDC);
+
+ iTextItemHeight = baseUnitY + 4;
+ }
+
+ /*
+ * Check the ownerdraw case if we haven't asked the parent the size
+ * of the item yet.
+ */
+ if ( CB_OWNERDRAWN(lphc) &&
+ (lphc->wState & CBF_MEASUREITEM) )
+ {
+ MEASUREITEMSTRUCT measureItem;
+ RECT clientRect;
+ INT originalItemHeight = iTextItemHeight;
+ UINT id = (UINT)GetWindowLongPtrW( lphc->self, GWLP_ID );
+
+ /*
+ * We use the client rect for the width of the item.
+ */
+ GetClientRect(hwnd, &clientRect);
+
+ lphc->wState &= ~CBF_MEASUREITEM;
+
+ /*
+ * Send a first one to measure the size of the text area
+ */
+ measureItem.CtlType = ODT_COMBOBOX;
+ measureItem.CtlID = id;
+ measureItem.itemID = -1;
+ measureItem.itemWidth = clientRect.right;
+ measureItem.itemHeight = iTextItemHeight - 6; /* ownerdrawn cb is taller */
+ measureItem.itemData = 0;
+ SendMessageW(lphc->owner, WM_MEASUREITEM, id, (LPARAM)&measureItem);
+ iTextItemHeight = 6 + measureItem.itemHeight;
+
+ /*
+ * Send a second one in the case of a fixed ownerdraw list to calculate the
+ * size of the list items. (we basically do this on behalf of the listbox)
+ */
+ if (lphc->dwStyle & CBS_OWNERDRAWFIXED)
+ {
+ measureItem.CtlType = ODT_COMBOBOX;
+ measureItem.CtlID = id;
+ measureItem.itemID = 0;
+ measureItem.itemWidth = clientRect.right;
+ measureItem.itemHeight = originalItemHeight;
+ measureItem.itemData = 0;
+ SendMessageW(lphc->owner, WM_MEASUREITEM, id, (LPARAM)&measureItem);
+ lphc->fixedOwnerDrawHeight = measureItem.itemHeight;
+ }
+
+ /*
+ * Keep the size for the next time
+ */
+ lphc->editHeight = iTextItemHeight;
+ }
+
+ return iTextItemHeight;
+}
+
+/***********************************************************************
+ * CBForceDummyResize
+ *
+ * The dummy resize is used for listboxes that have a popup to trigger
+ * a re-arranging of the contents of the combobox and the recalculation
+ * of the size of the "real" control window.
+ */
+static void CBForceDummyResize(
+ LPHEADCOMBO lphc)
+{
+ RECT windowRect;
+ int newComboHeight;
+
+ newComboHeight = CBGetTextAreaHeight(lphc->self,lphc) + 2*COMBO_YBORDERSIZE();
+
+ GetWindowRect(lphc->self, &windowRect);
+
+ /*
+ * We have to be careful, resizing a combobox also has the meaning that the
+ * dropped rect will be resized. In this case, we want to trigger a resize
+ * to recalculate layout but we don't want to change the dropped rectangle
+ * So, we pass the height of text area of control as the height.
+ * this will cancel-out in the processing of the WM_WINDOWPOSCHANGING
+ * message.
+ */
+ SetWindowPos( lphc->self,
+ NULL,
+ 0, 0,
+ windowRect.right - windowRect.left,
+ newComboHeight,
+ SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
+}
+
+/***********************************************************************
+ * CBCalcPlacement
+ *
+ * Set up component coordinates given valid lphc->RectCombo.
+ */
+static void CBCalcPlacement(
+ HWND hwnd,
+ LPHEADCOMBO lphc,
+ LPRECT lprEdit,
+ LPRECT lprButton,
+ LPRECT lprLB)
+{
+ /*
+ * Again, start with the client rectangle.
+ */
+ GetClientRect(hwnd, lprEdit);
+
+ /*
+ * Remove the borders
+ */
+ InflateRect(lprEdit, -COMBO_XBORDERSIZE(), -COMBO_YBORDERSIZE());
+
+ /*
+ * Chop off the bottom part to fit with the height of the text area.
+ */
+ lprEdit->bottom = lprEdit->top + CBGetTextAreaHeight(hwnd, lphc);
+
+ /*
+ * The button starts the same vertical position as the text area.
+ */
+ CopyRect(lprButton, lprEdit);
+
+ /*
+ * If the combobox is "simple" there is no button.
+ */
+ if( CB_GETTYPE(lphc) == CBS_SIMPLE )
+ lprButton->left = lprButton->right = lprButton->bottom = 0;
+ else
+ {
+ /*
+ * Let's assume the combobox button is the same width as the
+ * scrollbar button.
+ * size the button horizontally and cut-off the text area.
+ */
+ lprButton->left = lprButton->right - GetSystemMetrics(SM_CXVSCROLL);
+ lprEdit->right = lprButton->left;
+ }
+
+ /*
+ * In the case of a dropdown, there is an additional spacing between the
+ * text area and the button.
+ */
+ if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+ {
+ lprEdit->right -= COMBO_EDITBUTTONSPACE();
+ }
+
+ /*
+ * If we have an edit control, we space it away from the borders slightly.
+ */
+ if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
+ {
+ InflateRect(lprEdit, -EDIT_CONTROL_PADDING(), -EDIT_CONTROL_PADDING());
+ }
+
+ /*
+ * Adjust the size of the listbox popup.
+ */
+ if( CB_GETTYPE(lphc) == CBS_SIMPLE )
+ {
+ /*
+ * Use the client rectangle to initialize the listbox rectangle
+ */
+ GetClientRect(hwnd, lprLB);
+
+ /*
+ * Then, chop-off the top part.
+ */
+ lprLB->top = lprEdit->bottom + COMBO_YBORDERSIZE();
+ }
+ else
+ {
+ /*
+ * Make sure the dropped width is as large as the combobox itself.
+ */
+ if (lphc->droppedWidth < (lprButton->right + COMBO_XBORDERSIZE()))
+ {
+ lprLB->right = lprLB->left + (lprButton->right + COMBO_XBORDERSIZE());
+
+ /*
+ * In the case of a dropdown, the popup listbox is offset to the right.
+ * so, we want to make sure it's flush with the right side of the
+ * combobox
+ */
+ if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+ lprLB->right -= COMBO_EDITBUTTONSPACE();
+ }
+ else
+ lprLB->right = lprLB->left + lphc->droppedWidth;
+ }
+
+ /* don't allow negative window width */
+ if (lprEdit->right < lprEdit->left)
+ lprEdit->right = lprEdit->left;
+
+ TRACE("\ttext\t= (%s)\n", wine_dbgstr_rect(lprEdit));
+
+ TRACE("\tbutton\t= (%s)\n", wine_dbgstr_rect(lprButton));
+
+ TRACE("\tlbox\t= (%s)\n", wine_dbgstr_rect(lprLB));
+}
+
+/***********************************************************************
+ * CBGetDroppedControlRect
+ */
+static void CBGetDroppedControlRect( LPHEADCOMBO lphc, LPRECT lpRect)
+{
+ /* In windows, CB_GETDROPPEDCONTROLRECT returns the upper left corner
+ of the combo box and the lower right corner of the listbox */
+
+ GetWindowRect(lphc->self, lpRect);
+
+ lpRect->right = lpRect->left + lphc->droppedRect.right -
lphc->droppedRect.left;
+ lpRect->bottom = lpRect->top + lphc->droppedRect.bottom -
lphc->droppedRect.top;
+
+}
+
+/***********************************************************************
+ * COMBO_Create
+ */
+static LRESULT COMBO_Create( HWND hwnd, LPHEADCOMBO lphc, HWND hwndParent, LONG style )
+{
+ static const WCHAR clbName[] =
{'C','o','m','b','o','L','B','o','x',0};
+ static const WCHAR editName[] = {'E','d','i','t',0};
+
+ OpenThemeData( hwnd, WC_COMBOBOXW );
+ if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
+ if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
+
+ lphc->owner = hwndParent;
+
+ /*
+ * The item height and dropped width are not set when the control
+ * is created.
+ */
+ lphc->droppedWidth = lphc->editHeight = 0;
+
+ /*
+ * The first time we go through, we want to measure the ownerdraw item
+ */
+ lphc->wState |= CBF_MEASUREITEM;
+
+ /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
+
+ if( lphc->owner || !(style & WS_VISIBLE) )
+ {
+ UINT lbeStyle = 0;
+ UINT lbeExStyle = 0;
+
+ /*
+ * Initialize the dropped rect to the size of the client area of the
+ * control and then, force all the areas of the combobox to be
+ * recalculated.
+ */
+ GetClientRect( hwnd, &lphc->droppedRect );
+ CBCalcPlacement(hwnd, lphc, &lphc->textRect, &lphc->buttonRect,
&lphc->droppedRect );
+
+ /*
+ * Adjust the position of the popup listbox if it's necessary
+ */
+ if ( CB_GETTYPE(lphc) != CBS_SIMPLE )
+ {
+ lphc->droppedRect.top = lphc->textRect.bottom + COMBO_YBORDERSIZE();
+
+ /*
+ * If it's a dropdown, the listbox is offset
+ */
+ if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+ lphc->droppedRect.left += COMBO_EDITBUTTONSPACE();
+
+ if (lphc->droppedRect.bottom < lphc->droppedRect.top)
+ lphc->droppedRect.bottom = lphc->droppedRect.top;
+ if (lphc->droppedRect.right < lphc->droppedRect.left)
+ lphc->droppedRect.right = lphc->droppedRect.left;
+ MapWindowPoints( hwnd, 0, (LPPOINT)&lphc->droppedRect, 2 );
+ }
+
+ /* create listbox popup */
+
+ lbeStyle = (LBS_NOTIFY | LBS_COMBOBOX | WS_BORDER | WS_CLIPSIBLINGS | WS_CHILD) |
+ (style & (WS_VSCROLL | CBS_OWNERDRAWFIXED |
CBS_OWNERDRAWVARIABLE));
+
+ if( lphc->dwStyle & CBS_SORT )
+ lbeStyle |= LBS_SORT;
+ if( lphc->dwStyle & CBS_HASSTRINGS )
+ lbeStyle |= LBS_HASSTRINGS;
+ if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT )
+ lbeStyle |= LBS_NOINTEGRALHEIGHT;
+ if( lphc->dwStyle & CBS_DISABLENOSCROLL )
+ lbeStyle |= LBS_DISABLENOSCROLL;
+
+ if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* child listbox */
+ {
+ lbeStyle |= WS_VISIBLE;
+
+ /*
+ * In win 95 look n feel, the listbox in the simple combobox has
+ * the WS_EXCLIENTEDGE style instead of the WS_BORDER style.
+ */
+ lbeStyle &= ~WS_BORDER;
+ lbeExStyle |= WS_EX_CLIENTEDGE;
+ }
+ else
+ {
+ lbeExStyle |= (WS_EX_TOPMOST | WS_EX_TOOLWINDOW);
+ }
+
+ lphc->hWndLBox = CreateWindowExW(lbeExStyle, clbName, NULL, lbeStyle,
+ lphc->droppedRect.left, lphc->droppedRect.top,
lphc->droppedRect.right - lphc->droppedRect.left,
+ lphc->droppedRect.bottom - lphc->droppedRect.top, hwnd,
(HMENU)ID_CB_LISTBOX,
+ (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ), lphc );
+ if( lphc->hWndLBox )
+ {
+ BOOL bEdit = TRUE;
+ lbeStyle = WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | ES_LEFT | ES_COMBO;
+
+ if( lphc->wState & CBF_EDIT )
+ {
+ if( lphc->dwStyle & CBS_OEMCONVERT )
+ lbeStyle |= ES_OEMCONVERT;
+ if( lphc->dwStyle & CBS_AUTOHSCROLL )
+ lbeStyle |= ES_AUTOHSCROLL;
+ if( lphc->dwStyle & CBS_LOWERCASE )
+ lbeStyle |= ES_LOWERCASE;
+ else if( lphc->dwStyle & CBS_UPPERCASE )
+ lbeStyle |= ES_UPPERCASE;
+
+ if (!IsWindowEnabled(hwnd)) lbeStyle |= WS_DISABLED;
+
+ lphc->hWndEdit = CreateWindowExW(0, editName, NULL, lbeStyle,
+ lphc->textRect.left,
lphc->textRect.top,
+ lphc->textRect.right -
lphc->textRect.left,
+ lphc->textRect.bottom -
lphc->textRect.top,
+ hwnd, (HMENU)ID_CB_EDIT,
+ (HINSTANCE)GetWindowLongPtrW( hwnd,
GWLP_HINSTANCE ), NULL );
+ if( !lphc->hWndEdit )
+ bEdit = FALSE;
+ }
+
+ if( bEdit )
+ {
+ if( CB_GETTYPE(lphc) != CBS_SIMPLE )
+ {
+ /* Now do the trick with parent */
+ SetParent(lphc->hWndLBox, HWND_DESKTOP);
+ /*
+ * If the combo is a dropdown, we must resize the control
+ * to fit only the text area and button. To do this,
+ * we send a dummy resize and the WM_WINDOWPOSCHANGING message
+ * will take care of setting the height for us.
+ */
+ CBForceDummyResize(lphc);
+ }
+
+ TRACE("init done\n");
+ return 0;
+ }
+ ERR("edit control failure.\n");
+ } else ERR("listbox failure.\n");
+ } else ERR("no owner for visible combo.\n");
+
+ /* CreateWindow() will send WM_NCDESTROY to cleanup */
+
+ return -1;
+}
+
+/***********************************************************************
+ * CBPaintButton
+ *
+ * Paint combo button (normal, pressed, and disabled states).
+ */
+static void CBPaintButton( LPHEADCOMBO lphc, HDC hdc, RECT rectButton)
+{
+ UINT buttonState = DFCS_SCROLLCOMBOBOX;
+
+ if( lphc->wState & CBF_NOREDRAW )
+ return;
+
+
+ if (lphc->wState & CBF_BUTTONDOWN)
+ buttonState |= DFCS_PUSHED;
+
+ if (CB_DISABLED(lphc))
+ buttonState |= DFCS_INACTIVE;
+
+ DrawFrameControl(hdc, &rectButton, DFC_SCROLL, buttonState);
+}
+
+/***********************************************************************
+ * COMBO_PrepareColors
+ *
+ * This method will sent the appropriate WM_CTLCOLOR message to
+ * prepare and setup the colors for the combo's DC.
+ *
+ * It also returns the brush to use for the background.
+ */
+static HBRUSH COMBO_PrepareColors(
+ LPHEADCOMBO lphc,
+ HDC hDC)
+{
+ HBRUSH hBkgBrush;
+
+ /*
+ * Get the background brush for this control.
+ */
+ if (CB_DISABLED(lphc))
+ {
+ hBkgBrush = (HBRUSH)SendMessageW(lphc->owner, WM_CTLCOLORSTATIC,
+ (WPARAM)hDC, (LPARAM)lphc->self );
+
+ /*
+ * We have to change the text color since WM_CTLCOLORSTATIC will
+ * set it to the "enabled" color. This is the same behavior as the
+ * edit control
+ */
+ SetTextColor(hDC, GetSysColor(COLOR_GRAYTEXT));
+ }
+ else
+ {
+ /* FIXME: In which cases WM_CTLCOLORLISTBOX should be sent? */
+ hBkgBrush = (HBRUSH)SendMessageW(lphc->owner, WM_CTLCOLOREDIT,
+ (WPARAM)hDC, (LPARAM)lphc->self );
+ }
+
+ /*
+ * Catch errors.
+ */
+ if( !hBkgBrush )
+ hBkgBrush = GetSysColorBrush(COLOR_WINDOW);
+
+ return hBkgBrush;
+}
+
+/***********************************************************************
+ * CBPaintText
+ *
+ * Paint CBS_DROPDOWNLIST text field / update edit control contents.
+ */
+static void CBPaintText(HEADCOMBO *lphc, HDC hdc_paint)
+{
+ RECT rectEdit = lphc->textRect;
+ INT id, size = 0;
+ LPWSTR pText = NULL;
+
+ TRACE("\n");
+
+ /* follow Windows combobox that sends a bunch of text
+ * inquiries to its listbox while processing WM_PAINT. */
+
+ if( (id = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0) ) != LB_ERR )
+ {
+ size = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, id, 0);
+ if (size == LB_ERR)
+ FIXME("LB_ERR probably not handled yet\n");
+ if ((pText = heap_alloc((size + 1) * sizeof(WCHAR))))
+ {
+ /* size from LB_GETTEXTLEN may be too large, from LB_GETTEXT is accurate */
+ size=SendMessageW(lphc->hWndLBox, LB_GETTEXT, id, (LPARAM)pText);
+ pText[size] = '\0'; /* just in case */
+ } else return;
+ }
+
+ if( lphc->wState & CBF_EDIT )
+ {
+ static const WCHAR empty_stringW[] = { 0 };
+ if( CB_HASSTRINGS(lphc) ) SetWindowTextW( lphc->hWndEdit, pText ? pText :
empty_stringW );
+ if( lphc->wState & CBF_FOCUSED )
+ SendMessageW(lphc->hWndEdit, EM_SETSEL, 0, MAXLONG);
+ }
+ else if(!(lphc->wState & CBF_NOREDRAW) && IsWindowVisible(
lphc->self ))
+ {
+ /* paint text field ourselves */
+ HDC hdc = hdc_paint ? hdc_paint : GetDC(lphc->self);
+ UINT itemState = ODS_COMBOBOXEDIT;
+ HFONT hPrevFont = (lphc->hFont) ? SelectObject(hdc, lphc->hFont) : 0;
+ HBRUSH hPrevBrush, hBkgBrush;
+
+ /*
+ * Give ourselves some space.
+ */
+ InflateRect( &rectEdit, -1, -1 );
+
+ hBkgBrush = COMBO_PrepareColors( lphc, hdc );
+ hPrevBrush = SelectObject( hdc, hBkgBrush );
+ FillRect( hdc, &rectEdit, hBkgBrush );
+
+ if( CB_OWNERDRAWN(lphc) )
+ {
+ DRAWITEMSTRUCT dis;
+ HRGN clipRegion;
+ UINT ctlid = (UINT)GetWindowLongPtrW( lphc->self, GWLP_ID );
+
+ /* setup state for DRAWITEM message. Owner will highlight */
+ if ( (lphc->wState & CBF_FOCUSED) &&
+ !(lphc->wState & CBF_DROPPED) )
+ itemState |= ODS_SELECTED | ODS_FOCUS;
+
+ if (!IsWindowEnabled(lphc->self)) itemState |= ODS_DISABLED;
+
+ dis.CtlType = ODT_COMBOBOX;
+ dis.CtlID = ctlid;
+ dis.hwndItem = lphc->self;
+ dis.itemAction = ODA_DRAWENTIRE;
+ dis.itemID = id;
+ dis.itemState = itemState;
+ dis.hDC = hdc;
+ dis.rcItem = rectEdit;
+ dis.itemData = SendMessageW(lphc->hWndLBox, LB_GETITEMDATA, id, 0);
+
+ /*
+ * Clip the DC and have the parent draw the item.
+ */
+ clipRegion = set_control_clipping( hdc, &rectEdit );
+
+ SendMessageW(lphc->owner, WM_DRAWITEM, ctlid, (LPARAM)&dis );
+
+ SelectClipRgn( hdc, clipRegion );
+ if (clipRegion) DeleteObject( clipRegion );
+ }
+ else
+ {
+ static const WCHAR empty_stringW[] = { 0 };
+
+ if ( (lphc->wState & CBF_FOCUSED) &&
+ !(lphc->wState & CBF_DROPPED) ) {
+
+ /* highlight */
+ FillRect( hdc, &rectEdit, GetSysColorBrush(COLOR_HIGHLIGHT) );
+ SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
+ SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
+ }
+
+ ExtTextOutW( hdc,
+ rectEdit.left + 1,
+ rectEdit.top + 1,
+ ETO_OPAQUE | ETO_CLIPPED,
+ &rectEdit,
+ pText ? pText : empty_stringW , size, NULL );
+
+ if(lphc->wState & CBF_FOCUSED && !(lphc->wState &
CBF_DROPPED))
+ DrawFocusRect( hdc, &rectEdit );
+ }
+
+ if( hPrevFont )
+ SelectObject(hdc, hPrevFont );
+
+ if( hPrevBrush )
+ SelectObject( hdc, hPrevBrush );
+
+ if( !hdc_paint )
+ ReleaseDC( lphc->self, hdc );
+ }
+
+ heap_free(pText);
+}
+
+/***********************************************************************
+ * CBPaintBorder
+ */
+static void CBPaintBorder(
+ HWND hwnd,
+ const HEADCOMBO *lphc,
+ HDC hdc)
+{
+ RECT clientRect;
+
+ if (CB_GETTYPE(lphc) != CBS_SIMPLE)
+ {
+ GetClientRect(hwnd, &clientRect);
+ }
+ else
+ {
+ clientRect = lphc->textRect;
+
+ InflateRect(&clientRect, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
+ InflateRect(&clientRect, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
+ }
+
+ DrawEdge(hdc, &clientRect, EDGE_SUNKEN, BF_RECT);
+}
+
+static LRESULT COMBO_ThemedPaint(HTHEME theme, HEADCOMBO *lphc, HDC hdc)
+{
+ int button_state;
+ RECT frame;
+
+ /* paint border */
+ if (CB_GETTYPE(lphc) != CBS_SIMPLE)
+ GetClientRect(lphc->self, &frame);
+ else
+ {
+ frame = lphc->textRect;
+ InflateRect(&frame, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
+ InflateRect(&frame, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
+ }
+
+ DrawThemeBackground(theme, hdc, 0, IsWindowEnabled(lphc->self) ? CBXS_NORMAL :
CBXS_DISABLED, &frame, NULL);
+
+ /* Paint button */
+ if (!IsRectEmpty(&lphc->buttonRect))
+ {
+ if (!IsWindowEnabled(lphc->self))
+ button_state = CBXS_DISABLED;
+ else if (lphc->wState & CBF_BUTTONDOWN)
+ button_state = CBXS_PRESSED;
+ else if (lphc->wState & CBF_HOT)
+ button_state = CBXS_HOT;
+ else
+ button_state = CBXS_NORMAL;
+ DrawThemeBackground(theme, hdc, CP_DROPDOWNBUTTON, button_state,
&lphc->buttonRect, NULL);
+ }
+
+ if ((lphc->dwStyle & CBS_DROPDOWNLIST) == CBS_DROPDOWNLIST)
+ CBPaintText(lphc, hdc);
+
+ return 0;
+}
+
+/***********************************************************************
+ * COMBO_Paint
+ */
+static LRESULT COMBO_Paint(HEADCOMBO *lphc, HDC hdc)
+{
+ HBRUSH hPrevBrush, hBkgBrush;
+
+ TRACE("hdc=%p\n", hdc);
+
+ /*
+ * Retrieve the background brush and select it in the
+ * DC.
+ */
+ hBkgBrush = COMBO_PrepareColors(lphc, hdc);
+ hPrevBrush = SelectObject(hdc, hBkgBrush);
+ if (!(lphc->wState & CBF_EDIT))
+ FillRect(hdc, &lphc->textRect, hBkgBrush);
+
+ /*
+ * In non 3.1 look, there is a sunken border on the combobox
+ */
+ CBPaintBorder(lphc->self, lphc, hdc);
+
+ if (!IsRectEmpty(&lphc->buttonRect))
+ CBPaintButton(lphc, hdc, lphc->buttonRect);
+
+ /* paint the edit control padding area */
+ if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
+ {
+ RECT rPadEdit = lphc->textRect;
+
+ InflateRect(&rPadEdit, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
+
+ FrameRect(hdc, &rPadEdit, GetSysColorBrush(COLOR_WINDOW));
+ }
+
+ if (!(lphc->wState & CBF_EDIT))
+ CBPaintText( lphc, hdc );
+
+ if (hPrevBrush)
+ SelectObject( hdc, hPrevBrush );
+
+ return 0;
+}
+
+/***********************************************************************
+ * CBUpdateLBox
+ *
+ * Select listbox entry according to the contents of the edit control.
+ */
+static INT CBUpdateLBox( LPHEADCOMBO lphc, BOOL bSelect )
+{
+ INT length, idx;
+ LPWSTR pText = NULL;
+
+ idx = LB_ERR;
+ length = SendMessageW( lphc->hWndEdit, WM_GETTEXTLENGTH, 0, 0 );
+
+ if (length > 0)
+ pText = heap_alloc((length + 1) * sizeof(WCHAR));
+
+ TRACE("\t edit text length %i\n", length );
+
+ if( pText )
+ {
+ GetWindowTextW( lphc->hWndEdit, pText, length + 1);
+ idx = SendMessageW(lphc->hWndLBox, LB_FINDSTRING, -1, (LPARAM)pText);
+ heap_free( pText );
+ }
+
+ SendMessageW(lphc->hWndLBox, LB_SETCURSEL, bSelect ? idx : -1, 0);
+
+ /* probably superfluous but Windows sends this too */
+ SendMessageW(lphc->hWndLBox, LB_SETCARETINDEX, idx < 0 ? 0 : idx, 0);
+ SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX, idx < 0 ? 0 : idx, 0);
+
+ return idx;
+}
+
+/***********************************************************************
+ * CBUpdateEdit
+ *
+ * Copy a listbox entry to the edit control.
+ */
+static void CBUpdateEdit( LPHEADCOMBO lphc , INT index )
+{
+ INT length;
+ LPWSTR pText = NULL;
+ static const WCHAR empty_stringW[] = { 0 };
+
+ TRACE("\t %i\n", index );
+
+ if( index >= 0 ) /* got an entry */
+ {
+ length = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, index, 0);
+ if( length != LB_ERR)
+ {
+ if ((pText = heap_alloc((length + 1) * sizeof(WCHAR))))
+ SendMessageW(lphc->hWndLBox, LB_GETTEXT, index, (LPARAM)pText);
+ }
+ }
+
+ if( CB_HASSTRINGS(lphc) )
+ {
+ lphc->wState |= (CBF_NOEDITNOTIFY | CBF_NOLBSELECT);
+ SendMessageW(lphc->hWndEdit, WM_SETTEXT, 0, pText ? (LPARAM)pText :
(LPARAM)empty_stringW);
+ lphc->wState &= ~(CBF_NOEDITNOTIFY | CBF_NOLBSELECT);
+ }
+
+ if( lphc->wState & CBF_FOCUSED )
+ SendMessageW(lphc->hWndEdit, EM_SETSEL, 0, -1);
+
+ heap_free( pText );
+}
+
+/***********************************************************************
+ * CBDropDown
+ *
+ * Show listbox popup.
+ */
+static void CBDropDown( LPHEADCOMBO lphc )
+{
+ HMONITOR monitor;
+ MONITORINFO mon_info;
+ RECT rect,r;
+ int nItems;
+ int nDroppedHeight;
+
+ TRACE("[%p]: drop down\n", lphc->self);
+
+ CB_NOTIFY( lphc, CBN_DROPDOWN );
+
+ /* set selection */
+
+ lphc->wState |= CBF_DROPPED;
+ if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+ {
+ lphc->droppedIndex = CBUpdateLBox( lphc, TRUE );
+
+ /* Update edit only if item is in the list */
+ if( !(lphc->wState & CBF_CAPTURE) && lphc->droppedIndex >=
0)
+ CBUpdateEdit( lphc, lphc->droppedIndex );
+ }
+ else
+ {
+ lphc->droppedIndex = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+
+ SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX,
+ lphc->droppedIndex == LB_ERR ? 0 : lphc->droppedIndex, 0);
+ SendMessageW(lphc->hWndLBox, LB_CARETON, 0, 0);
+ }
+
+ /* now set popup position */
+ GetWindowRect( lphc->self, &rect );
+
+ /*
+ * If it's a dropdown, the listbox is offset
+ */
+ if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+ rect.left += COMBO_EDITBUTTONSPACE();
+
+ /* if the dropped height is greater than the total height of the dropped
+ items list, then force the drop down list height to be the total height
+ of the items in the dropped list */
+
+ /* And Remove any extra space (Best Fit) */
+ nDroppedHeight = lphc->droppedRect.bottom - lphc->droppedRect.top;
+ /* if listbox length has been set directly by its handle */
+ GetWindowRect(lphc->hWndLBox, &r);
+ if (nDroppedHeight < r.bottom - r.top)
+ nDroppedHeight = r.bottom - r.top;
+ nItems = (int)SendMessageW(lphc->hWndLBox, LB_GETCOUNT, 0, 0);
+
+ if (nItems > 0)
+ {
+ int nHeight;
+ int nIHeight;
+
+ nIHeight = (int)SendMessageW(lphc->hWndLBox, LB_GETITEMHEIGHT, 0, 0);
+
+ nHeight = nIHeight*nItems;
+
+ if (nHeight < nDroppedHeight - COMBO_YBORDERSIZE())
+ nDroppedHeight = nHeight + COMBO_YBORDERSIZE();
+
+ if (nDroppedHeight < nHeight)
+ {
+ if (nItems < 5)
+ nDroppedHeight = (nItems+1)*nIHeight;
+ else if (nDroppedHeight < 6*nIHeight)
+ nDroppedHeight = 6*nIHeight;
+ }
+ }
+
+ r.left = rect.left;
+ r.top = rect.bottom;
+ r.right = r.left + lphc->droppedRect.right - lphc->droppedRect.left;
+ r.bottom = r.top + nDroppedHeight;
+
+ /*If height of dropped rectangle gets beyond a screen size it should go up, otherwise
down.*/
+ monitor = MonitorFromRect( &rect, MONITOR_DEFAULTTOPRIMARY );
+ mon_info.cbSize = sizeof(mon_info);
+ GetMonitorInfoW( monitor, &mon_info );
+
+ if (r.bottom > mon_info.rcWork.bottom)
+ {
+ r.top = max( rect.top - nDroppedHeight, mon_info.rcWork.top );
+ r.bottom = min( r.top + nDroppedHeight, mon_info.rcWork.bottom );
+ }
+
+ SetWindowPos( lphc->hWndLBox, HWND_TOPMOST, r.left, r.top, r.right - r.left,
r.bottom - r.top,
+ SWP_NOACTIVATE | SWP_SHOWWINDOW );
+
+
+ if( !(lphc->wState & CBF_NOREDRAW) )
+ RedrawWindow( lphc->self, NULL, 0, RDW_INVALIDATE |
+ RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
+
+ EnableWindow( lphc->hWndLBox, TRUE );
+ if (GetCapture() != lphc->self)
+ SetCapture(lphc->hWndLBox);
+}
+
+/***********************************************************************
+ * CBRollUp
+ *
+ * Hide listbox popup.
+ */
+static void CBRollUp( LPHEADCOMBO lphc, BOOL ok, BOOL bButton )
+{
+ HWND hWnd = lphc->self;
+
+ TRACE("[%p]: sel ok? [%i] dropped? [%i]\n",
+ lphc->self, ok, (INT)(lphc->wState & CBF_DROPPED));
+
+ CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL );
+
+ if( IsWindow( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE )
+ {
+
+ if( lphc->wState & CBF_DROPPED )
+ {
+ RECT rect;
+
+ lphc->wState &= ~CBF_DROPPED;
+ ShowWindow( lphc->hWndLBox, SW_HIDE );
+
+ if(GetCapture() == lphc->hWndLBox)
+ {
+ ReleaseCapture();
+ }
+
+ if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+ {
+ rect = lphc->buttonRect;
+ }
+ else
+ {
+ if( bButton )
+ {
+ UnionRect( &rect,
+ &lphc->buttonRect,
+ &lphc->textRect);
+ }
+ else
+ rect = lphc->textRect;
+
+ bButton = TRUE;
+ }
+
+ if( bButton && !(lphc->wState & CBF_NOREDRAW) )
+ RedrawWindow( hWnd, &rect, 0, RDW_INVALIDATE |
+ RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
+ CB_NOTIFY( lphc, CBN_CLOSEUP );
+ }
+ }
+}
+
+/***********************************************************************
+ * COMBO_FlipListbox
+ *
+ * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
+ */
+BOOL COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL ok, BOOL bRedrawButton )
+{
+ if( lphc->wState & CBF_DROPPED )
+ {
+ CBRollUp( lphc, ok, bRedrawButton );
+ return FALSE;
+ }
+
+ CBDropDown( lphc );
+ return TRUE;
+}
+
+/***********************************************************************
+ * CBRepaintButton
+ */
+static void CBRepaintButton( LPHEADCOMBO lphc )
+ {
+ InvalidateRect(lphc->self, &lphc->buttonRect, TRUE);
+ UpdateWindow(lphc->self);
+}
+
+/***********************************************************************
+ * COMBO_SetFocus
+ */
+static void COMBO_SetFocus( LPHEADCOMBO lphc )
+{
+ if( !(lphc->wState & CBF_FOCUSED) )
+ {
+ if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
+ SendMessageW(lphc->hWndLBox, LB_CARETON, 0, 0);
+
+ /* This is wrong. Message sequences seem to indicate that this
+ is set *after* the notify. */
+ /* lphc->wState |= CBF_FOCUSED; */
+
+ if( !(lphc->wState & CBF_EDIT) )
+ InvalidateRect(lphc->self, &lphc->textRect, TRUE);
+
+ CB_NOTIFY( lphc, CBN_SETFOCUS );
+ lphc->wState |= CBF_FOCUSED;
+ }
+}
+
+/***********************************************************************
+ * COMBO_KillFocus
+ */
+static void COMBO_KillFocus( LPHEADCOMBO lphc )
+{
+ HWND hWnd = lphc->self;
+
+ if( lphc->wState & CBF_FOCUSED )
+ {
+ CBRollUp( lphc, FALSE, TRUE );
+ if( IsWindow( hWnd ) )
+ {
+ if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
+ SendMessageW(lphc->hWndLBox, LB_CARETOFF, 0, 0);
+
+ lphc->wState &= ~CBF_FOCUSED;
+
+ /* redraw text */
+ if( !(lphc->wState & CBF_EDIT) )
+ InvalidateRect(lphc->self, &lphc->textRect, TRUE);
+
+ CB_NOTIFY( lphc, CBN_KILLFOCUS );
+ }
+ }
+}
+
+/***********************************************************************
+ * COMBO_Command
+ */
+static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd )
+{
+ if ( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd )
+ {
+ /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
+
+ switch( HIWORD(wParam) >> 8 )
+ {
+ case (EN_SETFOCUS >> 8):
+
+ TRACE("[%p]: edit [%p] got focus\n", lphc->self,
lphc->hWndEdit );
+
+ COMBO_SetFocus( lphc );
+ break;
+
+ case (EN_KILLFOCUS >> 8):
+
+ TRACE("[%p]: edit [%p] lost focus\n", lphc->self,
lphc->hWndEdit );
+
+ /* NOTE: it seems that Windows' edit control sends an
+ * undocumented message WM_USER + 0x1B instead of this
+ * notification (only when it happens to be a part of
+ * the combo). ?? - AK.
+ */
+
+ COMBO_KillFocus( lphc );
+ break;
+
+
+ case (EN_CHANGE >> 8):
+ /*
+ * In some circumstances (when the selection of the combobox
+ * is changed for example) we don't want the EN_CHANGE notification
+ * to be forwarded to the parent of the combobox. This code
+ * checks a flag that is set in these occasions and ignores the
+ * notification.
+ */
+ if (lphc->wState & CBF_NOLBSELECT)
+ {
+ lphc->wState &= ~CBF_NOLBSELECT;
+ }
+ else
+ {
+ CBUpdateLBox( lphc, lphc->wState & CBF_DROPPED );
+ }
+
+ if (!(lphc->wState & CBF_NOEDITNOTIFY))
+ CB_NOTIFY( lphc, CBN_EDITCHANGE );
+ break;
+
+ case (EN_UPDATE >> 8):
+ if (!(lphc->wState & CBF_NOEDITNOTIFY))
+ CB_NOTIFY( lphc, CBN_EDITUPDATE );
+ break;
+
+ case (EN_ERRSPACE >> 8):
+ CB_NOTIFY( lphc, CBN_ERRSPACE );
+ }
+ }
+ else if( lphc->hWndLBox == hWnd )
+ {
+ switch( (short)HIWORD(wParam) )
+ {
+ case LBN_ERRSPACE:
+ CB_NOTIFY( lphc, CBN_ERRSPACE );
+ break;
+
+ case LBN_DBLCLK:
+ CB_NOTIFY( lphc, CBN_DBLCLK );
+ break;
+
+ case LBN_SELCHANGE:
+ case LBN_SELCANCEL:
+
+ TRACE("[%p]: lbox selection change [%x]\n", lphc->self,
lphc->wState );
+
+ /* do not roll up if selection is being tracked
+ * by arrow keys in the dropdown listbox */
+ if (!(lphc->wState & CBF_NOROLLUP))
+ {
+ CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
+ }
+ else lphc->wState &= ~CBF_NOROLLUP;
+
+ CB_NOTIFY( lphc, CBN_SELCHANGE );
+
+ if( HIWORD(wParam) == LBN_SELCHANGE)
+ {
+ if( lphc->wState & CBF_EDIT )
+ lphc->wState |= CBF_NOLBSELECT;
+ CBPaintText( lphc, NULL );
+ }
+ break;
+
+ case LBN_SETFOCUS:
+ case LBN_KILLFOCUS:
+ /* nothing to do here since ComboLBox always resets the focus to its
+ * combo/edit counterpart */
+ break;
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * COMBO_ItemOp
+ *
+ * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
+ */
+static LRESULT COMBO_ItemOp( LPHEADCOMBO lphc, UINT msg, LPARAM lParam )
+{
+ HWND hWnd = lphc->self;
+ UINT id = (UINT)GetWindowLongPtrW( hWnd, GWLP_ID );
+
+ TRACE("[%p]: ownerdraw op %04x\n", lphc->self, msg );
+
+ switch( msg )
+ {
+ case WM_DELETEITEM:
+ {
+ DELETEITEMSTRUCT *lpIS = (DELETEITEMSTRUCT *)lParam;
+ lpIS->CtlType = ODT_COMBOBOX;
+ lpIS->CtlID = id;
+ lpIS->hwndItem = hWnd;
+ break;
+ }
+ case WM_DRAWITEM:
+ {
+ DRAWITEMSTRUCT *lpIS = (DRAWITEMSTRUCT *)lParam;
+ lpIS->CtlType = ODT_COMBOBOX;
+ lpIS->CtlID = id;
+ lpIS->hwndItem = hWnd;
+ break;
+ }
+ case WM_COMPAREITEM:
+ {
+ COMPAREITEMSTRUCT *lpIS = (COMPAREITEMSTRUCT *)lParam;
+ lpIS->CtlType = ODT_COMBOBOX;
+ lpIS->CtlID = id;
+ lpIS->hwndItem = hWnd;
+ break;
+ }
+ case WM_MEASUREITEM:
+ {
+ MEASUREITEMSTRUCT *lpIS = (MEASUREITEMSTRUCT *)lParam;
+ lpIS->CtlType = ODT_COMBOBOX;
+ lpIS->CtlID = id;
+ break;
+ }
+ }
+ return SendMessageW(lphc->owner, msg, id, lParam);
+}
+
+
+/***********************************************************************
+ * COMBO_GetTextW
+ */
+static LRESULT COMBO_GetText( HEADCOMBO *lphc, INT count, LPWSTR buf )
+{
+ INT length;
+
+ if( lphc->wState & CBF_EDIT )
+ return SendMessageW( lphc->hWndEdit, WM_GETTEXT, count, (LPARAM)buf );
+
+ /* get it from the listbox */
+
+ if (!count || !buf) return 0;
+ if( lphc->hWndLBox )
+ {
+ INT idx = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+ if (idx == LB_ERR) goto error;
+ length = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, idx, 0 );
+ if (length == LB_ERR) goto error;
+
+ /* 'length' is without the terminating character */
+ if (length >= count)
+ {
+ WCHAR *lpBuffer = heap_alloc((length + 1) * sizeof(WCHAR));
+ if (!lpBuffer) goto error;
+ length = SendMessageW(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)lpBuffer);
+
+ /* truncate if buffer is too short */
+ if (length != LB_ERR)
+ {
+ lstrcpynW( buf, lpBuffer, count );
+ length = count;
+ }
+ heap_free( lpBuffer );
+ }
+ else length = SendMessageW(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)buf);
+
+ if (length == LB_ERR) return 0;
+ return length;
+ }
+
+ error: /* error - truncate string, return zero */
+ buf[0] = 0;
+ return 0;
+}
+
+/***********************************************************************
+ * CBResetPos
+ *
+ * This function sets window positions according to the updated
+ * component placement struct.
+ */
+static void CBResetPos(
+ LPHEADCOMBO lphc,
+ const RECT *rectEdit,
+ const RECT *rectLB,
+ BOOL bRedraw)
+{
+ BOOL bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
+
+ /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
+ * sizing messages */
+
+ if( lphc->wState & CBF_EDIT )
+ SetWindowPos( lphc->hWndEdit, 0,
+ rectEdit->left, rectEdit->top,
+ rectEdit->right - rectEdit->left,
+ rectEdit->bottom - rectEdit->top,
+ SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
+
+ SetWindowPos( lphc->hWndLBox, 0,
+ rectLB->left, rectLB->top,
+ rectLB->right - rectLB->left,
+ rectLB->bottom - rectLB->top,
+ SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
+
+ if( bDrop )
+ {
+ if( lphc->wState & CBF_DROPPED )
+ {
+ lphc->wState &= ~CBF_DROPPED;
+ ShowWindow( lphc->hWndLBox, SW_HIDE );
+ }
+
+ if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
+ RedrawWindow( lphc->self, NULL, 0,
+ RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
+ }
+}
+
+
+/***********************************************************************
+ * COMBO_Size
+ */
+static void COMBO_Size( LPHEADCOMBO lphc )
+{
+ /*
+ * Those controls are always the same height. So we have to make sure
+ * they are not resized to another value.
+ */
+ if( CB_GETTYPE(lphc) != CBS_SIMPLE )
+ {
+ int newComboHeight, curComboHeight, curComboWidth;
+ RECT rc;
+
+ GetWindowRect(lphc->self, &rc);
+ curComboHeight = rc.bottom - rc.top;
+ curComboWidth = rc.right - rc.left;
+ newComboHeight = CBGetTextAreaHeight(lphc->self, lphc) + 2*COMBO_YBORDERSIZE();
+
+ /*
+ * Resizing a combobox has another side effect, it resizes the dropped
+ * rectangle as well. However, it does it only if the new height for the
+ * combobox is more than the height it should have. In other words,
+ * if the application resizing the combobox only had the intention to resize
+ * the actual control, for example, to do the layout of a dialog that is
+ * resized, the height of the dropdown is not changed.
+ */
+ if( curComboHeight > newComboHeight )
+ {
+ TRACE("oldComboHeight=%d, newComboHeight=%d, oldDropBottom=%d,
oldDropTop=%d\n",
+ curComboHeight, newComboHeight, lphc->droppedRect.bottom,
+ lphc->droppedRect.top);
+ lphc->droppedRect.bottom = lphc->droppedRect.top + curComboHeight -
newComboHeight;
+ }
+ /*
+ * Restore original height
+ */
+ if( curComboHeight != newComboHeight )
+ SetWindowPos(lphc->self, 0, 0, 0, curComboWidth, newComboHeight,
+ SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW);
+ }
+
+ CBCalcPlacement(lphc->self,
+ lphc,
+ &lphc->textRect,
+ &lphc->buttonRect,
+ &lphc->droppedRect);
+
+ CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
+}
+
+
+/***********************************************************************
+ * COMBO_Font
+ */
+static void COMBO_Font( LPHEADCOMBO lphc, HFONT hFont, BOOL bRedraw )
+{
+ /*
+ * Set the font
+ */
+ lphc->hFont = hFont;
+
+ /*
+ * Propagate to owned windows.
+ */
+ if( lphc->wState & CBF_EDIT )
+ SendMessageW(lphc->hWndEdit, WM_SETFONT, (WPARAM)hFont, bRedraw);
+ SendMessageW(lphc->hWndLBox, WM_SETFONT, (WPARAM)hFont, bRedraw);
+
+ /*
+ * Redo the layout of the control.
+ */
+ if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
+ {
+ CBCalcPlacement(lphc->self,
+ lphc,
+ &lphc->textRect,
+ &lphc->buttonRect,
+ &lphc->droppedRect);
+
+ CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
+ }
+ else
+ {
+ CBForceDummyResize(lphc);
+ }
+}
+
+
+/***********************************************************************
+ * COMBO_SetItemHeight
+ */
+static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT index, INT height )
+{
+ LRESULT lRet = CB_ERR;
+
+ if( index == -1 ) /* set text field height */
+ {
+ if( height < 32768 )
+ {
+ lphc->editHeight = height + 2; /* Is the 2 for 2*EDIT_CONTROL_PADDING? */
+
+ /*
+ * Redo the layout of the control.
+ */
+ if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
+ {
+ CBCalcPlacement(lphc->self,
+ lphc,
+ &lphc->textRect,
+ &lphc->buttonRect,
+ &lphc->droppedRect);
+
+ CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
+ }
+ else
+ {
+ CBForceDummyResize(lphc);
+ }
+
+ lRet = height;
+ }
+ }
+ else if ( CB_OWNERDRAWN(lphc) ) /* set listbox item height */
+ lRet = SendMessageW(lphc->hWndLBox, LB_SETITEMHEIGHT, index, height);
+ return lRet;
+}
+
+/***********************************************************************
+ * COMBO_SelectString
+ */
+static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT start, LPARAM pText)
+{
+ INT index = SendMessageW(lphc->hWndLBox, LB_SELECTSTRING, start, pText);
+ if( index >= 0 )
+ {
+ if( lphc->wState & CBF_EDIT )
+ CBUpdateEdit( lphc, index );
+ else
+ {
+ InvalidateRect(lphc->self, &lphc->textRect, TRUE);
+ }
+ }
+ return (LRESULT)index;
+}
+
+/***********************************************************************
+ * COMBO_LButtonDown
+ */
+static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
+{
+ POINT pt;
+ BOOL bButton;
+ HWND hWnd = lphc->self;
+
+ pt.x = (short)LOWORD(lParam);
+ pt.y = (short)HIWORD(lParam);
+ bButton = PtInRect(&lphc->buttonRect, pt);
+
+ if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
+ (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
+ {
+ lphc->wState |= CBF_BUTTONDOWN;
+ if( lphc->wState & CBF_DROPPED )
+ {
+ /* got a click to cancel selection */
+
+ lphc->wState &= ~CBF_BUTTONDOWN;
+ CBRollUp( lphc, TRUE, FALSE );
+ if( !IsWindow( hWnd ) ) return;
+
+ if( lphc->wState & CBF_CAPTURE )
+ {
+ lphc->wState &= ~CBF_CAPTURE;
+ ReleaseCapture();
+ }
+ }
+ else
+ {
+ /* drop down the listbox and start tracking */
+
+ lphc->wState |= CBF_CAPTURE;
+ SetCapture( hWnd );
+ CBDropDown( lphc );
+ }
+ if( bButton ) CBRepaintButton( lphc );
+ }
+}
+
+/***********************************************************************
+ * COMBO_LButtonUp
+ *
+ * Release capture and stop tracking if needed.
+ */
+static void COMBO_LButtonUp( LPHEADCOMBO lphc )
+{
+ if( lphc->wState & CBF_CAPTURE )
+ {
+ lphc->wState &= ~CBF_CAPTURE;
+ if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
+ {
+ INT index = CBUpdateLBox( lphc, TRUE );
+ /* Update edit only if item is in the list */
+ if(index >= 0)
+ {
+ lphc->wState |= CBF_NOLBSELECT;
+ CBUpdateEdit( lphc, index );
+ lphc->wState &= ~CBF_NOLBSELECT;
+ }
+ }
+ ReleaseCapture();
+ SetCapture(lphc->hWndLBox);
+ }
+
+ if( lphc->wState & CBF_BUTTONDOWN )
+ {
+ lphc->wState &= ~CBF_BUTTONDOWN;
+ CBRepaintButton( lphc );
+ }
+}
+
+/***********************************************************************
+ * COMBO_MouseMove
+ *
+ * Two things to do - track combo button and release capture when
+ * pointer goes into the listbox.
+ */
+static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM wParam, LPARAM lParam )
+{
+ POINT pt;
+ RECT lbRect;
+
+ pt.x = (short)LOWORD(lParam);
+ pt.y = (short)HIWORD(lParam);
+
+ if( lphc->wState & CBF_BUTTONDOWN )
+ {
+ BOOL bButton;
+
+ bButton = PtInRect(&lphc->buttonRect, pt);
+
+ if( !bButton )
+ {
+ lphc->wState &= ~CBF_BUTTONDOWN;
+ CBRepaintButton( lphc );
+ }
+ }
+
+ GetClientRect( lphc->hWndLBox, &lbRect );
+ MapWindowPoints( lphc->self, lphc->hWndLBox, &pt, 1 );
+ if( PtInRect(&lbRect, pt) )
+ {
+ lphc->wState &= ~CBF_CAPTURE;
+ ReleaseCapture();
+ if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc, TRUE );
+
+ /* hand over pointer tracking */
+ SendMessageW(lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam);
+ }
+}
+
+static LRESULT COMBO_GetComboBoxInfo(const HEADCOMBO *lphc, COMBOBOXINFO *pcbi)
+{
+ if (!pcbi || (pcbi->cbSize < sizeof(COMBOBOXINFO)))
+ return FALSE;
+
+ pcbi->rcItem = lphc->textRect;
+ pcbi->rcButton = lphc->buttonRect;
+ pcbi->stateButton = 0;
+ if (lphc->wState & CBF_BUTTONDOWN)
+ pcbi->stateButton |= STATE_SYSTEM_PRESSED;
+ if (IsRectEmpty(&lphc->buttonRect))
+ pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
+ pcbi->hwndCombo = lphc->self;
+ pcbi->hwndItem = lphc->hWndEdit;
+ pcbi->hwndList = lphc->hWndLBox;
+ return TRUE;
+}
+
+static LRESULT CALLBACK COMBO_WindowProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM
lParam )
+{
+ HEADCOMBO *lphc = (HEADCOMBO *)GetWindowLongPtrW( hwnd, 0 );
+ HTHEME theme;
+
+ TRACE("[%p]: msg %#x wp %08lx lp %08lx\n", hwnd, message, wParam, lParam
);
+
+ if (!IsWindow(hwnd)) return 0;
+
+ if (lphc || message == WM_NCCREATE)
+ switch(message)
+ {
+ case WM_NCCREATE:
+ {
+ LONG style = ((CREATESTRUCTW *)lParam)->style;
+ return COMBO_NCCreate(hwnd, style);
+ }
+
+ case WM_NCDESTROY:
+ COMBO_NCDestroy(lphc);
+ break;/* -> DefWindowProc */
+
+ case WM_CREATE:
+ {
+ HWND hwndParent;
+ LONG style;
+
+ hwndParent = ((CREATESTRUCTW *)lParam)->hwndParent;
+ style = ((CREATESTRUCTW *)lParam)->style;
+ return COMBO_Create(hwnd, lphc, hwndParent, style);
+ }
+
+ case WM_DESTROY:
+ theme = GetWindowTheme( hwnd );
+ CloseThemeData( theme );
+ break;
+
+ case WM_THEMECHANGED:
+ theme = GetWindowTheme( hwnd );
+ CloseThemeData( theme );
+ OpenThemeData( hwnd, WC_COMBOBOXW );
+ break;
+
+ case WM_PRINTCLIENT:
+ case WM_PAINT:
+ {
+ LRESULT ret = 0;
+ PAINTSTRUCT ps;
+ HDC hdc;
+
+ hdc = wParam ? (HDC)wParam : BeginPaint(hwnd, &ps);
+
+ if (hdc && !(lphc->wState & CBF_NOREDRAW))
+ {
+ HTHEME theme = GetWindowTheme(hwnd);
+
+ if (theme)
+ ret = COMBO_ThemedPaint(theme, lphc, hdc);
+ else
+ ret = COMBO_Paint(lphc, hdc);
+ }
+
+ if (!wParam)
+ EndPaint(hwnd, &ps);
+
+ return ret;
+ }
+ case WM_ERASEBKGND:
+ /* do all painting in WM_PAINT like Windows does */
+ return 1;
+
+ case WM_GETDLGCODE:
+ {
+ LRESULT result = DLGC_WANTARROWS | DLGC_WANTCHARS;
+ if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN))
+ {
+ int vk = (int)((LPMSG)lParam)->wParam;
+
+ if ((vk == VK_RETURN || vk == VK_ESCAPE) && (lphc->wState &
CBF_DROPPED))
+ result |= DLGC_WANTMESSAGE;
+ }
+ return result;
+ }
+
+ case WM_SIZE:
+ if (lphc->hWndLBox && !(lphc->wState & CBF_NORESIZE))
+ COMBO_Size( lphc );
+ return TRUE;
+
+ case WM_SETFONT:
+ COMBO_Font( lphc, (HFONT)wParam, (BOOL)lParam );
+ return TRUE;
+
+ case WM_GETFONT:
+ return (LRESULT)lphc->hFont;
+
+ case WM_SETFOCUS:
+ if (lphc->wState & CBF_EDIT)
+ {
+ SetFocus( lphc->hWndEdit );
+ /* The first time focus is received, select all the text */
+ if (!(lphc->wState & CBF_BEENFOCUSED))
+ {
+ SendMessageW(lphc->hWndEdit, EM_SETSEL, 0, -1);
+ lphc->wState |= CBF_BEENFOCUSED;
+ }
+ }
+ else
+ COMBO_SetFocus( lphc );
+ return TRUE;
+
+ case WM_KILLFOCUS:
+ {
+ HWND hwndFocus = (HWND)wParam;
+ if (!hwndFocus || (hwndFocus != lphc->hWndEdit && hwndFocus !=
lphc->hWndLBox))
+ COMBO_KillFocus( lphc );
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ return COMBO_Command( lphc, wParam, (HWND)lParam );
+
+ case WM_GETTEXT:
+ return COMBO_GetText( lphc, wParam, (LPWSTR)lParam );
+
+ case WM_SETTEXT:
+ case WM_GETTEXTLENGTH:
+ case WM_CLEAR:
+ if ((message == WM_GETTEXTLENGTH) && !ISWIN31 &&
!(lphc->wState & CBF_EDIT))
+ {
+ int j = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+ if (j == -1) return 0;
+ return SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, j, 0);
+ }
+ else if ( lphc->wState & CBF_EDIT )
+ {
+ LRESULT ret;
+ lphc->wState |= CBF_NOEDITNOTIFY;
+ ret = SendMessageW(lphc->hWndEdit, message, wParam, lParam);
+ lphc->wState &= ~CBF_NOEDITNOTIFY;
+ return ret;
+ }
+ else
+ return CB_ERR;
+
+ case WM_CUT:
+ case WM_PASTE:
+ case WM_COPY:
+ if (lphc->wState & CBF_EDIT)
+ return SendMessageW(lphc->hWndEdit, message, wParam, lParam);
+ else return CB_ERR;
+
+ case WM_DRAWITEM:
+ case WM_DELETEITEM:
+ case WM_COMPAREITEM:
+ case WM_MEASUREITEM:
+ return COMBO_ItemOp(lphc, message, lParam);
+
+ case WM_ENABLE:
+ if (lphc->wState & CBF_EDIT)
+ EnableWindow( lphc->hWndEdit, (BOOL)wParam );
+ EnableWindow( lphc->hWndLBox, (BOOL)wParam );
+
+ /* Force the control to repaint when the enabled state changes. */
+ InvalidateRect(lphc->self, NULL, TRUE);
+ return TRUE;
+
+ case WM_SETREDRAW:
+ if (wParam)
+ lphc->wState &= ~CBF_NOREDRAW;
+ else
+ lphc->wState |= CBF_NOREDRAW;
+
+ if ( lphc->wState & CBF_EDIT )
+ SendMessageW(lphc->hWndEdit, message, wParam, lParam);
+ SendMessageW(lphc->hWndLBox, message, wParam, lParam);
+ return 0;
+
+ case WM_SYSKEYDOWN:
+ if ( KEYDATA_ALT & HIWORD(lParam) )
+ if( wParam == VK_UP || wParam == VK_DOWN )
+ COMBO_FlipListbox( lphc, FALSE, FALSE );
+ return 0;
+
+ case WM_KEYDOWN:
+ if ((wParam == VK_RETURN || wParam == VK_ESCAPE) &&
+ (lphc->wState & CBF_DROPPED))
+ {
+ CBRollUp( lphc, wParam == VK_RETURN, FALSE );
+ return TRUE;
+ }
+ else if ((wParam == VK_F4) && !(lphc->wState & CBF_EUI))
+ {
+ COMBO_FlipListbox( lphc, FALSE, FALSE );
+ return TRUE;
+ }
+ /* fall through */
+ case WM_CHAR:
+ case WM_IME_CHAR:
+ {
+ HWND hwndTarget;
+
+ if ( lphc->wState & CBF_EDIT )
+ hwndTarget = lphc->hWndEdit;
+ else
+ hwndTarget = lphc->hWndLBox;
+
+ return SendMessageW(hwndTarget, message, wParam, lParam);
+ }
+
+ case WM_LBUTTONDOWN:
+ if ( !(lphc->wState & CBF_FOCUSED) ) SetFocus( lphc->self );
+ if ( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam );
+ return TRUE;
+
+ case WM_LBUTTONUP:
+ COMBO_LButtonUp( lphc );
+ return TRUE;
+
+ case WM_MOUSEMOVE:
+ if (!IsRectEmpty(&lphc->buttonRect))
+ {
+ POINT pt;
+
+ pt.x = (short)LOWORD(lParam);
+ pt.y = (short)HIWORD(lParam);
+
+ if (PtInRect(&lphc->buttonRect, pt))
+ {
+ if (!(lphc->wState & CBF_HOT))
+ {
+ lphc->wState |= CBF_HOT;
+ RedrawWindow(hwnd, &lphc->buttonRect, 0, RDW_INVALIDATE |
RDW_UPDATENOW);
+ }
+ }
+ else if (lphc->wState & CBF_HOT)
+ {
+ lphc->wState &= ~CBF_HOT;
+ RedrawWindow(hwnd, &lphc->buttonRect, 0, RDW_INVALIDATE |
RDW_UPDATENOW);
+ }
+ }
+
+ if ( lphc->wState & CBF_CAPTURE )
+ COMBO_MouseMove( lphc, wParam, lParam );
+ return TRUE;
+
+ case WM_MOUSEWHEEL:
+ if (wParam & (MK_SHIFT | MK_CONTROL))
+ return DefWindowProcW(hwnd, message, wParam, lParam);
+
+ if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) return SendMessageW(hwnd, WM_KEYDOWN,
VK_UP, 0);
+ if (GET_WHEEL_DELTA_WPARAM(wParam) < 0) return SendMessageW(hwnd, WM_KEYDOWN,
VK_DOWN, 0);
+ return TRUE;
+
+ /* Combo messages */
+ case CB_ADDSTRING:
+ if (lphc->dwStyle & CBS_LOWERCASE)
+ CharLowerW((LPWSTR)lParam);
+ else if (lphc->dwStyle & CBS_UPPERCASE)
+ CharUpperW((LPWSTR)lParam);
+ return SendMessageW(lphc->hWndLBox, LB_ADDSTRING, 0, lParam);
+
+ case CB_INSERTSTRING:
+ if (lphc->dwStyle & CBS_LOWERCASE)
+ CharLowerW((LPWSTR)lParam);
+ else if (lphc->dwStyle & CBS_UPPERCASE)
+ CharUpperW((LPWSTR)lParam);
+ return SendMessageW(lphc->hWndLBox, LB_INSERTSTRING, wParam, lParam);
+
+ case CB_DELETESTRING:
+ return SendMessageW(lphc->hWndLBox, LB_DELETESTRING, wParam, 0);
+
+ case CB_SELECTSTRING:
+ return COMBO_SelectString(lphc, (INT)wParam, lParam);
+
+ case CB_FINDSTRING:
+ return SendMessageW(lphc->hWndLBox, LB_FINDSTRING, wParam, lParam);
+
+ case CB_FINDSTRINGEXACT:
+ return SendMessageW(lphc->hWndLBox, LB_FINDSTRINGEXACT, wParam, lParam);
+
+ case CB_SETITEMHEIGHT:
+ return COMBO_SetItemHeight( lphc, (INT)wParam, (INT)lParam);
+
+ case CB_GETITEMHEIGHT:
+ if ((INT)wParam >= 0) /* listbox item */
+ return SendMessageW(lphc->hWndLBox, LB_GETITEMHEIGHT, wParam, 0);
+ return CBGetTextAreaHeight(hwnd, lphc);
+
+ case CB_RESETCONTENT:
+ SendMessageW(lphc->hWndLBox, LB_RESETCONTENT, 0, 0);
+
+ if ((lphc->wState & CBF_EDIT) && CB_HASSTRINGS(lphc))
+ {
+ static const WCHAR empty_stringW[] = { 0 };
+ SendMessageW(lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)empty_stringW);
+ }
+ else
+ InvalidateRect(lphc->self, NULL, TRUE);
+ return TRUE;
+
+ case CB_INITSTORAGE:
+ return SendMessageW(lphc->hWndLBox, LB_INITSTORAGE, wParam, lParam);
+
+ case CB_GETHORIZONTALEXTENT:
+ return SendMessageW(lphc->hWndLBox, LB_GETHORIZONTALEXTENT, 0, 0);
+
+ case CB_SETHORIZONTALEXTENT:
+ return SendMessageW(lphc->hWndLBox, LB_SETHORIZONTALEXTENT, wParam, 0);
+
+ case CB_GETTOPINDEX:
+ return SendMessageW(lphc->hWndLBox, LB_GETTOPINDEX, 0, 0);
+
+ case CB_GETLOCALE:
+ return SendMessageW(lphc->hWndLBox, LB_GETLOCALE, 0, 0);
+
+ case CB_SETLOCALE:
+ return SendMessageW(lphc->hWndLBox, LB_SETLOCALE, wParam, 0);
+
+ case CB_SETDROPPEDWIDTH:
+ if ((CB_GETTYPE(lphc) == CBS_SIMPLE) || (INT)wParam >= 32768)
+ return CB_ERR;
+
+ /* new value must be higher than combobox width */
+ if ((INT)wParam >= lphc->droppedRect.right - lphc->droppedRect.left)
+ lphc->droppedWidth = wParam;
+ else if (wParam)
+ lphc->droppedWidth = 0;
+
+ /* recalculate the combobox area */
+ CBCalcPlacement(hwnd, lphc, &lphc->textRect, &lphc->buttonRect,
&lphc->droppedRect );
+
+ /* fall through */
+ case CB_GETDROPPEDWIDTH:
+ if (lphc->droppedWidth)
+ return lphc->droppedWidth;
+ return lphc->droppedRect.right - lphc->droppedRect.left;
+
+ case CB_GETDROPPEDCONTROLRECT:
+ if (lParam)
+ CBGetDroppedControlRect(lphc, (LPRECT)lParam );
+ return CB_OKAY;
+
+ case CB_GETDROPPEDSTATE:
+ return (lphc->wState & CBF_DROPPED) != 0;
+
+ case CB_DIR:
+ return SendMessageW(lphc->hWndLBox, LB_DIR, wParam, lParam);
+
+ case CB_SHOWDROPDOWN:
+ if (CB_GETTYPE(lphc) != CBS_SIMPLE)
+ {
+ if (wParam)
+ {
+ if (!(lphc->wState & CBF_DROPPED))
+ CBDropDown( lphc );
+ }
+ else if (lphc->wState & CBF_DROPPED)
+ CBRollUp( lphc, FALSE, TRUE );
+ }
+ return TRUE;
+
+ case CB_GETCOUNT:
+ return SendMessageW(lphc->hWndLBox, LB_GETCOUNT, 0, 0);
+
+ case CB_GETCURSEL:
+ return SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+
+ case CB_SETCURSEL:
+ lParam = SendMessageW(lphc->hWndLBox, LB_SETCURSEL, wParam, 0);
+ if (lParam >= 0)
+ SendMessageW(lphc->hWndLBox, LB_SETTOPINDEX, wParam, 0);
+
+ /* no LBN_SELCHANGE in this case, update manually */
+ CBPaintText(lphc, NULL);
+ lphc->wState &= ~CBF_SELCHANGE;
+ return lParam;
+
+ case CB_GETLBTEXT:
+ return SendMessageW(lphc->hWndLBox, LB_GETTEXT, wParam, lParam);
+
+ case CB_GETLBTEXTLEN:
+ return SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, wParam, 0);
+
+ case CB_GETITEMDATA:
+ return SendMessageW(lphc->hWndLBox, LB_GETITEMDATA, wParam, 0);
+
+ case CB_SETITEMDATA:
+ return SendMessageW(lphc->hWndLBox, LB_SETITEMDATA, wParam, lParam);
+
+ case CB_GETEDITSEL:
+ /* Edit checks passed parameters itself */
+ if (lphc->wState & CBF_EDIT)
+ return SendMessageW(lphc->hWndEdit, EM_GETSEL, wParam, lParam);
+ return CB_ERR;
+
+ case CB_SETEDITSEL:
+ if (lphc->wState & CBF_EDIT)
+ return SendMessageW(lphc->hWndEdit, EM_SETSEL, (INT)(SHORT)LOWORD(lParam),
(INT)(SHORT)HIWORD(lParam) );
+ return CB_ERR;
+
+ case CB_SETEXTENDEDUI:
+ if (CB_GETTYPE(lphc) == CBS_SIMPLE )
+ return CB_ERR;
+ if (wParam)
+ lphc->wState |= CBF_EUI;
+ else
+ lphc->wState &= ~CBF_EUI;
+ return CB_OKAY;
+
+ case CB_GETEXTENDEDUI:
+ return (lphc->wState & CBF_EUI) != 0;
+
+ case CB_GETCOMBOBOXINFO:
+ return COMBO_GetComboBoxInfo(lphc, (COMBOBOXINFO *)lParam);
+
+ case CB_LIMITTEXT:
+ if (lphc->wState & CBF_EDIT)
+ return SendMessageW(lphc->hWndEdit, EM_LIMITTEXT, wParam, lParam);
+ return TRUE;
+
+ default:
+ if (message >= WM_USER)
+ WARN("unknown msg WM_USER+%04x wp=%04lx lp=%08lx\n", message -
WM_USER, wParam, lParam );
+ break;
+ }
+
+ return DefWindowProcW(hwnd, message, wParam, lParam);
+}
+
+void COMBO_Register(void)
+{
+ WNDCLASSW wndClass;
+
+ memset(&wndClass, 0, sizeof(wndClass));
+ wndClass.style = CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW |
CS_GLOBALCLASS;
+ wndClass.lpfnWndProc = COMBO_WindowProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = sizeof(HEADCOMBO *);
+ wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
+ wndClass.hbrBackground = NULL;
+ wndClass.lpszClassName = WC_COMBOBOXW;
+ RegisterClassW(&wndClass);
+}
diff --git a/dll/win32/comctl32/comboex.c b/dll/win32/comctl32/comboex.c
index 68709f018e..3c3714ac56 100644
--- a/dll/win32/comctl32/comboex.c
+++ b/dll/win32/comctl32/comboex.c
@@ -18,19 +18,19 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
- * NOTE
- *
... 11900 lines suppressed ...