https://git.reactos.org/?p=reactos.git;a=commitdiff;h=0707475f6974a0add99fc…
commit 0707475f6974a0add99fc396146c26a970c5148b
Author: Justin Miller <justin.miller(a)reactos.org>
AuthorDate: Tue Sep 3 21:54:05 2024 -0700
Commit: GitHub <noreply(a)github.com>
CommitDate: Tue Sep 3 21:54:05 2024 -0700
[COMCTL32][MEDIA] Sync comctl32 to wine 5.0 (#6789)
For SOME reason comctl32 has been synched manually multiple times to different
versions and different pots
This PR aims to fix that
With the exception of button.c which all in all is a massive fork over wines code
entirely.
and datetime.c which is at wine 6.0
Comctl32 is now at wine-5.0
---
dll/win32/comctl32/button.c | 87 ++
dll/win32/comctl32/combo.c | 362 +++---
dll/win32/comctl32/comboex.c | 11 +-
dll/win32/comctl32/comctl32.h | 17 +-
dll/win32/comctl32/comctl32undoc.c | 13 +-
dll/win32/comctl32/commctrl.c | 13 +-
dll/win32/comctl32/edit.c | 244 ++--
dll/win32/comctl32/header.c | 3 +-
dll/win32/comctl32/hotkey.c | 2 +-
dll/win32/comctl32/idb_cmdlink.bmp | Bin 0 -> 3522 bytes
dll/win32/comctl32/imagelist.c | 6 +-
dll/win32/comctl32/ipaddress.c | 13 +-
dll/win32/comctl32/listbox.c | 600 +++++----
dll/win32/comctl32/listview.c | 51 +-
dll/win32/comctl32/monthcal.c | 29 +-
dll/win32/comctl32/pager.c | 460 +++++++
dll/win32/comctl32/propsheet.c | 27 +-
dll/win32/comctl32/rebar.c | 48 +-
dll/win32/comctl32/static.c | 6 -
dll/win32/comctl32/status.c | 25 +-
dll/win32/comctl32/string.c | 36 +-
dll/win32/comctl32/syslink.c | 31 +-
dll/win32/comctl32/taskdialog.c | 1495 +++++++++++++++++-----
dll/win32/comctl32/theming.c | 10 -
dll/win32/comctl32/toolbar.c | 108 +-
dll/win32/comctl32/tooltips.c | 158 +--
dll/win32/comctl32/trackbar.c | 93 +-
dll/win32/comctl32/treeview.c | 76 +-
dll/win32/comctl32/updown.c | 30 +-
media/doc/WINESYNC.txt | 6 +-
modules/rostests/winetests/comctl32/combo.c | 136 +-
modules/rostests/winetests/comctl32/edit.c | 29 +-
modules/rostests/winetests/comctl32/imagelist.c | 6 +-
modules/rostests/winetests/comctl32/listbox.c | 36 +-
modules/rostests/winetests/comctl32/listview.c | 163 ++-
modules/rostests/winetests/comctl32/misc.c | 4 -
modules/rostests/winetests/comctl32/msg.h | 6 +-
modules/rostests/winetests/comctl32/pager.c | 116 +-
modules/rostests/winetests/comctl32/precomp.h | 9 +
modules/rostests/winetests/comctl32/propsheet.c | 6 +-
modules/rostests/winetests/comctl32/rebar.c | 25 +-
modules/rostests/winetests/comctl32/resources.h | 1 +
modules/rostests/winetests/comctl32/static.c | 2 -
modules/rostests/winetests/comctl32/subclass.c | 2 +
modules/rostests/winetests/comctl32/taskdialog.c | 1 +
modules/rostests/winetests/comctl32/toolbar.c | 4 +
modules/rostests/winetests/comctl32/tooltips.c | 20 +-
modules/rostests/winetests/comctl32/treeview.c | 96 +-
modules/rostests/winetests/comctl32/updown.c | 4 +-
modules/rostests/winetests/comctl32/v6util.h | 6 +-
sdk/include/psdk/winuser.h | 3 +
sdk/tools/winesync/comctl32.cfg | 5 +
52 files changed, 3323 insertions(+), 1417 deletions(-)
diff --git a/dll/win32/comctl32/button.c b/dll/win32/comctl32/button.c
index 9002697d60c..c979483b80b 100644
--- a/dll/win32/comctl32/button.c
+++ b/dll/win32/comctl32/button.c
@@ -93,8 +93,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(button);
typedef struct _BUTTON_INFO
{
HWND hwnd;
+ HWND parent;
LONG state;
HFONT font;
+ WCHAR *note;
+ INT note_length;
union
{
HICON icon;
@@ -256,6 +259,14 @@ HRGN set_control_clipping( HDC hdc, const RECT *rect )
return hrgn;
}
+static WCHAR *heap_strndupW(const WCHAR *src, size_t length)
+{
+ size_t size = (length + 1) * sizeof(WCHAR);
+ WCHAR *dst = heap_alloc(size);
+ if (dst) memcpy(dst, src, size);
+ return dst;
+}
+
/**********************************************************************
* Convert button styles to flags used by DrawText.
*/
@@ -642,6 +653,7 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM
wParam, L
case WM_NCDESTROY:
SetWindowLongPtrW( hWnd, 0, 0 );
+ heap_free(infoPtr->note);
heap_free(infoPtr);
break;
@@ -1024,6 +1036,81 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg,
WPARAM wParam, L
return 1; /* success. FIXME: check text length */
}
+ case BCM_SETNOTE:
+ {
+ WCHAR *note = (WCHAR *)lParam;
+ if (btn_type != BS_COMMANDLINK && btn_type != BS_DEFCOMMANDLINK)
+ {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return FALSE;
+ }
+
+ heap_free(infoPtr->note);
+ if (note)
+ {
+ infoPtr->note_length = lstrlenW(note);
+ infoPtr->note = heap_strndupW(note, infoPtr->note_length);
+ }
+
+ if (!note || !infoPtr->note)
+ {
+ infoPtr->note_length = 0;
+ infoPtr->note = heap_alloc_zero(sizeof(WCHAR));
+ }
+
+ SetLastError(NO_ERROR);
+ return TRUE;
+ }
+
+ case BCM_GETNOTE:
+ {
+ DWORD *size = (DWORD *)wParam;
+ WCHAR *buffer = (WCHAR *)lParam;
+ INT length = 0;
+
+ if (btn_type != BS_COMMANDLINK && btn_type != BS_DEFCOMMANDLINK)
+ {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return FALSE;
+ }
+
+ if (!buffer || !size || !infoPtr->note)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ if (*size > 0)
+ {
+ length = min(*size - 1, infoPtr->note_length);
+ memcpy(buffer, infoPtr->note, length * sizeof(WCHAR));
+ buffer[length] = '\0';
+ }
+
+ if (*size < infoPtr->note_length + 1)
+ {
+ *size = infoPtr->note_length + 1;
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
+ }
+ else
+ {
+ SetLastError(NO_ERROR);
+ return TRUE;
+ }
+ }
+
+ case BCM_GETNOTELENGTH:
+ {
+ if (btn_type != BS_COMMANDLINK && btn_type != BS_DEFCOMMANDLINK)
+ {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return 0;
+ }
+
+ return infoPtr->note_length;
+ }
+
case WM_SETFONT:
infoPtr->font = (HFONT)wParam;
if (lParam) InvalidateRect(hWnd, NULL, TRUE);
diff --git a/dll/win32/comctl32/combo.c b/dll/win32/comctl32/combo.c
index 0c67b2ee729..e083a58034f 100644
--- a/dll/win32/comctl32/combo.c
+++ b/dll/win32/comctl32/combo.c
@@ -32,7 +32,6 @@
#include "uxtheme.h"
#include "vssym32.h"
#include "commctrl.h"
-#include "wine/unicode.h"
#include "wine/debug.h"
#include "wine/heap.h"
@@ -79,6 +78,9 @@ static UINT CBitHeight, CBitWidth;
#define ID_CB_LISTBOX 1000
#define ID_CB_EDIT 1001
+static void CBCalcPlacement(HEADCOMBO *combo);
+static void CBResetPos(HEADCOMBO *combo);
+
/***********************************************************************
* COMBO_Init
*
@@ -170,6 +172,25 @@ static LRESULT COMBO_NCDestroy( HEADCOMBO *lphc )
return 0;
}
+static INT combo_get_text_height(const HEADCOMBO *combo)
+{
+ HDC hdc = GetDC(combo->self);
+ HFONT prev_font = 0;
+ TEXTMETRICW tm;
+
+ if (combo->hFont)
+ prev_font = SelectObject(hdc, combo->hFont);
+
+ GetTextMetricsW(hdc, &tm);
+
+ if (prev_font)
+ SelectObject(hdc, prev_font);
+
+ ReleaseDC(combo->self, hdc);
+
+ return tm.tmHeight + 4;
+}
+
/***********************************************************************
* CBGetTextAreaHeight
*
@@ -182,37 +203,18 @@ static LRESULT COMBO_NCDestroy( HEADCOMBO *lphc )
* This height was determined through experimentation.
* CBCalcPlacement will add 2*COMBO_YBORDERSIZE pixels for the border
*/
-static INT CBGetTextAreaHeight(
- HWND hwnd,
- LPHEADCOMBO lphc)
+static INT CBGetTextAreaHeight(HEADCOMBO *lphc, BOOL clip_item_height)
{
- INT iTextItemHeight;
+ INT item_height, text_height;
- if( lphc->editHeight ) /* explicitly set height */
+ if (clip_item_height && !CB_OWNERDRAWN(lphc))
{
- iTextItemHeight = lphc->editHeight;
+ text_height = combo_get_text_height(lphc);
+ if (lphc->item_height < text_height)
+ lphc->item_height = text_height;
}
- 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);
+ item_height = lphc->item_height;
- iTextItemHeight = baseUnitY + 4;
- }
/*
* Check the ownerdraw case if we haven't asked the parent the size
@@ -223,13 +225,13 @@ static INT CBGetTextAreaHeight(
{
MEASUREITEMSTRUCT measureItem;
RECT clientRect;
- INT originalItemHeight = iTextItemHeight;
+ INT originalItemHeight = item_height;
UINT id = (UINT)GetWindowLongPtrW( lphc->self, GWLP_ID );
/*
* We use the client rect for the width of the item.
*/
- GetClientRect(hwnd, &clientRect);
+ GetClientRect(lphc->self, &clientRect);
lphc->wState &= ~CBF_MEASUREITEM;
@@ -240,10 +242,10 @@ static INT CBGetTextAreaHeight(
measureItem.CtlID = id;
measureItem.itemID = -1;
measureItem.itemWidth = clientRect.right;
- measureItem.itemHeight = iTextItemHeight - 6; /* ownerdrawn cb is taller */
+ measureItem.itemHeight = item_height - 6; /* ownerdrawn cb is taller */
measureItem.itemData = 0;
SendMessageW(lphc->owner, WM_MEASUREITEM, id, (LPARAM)&measureItem);
- iTextItemHeight = 6 + measureItem.itemHeight;
+ item_height = 6 + measureItem.itemHeight;
/*
* Send a second one in the case of a fixed ownerdraw list to calculate the
@@ -264,10 +266,10 @@ static INT CBGetTextAreaHeight(
/*
* Keep the size for the next time
*/
- lphc->editHeight = iTextItemHeight;
+ lphc->item_height = item_height;
}
- return iTextItemHeight;
+ return item_height;
}
/***********************************************************************
@@ -277,13 +279,12 @@ static INT CBGetTextAreaHeight(
* 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)
+static void CBForceDummyResize(LPHEADCOMBO lphc)
{
RECT windowRect;
int newComboHeight;
- newComboHeight = CBGetTextAreaHeight(lphc->self,lphc) + 2*COMBO_YBORDERSIZE();
+ newComboHeight = CBGetTextAreaHeight(lphc, FALSE) + 2*COMBO_YBORDERSIZE();
GetWindowRect(lphc->self, &windowRect);
@@ -295,12 +296,17 @@ static void CBForceDummyResize(
* this will cancel-out in the processing of the WM_WINDOWPOSCHANGING
* message.
*/
+ lphc->wState |= CBF_NORESIZE;
SetWindowPos( lphc->self,
NULL,
0, 0,
windowRect.right - windowRect.left,
newComboHeight,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
+ lphc->wState &= ~CBF_NORESIZE;
+
+ CBCalcPlacement(lphc);
+ CBResetPos(lphc);
}
/***********************************************************************
@@ -308,111 +314,70 @@ static void CBForceDummyResize(
*
* Set up component coordinates given valid lphc->RectCombo.
*/
-static void CBCalcPlacement(
- HWND hwnd,
- LPHEADCOMBO lphc,
- LPRECT lprEdit,
- LPRECT lprButton,
- LPRECT lprLB)
+static void CBCalcPlacement(HEADCOMBO *combo)
{
- /*
- * Again, start with the client rectangle.
- */
- GetClientRect(hwnd, lprEdit);
+ /* Start with the client rectangle. */
+ GetClientRect(combo->self, &combo->textRect);
- /*
- * Remove the borders
- */
- InflateRect(lprEdit, -COMBO_XBORDERSIZE(), -COMBO_YBORDERSIZE());
+ /* Remove the borders */
+ InflateRect(&combo->textRect, -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);
+ /* Chop off the bottom part to fit with the height of the text area. */
+ combo->textRect.bottom = combo->textRect.top + CBGetTextAreaHeight(combo,
FALSE);
- /*
- * 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;
- }
+ /* The button starts the same vertical position as the text area. */
+ combo->buttonRect = combo->textRect;
- /*
- * 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 the combobox is "simple" there is no button. */
+ if (CB_GETTYPE(combo) == CBS_SIMPLE)
+ combo->buttonRect.left = combo->buttonRect.right =
combo->buttonRect.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.
+ */
+ combo->buttonRect.left = combo->buttonRect.right -
GetSystemMetrics(SM_CXVSCROLL);
+ combo->textRect.right = combo->buttonRect.left;
+ }
- /*
- * 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());
- }
+ /* In the case of a dropdown, there is an additional spacing between the text area
and the button. */
+ if (CB_GETTYPE(combo) == CBS_DROPDOWN)
+ combo->textRect.right -= COMBO_EDITBUTTONSPACE();
- /*
- * 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);
+ /* If we have an edit control, we space it away from the borders slightly. */
+ if (CB_GETTYPE(combo) != CBS_DROPDOWNLIST)
+ InflateRect(&combo->textRect, -EDIT_CONTROL_PADDING(),
-EDIT_CONTROL_PADDING());
- /*
- * 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()))
+ /* Adjust the size of the listbox popup. */
+ if (CB_GETTYPE(combo) == CBS_SIMPLE)
{
- 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();
+ GetClientRect(combo->self, &combo->droppedRect);
+ combo->droppedRect.top = combo->textRect.bottom + COMBO_YBORDERSIZE();
}
else
- lprLB->right = lprLB->left + lphc->droppedWidth;
- }
-
- /* don't allow negative window width */
- if (lprEdit->right < lprEdit->left)
- lprEdit->right = lprEdit->left;
+ {
+ /* Make sure the dropped width is as large as the combobox itself. */
+ if (combo->droppedWidth < (combo->buttonRect.right +
COMBO_XBORDERSIZE()))
+ {
+ combo->droppedRect.right = combo->droppedRect.left +
(combo->buttonRect.right + COMBO_XBORDERSIZE());
- TRACE("\ttext\t= (%s)\n", wine_dbgstr_rect(lprEdit));
+ /* In the case of a dropdown, the popup listbox is offset to the right. We
want to make sure it's flush
+ with the right side of the combobox */
+ if (CB_GETTYPE(combo) == CBS_DROPDOWN)
+ combo->droppedRect.right -= COMBO_EDITBUTTONSPACE();
+ }
+ else
+ combo->droppedRect.right = combo->droppedRect.left +
combo->droppedWidth;
+ }
- TRACE("\tbutton\t= (%s)\n", wine_dbgstr_rect(lprButton));
+ /* Disallow negative window width */
+ if (combo->textRect.right < combo->textRect.left)
+ combo->textRect.right = combo->textRect.left;
- TRACE("\tlbox\t= (%s)\n", wine_dbgstr_rect(lprLB));
+ TRACE("text %s, button %s, lbox %s.\n",
wine_dbgstr_rect(&combo->textRect), wine_dbgstr_rect(&combo->buttonRect),
+ wine_dbgstr_rect(&combo->droppedRect));
}
/***********************************************************************
@@ -444,11 +409,9 @@ static LRESULT COMBO_Create( HWND hwnd, LPHEADCOMBO lphc, HWND
hwndParent, LONG
lphc->owner = hwndParent;
- /*
- * The item height and dropped width are not set when the control
- * is created.
- */
- lphc->droppedWidth = lphc->editHeight = 0;
+ lphc->droppedWidth = 0;
+
+ lphc->item_height = combo_get_text_height(lphc);
/*
* The first time we go through, we want to measure the ownerdraw item
@@ -473,7 +436,7 @@ static LRESULT COMBO_Create( HWND hwnd, LPHEADCOMBO lphc, HWND
hwndParent, LONG
* recalculated.
*/
GetClientRect( hwnd, &lphc->droppedRect );
- CBCalcPlacement(hwnd, lphc, &lphc->textRect, &lphc->buttonRect,
&lphc->droppedRect );
+ CBCalcPlacement(lphc);
/*
* Adjust the position of the popup listbox if it's necessary
@@ -589,10 +552,13 @@ static LRESULT COMBO_Create( HWND hwnd, LPHEADCOMBO lphc, HWND
hwndParent, LONG
*
* Paint combo button (normal, pressed, and disabled states).
*/
-static void CBPaintButton( LPHEADCOMBO lphc, HDC hdc, RECT rectButton)
+static void CBPaintButton(HEADCOMBO *lphc, HDC hdc)
{
UINT buttonState = DFCS_SCROLLCOMBOBOX;
+ if (IsRectEmpty(&lphc->buttonRect))
+ return;
+
if( lphc->wState & CBF_NOREDRAW )
return;
@@ -603,7 +569,7 @@ static void CBPaintButton( LPHEADCOMBO lphc, HDC hdc, RECT
rectButton)
if (CB_DISABLED(lphc))
buttonState |= DFCS_INACTIVE;
- DrawFrameControl(hdc, &rectButton, DFC_SCROLL, buttonState);
+ DrawFrameControl(hdc, &lphc->buttonRect, DFC_SCROLL, buttonState);
}
/***********************************************************************
@@ -777,16 +743,13 @@ static void CBPaintText(HEADCOMBO *lphc, HDC hdc_paint)
/***********************************************************************
* CBPaintBorder
*/
-static void CBPaintBorder(
- HWND hwnd,
- const HEADCOMBO *lphc,
- HDC hdc)
+static void CBPaintBorder(const HEADCOMBO *lphc, HDC hdc)
{
RECT clientRect;
if (CB_GETTYPE(lphc) != CBS_SIMPLE)
{
- GetClientRect(hwnd, &clientRect);
+ GetClientRect(lphc->self, &clientRect);
}
else
{
@@ -857,10 +820,9 @@ static LRESULT COMBO_Paint(HEADCOMBO *lphc, HDC hdc)
/*
* In non 3.1 look, there is a sunken border on the combobox
*/
- CBPaintBorder(lphc->self, lphc, hdc);
+ CBPaintBorder(lphc, hdc);
- if (!IsRectEmpty(&lphc->buttonRect))
- CBPaintButton(lphc, hdc, lphc->buttonRect);
+ CBPaintButton(lphc, hdc);
/* paint the edit control padding area */
if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
@@ -1391,50 +1353,45 @@ static LRESULT COMBO_GetText( HEADCOMBO *lphc, INT count, LPWSTR
buf )
* 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)
+static void CBResetPos(HEADCOMBO *combo)
{
- 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 );
- }
+ BOOL drop = CB_GETTYPE(combo) != CBS_SIMPLE;
+
+ /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
+ * sizing messages */
+ if (combo->wState & CBF_EDIT)
+ SetWindowPos(combo->hWndEdit, 0, combo->textRect.left,
combo->textRect.top,
+ combo->textRect.right - combo->textRect.left,
+ combo->textRect.bottom - combo->textRect.top,
+ SWP_NOZORDER | SWP_NOACTIVATE | (drop ? SWP_NOREDRAW : 0));
+
+ SetWindowPos(combo->hWndLBox, 0, combo->droppedRect.left,
combo->droppedRect.top,
+ combo->droppedRect.right - combo->droppedRect.left,
+ combo->droppedRect.bottom - combo->droppedRect.top,
+ SWP_NOACTIVATE | SWP_NOZORDER | (drop ? SWP_NOREDRAW : 0));
+
+ if (drop)
+ {
+ if (combo->wState & CBF_DROPPED)
+ {
+ combo->wState &= ~CBF_DROPPED;
+ ShowWindow(combo->hWndLBox, SW_HIDE);
+ }
- if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
- RedrawWindow( lphc->self, NULL, 0,
- RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
- }
+ if (!(combo->wState & CBF_NOREDRAW))
+ RedrawWindow(combo->self, NULL, 0, RDW_INVALIDATE | RDW_ERASE |
RDW_UPDATENOW);
+ }
}
/***********************************************************************
* COMBO_Size
*/
-static void COMBO_Size( LPHEADCOMBO lphc )
+static void COMBO_Size( HEADCOMBO *lphc )
{
+ if (!lphc->hWndLBox || (lphc->wState & CBF_NORESIZE))
+ return;
+
/*
* Those controls are always the same height. So we have to make sure
* they are not resized to another value.
@@ -1447,7 +1404,7 @@ static void COMBO_Size( LPHEADCOMBO lphc )
GetWindowRect(lphc->self, &rc);
curComboHeight = rc.bottom - rc.top;
curComboWidth = rc.right - rc.left;
- newComboHeight = CBGetTextAreaHeight(lphc->self, lphc) + 2*COMBO_YBORDERSIZE();
+ newComboHeight = CBGetTextAreaHeight(lphc, TRUE) + 2*COMBO_YBORDERSIZE();
/*
* Resizing a combobox has another side effect, it resizes the dropped
@@ -1467,18 +1424,18 @@ static void COMBO_Size( LPHEADCOMBO lphc )
/*
* Restore original height
*/
- if( curComboHeight != newComboHeight )
- SetWindowPos(lphc->self, 0, 0, 0, curComboWidth, newComboHeight,
- SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW);
+ if (curComboHeight != newComboHeight)
+ {
+ lphc->wState |= CBF_NORESIZE;
+ SetWindowPos(lphc->self, 0, 0, 0, curComboWidth, newComboHeight,
+ SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOREDRAW);
+ lphc->wState &= ~CBF_NORESIZE;
+ }
}
- CBCalcPlacement(lphc->self,
- lphc,
- &lphc->textRect,
- &lphc->buttonRect,
- &lphc->droppedRect);
+ CBCalcPlacement(lphc);
- CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
+ CBResetPos(lphc);
}
@@ -1487,10 +1444,8 @@ static void COMBO_Size( LPHEADCOMBO lphc )
*/
static void COMBO_Font( LPHEADCOMBO lphc, HFONT hFont, BOOL bRedraw )
{
- /*
- * Set the font
- */
lphc->hFont = hFont;
+ lphc->item_height = combo_get_text_height(lphc);
/*
* Propagate to owned windows.
@@ -1504,13 +1459,9 @@ static void COMBO_Font( LPHEADCOMBO lphc, HFONT hFont, BOOL bRedraw
)
*/
if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
{
- CBCalcPlacement(lphc->self,
- lphc,
- &lphc->textRect,
- &lphc->buttonRect,
- &lphc->droppedRect);
+ CBCalcPlacement(lphc);
- CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
+ CBResetPos(lphc);
}
else
{
@@ -1530,20 +1481,16 @@ static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT index,
INT height )
{
if( height < 32768 )
{
- lphc->editHeight = height + 2; /* Is the 2 for 2*EDIT_CONTROL_PADDING? */
+ lphc->item_height = 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);
+ CBCalcPlacement(lphc);
- CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
+ CBResetPos(lphc);
}
else
{
@@ -1794,8 +1741,7 @@ static LRESULT CALLBACK COMBO_WindowProc( HWND hwnd, UINT message,
WPARAM wParam
}
case WM_SIZE:
- if (lphc->hWndLBox && !(lphc->wState & CBF_NORESIZE))
- COMBO_Size( lphc );
+ COMBO_Size( lphc );
return TRUE;
case WM_SETFONT:
@@ -2017,7 +1963,7 @@ static LRESULT CALLBACK COMBO_WindowProc( HWND hwnd, UINT message,
WPARAM wParam
case CB_GETITEMHEIGHT:
if ((INT)wParam >= 0) /* listbox item */
return SendMessageW(lphc->hWndLBox, LB_GETITEMHEIGHT, wParam, 0);
- return CBGetTextAreaHeight(hwnd, lphc);
+ return CBGetTextAreaHeight(lphc, FALSE);
case CB_RESETCONTENT:
SendMessageW(lphc->hWndLBox, LB_RESETCONTENT, 0, 0);
@@ -2060,7 +2006,7 @@ static LRESULT CALLBACK COMBO_WindowProc( HWND hwnd, UINT message,
WPARAM wParam
lphc->droppedWidth = 0;
/* recalculate the combobox area */
- CBCalcPlacement(hwnd, lphc, &lphc->textRect, &lphc->buttonRect,
&lphc->droppedRect );
+ CBCalcPlacement(lphc);
/* fall through */
case CB_GETDROPPEDWIDTH:
diff --git a/dll/win32/comctl32/comboex.c b/dll/win32/comctl32/comboex.c
index 3c3714ac569..c3c39be3058 100644
--- a/dll/win32/comctl32/comboex.c
+++ b/dll/win32/comctl32/comboex.c
@@ -30,7 +30,6 @@
#include "commctrl.h"
#include "comctl32.h"
#include "wine/debug.h"
-#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(comboex);
@@ -632,14 +631,14 @@ static INT COMBOEX_InsertItemW (COMBOEX_INFO *infoPtr,
COMBOBOXEXITEMW const *ci
if (item->mask & CBEIF_TEXT) {
INT len = 0;
- if (is_textW(cit->pszText)) len = strlenW (cit->pszText);
+ if (is_textW(cit->pszText)) len = lstrlenW (cit->pszText);
if (len > 0) {
item->pszText = Alloc ((len + 1)*sizeof(WCHAR));
if (!item->pszText) {
Free(item);
return -1;
}
- strcpyW (item->pszText, cit->pszText);
+ lstrcpyW (item->pszText, cit->pszText);
}
else if (cit->pszText == LPSTR_TEXTCALLBACKW)
item->pszText = LPSTR_TEXTCALLBACKW;
@@ -765,11 +764,11 @@ static BOOL COMBOEX_SetItemW (COMBOEX_INFO *infoPtr, const
COMBOBOXEXITEMW *cit)
INT len = 0;
COMBOEX_FreeText(item);
- if (is_textW(cit->pszText)) len = strlenW(cit->pszText);
+ if (is_textW(cit->pszText)) len = lstrlenW(cit->pszText);
if (len > 0) {
item->pszText = Alloc ((len + 1)*sizeof(WCHAR));
if (!item->pszText) return FALSE;
- strcpyW(item->pszText, cit->pszText);
+ lstrcpyW(item->pszText, cit->pszText);
} else if (cit->pszText == LPSTR_TEXTCALLBACKW)
item->pszText = LPSTR_TEXTCALLBACKW;
item->cchTextMax = cit->cchTextMax;
@@ -1404,7 +1403,7 @@ static LRESULT COMBOEX_DrawItem (COMBOEX_INFO *infoPtr,
DRAWITEMSTRUCT const *di
str = COMBOEX_GetText(infoPtr, item);
if (!str) str = nil;
- len = strlenW (str);
+ len = lstrlenW (str);
GetTextExtentPoint32W (dis->hDC, str, len, &txtsize);
if (dis->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) {
diff --git a/dll/win32/comctl32/comctl32.h b/dll/win32/comctl32/comctl32.h
index 40baabb24ff..6f9c951b9e6 100644
--- a/dll/win32/comctl32/comctl32.h
+++ b/dll/win32/comctl32/comctl32.h
@@ -88,6 +88,9 @@ extern HBRUSH COMCTL32_hPattern55AABrush DECLSPEC_HIDDEN;
#define IDT_CHECK 401
+/* Command Link arrow */
+#define IDB_CMDLINK 402
+
/* Cursors */
#define IDC_MOVEBUTTON 102
@@ -115,6 +118,9 @@ extern HBRUSH COMCTL32_hPattern55AABrush DECLSPEC_HIDDEN;
#define IDS_BUTTON_CANCEL 3004
#define IDS_BUTTON_CLOSE 3005
+#define IDS_TD_EXPANDED 3020
+#define IDS_TD_COLLAPSED 3021
+
#ifndef __REACTOS__
#define WM_SYSTIMER 0x0118
#endif
@@ -153,8 +159,8 @@ typedef struct
RECT droppedRect;
INT droppedIndex;
INT fixedOwnerDrawHeight;
- INT droppedWidth; /* last two are not used unless set */
- INT editHeight; /* explicitly */
+ INT droppedWidth; /* not used unless set explicitly */
+ INT item_height;
INT visibleItems;
} HEADCOMBO, *LPHEADCOMBO;
@@ -299,6 +305,11 @@ extern void THEMING_Initialize(void) DECLSPEC_HIDDEN;
#endif
extern void THEMING_Uninitialize(void) DECLSPEC_HIDDEN;
extern LRESULT THEMING_CallOriginalClass(HWND, UINT, WPARAM, LPARAM) DECLSPEC_HIDDEN;
-extern void THEMING_SetSubclassData(HWND, ULONG_PTR) DECLSPEC_HIDDEN;
+
+#ifdef __REACTOS__
+#define IDI_SHIELD 32518
+#define wcsnicmp _wcsnicmp
+#define GetDpiForWindow(PVOID) 96
+#endif
#endif /* __WINE_COMCTL32_H */
diff --git a/dll/win32/comctl32/comctl32undoc.c b/dll/win32/comctl32/comctl32undoc.c
index 639db05d1bd..753b0f5f501 100644
--- a/dll/win32/comctl32/comctl32undoc.c
+++ b/dll/win32/comctl32/comctl32undoc.c
@@ -26,8 +26,6 @@
* COMCTL32.DLL (internally).
*
*/
-#include "config.h"
-#include "wine/port.h"
#include <stdarg.h>
#include <string.h>
@@ -47,7 +45,6 @@
#include "objbase.h"
#include "winerror.h"
-#include "wine/unicode.h"
#include "comctl32.h"
#include "wine/debug.h"
@@ -311,7 +308,7 @@ static void MRU_SaveChanged ( LPWINEMRULIST mp )
if (mp->wineFlags & WMRUF_CHANGED) {
mp->wineFlags &= ~WMRUF_CHANGED;
err = RegSetValueExW(newkey, strMRUList, 0, REG_SZ, (LPBYTE)mp->realMRU,
- (strlenW(mp->realMRU) + 1)*sizeof(WCHAR));
+ (lstrlenW(mp->realMRU) + 1)*sizeof(WCHAR));
if (err) {
ERR("error saving MRUList, err=%d\n", err);
}
@@ -470,7 +467,7 @@ INT WINAPI AddMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData)
if ((replace = FindMRUData (hList, lpData, cbData, NULL)) >= 0) {
/* Item exists, just move it to the front */
- LPWSTR pos = strchrW(mp->realMRU, replace + 'a');
+ LPWSTR pos = wcschr(mp->realMRU, replace + 'a');
while (pos > mp->realMRU)
{
pos[0] = pos[-1];
@@ -555,7 +552,7 @@ INT WINAPI AddMRUStringW(HANDLE hList, LPCWSTR lpszString)
}
return AddMRUData(hList, lpszString,
- (strlenW(lpszString) + 1) * sizeof(WCHAR));
+ (lstrlenW(lpszString) + 1) * sizeof(WCHAR));
}
/**************************************************************************
@@ -747,8 +744,8 @@ HANDLE WINAPI CreateMRUListLazyW (const MRUINFOW *infoW, DWORD
dwParam2,
mp = Alloc(sizeof(WINEMRULIST));
memcpy(&mp->extview, infoW, sizeof(MRUINFOW));
- mp->extview.lpszSubKey = Alloc((strlenW(infoW->lpszSubKey) + 1) *
sizeof(WCHAR));
- strcpyW(mp->extview.lpszSubKey, infoW->lpszSubKey);
+ mp->extview.lpszSubKey = Alloc((lstrlenW(infoW->lpszSubKey) + 1) *
sizeof(WCHAR));
+ lstrcpyW(mp->extview.lpszSubKey, infoW->lpszSubKey);
mp->isUnicode = TRUE;
return create_mru_list(mp);
diff --git a/dll/win32/comctl32/commctrl.c b/dll/win32/comctl32/commctrl.c
index a3bbd5fc31d..f85282413e9 100644
--- a/dll/win32/comctl32/commctrl.c
+++ b/dll/win32/comctl32/commctrl.c
@@ -678,20 +678,24 @@ void WINAPI DrawStatusTextW (HDC hdc, LPCRECT lprc, LPCWSTR text,
UINT style)
{
RECT r = *lprc;
UINT border = BDR_SUNKENOUTER;
+ COLORREF oldbkcolor;
if (style & SBT_POPOUT)
border = BDR_RAISEDOUTER;
else if (style & SBT_NOBORDERS)
border = 0;
- DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST);
+ oldbkcolor = SetBkColor (hdc, comctl32_color.clrBtnFace);
+ DrawEdge (hdc, &r, border, BF_MIDDLE|BF_RECT|BF_ADJUST);
/* now draw text */
if (text) {
int oldbkmode = SetBkMode (hdc, TRANSPARENT);
+ COLORREF oldtextcolor;
UINT align = DT_LEFT;
int strCnt = 0;
+ oldtextcolor = SetTextColor (hdc, comctl32_color.clrBtnText);
if (style & SBT_RTLREADING)
FIXME("Unsupported RTL style!\n");
r.left += 3;
@@ -711,8 +715,11 @@ void WINAPI DrawStatusTextW (HDC hdc, LPCRECT lprc, LPCWSTR text,
UINT style)
} while(*text++);
if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r,
align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
- SetBkMode(hdc, oldbkmode);
+ SetBkMode (hdc, oldbkmode);
+ SetTextColor (hdc, oldtextcolor);
}
+
+ SetBkColor (hdc, oldbkcolor);
}
@@ -856,7 +863,7 @@ CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
*
* NOTES
* This function is just a dummy - all the controls are registered at
- * the DLL initialization time. See InitCommonContolsEx for details.
+ * the DLL initialization time. See InitCommonControlsEx for details.
*/
VOID WINAPI
diff --git a/dll/win32/comctl32/edit.c b/dll/win32/comctl32/edit.c
index ccd9373b199..6d124ce64a4 100644
--- a/dll/win32/comctl32/edit.c
+++ b/dll/win32/comctl32/edit.c
@@ -23,9 +23,7 @@
*
* TODO:
* - EDITBALLOONTIP structure
- * - EM_GETCUEBANNER/Edit_GetCueBannerText
* - EM_HIDEBALLOONTIP/Edit_HideBalloonTip
- * - EM_SETCUEBANNER/Edit_SetCueBannerText
* - EM_SHOWBALLOONTIP/Edit_ShowBalloonTip
* - EM_GETIMESTATUS, EM_SETIMESTATUS
* - EN_ALIGN_LTR_EC
@@ -34,8 +32,6 @@
*
*/
-#include "config.h"
-
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
@@ -53,7 +49,6 @@
#include "commctrl.h"
#include "uxtheme.h"
#include "vsstyle.h"
-#include "wine/unicode.h"
#include "wine/debug.h"
#include "wine/heap.h"
@@ -139,6 +134,9 @@ typedef struct
should be sent to the first parent. */
HWND hwndListBox; /* handle of ComboBox's listbox or NULL */
INT wheelDeltaRemainder; /* scroll wheel delta left over after scrolling whole
lines */
+ WCHAR *cue_banner_text;
+ BOOL cue_banner_draw_focused;
+
/*
* only for multi line controls
*/
@@ -183,7 +181,7 @@ static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL
after_wrap);
*/
static inline BOOL EDIT_EM_CanUndo(const EDITSTATE *es)
{
- return (es->undo_insert_count || strlenW(es->undo_text));
+ return (es->undo_insert_count || lstrlenW(es->undo_text));
}
@@ -219,7 +217,7 @@ static HBRUSH EDIT_NotifyCtlColor(EDITSTATE *es, HDC hdc)
static inline UINT get_text_length(EDITSTATE *es)
{
if(es->text_length == (UINT)-1)
- es->text_length = strlenW(es->text);
+ es->text_length = lstrlenW(es->text);
return es->text_length;
}
@@ -527,7 +525,7 @@ static void EDIT_BuildLineDefs_ML(EDITSTATE *es, INT istart, INT iend,
INT delta
/* Mark type of line termination */
if (!(*cp)) {
current_line->ending = END_0;
- current_line->net_length = strlenW(current_position);
+ current_line->net_length = lstrlenW(current_position);
} else if ((cp > current_position) && (*(cp - 1) == '\r')) {
current_line->ending = END_SOFT;
current_line->net_length = cp - current_position - 1;
@@ -1052,15 +1050,11 @@ static LRESULT EDIT_EM_PosFromChar(EDITSTATE *es, INT index, BOOL
after_wrap)
lw = line_def->width;
w = es->format_rect.right - es->format_rect.left;
if (line_def->ssa)
- {
ScriptStringCPtoX(line_def->ssa, (index - 1) - li, TRUE, &x);
- x -= es->x_offset;
- }
- else
#ifdef __REACTOS__ /* CORE-15780 */
- x = (lw > 0 ? es->x_offset : x - es->x_offset);
+ x = (lw > 0 ? es->x_offset : x - es->x_offset);
#else
- x = es->x_offset;
+ x = es->x_offset;
#endif
if (es->style & ES_RIGHT)
@@ -1836,7 +1830,6 @@ static void EDIT_EM_ScrollCaret(EDITSTATE *es)
}
}
- if(es->flags & EF_FOCUSED)
EDIT_SetCaretPos(es, es->selection_end, es->flags & EF_AFTER_WRAP);
}
@@ -2248,6 +2241,12 @@ static void EDIT_PaintLine(EDITSTATE *es, HDC dc, INT line, BOOL
rev)
x += EDIT_PaintText(es, dc, x, y, line, e - li, li + ll - e, FALSE);
} else
x += EDIT_PaintText(es, dc, x, y, line, 0, ll, FALSE);
+
+ if (es->cue_banner_text && es->text_length == 0 &&
(!(es->flags & EF_FOCUSED) || es->cue_banner_draw_focused))
+ {
+ SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
+ TextOutW(dc, x, y, es->cue_banner_text, lstrlenW(es->cue_banner_text));
+ }
}
@@ -2537,7 +2536,7 @@ static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, const
WCHAR *lpsz_r
memcpy(buf, es->text + s, bufl * sizeof(WCHAR));
buf[bufl] = 0; /* ensure 0 termination */
/* now delete */
- strcpyW(es->text + s, es->text + e);
+ lstrcpyW(es->text + s, es->text + e);
text_buffer_changed(es);
}
if (strl) {
@@ -2565,7 +2564,7 @@ static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, const
WCHAR *lpsz_r
/* if text is too long undo all changes */
if (honor_limit && !(es->style & ES_AUTOVSCROLL) &&
(es->line_count > vlc)) {
if (strl)
- strcpyW(es->text + e, es->text + e + strl);
+ lstrcpyW(es->text + e, es->text + e + strl);
if (e != s)
for (i = 0 , p = es->text ; i < e - s ; i++)
p[i + s] = buf[i];
@@ -2585,7 +2584,7 @@ static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, const
WCHAR *lpsz_r
/* remove chars that don't fit */
if (honor_limit && !(es->style & ES_AUTOHSCROLL) &&
(es->text_width > fw)) {
while ((es->text_width > fw) && s + strl >= s) {
- strcpyW(es->text + s + strl - 1, es->text + s + strl);
+ lstrcpyW(es->text + s + strl - 1, es->text + s + strl);
strl--;
es->text_length = -1;
EDIT_InvalidateUniscribeData(es);
@@ -2598,7 +2597,7 @@ static void EDIT_EM_ReplaceSel(EDITSTATE *es, BOOL can_undo, const
WCHAR *lpsz_r
if (e != s) {
if (can_undo) {
- utl = strlenW(es->undo_text);
+ utl = lstrlenW(es->undo_text);
if (!es->undo_insert_count && (*es->undo_text && (s ==
es->undo_position))) {
/* undo-buffer is extended to the right */
EDIT_MakeUndoFit(es, utl + e - s);
@@ -2742,6 +2741,36 @@ static void EDIT_EM_SetLimitText(EDITSTATE *es, UINT limit)
es->buffer_limit = limit;
}
+static BOOL is_cjk(HDC dc)
+{
+ const DWORD FS_DBCS_MASK =
FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD|FS_JOHAB;
+ FONTSIGNATURE fs;
+
+ switch (GdiGetCodePage(dc)) {
+ case 932: case 936: case 949: case 950: case 1361:
+ return TRUE;
+ default:
+ return (GetTextCharsetInfo(dc, &fs, 0) != DEFAULT_CHARSET &&
+ (fs.fsCsb[0] & FS_DBCS_MASK));
+ }
+}
+
+static int get_cjk_fontinfo_margin(int width, int side_bearing)
+{
+ int margin;
+ if (side_bearing < 0)
+ margin = min(-side_bearing, width/2);
+ else
+ margin = 0;
+ return margin;
+}
+
+struct char_width_info {
+ INT min_lsb, min_rsb, unknown;
+};
+
+/* Undocumented gdi32 export */
+extern BOOL WINAPI GetCharWidthInfo(HDC, struct char_width_info *);
/*********************************************************************
*
@@ -2751,26 +2780,10 @@ static void EDIT_EM_SetLimitText(EDITSTATE *es, UINT limit)
* action wParam despite what the docs say. EC_USEFONTINFO calculates the
* margin according to the textmetrics of the current font.
*
- * When EC_USEFONTINFO is used in the non_cjk case the margins only
- * change if the edit control is equal to or larger than a certain
- * size. Though there is an exception for the empty client rect case
- * with small font sizes.
+ * When EC_USEFONTINFO is used, the margins only change if the edit control is
+ * equal to or larger than a certain size. The empty client rect is treated as
+ * 80 pixels width.
*/
-static BOOL is_cjk(UINT charset)
-{
- switch(charset)
- {
- case SHIFTJIS_CHARSET:
- case HANGUL_CHARSET:
- case GB2312_CHARSET:
- case CHINESEBIG5_CHARSET:
- return TRUE;
- }
- /* HANGUL_CHARSET is strange, though treated as CJK by Win 8, it is
- * not by other versions including Win 10. */
- return FALSE;
-}
-
static void EDIT_EM_SetMargins(EDITSTATE *es, INT action,
WORD left, WORD right, BOOL repaint)
{
@@ -2782,26 +2795,30 @@ static void EDIT_EM_SetMargins(EDITSTATE *es, INT action,
if (es->font && (left == EC_USEFONTINFO || right == EC_USEFONTINFO))
{
HDC dc = GetDC(es->hwndSelf);
HFONT old_font = SelectObject(dc, es->font);
- LONG width = GdiGetCharDimensions(dc, &tm, NULL);
+ LONG width = GdiGetCharDimensions(dc, &tm, NULL), rc_width;
RECT rc;
/* The default margins are only non zero for TrueType or Vector fonts */
if (tm.tmPitchAndFamily & ( TMPF_VECTOR | TMPF_TRUETYPE )) {
- if (!is_cjk(tm.tmCharSet)) {
- default_left_margin = width / 2;
- default_right_margin = width / 2;
+ struct char_width_info width_info;
- GetClientRect(es->hwndSelf, &rc);
- if (rc.right - rc.left < (width / 2 + width) * 2 &&
- (width >= 28 || !IsRectEmpty(&rc)) ) {
- default_left_margin = es->left_margin;
- default_right_margin = es->right_margin;
- }
- } else {
- /* FIXME: figure out the CJK values. They are not affected by the
client rect. */
+ if (is_cjk(dc) && GetCharWidthInfo(dc, &width_info))
+ {
+ default_left_margin = get_cjk_fontinfo_margin(width,
width_info.min_lsb);
+ default_right_margin = get_cjk_fontinfo_margin(width,
width_info.min_rsb);
+ }
+ else
+ {
default_left_margin = width / 2;
default_right_margin = width / 2;
}
+
+ GetClientRect(es->hwndSelf, &rc);
+ rc_width = !IsRectEmpty(&rc) ? rc.right - rc.left : 80;
+ if (rc_width < default_left_margin + default_right_margin + width * 2)
{
+ default_left_margin = es->left_margin;
+ default_right_margin = es->right_margin;
+ }
}
SelectObject(dc, old_font);
ReleaseDC(es->hwndSelf, dc);
@@ -2919,11 +2936,11 @@ static BOOL EDIT_EM_Undo(EDITSTATE *es)
if( es->style & ES_READONLY )
return !(es->style & ES_MULTILINE);
- ulength = strlenW(es->undo_text);
+ ulength = lstrlenW(es->undo_text);
utext = heap_alloc((ulength + 1) * sizeof(WCHAR));
- strcpyW(utext, es->undo_text);
+ lstrcpyW(utext, es->undo_text);
TRACE("before UNDO:insertion length = %d, deletion buffer = %s\n",
es->undo_insert_count, debugstr_w(utext));
@@ -2974,9 +2991,9 @@ static void EDIT_WM_Paste(EDITSTATE *es)
OpenClipboard(es->hwndSelf);
if ((hsrc = GetClipboardData(CF_UNICODETEXT))) {
src = GlobalLock(hsrc);
- len = strlenW(src);
+ len = lstrlenW(src);
/* Protect single-line edit against pasting new line character */
- if (!(es->style & ES_MULTILINE) && ((ptr = strchrW(src, '\n'))))
{
+ if (!(es->style & ES_MULTILINE) && ((ptr = wcschr(src, '\n'))))
{
len = ptr - src;
if (len && src[len - 1] == '\r')
--len;
@@ -3246,7 +3263,7 @@ static INT EDIT_WM_GetText(const EDITSTATE *es, INT count, LPWSTR
dst)
return 0;
lstrcpynW(dst, es->text, count);
- return strlenW(dst);
+ return lstrlenW(dst);
}
/*********************************************************************
@@ -3381,22 +3398,17 @@ static LRESULT EDIT_WM_KeyDown(EDITSTATE *es, INT key)
else
EDIT_WM_Clear(es);
} else {
- if (shift) {
+ EDIT_EM_SetSel(es, ~0u, 0, FALSE);
+ if (shift)
/* delete character left of caret */
- EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
EDIT_MoveBackward(es, TRUE);
- EDIT_WM_Clear(es);
- } else if (control) {
+ else if (control)
/* delete to end of line */
- EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
EDIT_MoveEnd(es, TRUE, FALSE);
- EDIT_WM_Clear(es);
- } else {
+ else
/* delete character right of caret */
- EDIT_EM_SetSel(es, (UINT)-1, 0, FALSE);
EDIT_MoveForward(es, TRUE);
- EDIT_WM_Clear(es);
- }
+ EDIT_WM_Clear(es);
}
}
break;
@@ -3775,6 +3787,29 @@ static void EDIT_WM_SetFocus(HTHEME theme, EDITSTATE *es)
}
+static DWORD get_font_margins(HDC hdc, const TEXTMETRICW *tm)
+{
+ ABC abc[256];
+ SHORT left, right;
+ UINT i;
+
+ if (!(tm->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)))
+ return MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO);
+
+ if (!is_cjk(hdc))
+ return MAKELONG(EC_USEFONTINFO, EC_USEFONTINFO);
+
+ if (!GetCharABCWidthsW(hdc, 0, 255, abc))
+ return 0;
+
+ left = right = 0;
+ for (i = 0; i < ARRAY_SIZE(abc); i++) {
+ if (-abc[i].abcA > right) right = -abc[i].abcA;
+ if (-abc[i].abcC > left ) left = -abc[i].abcC;
+ }
+ return MAKELONG(left, right);
+}
+
/*********************************************************************
*
* WM_SETFONT
@@ -3790,6 +3825,7 @@ static void EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw)
HDC dc;
HFONT old_font = 0;
RECT clientRect;
+ DWORD margins;
es->font = font;
EDIT_InvalidateUniscribeData(es);
@@ -3799,6 +3835,7 @@ static void EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw)
GetTextMetricsW(dc, &tm);
es->line_height = tm.tmHeight;
es->char_width = tm.tmAveCharWidth;
+ margins = get_font_margins(dc, &tm);
if (font)
SelectObject(dc, old_font);
ReleaseDC(es->hwndSelf, dc);
@@ -3806,8 +3843,9 @@ static void EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw)
/* Reset the format rect and the margins */
GetClientRect(es->hwndSelf, &clientRect);
EDIT_SetRectNP(es, &clientRect);
- EDIT_EM_SetMargins(es, EC_LEFTMARGIN | EC_RIGHTMARGIN,
- EC_USEFONTINFO, EC_USEFONTINFO, FALSE);
+ if (margins)
+ EDIT_EM_SetMargins(es, EC_LEFTMARGIN | EC_RIGHTMARGIN,
+ LOWORD(margins), HIWORD(margins), FALSE);
if (es->style & ES_MULTILINE)
EDIT_BuildLineDefs_ML(es, 0, get_text_length(es), 0, NULL);
@@ -3865,7 +3903,7 @@ static void EDIT_WM_SetText(EDITSTATE *es, LPCWSTR text)
if (text)
{
TRACE("%s\n", debugstr_w(text));
- EDIT_EM_ReplaceSel(es, FALSE, text, strlenW(text), FALSE, FALSE);
+ EDIT_EM_ReplaceSel(es, FALSE, text, lstrlenW(text), FALSE, FALSE);
}
else
{
@@ -4264,6 +4302,55 @@ static LRESULT EDIT_EM_GetThumb(EDITSTATE *es)
EDIT_WM_HScroll(es, EM_GETTHUMB, 0));
}
+static inline WCHAR *heap_strdupW(const WCHAR *str)
+{
+ int len = lstrlenW(str) + 1;
+ WCHAR *ret = heap_alloc(len * sizeof(WCHAR));
+ lstrcpyW(ret, str);
+ return ret;
+}
+
+/*********************************************************************
+ *
+ * EM_SETCUEBANNER
+ *
+ */
+static BOOL EDIT_EM_SetCueBanner(EDITSTATE *es, BOOL draw_focused, const WCHAR
*cue_text)
+{
+ if (es->style & ES_MULTILINE || !cue_text)
+ return FALSE;
+
+ heap_free(es->cue_banner_text);
+ es->cue_banner_text = heap_strdupW(cue_text);
+ es->cue_banner_draw_focused = draw_focused;
+
+ return TRUE;
+}
+
+/*********************************************************************
+ *
+ * EM_GETCUEBANNER
+ *
+ */
+static BOOL EDIT_EM_GetCueBanner(EDITSTATE *es, WCHAR *buf, DWORD size)
+{
+ if (es->style & ES_MULTILINE)
+ return FALSE;
+
+ if (!es->cue_banner_text)
+ {
+ if (buf && size)
+ *buf = 0;
+ return FALSE;
+ }
+ else
+ {
+ if (buf)
+ lstrcpynW(buf, es->cue_banner_text, size);
+ return TRUE;
+ }
+}
+
/********************************************************************
*
@@ -4557,7 +4644,7 @@ static LRESULT EDIT_WM_Create(EDITSTATE *es, const WCHAR *name)
if (name && *name)
{
- EDIT_EM_ReplaceSel(es, FALSE, name, strlenW(name), FALSE, FALSE);
+ EDIT_EM_ReplaceSel(es, FALSE, name, lstrlenW(name), FALSE, FALSE);
/* if we insert text to the editline, the text scrolls out
* of the window, as the caret is placed after the insert
* pos normally; thus we reset es->selection... to 0 and
@@ -4614,6 +4701,7 @@ static LRESULT EDIT_WM_NCDestroy(EDITSTATE *es)
SetWindowLongPtrW( es->hwndSelf, 0, 0 );
heap_free(es->undo_text);
+ heap_free(es->cue_banner_text);
heap_free(es);
return 0;
@@ -4726,7 +4814,7 @@ static LRESULT CALLBACK EDIT_WindowProc(HWND hwnd, UINT msg, WPARAM
wParam, LPAR
{
const WCHAR *textW = (const WCHAR *)lParam;
- EDIT_EM_ReplaceSel(es, (BOOL)wParam, textW, strlenW(textW), TRUE, TRUE);
+ EDIT_EM_ReplaceSel(es, (BOOL)wParam, textW, lstrlenW(textW), TRUE, TRUE);
result = 1;
break;
}
@@ -4828,6 +4916,14 @@ static LRESULT CALLBACK EDIT_WindowProc(HWND hwnd, UINT msg, WPARAM
wParam, LPAR
result = EDIT_EM_CharFromPos(es, (short)LOWORD(lParam), (short)HIWORD(lParam));
break;
+ case EM_SETCUEBANNER:
+ result = EDIT_EM_SetCueBanner(es, (BOOL)wParam, (const WCHAR *)lParam);
+ break;
+
+ case EM_GETCUEBANNER:
+ result = EDIT_EM_GetCueBanner(es, (WCHAR *)wParam, (DWORD)lParam);
+ break;
+
/* End of the EM_ messages which were in numerical order; what order
* are these in? vaguely alphabetical?
*/
@@ -5036,7 +5132,7 @@ static LRESULT CALLBACK EDIT_WindowProc(HWND hwnd, UINT msg, WPARAM
wParam, LPAR
case WM_MOUSEWHEEL:
{
int wheelDelta;
- UINT pulScrollLines = 3;
+ INT pulScrollLines = 3;
SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
if (wParam & (MK_SHIFT | MK_CONTROL))
@@ -5056,9 +5152,9 @@ static LRESULT CALLBACK EDIT_WindowProc(HWND hwnd, UINT msg, WPARAM
wParam, LPAR
if (es->wheelDeltaRemainder && pulScrollLines)
{
int cLineScroll;
- pulScrollLines = (int) min((UINT) es->line_count, pulScrollLines);
- cLineScroll = pulScrollLines * (float)es->wheelDeltaRemainder /
WHEEL_DELTA;
- es->wheelDeltaRemainder -= WHEEL_DELTA * cLineScroll /
(int)pulScrollLines;
+ pulScrollLines = min(es->line_count, pulScrollLines);
+ cLineScroll = pulScrollLines * es->wheelDeltaRemainder / WHEEL_DELTA;
+ es->wheelDeltaRemainder -= WHEEL_DELTA * cLineScroll / pulScrollLines;
result = EDIT_EM_LineScroll(es, 0, -cLineScroll);
}
break;
diff --git a/dll/win32/comctl32/header.c b/dll/win32/comctl32/header.c
index e72324ce1f1..522f6dd1676 100644
--- a/dll/win32/comctl32/header.c
+++ b/dll/win32/comctl32/header.c
@@ -33,7 +33,6 @@
#include "windef.h"
#include "winbase.h"
-#include "wine/unicode.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
@@ -389,7 +388,7 @@ HEADER_DrawItem (HEADER_INFO *infoPtr, HDC hdc, INT iItem, BOOL
bHotTrack, LRESU
state = (phdi->bDown) ? HIS_PRESSED : (bHotTrack ? HIS_HOT : HIS_NORMAL);
/* Set the colors before sending NM_CUSTOMDRAW so that it can change them */
- SetTextColor(hdc, (bHotTrack && !theme) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT);
+ SetTextColor(hdc, (bHotTrack && !theme) ? comctl32_color.clrHighlight :
comctl32_color.clrBtnText);
SetBkColor(hdc, comctl32_color.clr3dFace);
if (lCDFlags & CDRF_NOTIFYITEMDRAW && !(phdi->fmt &
HDF_OWNERDRAW))
diff --git a/dll/win32/comctl32/hotkey.c b/dll/win32/comctl32/hotkey.c
index 7c3bff7f750..58717a2a493 100644
--- a/dll/win32/comctl32/hotkey.c
+++ b/dll/win32/comctl32/hotkey.c
@@ -221,7 +221,7 @@ HOTKEY_SetRules(HOTKEY_INFO *infoPtr, WORD invComb, WORD invMod)
{
infoPtr->InvComb = invComb;
infoPtr->InvMod = invMod;
- TRACE("(infoPtr=%p) Invalid Modifers: 0x%x, If Invalid: 0x%x\n", infoPtr,
+ TRACE("(infoPtr=%p) Invalid Modifiers: 0x%x, If Invalid: 0x%x\n", infoPtr,
infoPtr->InvComb, infoPtr->InvMod);
}
diff --git a/dll/win32/comctl32/idb_cmdlink.bmp b/dll/win32/comctl32/idb_cmdlink.bmp
new file mode 100644
index 00000000000..4b3f07b3aae
Binary files /dev/null and b/dll/win32/comctl32/idb_cmdlink.bmp differ
diff --git a/dll/win32/comctl32/imagelist.c b/dll/win32/comctl32/imagelist.c
index 78407dfdd94..8d74aac6ba6 100644
--- a/dll/win32/comctl32/imagelist.c
+++ b/dll/win32/comctl32/imagelist.c
@@ -1037,7 +1037,7 @@ ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
imldp.cbSize = sizeof(imldp);
imldp.himl = InternalDrag.himl;
imldp.i = 0;
- imldp.hdcDst = hdc,
+ imldp.hdcDst = hdc;
imldp.x = x;
imldp.y = y;
imldp.rgbBk = CLR_DEFAULT;
@@ -1271,7 +1271,7 @@ ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
imldp.cbSize = sizeof(imldp);
imldp.himl = himl;
imldp.i = i;
- imldp.hdcDst = hdc,
+ imldp.hdcDst = hdc;
imldp.x = x;
imldp.y = y;
imldp.cx = dx;
@@ -2483,7 +2483,7 @@ HIMAGELIST WINAPI ImageList_Read(IStream *pstm)
TRACE("cx %u, cy %u, flags 0x%04x, cCurImage %u, cMaxImage %u\n",
ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage, ilHead.cMaxImage);
- himl = ImageList_Create(ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cCurImage,
ilHead.cMaxImage);
+ himl = ImageList_Create(ilHead.cx, ilHead.cy, ilHead.flags, ilHead.cMaxImage,
ilHead.cGrow);
if (!himl)
return NULL;
diff --git a/dll/win32/comctl32/ipaddress.c b/dll/win32/comctl32/ipaddress.c
index aa2b6efc41d..aad2f5d86dd 100644
--- a/dll/win32/comctl32/ipaddress.c
+++ b/dll/win32/comctl32/ipaddress.c
@@ -38,7 +38,6 @@
#include "uxtheme.h"
#include "vsstyle.h"
#include "vssym32.h"
-#include "wine/unicode.h"
#include "wine/debug.h"
#include "wine/heap.h"
@@ -83,12 +82,12 @@ static void IPADDRESS_UpdateText (const IPADDRESS_INFO *infoPtr)
for (i = 0; i < 4; i++) {
if (GetWindowTextW (infoPtr->Part[i].EditHwnd, field, 4))
- strcatW(ip, field);
+ lstrcatW(ip, field);
else
/* empty edit treated as zero */
- strcatW(ip, zero);
+ lstrcatW(ip, zero);
if (i != 3)
- strcatW(ip, dot);
+ lstrcatW(ip, dot);
}
SetWindowTextW(infoPtr->Self, ip);
@@ -245,7 +244,7 @@ static LRESULT IPADDRESS_Create (HWND hwnd, const CREATESTRUCTA
*lpCreate)
hSysFont = GetStockObject(ANSI_VAR_FONT);
GetObjectW(hSysFont, sizeof(LOGFONTW), &logSysFont);
SystemParametersInfoW(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
- strcpyW(logFont.lfFaceName, logSysFont.lfFaceName);
+ lstrcpyW(logFont.lfFaceName, logSysFont.lfFaceName);
hFont = CreateFontIndirectW(&logFont);
for (i = 0; i < 4; i++) {
@@ -344,7 +343,7 @@ static int IPADDRESS_GetAddress (const IPADDRESS_INFO *infoPtr,
LPDWORD ip_addre
for (i = 0; i < 4; i++) {
ip_addr *= 256;
if (GetWindowTextW (infoPtr->Part[i].EditHwnd, field, 4))
- ip_addr += atolW(field);
+ ip_addr += wcstol(field, NULL, 10);
else
invalid++;
}
@@ -426,7 +425,7 @@ static BOOL IPADDRESS_ConstrainField (const IPADDRESS_INFO *infoPtr,
int current
part = &infoPtr->Part[currentfield];
if (!GetWindowTextW (part->EditHwnd, field, 4)) return FALSE;
- curValue = atoiW(field);
+ curValue = wcstol(field, NULL, 10);
TRACE(" curValue=%d\n", curValue);
newValue = IPADDRESS_IPNotify(infoPtr, currentfield, curValue);
diff --git a/dll/win32/comctl32/listbox.c b/dll/win32/comctl32/listbox.c
index 897f2dc2c69..804edeca47a 100644
--- a/dll/win32/comctl32/listbox.c
+++ b/dll/win32/comctl32/listbox.c
@@ -18,8 +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
*
- * TODO:
- * - LBS_NODATA
*/
#include <string.h>
@@ -33,15 +31,15 @@
#include "commctrl.h"
#include "uxtheme.h"
#include "vssym32.h"
-#include "wine/unicode.h"
#include "wine/exception.h"
#include "wine/debug.h"
+#include "wine/heap.h"
#include "comctl32.h"
-WINE_DEFAULT_DEBUG_CHANNEL(listbox2);
+WINE_DEFAULT_DEBUG_CHANNEL(listbox);
-/* Items array granularity */
+/* Items array granularity (must be power of 2) */
#define LB_ARRAY_GRANULARITY 16
/* Scrolling timeout in ms */
@@ -70,8 +68,13 @@ typedef struct
UINT style; /* Window style */
INT width; /* Window width */
INT height; /* Window height */
- LB_ITEMDATA *items; /* Array of items */
+ union
+ {
+ LB_ITEMDATA *items; /* Array of items */
+ BYTE *nodata_items; /* For multi-selection LBS_NODATA */
+ } u;
INT nb_items; /* Number of items */
+ UINT items_size; /* Total number of allocated items in the array */
INT top_item; /* Top visible item */
INT selected_item; /* Selected item */
INT focus_item; /* Item that has the focus */
@@ -125,6 +128,123 @@ static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
static LRESULT LISTBOX_GetItemRect( const LB_DESCR *descr, INT index, RECT *rect );
+/*
+ For listboxes without LBS_NODATA, an array of LB_ITEMDATA is allocated
+ to store the states of each item into descr->u.items.
+
+ For single-selection LBS_NODATA listboxes, no storage is allocated,
+ and thus descr->u.nodata_items will always be NULL.
+
+ For multi-selection LBS_NODATA listboxes, one byte per item is stored
+ for the item's selection state into descr->u.nodata_items.
+*/
+static size_t get_sizeof_item( const LB_DESCR *descr )
+{
+ return (descr->style & LBS_NODATA) ? sizeof(BYTE) : sizeof(LB_ITEMDATA);
+}
+
+static BOOL resize_storage(LB_DESCR *descr, UINT items_size)
+{
+ LB_ITEMDATA *items;
+
+ if (items_size > descr->items_size ||
+ items_size + LB_ARRAY_GRANULARITY * 2 < descr->items_size)
+ {
+ items_size = (items_size + LB_ARRAY_GRANULARITY - 1) & ~(LB_ARRAY_GRANULARITY
- 1);
+ if ((descr->style & (LBS_NODATA | LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) !=
LBS_NODATA)
+ {
+ items = heap_realloc(descr->u.items, items_size *
get_sizeof_item(descr));
+ if (!items)
+ {
+ SEND_NOTIFICATION(descr, LBN_ERRSPACE);
+ return FALSE;
+ }
+ descr->u.items = items;
+ }
+ descr->items_size = items_size;
+ }
+
+ if ((descr->style & LBS_NODATA) && descr->u.nodata_items &&
items_size > descr->nb_items)
+ {
+ memset(descr->u.nodata_items + descr->nb_items, 0,
+ (items_size - descr->nb_items) * get_sizeof_item(descr));
+ }
+ return TRUE;
+}
+
+static ULONG_PTR get_item_data( const LB_DESCR *descr, UINT index )
+{
+ return (descr->style & LBS_NODATA) ? 0 : descr->u.items[index].data;
+}
+
+static void set_item_data( LB_DESCR *descr, UINT index, ULONG_PTR data )
+{
+ if (!(descr->style & LBS_NODATA)) descr->u.items[index].data = data;
+}
+
+static WCHAR *get_item_string( const LB_DESCR *descr, UINT index )
+{
+ return HAS_STRINGS(descr) ? descr->u.items[index].str : NULL;
+}
+
+static void set_item_string( const LB_DESCR *descr, UINT index, WCHAR *string )
+{
+ if (!(descr->style & LBS_NODATA)) descr->u.items[index].str = string;
+}
+
+static UINT get_item_height( const LB_DESCR *descr, UINT index )
+{
+ return (descr->style & LBS_NODATA) ? 0 : descr->u.items[index].height;
+}
+
+static void set_item_height( LB_DESCR *descr, UINT index, UINT height )
+{
+ if (!(descr->style & LBS_NODATA)) descr->u.items[index].height = height;
+}
+
+static BOOL is_item_selected( const LB_DESCR *descr, UINT index )
+{
+ if (!(descr->style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)))
+ return index == descr->selected_item;
+ if (descr->style & LBS_NODATA)
+ return descr->u.nodata_items[index];
+ else
+ return descr->u.items[index].selected;
+}
+
+static void set_item_selected_state(LB_DESCR *descr, UINT index, BOOL state)
+{
+ if (descr->style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL))
+ {
+ if (descr->style & LBS_NODATA)
+ descr->u.nodata_items[index] = state;
+ else
+ descr->u.items[index].selected = state;
+ }
+}
+
+static void insert_item_data(LB_DESCR *descr, UINT index)
+{
+ size_t size = get_sizeof_item(descr);
+ BYTE *p = descr->u.nodata_items + index * size;
+
+ if (!descr->u.items) return;
+
+ if (index < descr->nb_items)
+ memmove(p + size, p, (descr->nb_items - index) * size);
+}
+
+static void remove_item_data(LB_DESCR *descr, UINT index)
+{
+ size_t size = get_sizeof_item(descr);
+ BYTE *p = descr->u.nodata_items + index * size;
+
+ if (!descr->u.items) return;
+
+ if (index < descr->nb_items)
+ memmove(p, p + size, (descr->nb_items - index) * size);
+}
+
/***********************************************************************
* LISTBOX_GetCurrentPageSize
*
@@ -136,7 +256,7 @@ static INT LISTBOX_GetCurrentPageSize( const LB_DESCR *descr )
if (!(descr->style & LBS_OWNERDRAWVARIABLE)) return descr->page_size;
for (i = descr->top_item, height = 0; i < descr->nb_items; i++)
{
- if ((height += descr->items[i].height) > descr->height) break;
+ if ((height += get_item_height(descr, i)) > descr->height) break;
}
if (i == descr->top_item) return 1;
else return i - descr->top_item;
@@ -156,7 +276,7 @@ static INT LISTBOX_GetMaxTopIndex( const LB_DESCR *descr )
{
page = descr->height;
for (max = descr->nb_items - 1; max >= 0; max--)
- if ((page -= descr->items[max].height) < 0) break;
+ if ((page -= get_item_height(descr, max)) < 0) break;
if (max < descr->nb_items - 1) max++;
}
else if (descr->style & LBS_MULTICOLUMN)
@@ -275,28 +395,27 @@ static LRESULT LISTBOX_SetTopItem( LB_DESCR *descr, INT index, BOOL
scroll )
if (descr->top_item == index) return LB_OKAY;
if (scroll)
{
- INT diff;
+ INT dx = 0, dy = 0;
if (descr->style & LBS_MULTICOLUMN)
- diff = (descr->top_item - index) / descr->page_size *
descr->column_width;
+ dx = (descr->top_item - index) / descr->page_size *
descr->column_width;
else if (descr->style & LBS_OWNERDRAWVARIABLE)
{
INT i;
- diff = 0;
if (index > descr->top_item)
{
for (i = index - 1; i >= descr->top_item; i--)
- diff -= descr->items[i].height;
+ dy -= get_item_height(descr, i);
}
else
{
for (i = index; i < descr->top_item; i++)
- diff += descr->items[i].height;
+ dy += get_item_height(descr, i);
}
}
else
- diff = (descr->top_item - index) * descr->item_height;
+ dy = (descr->top_item - index) * descr->item_height;
- ScrollWindowEx( descr->self, 0, diff, NULL, NULL, 0, NULL,
+ ScrollWindowEx( descr->self, dx, dy, NULL, NULL, 0, NULL,
SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
}
else
@@ -406,14 +525,14 @@ static LRESULT LISTBOX_GetItemRect( const LB_DESCR *descr, INT
index, RECT *rect
if (index < descr->top_item)
{
for (i = descr->top_item-1; i >= index; i--)
- rect->top -= descr->items[i].height;
+ rect->top -= get_item_height(descr, i);
}
else
{
for (i = descr->top_item; i < index; i++)
- rect->top += descr->items[i].height;
+ rect->top += get_item_height(descr, i);
}
- rect->bottom = rect->top + descr->items[index].height;
+ rect->bottom = rect->top + get_item_height(descr, index);
}
}
@@ -448,7 +567,7 @@ static INT LISTBOX_GetItemFromPoint( const LB_DESCR *descr, INT x, INT
y )
{
while (index < descr->nb_items)
{
- if ((pos += descr->items[index].height) > y) break;
+ if ((pos += get_item_height(descr, index)) > y) break;
index++;
}
}
@@ -457,7 +576,7 @@ static INT LISTBOX_GetItemFromPoint( const LB_DESCR *descr, INT x, INT
y )
while (index > 0)
{
index--;
- if ((pos -= descr->items[index].height) <= y) break;
+ if ((pos -= get_item_height(descr, index)) <= y) break;
}
}
}
@@ -486,8 +605,16 @@ static INT LISTBOX_GetItemFromPoint( const LB_DESCR *descr, INT x,
INT y )
static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT *rect,
INT index, UINT action, BOOL ignoreFocus )
{
- LB_ITEMDATA *item = NULL;
- if (index < descr->nb_items) item = &descr->items[index];
+ BOOL selected = FALSE, focused;
+ WCHAR *item_str = NULL;
+
+ if (index < descr->nb_items)
+ {
+ item_str = get_item_string(descr, index);
+ selected = is_item_selected(descr, index);
+ }
+
+ focused = !ignoreFocus && descr->focus_item == index &&
descr->caret_on && descr->in_focus;
if (IS_OWNERDRAW(descr))
{
@@ -495,7 +622,7 @@ static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT
*rect,
RECT r;
HRGN hrgn;
- if (!item)
+ if (index >= descr->nb_items)
{
if (action == ODA_FOCUS)
DrawFocusRect( hdc, rect );
@@ -518,15 +645,15 @@ static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT
*rect,
dis.hDC = hdc;
dis.itemID = index;
dis.itemState = 0;
- if (item->selected) dis.itemState |= ODS_SELECTED;
- if (!ignoreFocus && (descr->focus_item == index) &&
- (descr->caret_on) &&
- (descr->in_focus)) dis.itemState |= ODS_FOCUS;
+ if (selected)
+ dis.itemState |= ODS_SELECTED;
+ if (focused)
+ dis.itemState |= ODS_FOCUS;
if (!IsWindowEnabled(descr->self)) dis.itemState |= ODS_DISABLED;
- dis.itemData = item->data;
+ dis.itemData = get_item_data(descr, index);
dis.rcItem = *rect;
TRACE("[%p]: drawitem %d (%s) action=%02x state=%02x rect=%s\n",
- descr->self, index, debugstr_w(item->str), action,
+ descr->self, index, debugstr_w(item_str), action,
dis.itemState, wine_dbgstr_rect(rect) );
SendMessageW(descr->owner, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
SelectClipRgn( hdc, hrgn );
@@ -541,39 +668,38 @@ static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT
*rect,
DrawFocusRect( hdc, rect );
return;
}
- if (item && item->selected)
+ if (selected)
{
oldBk = SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
oldText = SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
}
TRACE("[%p]: painting %d (%s) action=%02x rect=%s\n",
- descr->self, index, item ? debugstr_w(item->str) : "",
action,
+ descr->self, index, debugstr_w(item_str), action,
wine_dbgstr_rect(rect) );
- if (!item)
+ if (!item_str)
ExtTextOutW( hdc, rect->left + 1, rect->top,
ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
else if (!(descr->style & LBS_USETABSTOPS))
ExtTextOutW( hdc, rect->left + 1, rect->top,
- ETO_OPAQUE | ETO_CLIPPED, rect, item->str,
- strlenW(item->str), NULL );
+ ETO_OPAQUE | ETO_CLIPPED, rect, item_str,
+ lstrlenW(item_str), NULL );
else
{
/* Output empty string to paint background in the full width. */
ExtTextOutW( hdc, rect->left + 1, rect->top,
ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
TabbedTextOutW( hdc, rect->left + 1 , rect->top,
- item->str, strlenW(item->str),
+ item_str, lstrlenW(item_str),
descr->nb_tabs, descr->tabs, 0);
}
- if (item && item->selected)
+ if (selected)
{
SetBkColor( hdc, oldBk );
SetTextColor( hdc, oldText );
}
- if (!ignoreFocus && (descr->focus_item == index) &&
- (descr->caret_on) &&
- (descr->in_focus)) DrawFocusRect( hdc, rect );
+ if (focused)
+ DrawFocusRect( hdc, rect );
}
}
@@ -672,27 +798,11 @@ static void LISTBOX_DrawFocusRect( LB_DESCR *descr, BOOL on )
*/
static LRESULT LISTBOX_InitStorage( LB_DESCR *descr, INT nb_items )
{
- LB_ITEMDATA *item;
+ UINT new_size = descr->nb_items + nb_items;
- nb_items += LB_ARRAY_GRANULARITY - 1;
- nb_items -= (nb_items % LB_ARRAY_GRANULARITY);
- if (descr->items) {
- nb_items += HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
- item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
- nb_items * sizeof(LB_ITEMDATA));
- }
- else {
- item = HeapAlloc( GetProcessHeap(), 0,
- nb_items * sizeof(LB_ITEMDATA));
- }
-
- if (!item)
- {
- SEND_NOTIFICATION( descr, LBN_ERRSPACE );
+ if (new_size > descr->items_size && !resize_storage(descr, new_size))
return LB_ERRSPACE;
- }
- descr->items = item;
- return LB_OKAY;
+ return descr->items_size;
}
@@ -743,15 +853,17 @@ static LRESULT LISTBOX_GetText( LB_DESCR *descr, INT index, LPWSTR
buffer, BOOL
if (HAS_STRINGS(descr))
{
+ WCHAR *str = get_item_string(descr, index);
+
if (!buffer)
- return strlenW(descr->items[index].str);
+ return lstrlenW(str);
- TRACE("index %d (0x%04x) %s\n", index, index,
debugstr_w(descr->items[index].str));
+ TRACE("index %d (0x%04x) %s\n", index, index, debugstr_w(str));
__TRY /* hide a Delphi bug that passes a read-only buffer */
{
- strcpyW( buffer, descr->items[index].str );
- len = strlenW(buffer);
+ lstrcpyW(buffer, str);
+ len = lstrlenW(buffer);
}
__EXCEPT_PAGE_FAULT
{
@@ -763,8 +875,8 @@ static LRESULT LISTBOX_GetText( LB_DESCR *descr, INT index, LPWSTR
buffer, BOOL
} else
{
if (buffer)
- *((DWORD *)buffer) = *(DWORD *)&descr->items[index].data;
- len = sizeof(DWORD);
+ *((ULONG_PTR *)buffer) = get_item_data(descr, index);
+ len = sizeof(ULONG_PTR);
}
return len;
}
@@ -791,14 +903,15 @@ static INT LISTBOX_FindStringPos( LB_DESCR *descr, LPCWSTR str, BOOL
exact )
{
INT index, min, max, res;
- if (!(descr->style & LBS_SORT)) return -1; /* Add it at the end */
+ if (!descr->nb_items || !(descr->style & LBS_SORT)) return -1; /* Add it
at the end */
+
min = 0;
- max = descr->nb_items;
- while (min != max)
+ max = descr->nb_items - 1;
+ while (min <= max)
{
index = (min + max) / 2;
if (HAS_STRINGS(descr))
- res = LISTBOX_lstrcmpiW( descr->locale, str, descr->items[index].str);
+ res = LISTBOX_lstrcmpiW( descr->locale, get_item_string(descr, index), str
);
else
{
COMPAREITEMSTRUCT cis;
@@ -809,18 +922,18 @@ static INT LISTBOX_FindStringPos( LB_DESCR *descr, LPCWSTR str, BOOL
exact )
cis.hwndItem = descr->self;
/* note that some application (MetaStock) expects the second item
* to be in the listbox */
- cis.itemID1 = -1;
- cis.itemData1 = (ULONG_PTR)str;
- cis.itemID2 = index;
- cis.itemData2 = descr->items[index].data;
+ cis.itemID1 = index;
+ cis.itemData1 = get_item_data(descr, index);
+ cis.itemID2 = -1;
+ cis.itemData2 = (ULONG_PTR)str;
cis.dwLocaleId = descr->locale;
res = SendMessageW( descr->owner, WM_COMPAREITEM, id, (LPARAM)&cis );
}
if (!res) return index;
- if (res < 0) max = index;
+ if (res > 0) max = index - 1;
else min = index + 1;
}
- return exact ? -1 : max;
+ return exact ? -1 : min;
}
@@ -841,7 +954,7 @@ static INT LISTBOX_FindFileStrPos( LB_DESCR *descr, LPCWSTR str )
while (min != max)
{
INT index = (min + max) / 2;
- LPCWSTR p = descr->items[index].str;
+ LPCWSTR p = get_item_string(descr, index);
if (*p == '[') /* drive or directory */
{
if (*str != '[') res = -1;
@@ -876,44 +989,42 @@ static INT LISTBOX_FindFileStrPos( LB_DESCR *descr, LPCWSTR str )
*/
static INT LISTBOX_FindString( LB_DESCR *descr, INT start, LPCWSTR str, BOOL exact )
{
- INT i;
- LB_ITEMDATA *item;
+ INT i, index;
+
+ if (descr->style & LBS_NODATA) return LB_ERR;
- if (start >= descr->nb_items) start = -1;
- item = descr->items + start + 1;
+ start++;
+ if (start >= descr->nb_items) start = 0;
if (HAS_STRINGS(descr))
{
if (!str || ! str[0] ) return LB_ERR;
if (exact)
{
- for (i = start + 1; i < descr->nb_items; i++, item++)
- if (!LISTBOX_lstrcmpiW( descr->locale, str, item->str )) return i;
- for (i = 0, item = descr->items; i <= start; i++, item++)
- if (!LISTBOX_lstrcmpiW( descr->locale, str, item->str )) return i;
+ for (i = 0, index = start; i < descr->nb_items; i++, index++)
+ {
+ if (index == descr->nb_items) index = 0;
+ if (!LISTBOX_lstrcmpiW(descr->locale, str, get_item_string(descr,
index)))
+ return index;
+ }
}
else
{
- /* Special case for drives and directories: ignore prefix */
-#define CHECK_DRIVE(item) \
- if ((item)->str[0] == '[') \
- { \
- if (!strncmpiW( str, (item)->str+1, len )) return i; \
- if (((item)->str[1] == '-') && !strncmpiW(str,
(item)->str+2, len)) \
- return i; \
- }
+ /* Special case for drives and directories: ignore prefix */
+ INT len = lstrlenW(str);
+ WCHAR *item_str;
- INT len = strlenW(str);
- for (i = start + 1; i < descr->nb_items; i++, item++)
- {
- if (!strncmpiW( str, item->str, len )) return i;
- CHECK_DRIVE(item);
- }
- for (i = 0, item = descr->items; i <= start; i++, item++)
+ for (i = 0, index = start; i < descr->nb_items; i++, index++)
{
- if (!strncmpiW( str, item->str, len )) return i;
- CHECK_DRIVE(item);
+ if (index == descr->nb_items) index = 0;
+ item_str = get_item_string(descr, index);
+
+ if (!wcsnicmp(str, item_str, len)) return index;
+ if (item_str[0] == '[')
+ {
+ if (!wcsnicmp(str, item_str + 1, len)) return index;
+ if (item_str[1] == '-' && !wcsnicmp(str, item_str +
2, len)) return index;
+ }
}
-#undef CHECK_DRIVE
}
}
else
@@ -923,10 +1034,11 @@ static INT LISTBOX_FindString( LB_DESCR *descr, INT start, LPCWSTR
str, BOOL exa
return LISTBOX_FindStringPos( descr, str, TRUE );
/* Otherwise use a linear search */
- for (i = start + 1; i < descr->nb_items; i++, item++)
- if (item->data == (ULONG_PTR)str) return i;
- for (i = 0, item = descr->items; i <= start; i++, item++)
- if (item->data == (ULONG_PTR)str) return i;
+ for (i = 0, index = start; i < descr->nb_items; i++, index++)
+ {
+ if (index == descr->nb_items) index = 0;
+ if (get_item_data(descr, index) == (ULONG_PTR)str) return index;
+ }
}
return LB_ERR;
}
@@ -938,13 +1050,12 @@ static INT LISTBOX_FindString( LB_DESCR *descr, INT start, LPCWSTR
str, BOOL exa
static LRESULT LISTBOX_GetSelCount( const LB_DESCR *descr )
{
INT i, count;
- const LB_ITEMDATA *item = descr->items;
if (!(descr->style & LBS_MULTIPLESEL) ||
(descr->style & LBS_NOSEL))
return LB_ERR;
- for (i = count = 0; i < descr->nb_items; i++, item++)
- if (item->selected) count++;
+ for (i = count = 0; i < descr->nb_items; i++)
+ if (is_item_selected(descr, i)) count++;
return count;
}
@@ -955,11 +1066,10 @@ static LRESULT LISTBOX_GetSelCount( const LB_DESCR *descr )
static LRESULT LISTBOX_GetSelItems( const LB_DESCR *descr, INT max, LPINT array )
{
INT i, count;
- const LB_ITEMDATA *item = descr->items;
if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
- for (i = count = 0; (i < descr->nb_items) && (count < max); i++,
item++)
- if (item->selected) array[count++] = i;
+ for (i = count = 0; (i < descr->nb_items) && (count < max); i++)
+ if (is_item_selected(descr, i)) array[count++] = i;
return count;
}
@@ -1011,7 +1121,7 @@ static LRESULT LISTBOX_Paint( LB_DESCR *descr, HDC hdc )
if (!(descr->style & LBS_OWNERDRAWVARIABLE))
rect.bottom = rect.top + descr->item_height;
else
- rect.bottom = rect.top + descr->items[i].height;
+ rect.bottom = rect.top + get_item_height(descr, i);
/* keep the focus rect, to paint the focus item after */
if (i == descr->focus_item)
@@ -1038,6 +1148,7 @@ static LRESULT LISTBOX_Paint( LB_DESCR *descr, HDC hdc )
rect.right += descr->column_width;
rect.top = 0;
col_pos = descr->page_size - 1;
+ if (rect.left >= descr->width) break;
}
else
{
@@ -1087,7 +1198,7 @@ static void LISTBOX_NCPaint( LB_DESCR *descr, HRGN region )
if (!theme || !(exstyle & WS_EX_CLIENTEDGE))
return;
- cxEdge = GetSystemMetrics(SM_CXEDGE),
+ cxEdge = GetSystemMetrics(SM_CXEDGE);
cyEdge = GetSystemMetrics(SM_CYEDGE);
GetWindowRect(descr->self, &r);
@@ -1168,7 +1279,7 @@ static LRESULT LISTBOX_GetItemHeight( const LB_DESCR *descr, INT
index )
SetLastError(ERROR_INVALID_INDEX);
return LB_ERR;
}
- return descr->items[index].height;
+ return get_item_height(descr, index);
}
else return descr->item_height;
}
@@ -1179,7 +1290,7 @@ static LRESULT LISTBOX_GetItemHeight( const LB_DESCR *descr, INT
index )
*/
static LRESULT LISTBOX_SetItemHeight( LB_DESCR *descr, INT index, INT height, BOOL
repaint )
{
- if (height > MAXBYTE)
+ if (height > MAXWORD)
return -1;
if (!height) height = 1;
@@ -1192,7 +1303,7 @@ static LRESULT LISTBOX_SetItemHeight( LB_DESCR *descr, INT index,
INT height, BO
return LB_ERR;
}
TRACE("[%p]: item %d height = %d\n", descr->self, index, height );
- descr->items[index].height = height;
+ set_item_height(descr, index, height);
LISTBOX_UpdateScroll( descr );
if (repaint)
LISTBOX_InvalidateItems( descr, index );
@@ -1267,12 +1378,19 @@ static LRESULT LISTBOX_SetHorizontalExtent( LB_DESCR *descr, INT
extent )
/***********************************************************************
* LISTBOX_SetColumnWidth
*/
-static LRESULT LISTBOX_SetColumnWidth( LB_DESCR *descr, INT width)
+static LRESULT LISTBOX_SetColumnWidth( LB_DESCR *descr, INT column_width)
{
- if (width == descr->column_width) return LB_OKAY;
- TRACE("[%p]: new column width = %d\n", descr->self, width );
- descr->column_width = width;
- LISTBOX_UpdatePage( descr );
+ RECT rect;
+
+ TRACE("[%p]: new column width = %d\n", descr->self, column_width);
+
+ GetClientRect(descr->self, &rect);
+ descr->width = rect.right - rect.left;
+ descr->height = rect.bottom - rect.top;
+ descr->column_width = column_width;
+
+ LISTBOX_UpdatePage(descr);
+ LISTBOX_UpdateScroll(descr);
return LB_OKAY;
}
@@ -1331,9 +1449,9 @@ static void LISTBOX_MakeItemVisible( LB_DESCR *descr, INT index,
BOOL fully )
}
else if (descr->style & LBS_OWNERDRAWVARIABLE)
{
- INT height = fully ? descr->items[index].height : 1;
+ INT height = fully ? get_item_height(descr, index) : 1;
for (top = index; top > descr->top_item; top--)
- if ((height += descr->items[top-1].height) > descr->height) break;
+ if ((height += get_item_height(descr, top - 1)) > descr->height)
break;
}
else
{
@@ -1354,19 +1472,23 @@ static void LISTBOX_MakeItemVisible( LB_DESCR *descr, INT index,
BOOL fully )
*/
static LRESULT LISTBOX_SetCaretIndex( LB_DESCR *descr, INT index, BOOL fully_visible )
{
- INT oldfocus = descr->focus_item;
+ BOOL focus_changed = descr->focus_item != index;
- TRACE("old focus %d, index %d\n", oldfocus, index);
+ TRACE("old focus %d, index %d\n", descr->focus_item, index);
if (descr->style & LBS_NOSEL) return LB_ERR;
if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
- if (index == oldfocus) return LB_OKAY;
- LISTBOX_DrawFocusRect( descr, FALSE );
- descr->focus_item = index;
+ if (focus_changed)
+ {
+ LISTBOX_DrawFocusRect( descr, FALSE );
+ descr->focus_item = index;
+ }
LISTBOX_MakeItemVisible( descr, index, fully_visible );
- LISTBOX_DrawFocusRect( descr, TRUE );
+
+ if (focus_changed)
+ LISTBOX_DrawFocusRect( descr, TRUE );
return LB_OKAY;
}
@@ -1397,8 +1519,8 @@ static LRESULT LISTBOX_SelectItemRange( LB_DESCR *descr, INT first,
{
for (i = first; i <= last; i++)
{
- if (descr->items[i].selected) continue;
- descr->items[i].selected = TRUE;
+ if (is_item_selected(descr, i)) continue;
+ set_item_selected_state(descr, i, TRUE);
LISTBOX_InvalidateItemRect(descr, i);
}
}
@@ -1406,8 +1528,8 @@ static LRESULT LISTBOX_SelectItemRange( LB_DESCR *descr, INT first,
{
for (i = first; i <= last; i++)
{
- if (!descr->items[i].selected) continue;
- descr->items[i].selected = FALSE;
+ if (!is_item_selected(descr, i)) continue;
+ set_item_selected_state(descr, i, FALSE);
LISTBOX_InvalidateItemRect(descr, i);
}
}
@@ -1440,10 +1562,10 @@ static LRESULT LISTBOX_SetSelection( LB_DESCR *descr, INT index,
{
INT oldsel = descr->selected_item;
if (index == oldsel) return LB_OKAY;
- if (oldsel != -1) descr->items[oldsel].selected = FALSE;
- if (index != -1) descr->items[index].selected = TRUE;
- if (oldsel != -1) LISTBOX_RepaintItem( descr, oldsel, ODA_SELECT );
+ if (oldsel != -1) set_item_selected_state(descr, oldsel, FALSE);
+ if (index != -1) set_item_selected_state(descr, index, TRUE);
descr->selected_item = index;
+ if (oldsel != -1) LISTBOX_RepaintItem( descr, oldsel, ODA_SELECT );
if (index != -1) LISTBOX_RepaintItem( descr, index, ODA_SELECT );
if (send_notify && descr->nb_items) SEND_NOTIFICATION( descr,
(index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
@@ -1510,43 +1632,18 @@ static void LISTBOX_MoveCaret( LB_DESCR *descr, INT index, BOOL
fully_visible )
static LRESULT LISTBOX_InsertItem( LB_DESCR *descr, INT index,
LPWSTR str, ULONG_PTR data )
{
- LB_ITEMDATA *item;
- INT max_items;
INT oldfocus = descr->focus_item;
if (index == -1) index = descr->nb_items;
else if ((index < 0) || (index > descr->nb_items)) return LB_ERR;
- if (!descr->items) max_items = 0;
- else max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
- if (descr->nb_items == max_items)
- {
- /* We need to grow the array */
- max_items += LB_ARRAY_GRANULARITY;
- if (descr->items)
- item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
- max_items * sizeof(LB_ITEMDATA) );
- else
- item = HeapAlloc( GetProcessHeap(), 0,
- max_items * sizeof(LB_ITEMDATA) );
- if (!item)
- {
- SEND_NOTIFICATION( descr, LBN_ERRSPACE );
- return LB_ERRSPACE;
- }
- descr->items = item;
- }
-
- /* Insert the item structure */
+ if (!resize_storage(descr, descr->nb_items + 1)) return LB_ERR;
- item = &descr->items[index];
- if (index < descr->nb_items)
- RtlMoveMemory( item + 1, item,
- (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
- item->str = str;
- item->data = HAS_STRINGS(descr) ? 0 : data;
- item->height = 0;
- item->selected = FALSE;
+ insert_item_data(descr, index);
descr->nb_items++;
+ set_item_string(descr, index, str);
+ set_item_data(descr, index, HAS_STRINGS(descr) ? 0 : data);
+ set_item_height(descr, index, 0);
+ set_item_selected_state(descr, index, FALSE);
/* Get item height */
@@ -1561,9 +1658,9 @@ static LRESULT LISTBOX_InsertItem( LB_DESCR *descr, INT index,
mis.itemData = data;
mis.itemHeight = descr->item_height;
SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
- item->height = mis.itemHeight ? mis.itemHeight : 1;
+ set_item_height(descr, index, mis.itemHeight ? mis.itemHeight : 1);
TRACE("[%p]: measure item %d (%s) = %d\n",
- descr->self, index, str ? debugstr_w(str) : "",
item->height );
+ descr->self, index, str ? debugstr_w(str) : "",
get_item_height(descr, index));
}
/* Repaint the items */
@@ -1605,12 +1702,12 @@ static LRESULT LISTBOX_InsertString( LB_DESCR *descr, INT index,
LPCWSTR str )
{
static const WCHAR empty_stringW[] = { 0 };
if (!str) str = empty_stringW;
- if (!(new_str = HeapAlloc( GetProcessHeap(), 0, (strlenW(str) + 1) *
sizeof(WCHAR) )))
+ if (!(new_str = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(str) + 1) *
sizeof(WCHAR) )))
{
SEND_NOTIFICATION( descr, LBN_ERRSPACE );
return LB_ERRSPACE;
}
- strcpyW(new_str, str);
+ lstrcpyW(new_str, str);
}
if (index == -1) index = descr->nb_items;
@@ -1633,19 +1730,12 @@ static LRESULT LISTBOX_InsertString( LB_DESCR *descr, INT index,
LPCWSTR str )
*/
static void LISTBOX_DeleteItem( LB_DESCR *descr, INT index )
{
- /* save the item data before it gets freed by LB_RESETCONTENT */
- ULONG_PTR item_data = descr->items[index].data;
- LPWSTR item_str = descr->items[index].str;
-
- if (!descr->nb_items)
- SendMessageW( descr->self, LB_RESETCONTENT, 0, 0 );
-
/* Note: Win 3.1 only sends DELETEITEM on owner-draw items,
* while Win95 sends it for all items with user data.
* It's probably better to send it too often than not
* often enough, so this is what we do here.
*/
- if (IS_OWNERDRAW(descr) || item_data)
+ if (IS_OWNERDRAW(descr) || get_item_data(descr, index))
{
DELETEITEMSTRUCT dis;
UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
@@ -1654,11 +1744,10 @@ static void LISTBOX_DeleteItem( LB_DESCR *descr, INT index )
dis.CtlID = id;
dis.itemID = index;
dis.hwndItem = descr->self;
- dis.itemData = item_data;
+ dis.itemData = get_item_data(descr, index);
SendMessageW( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis );
}
- if (HAS_STRINGS(descr))
- HeapFree( GetProcessHeap(), 0, item_str );
+ HeapFree( GetProcessHeap(), 0, get_item_string(descr, index) );
}
@@ -1669,37 +1758,23 @@ static void LISTBOX_DeleteItem( LB_DESCR *descr, INT index )
*/
static LRESULT LISTBOX_RemoveItem( LB_DESCR *descr, INT index )
{
- LB_ITEMDATA *item;
- INT max_items;
-
if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
/* We need to invalidate the original rect instead of the updated one. */
LISTBOX_InvalidateItems( descr, index );
+ if (descr->nb_items == 1)
+ {
+ SendMessageW(descr->self, LB_RESETCONTENT, 0, 0);
+ return LB_OKAY;
+ }
descr->nb_items--;
LISTBOX_DeleteItem( descr, index );
+ remove_item_data(descr, index);
- if (!descr->nb_items) return LB_OKAY;
-
- /* Remove the item */
-
- item = &descr->items[index];
- if (index < descr->nb_items)
- RtlMoveMemory( item, item + 1,
- (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
if (descr->anchor_item == descr->nb_items) descr->anchor_item--;
+ resize_storage(descr, descr->nb_items);
- /* Shrink the item array if possible */
-
- max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(LB_ITEMDATA);
- if (descr->nb_items < max_items - 2*LB_ARRAY_GRANULARITY)
- {
- max_items -= LB_ARRAY_GRANULARITY;
- item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
- max_items * sizeof(LB_ITEMDATA) );
- if (item) descr->items = item;
- }
/* Repaint the items */
LISTBOX_UpdateScroll( descr );
@@ -1737,43 +1812,52 @@ static void LISTBOX_ResetContent( LB_DESCR *descr )
{
INT i;
- for(i = descr->nb_items - 1; i>=0; i--) LISTBOX_DeleteItem( descr, i);
- HeapFree( GetProcessHeap(), 0, descr->items );
+ if (!(descr->style & LBS_NODATA))
+ for (i = descr->nb_items - 1; i >= 0; i--) LISTBOX_DeleteItem(descr, i);
+ HeapFree( GetProcessHeap(), 0, descr->u.items );
descr->nb_items = 0;
descr->top_item = 0;
descr->selected_item = -1;
descr->focus_item = 0;
descr->anchor_item = -1;
- descr->items = NULL;
+ descr->items_size = 0;
+ descr->u.items = NULL;
}
/***********************************************************************
* LISTBOX_SetCount
*/
-static LRESULT LISTBOX_SetCount( LB_DESCR *descr, INT count )
+static LRESULT LISTBOX_SetCount( LB_DESCR *descr, UINT count )
{
- LRESULT ret;
+ UINT orig_num = descr->nb_items;
- if (HAS_STRINGS(descr))
- {
- SetLastError(ERROR_SETCOUNT_ON_BAD_LB);
- return LB_ERR;
- }
+ if (!(descr->style & LBS_NODATA)) return LB_ERR;
- /* FIXME: this is far from optimal... */
- if (count > descr->nb_items)
- {
- while (count > descr->nb_items)
- if ((ret = LISTBOX_InsertString( descr, -1, 0 )) < 0)
- return ret;
- }
- else if (count < descr->nb_items)
+ if (!resize_storage(descr, count))
+ return LB_ERRSPACE;
+ descr->nb_items = count;
+
+ if (count)
{
- while (count < descr->nb_items)
- if ((ret = LISTBOX_RemoveItem( descr, (descr->nb_items - 1) )) < 0)
- return ret;
+ LISTBOX_UpdateScroll(descr);
+ if (count < orig_num)
+ {
+ descr->anchor_item = min(descr->anchor_item, count - 1);
+ if (descr->selected_item >= count)
+ descr->selected_item = -1;
+
+ /* If we removed the scrollbar, reset the top of the list */
+ if (count <= descr->page_size && orig_num >
descr->page_size)
+ LISTBOX_SetTopItem(descr, 0, TRUE);
+
+ descr->focus_item = min(descr->focus_item, count - 1);
+ }
+
+ /* If it was empty before growing, set focus to the first item */
+ else if (orig_num == 0) LISTBOX_SetCaretIndex(descr, 0, FALSE);
}
+ else SendMessageW(descr->self, LB_RESETCONTENT, 0, 0);
InvalidateRect( descr->self, NULL, TRUE );
return LB_OKAY;
@@ -1810,13 +1894,13 @@ static LRESULT LISTBOX_Directory( LB_DESCR *descr, UINT attrib,
static const WCHAR bracketW[] = { ']',0 };
static const WCHAR dotW[] = { '.',0 };
if (!(attrib & DDL_DIRECTORY) ||
- !strcmpW( entry.cFileName, dotW )) continue;
+ !lstrcmpW( entry.cFileName, dotW )) continue;
buffer[0] = '[';
if (!long_names && entry.cAlternateFileName[0])
- strcpyW( buffer + 1, entry.cAlternateFileName );
+ lstrcpyW( buffer + 1, entry.cAlternateFileName );
else
- strcpyW( buffer + 1, entry.cFileName );
- strcatW(buffer, bracketW);
+ lstrcpyW( buffer + 1, entry.cFileName );
+ lstrcatW(buffer, bracketW);
}
else /* not a directory */
{
@@ -1828,9 +1912,9 @@ static LRESULT LISTBOX_Directory( LB_DESCR *descr, UINT attrib,
continue;
#undef ATTRIBS
if (!long_names && entry.cAlternateFileName[0])
- strcpyW( buffer, entry.cAlternateFileName );
+ lstrcpyW( buffer, entry.cAlternateFileName );
else
- strcpyW( buffer, entry.cFileName );
+ lstrcpyW( buffer, entry.cFileName );
}
if (!long_names) CharLowerW( buffer );
pos = LISTBOX_FindFileStrPos( descr, buffer );
@@ -1998,7 +2082,7 @@ static LRESULT LISTBOX_HandleHScroll( LB_DESCR *descr, WORD
scrollReq, WORD pos
static LRESULT LISTBOX_HandleMouseWheel(LB_DESCR *descr, SHORT delta )
{
- UINT pulScrollLines = 3;
+ INT pulScrollLines = 3;
SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
@@ -2012,9 +2096,20 @@ static LRESULT LISTBOX_HandleMouseWheel(LB_DESCR *descr, SHORT
delta )
if (descr->wheel_remain && pulScrollLines)
{
int cLineScroll;
- pulScrollLines = min((UINT) descr->page_size, pulScrollLines);
- cLineScroll = pulScrollLines * (float)descr->wheel_remain / WHEEL_DELTA;
- descr->wheel_remain -= WHEEL_DELTA * cLineScroll / (int)pulScrollLines;
+ if (descr->style & LBS_MULTICOLUMN)
+ {
+ pulScrollLines = min(descr->width / descr->column_width,
pulScrollLines);
+ pulScrollLines = max(1, pulScrollLines);
+ cLineScroll = pulScrollLines * descr->wheel_remain / WHEEL_DELTA;
+ descr->wheel_remain -= WHEEL_DELTA * cLineScroll / pulScrollLines;
+ cLineScroll *= descr->page_size;
+ }
+ else
+ {
+ pulScrollLines = min(descr->page_size, pulScrollLines);
+ cLineScroll = pulScrollLines * descr->wheel_remain / WHEEL_DELTA;
+ descr->wheel_remain -= WHEEL_DELTA * cLineScroll / pulScrollLines;
+ }
LISTBOX_SetTopItem( descr, descr->top_item - cLineScroll, TRUE );
}
return 0;
@@ -2063,7 +2158,7 @@ static LRESULT LISTBOX_HandleLButtonDown( LB_DESCR *descr, DWORD
keys, INT x, IN
{
LISTBOX_SetCaretIndex( descr, index, FALSE );
LISTBOX_SetSelection( descr, index,
- !descr->items[index].selected,
+ !is_item_selected(descr, index),
(descr->style & LBS_NOTIFY) != 0);
}
else
@@ -2073,13 +2168,13 @@ static LRESULT LISTBOX_HandleLButtonDown( LB_DESCR *descr, DWORD
keys, INT x, IN
if (descr->style & LBS_EXTENDEDSEL)
{
LISTBOX_SetSelection( descr, index,
- descr->items[index].selected,
+ is_item_selected(descr, index),
(descr->style & LBS_NOTIFY) != 0 );
}
else
{
LISTBOX_SetSelection( descr, index,
- !descr->items[index].selected,
+ !is_item_selected(descr, index),
(descr->style & LBS_NOTIFY) != 0 );
}
}
@@ -2359,8 +2454,7 @@ static LRESULT LISTBOX_HandleKeyDown( LB_DESCR *descr, DWORD key )
if (descr->style & LBS_MULTICOLUMN)
{
bForceSelection = FALSE;
- if (descr->focus_item + descr->page_size < descr->nb_items)
- caret = descr->focus_item + descr->page_size;
+ caret = min(descr->focus_item + descr->page_size, descr->nb_items -
1);
break;
}
/* fall through */
@@ -2400,7 +2494,7 @@ static LRESULT LISTBOX_HandleKeyDown( LB_DESCR *descr, DWORD key )
else if (descr->style & LBS_MULTIPLESEL)
{
LISTBOX_SetSelection( descr, descr->focus_item,
- !descr->items[descr->focus_item].selected,
+ !is_item_selected(descr, descr->focus_item),
(descr->style & LBS_NOTIFY) != 0 );
}
break;
@@ -2485,7 +2579,8 @@ static BOOL LISTBOX_Create( HWND hwnd, LPHEADCOMBO lphc )
descr->style = GetWindowLongW( descr->self, GWL_STYLE );
descr->width = rect.right - rect.left;
descr->height = rect.bottom - rect.top;
- descr->items = NULL;
+ descr->u.items = NULL;
+ descr->items_size = 0;
descr->nb_items = 0;
descr->top_item = 0;
descr->selected_item = -1;
@@ -2520,10 +2615,14 @@ static BOOL LISTBOX_Create( HWND hwnd, LPHEADCOMBO lphc )
if (descr->style & LBS_EXTENDEDSEL) descr->style |= LBS_MULTIPLESEL;
if (descr->style & LBS_MULTICOLUMN) descr->style &=
~LBS_OWNERDRAWVARIABLE;
if (descr->style & LBS_OWNERDRAWVARIABLE) descr->style |=
LBS_NOINTEGRALHEIGHT;
+ if ((descr->style & (LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_SORT)) !=
LBS_OWNERDRAWFIXED)
+ descr->style &= ~LBS_NODATA;
descr->item_height = LISTBOX_SetFont( descr, 0 );
if (descr->style & LBS_OWNERDRAWFIXED)
{
+ descr->style &= ~LBS_OWNERDRAWVARIABLE;
+
if( descr->lphc && (descr->lphc->dwStyle & CBS_DROPDOWN))
{
/* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */
@@ -2633,7 +2732,7 @@ static LRESULT CALLBACK LISTBOX_WindowProc( HWND hwnd, UINT msg,
WPARAM wParam,
SetLastError(ERROR_INVALID_INDEX);
return LB_ERR;
}
- return descr->items[wParam].data;
+ return get_item_data(descr, wParam);
case LB_SETITEMDATA:
if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
@@ -2641,7 +2740,7 @@ static LRESULT CALLBACK LISTBOX_WindowProc( HWND hwnd, UINT msg,
WPARAM wParam,
SetLastError(ERROR_INVALID_INDEX);
return LB_ERR;
}
- descr->items[wParam].data = lParam;
+ set_item_data(descr, wParam, lParam);
/* undocumented: returns TRUE, not LB_OKAY (0) */
return TRUE;
@@ -2657,8 +2756,8 @@ static LRESULT CALLBACK LISTBOX_WindowProc( HWND hwnd, UINT msg,
WPARAM wParam,
SetLastError(ERROR_INVALID_INDEX);
return LB_ERR;
}
- if (!HAS_STRINGS(descr)) return sizeof(DWORD);
- return strlenW( descr->items[wParam].str );
+ if (!HAS_STRINGS(descr)) return sizeof(ULONG_PTR);
+ return lstrlenW(get_item_string(descr, wParam));
case LB_GETCURSEL:
if (descr->nb_items == 0)
@@ -2764,10 +2863,17 @@ static LRESULT CALLBACK LISTBOX_WindowProc( HWND hwnd, UINT msg,
WPARAM wParam,
case LB_GETSEL:
if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
return LB_ERR;
- return descr->items[wParam].selected;
+ return is_item_selected(descr, wParam);
case LB_SETSEL:
- return LISTBOX_SetSelection( descr, lParam, wParam, FALSE );
+ ret = LISTBOX_SetSelection( descr, lParam, wParam, FALSE );
+ if (ret != LB_ERR && wParam)
+ {
+ descr->anchor_item = lParam;
+ if (lParam != -1)
+ LISTBOX_SetCaretIndex( descr, lParam, TRUE );
+ }
+ return ret;
case LB_SETCURSEL:
if (IS_MULTISELECT(descr)) return LB_ERR;
diff --git a/dll/win32/comctl32/listview.c b/dll/win32/comctl32/listview.c
index 53e8b546bf2..5279c7b0d27 100644
--- a/dll/win32/comctl32/listview.c
+++ b/dll/win32/comctl32/listview.c
@@ -542,12 +542,6 @@ static inline int textcmpWT(LPCWSTR aw, LPCWSTR bt, BOOL isW)
return 1;
}
-
-static inline int lstrncmpiW(LPCWSTR s1, LPCWSTR s2, int n)
-{
- n = min(min(n, lstrlenW(s1)), lstrlenW(s2));
- return CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, s1, n, s2, n) -
CSTR_EQUAL;
-}
/******** Debugging functions *****************************************/
@@ -1972,7 +1966,7 @@ static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM
charCode, L
item.cchTextMax = MAX_PATH;
if (!LISTVIEW_GetItemW(infoPtr, &item)) return 0;
- if (!lstrncmpiW(item.pszText, infoPtr->szSearchParam,
infoPtr->nSearchParamLength))
+ if (!wcsnicmp(item.pszText, infoPtr->szSearchParam,
infoPtr->nSearchParamLength))
{
nItem = i;
break;
@@ -1980,7 +1974,7 @@ static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM
charCode, L
/* this is used to find first char match when search string is not
available yet,
otherwise every WM_CHAR will search to next item by first char,
ignoring that we're
already waiting for user to complete a string */
- else if (nItem == -1 && infoPtr->nSearchParamLength == 1
&& !lstrncmpiW(item.pszText, infoPtr->szSearchParam, 1))
+ else if (nItem == -1 && infoPtr->nSearchParamLength == 1
&& !wcsnicmp(item.pszText, infoPtr->szSearchParam, 1))
{
/* this would work but we must keep looking for a longer match */
nItem = i;
@@ -6797,11 +6791,11 @@ static HIMAGELIST LISTVIEW_GetImageList(const LISTVIEW_INFO
*infoPtr, INT nImage
static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL
isW)
{
ITEMHDR callbackHdr = { LPSTR_TEXTCALLBACKW, I_IMAGECALLBACK };
+ BOOL is_subitem_invalid = FALSE;
NMLVDISPINFOW dispInfo;
ITEM_INFO *lpItem;
ITEMHDR* pItemHdr;
HDPA hdpaSubItems;
- INT isubitem;
TRACE("(item=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
@@ -6811,10 +6805,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr,
LPLVITEMW lpLVItem,
if (lpLVItem->mask == 0) return TRUE;
TRACE("mask=%x\n", lpLVItem->mask);
- /* make a local copy */
- isubitem = lpLVItem->iSubItem;
-
- if (isubitem && (lpLVItem->mask & LVIF_STATE))
+ if (lpLVItem->iSubItem && (lpLVItem->mask & LVIF_STATE))
lpLVItem->state = 0;
/* a quick optimization if all we're asked is the focus state
@@ -6824,7 +6815,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr,
LPLVITEMW lpLVItem,
!(infoPtr->uCallbackMask & LVIS_FOCUSED) )
{
lpLVItem->state = 0;
- if (infoPtr->nFocusedItem == lpLVItem->iItem && isubitem == 0)
+ if (infoPtr->nFocusedItem == lpLVItem->iItem &&
!lpLVItem->iSubItem)
lpLVItem->state |= LVIS_FOCUSED;
return TRUE;
}
@@ -6846,7 +6837,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr,
LPLVITEMW lpLVItem,
* depend on the uninitialized fields being 0 */
dispInfo.item.mask = lpLVItem->mask & ~LVIF_PARAM;
dispInfo.item.iItem = lpLVItem->iItem;
- dispInfo.item.iSubItem = isubitem;
+ dispInfo.item.iSubItem = lpLVItem->iSubItem;
if (lpLVItem->mask & LVIF_TEXT)
{
if (lpLVItem->mask & LVIF_NORECOMPUTE)
@@ -6893,7 +6884,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr,
LPLVITEMW lpLVItem,
lpLVItem->pszText = LPSTR_TEXTCALLBACKW;
/* we store only a little state, so if we're not asked, we're done */
- if (!(lpLVItem->mask & LVIF_STATE) || isubitem) return TRUE;
+ if (!(lpLVItem->mask & LVIF_STATE) || lpLVItem->iSubItem) return TRUE;
/* if focus is handled by us, report it */
if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED )
@@ -6919,21 +6910,22 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr,
LPLVITEMW lpLVItem,
lpItem = DPA_GetPtr(hdpaSubItems, 0);
assert (lpItem);
- if (isubitem)
+ if (lpLVItem->iSubItem)
{
- SUBITEM_INFO *lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, isubitem);
- pItemHdr = lpSubItem ? &lpSubItem->hdr : &callbackHdr;
- if (!lpSubItem)
+ SUBITEM_INFO *lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems,
lpLVItem->iSubItem);
+ if (lpSubItem)
+ pItemHdr = &lpSubItem->hdr;
+ else
{
- WARN(" iSubItem invalid (%08x), ignored.\n", isubitem);
- isubitem = 0;
+ pItemHdr = &callbackHdr;
+ is_subitem_invalid = TRUE;
}
}
else
pItemHdr = &lpItem->hdr;
/* Do we need to query the state from the app? */
- if ((lpLVItem->mask & LVIF_STATE) && infoPtr->uCallbackMask
&& isubitem == 0)
+ if ((lpLVItem->mask & LVIF_STATE) && infoPtr->uCallbackMask
&& (!lpLVItem->iSubItem || is_subitem_invalid))
{
dispInfo.item.mask |= LVIF_STATE;
dispInfo.item.stateMask = infoPtr->uCallbackMask;
@@ -6941,15 +6933,14 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr,
LPLVITEMW lpLVItem,
/* Do we need to enquire about the image? */
if ((lpLVItem->mask & LVIF_IMAGE) && pItemHdr->iImage ==
I_IMAGECALLBACK &&
- (isubitem == 0 || (infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES)))
+ (!lpLVItem->iSubItem || (infoPtr->dwLvExStyle &
LVS_EX_SUBITEMIMAGES)))
{
dispInfo.item.mask |= LVIF_IMAGE;
dispInfo.item.iImage = I_IMAGECALLBACK;
}
/* Only items support indentation */
- if ((lpLVItem->mask & LVIF_INDENT) && lpItem->iIndent ==
I_INDENTCALLBACK &&
- (isubitem == 0))
+ if ((lpLVItem->mask & LVIF_INDENT) && lpItem->iIndent ==
I_INDENTCALLBACK && !lpLVItem->iSubItem)
{
dispInfo.item.mask |= LVIF_INDENT;
dispInfo.item.iIndent = I_INDENTCALLBACK;
@@ -6970,14 +6961,14 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr,
LPLVITEMW lpLVItem,
if (dispInfo.item.mask)
{
dispInfo.item.iItem = lpLVItem->iItem;
- dispInfo.item.iSubItem = lpLVItem->iSubItem; /* yes: the original subitem */
+ dispInfo.item.iSubItem = lpLVItem->iSubItem;
dispInfo.item.lParam = lpItem->lParam;
notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW);
TRACE(" getdispinfo(2):item=%s\n", debuglvitem_t(&dispInfo.item, isW));
}
/* we should not store values for subitems */
- if (isubitem) dispInfo.item.mask &= ~LVIF_DI_SETITEM;
+ if (lpLVItem->iSubItem) dispInfo.item.mask &= ~LVIF_DI_SETITEM;
/* Now, handle the iImage field */
if (dispInfo.item.mask & LVIF_IMAGE)
@@ -6988,7 +6979,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr,
LPLVITEMW lpLVItem,
}
else if (lpLVItem->mask & LVIF_IMAGE)
{
- if(isubitem == 0 || (infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES))
+ if (!lpLVItem->iSubItem || (infoPtr->dwLvExStyle &
LVS_EX_SUBITEMIMAGES))
lpLVItem->iImage = pItemHdr->iImage;
else
lpLVItem->iImage = 0;
@@ -7020,7 +7011,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr,
LPLVITEMW lpLVItem,
lpLVItem->lParam = lpItem->lParam;
/* if this is a subitem, we're done */
- if (isubitem) return TRUE;
+ if (lpLVItem->iSubItem) return TRUE;
/* ... the state field (this one is different due to uCallbackmask) */
if (lpLVItem->mask & LVIF_STATE)
diff --git a/dll/win32/comctl32/monthcal.c b/dll/win32/comctl32/monthcal.c
index 744b9d382ce..00e0f79fe9a 100644
--- a/dll/win32/comctl32/monthcal.c
+++ b/dll/win32/comctl32/monthcal.c
@@ -45,7 +45,6 @@
#include "comctl32.h"
#include "uxtheme.h"
#include "vssym32.h"
-#include "wine/unicode.h"
#include "wine/debug.h"
#include "wine/heap.h"
@@ -216,7 +215,7 @@ static inline int MONTHCAL_MonthDiff(const SYSTEMTIME *left, const
SYSTEMTIME *r
/* January is 1, December is 12 */
int MONTHCAL_MonthLength(int month, int year)
{
- const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+ static const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/* Wrap around, this eases handling. Getting length only we shouldn't care
about year change here cause January and December have
the same day quantity */
@@ -888,18 +887,18 @@ static void MONTHCAL_PaintTitle(MONTHCAL_INFO *infoPtr, HDC hdc,
const PAINTSTRU
/* draw formatted date string */
GetDateFormatW(LOCALE_USER_DEFAULT, DATE_YEARMONTH, st, NULL, strW, ARRAY_SIZE(strW));
- DrawTextW(hdc, strW, strlenW(strW), title, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+ DrawTextW(hdc, strW, lstrlenW(strW), title, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SYEARMONTH, fmtW, ARRAY_SIZE(fmtW));
wsprintfW(yearW, fmtyearW, st->wYear);
/* month is trickier as it's possible to have different format pictures, we'll
test for M, MM, MMM, and MMMM */
- if (strstrW(fmtW, mmmmW))
+ if (wcsstr(fmtW, mmmmW))
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SMONTHNAME1+st->wMonth-1, monthW,
ARRAY_SIZE(monthW));
- else if (strstrW(fmtW, mmmW))
+ else if (wcsstr(fmtW, mmmW))
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SABBREVMONTHNAME1+st->wMonth-1, monthW,
ARRAY_SIZE(monthW));
- else if (strstrW(fmtW, mmW))
+ else if (wcsstr(fmtW, mmW))
wsprintfW(monthW, fmtmmW, st->wMonth);
else
wsprintfW(monthW, fmtmW, st->wMonth);
@@ -908,7 +907,7 @@ static void MONTHCAL_PaintTitle(MONTHCAL_INFO *infoPtr, HDC hdc, const
PAINTSTRU
yearoffset = 0;
while (strW[yearoffset])
{
- if (!strncmpW(&strW[yearoffset], yearW, strlenW(yearW)))
+ if (!wcsncmp(&strW[yearoffset], yearW, lstrlenW(yearW)))
break;
yearoffset++;
}
@@ -916,7 +915,7 @@ static void MONTHCAL_PaintTitle(MONTHCAL_INFO *infoPtr, HDC hdc, const
PAINTSTRU
monthoffset = 0;
while (strW[monthoffset])
{
- if (!strncmpW(&strW[monthoffset], monthW, strlenW(monthW)))
+ if (!wcsncmp(&strW[monthoffset], monthW, lstrlenW(monthW)))
break;
monthoffset++;
}
@@ -933,15 +932,15 @@ static void MONTHCAL_PaintTitle(MONTHCAL_INFO *infoPtr, HDC hdc,
const PAINTSTRU
infoPtr->calendars[calIdx].titlemonth.left = sz.cx;
/* for right limits use actual string parts lengths */
- GetTextExtentPoint32W(hdc, &strW[yearoffset], strlenW(yearW), &sz);
+ GetTextExtentPoint32W(hdc, &strW[yearoffset], lstrlenW(yearW), &sz);
infoPtr->calendars[calIdx].titleyear.right =
infoPtr->calendars[calIdx].titleyear.left + sz.cx;
- GetTextExtentPoint32W(hdc, monthW, strlenW(monthW), &sz);
+ GetTextExtentPoint32W(hdc, monthW, lstrlenW(monthW), &sz);
infoPtr->calendars[calIdx].titlemonth.right =
infoPtr->calendars[calIdx].titlemonth.left + sz.cx;
/* Finally translate rectangles to match center aligned string,
hit rectangles are relative to title rectangle before translation. */
- GetTextExtentPoint32W(hdc, strW, strlenW(strW), &sz);
+ GetTextExtentPoint32W(hdc, strW, lstrlenW(strW), &sz);
shiftX = (title->right - title->left - sz.cx) / 2 + title->left;
OffsetRect(&infoPtr->calendars[calIdx].titleyear, shiftX, 0);
OffsetRect(&infoPtr->calendars[calIdx].titlemonth, shiftX, 0);
@@ -977,7 +976,7 @@ static void MONTHCAL_PaintWeeknumbers(const MONTHCAL_INFO *infoPtr,
HDC hdc, con
The first week of the year must contain only days of the new year
*/
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTWEEKOFYEAR, buf, ARRAY_SIZE(buf));
- weeknum = atoiW(buf);
+ weeknum = wcstol(buf, NULL, 10);
switch (weeknum)
{
case 1: mindays = 6;
@@ -1208,7 +1207,7 @@ static void MONTHCAL_PaintCalendar(const MONTHCAL_INFO *infoPtr, HDC
hdc, const
i = infoPtr->firstDay;
for(j = 0; j < 7; j++) {
get_localized_dayname(infoPtr, (i + j + 6) % 7, buf, ARRAY_SIZE(buf));
- DrawTextW(hdc, buf, strlenW(buf), &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+ DrawTextW(hdc, buf, lstrlenW(buf), &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
OffsetRect(&r, infoPtr->width_increment, 0);
}
@@ -1414,9 +1413,9 @@ MONTHCAL_SetFirstDayOfWeek(MONTHCAL_INFO *infoPtr, INT day)
WCHAR buf[80];
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, buf, ARRAY_SIZE(buf));
- TRACE("%s %d\n", debugstr_w(buf), strlenW(buf));
+ TRACE("%s %d\n", debugstr_w(buf), lstrlenW(buf));
- new_day = atoiW(buf);
+ new_day = wcstol(buf, NULL, 10);
infoPtr->firstDaySet = FALSE;
}
diff --git a/dll/win32/comctl32/pager.c b/dll/win32/comctl32/pager.c
index fe68515e673..4763ed5640d 100644
--- a/dll/win32/comctl32/pager.c
+++ b/dll/win32/comctl32/pager.c
@@ -71,6 +71,7 @@ typedef struct
HWND hwndSelf; /* handle of the control wnd */
HWND hwndChild; /* handle of the contained wnd */
HWND hwndNotify; /* handle of the parent wnd */
+ BOOL bUnicode; /* send notifications in Unicode */
DWORD dwStyle; /* styles for this control */
COLORREF clrBk; /* background color */
INT nBorder; /* border size for the control */
@@ -83,6 +84,8 @@ typedef struct
INT TLbtnState; /* state of top or left btn */
INT BRbtnState; /* state of bottom or right btn */
INT direction; /* direction of the scroll, (e.g. PGF_SCROLLUP) */
+ WCHAR *pwszBuffer;/* text buffer for converted notifications */
+ INT nBufferSize;/* size of the above buffer */
} PAGER_INFO;
#define TIMERID1 1
@@ -90,6 +93,21 @@ typedef struct
#define INITIAL_DELAY 500
#define REPEAT_DELAY 50
+/* Text field conversion behavior flags for PAGER_SendConvertedNotify() */
+enum conversion_flags
+{
+ /* Convert Unicode text to ANSI for parent before sending. If not set, do nothing */
+ CONVERT_SEND = 0x01,
+ /* Convert ANSI text from parent back to Unicode for children */
+ CONVERT_RECEIVE = 0x02,
+ /* Send empty text to parent if text is NULL. Original text pointer still remains
NULL */
+ SEND_EMPTY_IF_NULL = 0x04,
+ /* Set text to null after parent received the notification if the required mask is
not set before sending notification */
+ SET_NULL_IF_NO_MASK = 0x08,
+ /* Zero out the text buffer before sending it to parent */
+ ZERO_SEND = 0x10
+};
+
static void
PAGER_GetButtonRects(const PAGER_INFO* infoPtr, RECT* prcTopLeft, RECT* prcBottomRight,
BOOL bClientCoords)
{
@@ -555,6 +573,7 @@ static LRESULT
PAGER_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
{
PAGER_INFO *infoPtr;
+ INT ret;
/* allocate memory for info structure */
infoPtr = heap_alloc_zero (sizeof(*infoPtr));
@@ -581,6 +600,9 @@ PAGER_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
if (infoPtr->dwStyle & PGS_DRAGNDROP)
FIXME("[%p] Drag and Drop style is not implemented yet.\n",
infoPtr->hwndSelf);
+ ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFYFORMAT,
(WPARAM)infoPtr->hwndSelf, NF_QUERY);
+ infoPtr->bUnicode = (ret == NFR_UNICODE);
+
return 0;
}
@@ -589,6 +611,7 @@ static LRESULT
PAGER_Destroy (PAGER_INFO *infoPtr)
{
SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
+ heap_free (infoPtr->pwszBuffer);
heap_free (infoPtr);
return 0;
}
@@ -998,6 +1021,438 @@ PAGER_StyleChanged(PAGER_INFO *infoPtr, WPARAM wStyleType, const
STYLESTRUCT *lp
return 0;
}
+static LRESULT PAGER_NotifyFormat(PAGER_INFO *infoPtr, INT command)
+{
+ INT ret;
+ switch (command)
+ {
+ case NF_REQUERY:
+ ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFYFORMAT,
(WPARAM)infoPtr->hwndSelf, NF_QUERY);
+ infoPtr->bUnicode = (ret == NFR_UNICODE);
+ return ret;
+ case NF_QUERY:
+ /* Pager always wants Unicode notifications from children */
+ return NFR_UNICODE;
+ default:
+ return 0;
+ }
+}
+
+static UINT PAGER_GetAnsiNtfCode(UINT code)
+{
+ switch (code)
+ {
+ /* ComboxBoxEx */
+ case CBEN_DRAGBEGINW: return CBEN_DRAGBEGINA;
+ case CBEN_ENDEDITW: return CBEN_ENDEDITA;
+ case CBEN_GETDISPINFOW: return CBEN_GETDISPINFOA;
+ /* Date and Time Picker */
+ case DTN_FORMATW: return DTN_FORMATA;
+ case DTN_FORMATQUERYW: return DTN_FORMATQUERYA;
+ case DTN_USERSTRINGW: return DTN_USERSTRINGA;
+ case DTN_WMKEYDOWNW: return DTN_WMKEYDOWNA;
+ /* Header */
+ case HDN_BEGINTRACKW: return HDN_BEGINTRACKA;
+ case HDN_DIVIDERDBLCLICKW: return HDN_DIVIDERDBLCLICKA;
+ case HDN_ENDTRACKW: return HDN_ENDTRACKA;
+ case HDN_GETDISPINFOW: return HDN_GETDISPINFOA;
+ case HDN_ITEMCHANGEDW: return HDN_ITEMCHANGEDA;
+ case HDN_ITEMCHANGINGW: return HDN_ITEMCHANGINGA;
+ case HDN_ITEMCLICKW: return HDN_ITEMCLICKA;
+ case HDN_ITEMDBLCLICKW: return HDN_ITEMDBLCLICKA;
+ case HDN_TRACKW: return HDN_TRACKA;
+ /* List View */
+ case LVN_BEGINLABELEDITW: return LVN_BEGINLABELEDITA;
+ case LVN_ENDLABELEDITW: return LVN_ENDLABELEDITA;
+ case LVN_GETDISPINFOW: return LVN_GETDISPINFOA;
+ case LVN_GETINFOTIPW: return LVN_GETINFOTIPA;
+ case LVN_INCREMENTALSEARCHW: return LVN_INCREMENTALSEARCHA;
+ case LVN_ODFINDITEMW: return LVN_ODFINDITEMA;
+ case LVN_SETDISPINFOW: return LVN_SETDISPINFOA;
+ /* Toolbar */
+ case TBN_GETBUTTONINFOW: return TBN_GETBUTTONINFOA;
+ case TBN_GETINFOTIPW: return TBN_GETINFOTIPA;
+ /* Tooltip */
+ case TTN_GETDISPINFOW: return TTN_GETDISPINFOA;
+ /* Tree View */
+ case TVN_BEGINDRAGW: return TVN_BEGINDRAGA;
+ case TVN_BEGINLABELEDITW: return TVN_BEGINLABELEDITA;
+ case TVN_BEGINRDRAGW: return TVN_BEGINRDRAGA;
+ case TVN_DELETEITEMW: return TVN_DELETEITEMA;
+ case TVN_ENDLABELEDITW: return TVN_ENDLABELEDITA;
+ case TVN_GETDISPINFOW: return TVN_GETDISPINFOA;
+ case TVN_GETINFOTIPW: return TVN_GETINFOTIPA;
+ case TVN_ITEMEXPANDEDW: return TVN_ITEMEXPANDEDA;
+ case TVN_ITEMEXPANDINGW: return TVN_ITEMEXPANDINGA;
+ case TVN_SELCHANGEDW: return TVN_SELCHANGEDA;
+ case TVN_SELCHANGINGW: return TVN_SELCHANGINGA;
+ case TVN_SETDISPINFOW: return TVN_SETDISPINFOA;
+ }
+ return code;
+}
+
+static BOOL PAGER_AdjustBuffer(PAGER_INFO *infoPtr, INT size)
+{
+ if (!infoPtr->pwszBuffer)
+ infoPtr->pwszBuffer = heap_alloc(size);
+ else if (infoPtr->nBufferSize < size)
+ infoPtr->pwszBuffer = heap_realloc(infoPtr->pwszBuffer, size);
+
+ if (!infoPtr->pwszBuffer) return FALSE;
+ if (infoPtr->nBufferSize < size) infoPtr->nBufferSize = size;
+
+ return TRUE;
+}
+
+/* Convert text to Unicode and return the original text address */
+static WCHAR *PAGER_ConvertText(WCHAR **text)
+{
+ WCHAR *oldText = *text;
+ *text = NULL;
+ Str_SetPtrWtoA((CHAR **)text, oldText);
+ return oldText;
+}
+
+static void PAGER_RestoreText(WCHAR **text, WCHAR *oldText)
+{
+ if (!oldText) return;
+
+ Free(*text);
+ *text = oldText;
+}
+
+static LRESULT PAGER_SendConvertedNotify(PAGER_INFO *infoPtr, NMHDR *hdr, UINT *mask,
UINT requiredMask, WCHAR **text,
+ INT *textMax, DWORD flags)
+{
+ CHAR *sendBuffer = NULL;
+ CHAR *receiveBuffer;
+ INT bufferSize;
+ WCHAR *oldText;
+ INT oldTextMax;
+ LRESULT ret = NO_ERROR;
+
+ oldText = *text;
+ oldTextMax = textMax ? *textMax : 0;
+
+ hdr->code = PAGER_GetAnsiNtfCode(hdr->code);
+
+ if (mask && !(*mask & requiredMask))
+ {
+ ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom,
(LPARAM)hdr);
+ if (flags & SET_NULL_IF_NO_MASK) oldText = NULL;
+ goto done;
+ }
+
+ if (oldTextMax < 0) goto done;
+
+ if ((*text && flags & (CONVERT_SEND | ZERO_SEND)) || (!*text &&
flags & SEND_EMPTY_IF_NULL))
+ {
+ bufferSize = textMax ? *textMax : lstrlenW(*text) + 1;
+ sendBuffer = heap_alloc_zero(bufferSize);
+ if (!sendBuffer) goto done;
+ if (!(flags & ZERO_SEND)) WideCharToMultiByte(CP_ACP, 0, *text, -1,
sendBuffer, bufferSize, NULL, FALSE);
+ *text = (WCHAR *)sendBuffer;
+ }
+
+ ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
+
+ if (*text && oldText && (flags & CONVERT_RECEIVE))
+ {
+ /* MultiByteToWideChar requires that source and destination are not the same
buffer */
+ if (*text == oldText)
+ {
+ bufferSize = lstrlenA((CHAR *)*text) + 1;
+ receiveBuffer = heap_alloc(bufferSize);
+ if (!receiveBuffer) goto done;
+ memcpy(receiveBuffer, *text, bufferSize);
+ MultiByteToWideChar(CP_ACP, 0, receiveBuffer, bufferSize, oldText,
oldTextMax);
+ heap_free(receiveBuffer);
+ }
+ else
+ MultiByteToWideChar(CP_ACP, 0, (CHAR *)*text, -1, oldText, oldTextMax);
+ }
+
+done:
+ heap_free(sendBuffer);
+ *text = oldText;
+ return ret;
+}
+
+static LRESULT PAGER_Notify(PAGER_INFO *infoPtr, NMHDR *hdr)
+{
+ LRESULT ret;
+
+ if (infoPtr->bUnicode) return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY,
hdr->idFrom, (LPARAM)hdr);
+
+ switch (hdr->code)
+ {
+ /* ComboBoxEx */
+ case CBEN_GETDISPINFOW:
+ {
+ NMCOMBOBOXEXW *nmcbe = (NMCOMBOBOXEXW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, &nmcbe->ceItem.mask,
CBEIF_TEXT, &nmcbe->ceItem.pszText,
+ &nmcbe->ceItem.cchTextMax, ZERO_SEND |
SET_NULL_IF_NO_MASK | CONVERT_RECEIVE);
+ }
+ case CBEN_DRAGBEGINW:
+ {
+ NMCBEDRAGBEGINW *nmdbW = (NMCBEDRAGBEGINW *)hdr;
+ NMCBEDRAGBEGINA nmdbA = {{0}};
+ nmdbA.hdr.code = PAGER_GetAnsiNtfCode(nmdbW->hdr.code);
+ nmdbA.hdr.hwndFrom = nmdbW->hdr.hwndFrom;
+ nmdbA.hdr.idFrom = nmdbW->hdr.idFrom;
+ nmdbA.iItemid = nmdbW->iItemid;
+ WideCharToMultiByte(CP_ACP, 0, nmdbW->szText, ARRAY_SIZE(nmdbW->szText),
nmdbA.szText, ARRAY_SIZE(nmdbA.szText),
+ NULL, FALSE);
+ return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom,
(LPARAM)&nmdbA);
+ }
+ case CBEN_ENDEDITW:
+ {
+ NMCBEENDEDITW *nmedW = (NMCBEENDEDITW *)hdr;
+ NMCBEENDEDITA nmedA = {{0}};
+ nmedA.hdr.code = PAGER_GetAnsiNtfCode(nmedW->hdr.code);
+ nmedA.hdr.hwndFrom = nmedW->hdr.hwndFrom;
+ nmedA.hdr.idFrom = nmedW->hdr.idFrom;
+ nmedA.fChanged = nmedW->fChanged;
+ nmedA.iNewSelection = nmedW->iNewSelection;
+ nmedA.iWhy = nmedW->iWhy;
+ WideCharToMultiByte(CP_ACP, 0, nmedW->szText, ARRAY_SIZE(nmedW->szText),
nmedA.szText, ARRAY_SIZE(nmedA.szText),
+ NULL, FALSE);
+ return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom,
(LPARAM)&nmedA);
+ }
+ /* Date and Time Picker */
+ case DTN_FORMATW:
+ {
+ NMDATETIMEFORMATW *nmdtf = (NMDATETIMEFORMATW *)hdr;
+ WCHAR *oldFormat;
+ INT textLength;
+
+ hdr->code = PAGER_GetAnsiNtfCode(hdr->code);
+ oldFormat = PAGER_ConvertText((WCHAR **)&nmdtf->pszFormat);
+ ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom,
(LPARAM)nmdtf);
+ PAGER_RestoreText((WCHAR **)&nmdtf->pszFormat, oldFormat);
+
+ if (nmdtf->pszDisplay)
+ {
+ textLength = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmdtf->pszDisplay, -1,
0, 0);
+ if (!PAGER_AdjustBuffer(infoPtr, textLength * sizeof(WCHAR))) return ret;
+ MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmdtf->pszDisplay, -1,
infoPtr->pwszBuffer, textLength);
+ if (nmdtf->pszDisplay != nmdtf->szDisplay)
+ nmdtf->pszDisplay = infoPtr->pwszBuffer;
+ else
+ {
+ textLength = min(textLength, ARRAY_SIZE(nmdtf->szDisplay));
+ memcpy(nmdtf->szDisplay, infoPtr->pwszBuffer, textLength *
sizeof(WCHAR));
+ }
+ }
+
+ return ret;
+ }
+ case DTN_FORMATQUERYW:
+ {
+ NMDATETIMEFORMATQUERYW *nmdtfq = (NMDATETIMEFORMATQUERYW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, (WCHAR
**)&nmdtfq->pszFormat, NULL, CONVERT_SEND);
+ }
+ case DTN_WMKEYDOWNW:
+ {
+ NMDATETIMEWMKEYDOWNW *nmdtkd = (NMDATETIMEWMKEYDOWNW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, (WCHAR
**)&nmdtkd->pszFormat, NULL, CONVERT_SEND);
+ }
+ case DTN_USERSTRINGW:
+ {
+ NMDATETIMESTRINGW *nmdts = (NMDATETIMESTRINGW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, (WCHAR
**)&nmdts->pszUserString, NULL, CONVERT_SEND);
+ }
+ /* Header */
+ case HDN_BEGINTRACKW:
+ case HDN_DIVIDERDBLCLICKW:
+ case HDN_ENDTRACKW:
+ case HDN_ITEMCHANGEDW:
+ case HDN_ITEMCHANGINGW:
+ case HDN_ITEMCLICKW:
+ case HDN_ITEMDBLCLICKW:
+ case HDN_TRACKW:
+ {
+ NMHEADERW *nmh = (NMHEADERW *)hdr;
+ WCHAR *oldText = NULL, *oldFilterText = NULL;
+ HD_TEXTFILTERW *tf = NULL;
+
+ hdr->code = PAGER_GetAnsiNtfCode(hdr->code);
+
+ if (!nmh->pitem) return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY,
hdr->idFrom, (LPARAM)hdr);
+ if (nmh->pitem->mask & HDI_TEXT) oldText =
PAGER_ConvertText(&nmh->pitem->pszText);
+ if ((nmh->pitem->mask & HDI_FILTER) && (nmh->pitem->type
== HDFT_ISSTRING) && nmh->pitem->pvFilter)
+ {
+ tf = (HD_TEXTFILTERW *)nmh->pitem->pvFilter;
+ oldFilterText = PAGER_ConvertText(&tf->pszText);
+ }
+ ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom,
(LPARAM)hdr);
+ PAGER_RestoreText(&nmh->pitem->pszText, oldText);
+ if (tf) PAGER_RestoreText(&tf->pszText, oldFilterText);
+ return ret;
+ }
+ case HDN_GETDISPINFOW:
+ {
+ NMHDDISPINFOW *nmhddi = (NMHDDISPINFOW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, &nmhddi->mask, HDI_TEXT,
&nmhddi->pszText, &nmhddi->cchTextMax,
+ SEND_EMPTY_IF_NULL | CONVERT_SEND |
CONVERT_RECEIVE);
+ }
+ /* List View */
+ case LVN_BEGINLABELEDITW:
+ case LVN_ENDLABELEDITW:
+ case LVN_SETDISPINFOW:
+ {
+ NMLVDISPINFOW *nmlvdi = (NMLVDISPINFOW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, &nmlvdi->item.mask,
LVIF_TEXT, &nmlvdi->item.pszText,
+ &nmlvdi->item.cchTextMax,
SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE);
+ }
+ case LVN_GETDISPINFOW:
+ {
+ NMLVDISPINFOW *nmlvdi = (NMLVDISPINFOW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, &nmlvdi->item.mask,
LVIF_TEXT, &nmlvdi->item.pszText,
+ &nmlvdi->item.cchTextMax,
CONVERT_RECEIVE);
+ }
+ case LVN_GETINFOTIPW:
+ {
+ NMLVGETINFOTIPW *nmlvgit = (NMLVGETINFOTIPW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, &nmlvgit->pszText,
&nmlvgit->cchTextMax,
+ CONVERT_SEND | CONVERT_RECEIVE);
+ }
+ case LVN_INCREMENTALSEARCHW:
+ case LVN_ODFINDITEMW:
+ {
+ NMLVFINDITEMW *nmlvfi = (NMLVFINDITEMW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, &nmlvfi->lvfi.flags,
LVFI_STRING | LVFI_SUBSTRING,
+ (WCHAR **)&nmlvfi->lvfi.psz, NULL,
CONVERT_SEND);
+ }
+ /* Toolbar */
+ case TBN_GETBUTTONINFOW:
+ {
+ NMTOOLBARW *nmtb = (NMTOOLBARW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, &nmtb->pszText,
&nmtb->cchText,
+ SEND_EMPTY_IF_NULL | CONVERT_SEND |
CONVERT_RECEIVE);
+ }
+ case TBN_GETINFOTIPW:
+ {
+ NMTBGETINFOTIPW *nmtbgit = (NMTBGETINFOTIPW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, &nmtbgit->pszText,
&nmtbgit->cchTextMax, CONVERT_RECEIVE);
+ }
+ /* Tooltip */
+ case TTN_GETDISPINFOW:
+ {
+ NMTTDISPINFOW *nmttdiW = (NMTTDISPINFOW *)hdr;
+ NMTTDISPINFOA nmttdiA = {{0}};
+ INT size;
+
+ nmttdiA.hdr.code = PAGER_GetAnsiNtfCode(nmttdiW->hdr.code);
+ nmttdiA.hdr.hwndFrom = nmttdiW->hdr.hwndFrom;
+ nmttdiA.hdr.idFrom = nmttdiW->hdr.idFrom;
+ nmttdiA.hinst = nmttdiW->hinst;
+ nmttdiA.uFlags = nmttdiW->uFlags;
+ nmttdiA.lParam = nmttdiW->lParam;
+ nmttdiA.lpszText = nmttdiA.szText;
+ WideCharToMultiByte(CP_ACP, 0, nmttdiW->szText,
ARRAY_SIZE(nmttdiW->szText), nmttdiA.szText,
+ ARRAY_SIZE(nmttdiA.szText), NULL, FALSE);
+
+ ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom,
(LPARAM)&nmttdiA);
+
+ nmttdiW->hinst = nmttdiA.hinst;
+ nmttdiW->uFlags = nmttdiA.uFlags;
+ nmttdiW->lParam = nmttdiA.lParam;
+
+ MultiByteToWideChar(CP_ACP, 0, nmttdiA.szText, ARRAY_SIZE(nmttdiA.szText),
nmttdiW->szText,
+ ARRAY_SIZE(nmttdiW->szText));
+ if (!nmttdiA.lpszText)
+ nmttdiW->lpszText = nmttdiW->szText;
+ else if (!IS_INTRESOURCE(nmttdiA.lpszText))
+ {
+ size = MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, 0, 0);
+ if (size > ARRAY_SIZE(nmttdiW->szText))
+ {
+ if (!PAGER_AdjustBuffer(infoPtr, size * sizeof(WCHAR))) return ret;
+ MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1,
infoPtr->pwszBuffer, size);
+ nmttdiW->lpszText = infoPtr->pwszBuffer;
+ /* Override content in szText */
+ memcpy(nmttdiW->szText, nmttdiW->lpszText,
min(sizeof(nmttdiW->szText), size * sizeof(WCHAR)));
+ }
+ else
+ {
+ MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, nmttdiW->szText,
ARRAY_SIZE(nmttdiW->szText));
+ nmttdiW->lpszText = nmttdiW->szText;
+ }
+ }
+ else
+ {
+ nmttdiW->szText[0] = 0;
+ nmttdiW->lpszText = (WCHAR *)nmttdiA.lpszText;
+ }
+
+ return ret;
+ }
+ /* Tree View */
+ case TVN_BEGINDRAGW:
+ case TVN_BEGINRDRAGW:
+ case TVN_ITEMEXPANDEDW:
+ case TVN_ITEMEXPANDINGW:
+ {
+ NMTREEVIEWW *nmtv = (NMTREEVIEWW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, &nmtv->itemNew.mask,
TVIF_TEXT, &nmtv->itemNew.pszText, NULL,
+ CONVERT_SEND);
+ }
+ case TVN_DELETEITEMW:
+ {
+ NMTREEVIEWW *nmtv = (NMTREEVIEWW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, &nmtv->itemOld.mask,
TVIF_TEXT, &nmtv->itemOld.pszText, NULL,
+ CONVERT_SEND);
+ }
+ case TVN_BEGINLABELEDITW:
+ case TVN_ENDLABELEDITW:
+ {
+ NMTVDISPINFOW *nmtvdi = (NMTVDISPINFOW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, &nmtvdi->item.mask,
TVIF_TEXT, &nmtvdi->item.pszText,
+ &nmtvdi->item.cchTextMax,
SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE);
+ }
+ case TVN_SELCHANGINGW:
+ case TVN_SELCHANGEDW:
+ {
+ NMTREEVIEWW *nmtv = (NMTREEVIEWW *)hdr;
+ WCHAR *oldItemOldText = NULL;
+ WCHAR *oldItemNewText = NULL;
+
+ hdr->code = PAGER_GetAnsiNtfCode(hdr->code);
+
+ if (!((nmtv->itemNew.mask | nmtv->itemOld.mask) & TVIF_TEXT))
+ return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom,
(LPARAM)hdr);
+
+ if (nmtv->itemOld.mask & TVIF_TEXT) oldItemOldText =
PAGER_ConvertText(&nmtv->itemOld.pszText);
+ if (nmtv->itemNew.mask & TVIF_TEXT) oldItemNewText =
PAGER_ConvertText(&nmtv->itemNew.pszText);
+
+ ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom,
(LPARAM)hdr);
+ PAGER_RestoreText(&nmtv->itemOld.pszText, oldItemOldText);
+ PAGER_RestoreText(&nmtv->itemNew.pszText, oldItemNewText);
+ return ret;
+ }
+ case TVN_GETDISPINFOW:
+ {
+ NMTVDISPINFOW *nmtvdi = (NMTVDISPINFOW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, &nmtvdi->item.mask,
TVIF_TEXT, &nmtvdi->item.pszText,
+ &nmtvdi->item.cchTextMax, ZERO_SEND |
CONVERT_RECEIVE);
+ }
+ case TVN_SETDISPINFOW:
+ {
+ NMTVDISPINFOW *nmtvdi = (NMTVDISPINFOW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, &nmtvdi->item.mask,
TVIF_TEXT, &nmtvdi->item.pszText,
+ &nmtvdi->item.cchTextMax,
SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE);
+ }
+ case TVN_GETINFOTIPW:
+ {
+ NMTVGETINFOTIPW *nmtvgit = (NMTVGETINFOTIPW *)hdr;
+ return PAGER_SendConvertedNotify(infoPtr, hdr, NULL, 0, &nmtvgit->pszText,
&nmtvgit->cchTextMax, CONVERT_RECEIVE);
+ }
+ }
+ /* Other notifications, no need to convert */
+ return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
+}
+
static LRESULT WINAPI
PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
@@ -1089,7 +1544,12 @@ PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
lParam)
case WM_TIMER:
return PAGER_Timer (infoPtr, (INT)wParam);
+ case WM_NOTIFYFORMAT:
+ return PAGER_NotifyFormat (infoPtr, lParam);
+
case WM_NOTIFY:
+ return PAGER_Notify (infoPtr, (NMHDR *)lParam);
+
case WM_COMMAND:
return SendMessageW (infoPtr->hwndNotify, uMsg, wParam, lParam);
diff --git a/dll/win32/comctl32/propsheet.c b/dll/win32/comctl32/propsheet.c
index fa348c249f5..9600e81482a 100644
--- a/dll/win32/comctl32/propsheet.c
+++ b/dll/win32/comctl32/propsheet.c
@@ -65,7 +65,6 @@
#include "uxtheme.h"
#include "wine/debug.h"
-#include "wine/unicode.h"
/******************************************************************************
* Data structures
@@ -177,9 +176,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(propsheet);
static WCHAR *heap_strdupW(const WCHAR *str)
{
- int len = strlenW(str) + 1;
+ int len = lstrlenW(str) + 1;
WCHAR *ret = Alloc(len * sizeof(WCHAR));
- strcpyW(ret, str);
+ lstrcpyW(ret, str);
return ret;
}
@@ -2021,6 +2020,13 @@ static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
if (!psInfo->proppage[index].hwndPage) {
if(!PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage)) {
PROPSHEET_RemovePage(hwndDlg, index, NULL);
+
+ if (!psInfo->isModeless)
+ {
+ DestroyWindow(hwndDlg);
+ return FALSE;
+ }
+
if(index >= psInfo->nPages)
index--;
if(index < 0)
@@ -2150,8 +2156,8 @@ static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR
lpszText)
if (dwStyle & PSH_PROPTITLE)
{
WCHAR* dest;
- int lentitle = strlenW(lpszText);
- int lenprop = strlenW(psInfo->strPropertiesFor);
+ int lentitle = lstrlenW(lpszText);
+ int lenprop = lstrlenW(psInfo->strPropertiesFor);
dest = Alloc( (lentitle + lenprop + 1)*sizeof (WCHAR));
wsprintfW(dest, psInfo->strPropertiesFor, lpszText);
@@ -2793,8 +2799,8 @@ static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg);
static INT do_loop(const PropSheetInfo *psInfo)
{
- MSG msg;
- INT ret = -1;
+ MSG msg = { 0 };
+ INT ret = 0;
HWND hwnd = psInfo->hwnd;
HWND parent = psInfo->ppshheader.hwndParent;
@@ -2814,11 +2820,8 @@ static INT do_loop(const PropSheetInfo *psInfo)
}
}
- if(ret == 0)
- {
+ if(ret == 0 && msg.message)
PostQuitMessage(msg.wParam);
- ret = -1;
- }
if(ret != -1)
ret = psInfo->result;
@@ -2974,7 +2977,7 @@ static LPWSTR load_string( HINSTANCE instance, LPCWSTR str )
}
else
{
- int len = (strlenW(str) + 1) * sizeof(WCHAR);
+ int len = (lstrlenW(str) + 1) * sizeof(WCHAR);
ret = Alloc( len );
if (ret) memcpy( ret, str, len );
}
diff --git a/dll/win32/comctl32/rebar.c b/dll/win32/comctl32/rebar.c
index 19019d7a547..818ae9948f3 100644
--- a/dll/win32/comctl32/rebar.c
+++ b/dll/win32/comctl32/rebar.c
@@ -84,7 +84,6 @@
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
-#include "wine/unicode.h"
#include "winuser.h"
#include "winnls.h"
#include "commctrl.h"
@@ -280,6 +279,9 @@ static const char * const band_stylename[] = {
"RBBS_VARIABLEHEIGHT", /* 0040 */
"RBBS_GRIPPERALWAYS", /* 0080 */
"RBBS_NOGRIPPER", /* 0100 */
+ "RBBS_USECHEVRON", /* 0200 */
+ "RBBS_HIDETITLE", /* 0400 */
+ "RBBS_TOPALIGN", /* 0800 */
NULL };
static const char * const band_maskname[] = {
@@ -295,50 +297,52 @@ static const char * const band_maskname[] = {
"RBBIM_IDEALSIZE", /* 0x00000200 */
"RBBIM_LPARAM", /* 0x00000400 */
"RBBIM_HEADERSIZE", /* 0x00000800 */
+ "RBBIM_CHEVRONLOCATION", /* 0x00001000 */
+ "RBBIM_CHEVRONSTATE", /* 0x00002000 */
NULL };
-static CHAR line[200];
-
static const WCHAR themeClass[] = {
'R','e','b','a','r',0 };
static CHAR *
-REBAR_FmtStyle( UINT style)
+REBAR_FmtStyle(char *buffer, UINT style)
{
INT i = 0;
- *line = 0;
+ *buffer = 0;
while (band_stylename[i]) {
if (style & (1<<i)) {
- if (*line != 0) strcat(line, " | ");
- strcat(line, band_stylename[i]);
+ if (*buffer) strcat(buffer, " | ");
+ strcat(buffer, band_stylename[i]);
}
i++;
}
- return line;
+ return buffer;
}
static CHAR *
-REBAR_FmtMask( UINT mask)
+REBAR_FmtMask(char *buffer, UINT mask)
{
INT i = 0;
- *line = 0;
+ *buffer = 0;
while (band_maskname[i]) {
if (mask & (1<<i)) {
- if (*line != 0) strcat(line, " | ");
- strcat(line, band_maskname[i]);
+ if (*buffer) strcat(buffer, " | ");
+ strcat(buffer, band_maskname[i]);
}
i++;
}
- return line;
+ return buffer;
}
static VOID
REBAR_DumpBandInfo(const REBARBANDINFOW *pB)
{
+ char buff[300];
+
if( !TRACE_ON(rebar) ) return;
TRACE("band info: ");
if (pB->fMask & RBBIM_ID)
@@ -348,9 +352,9 @@ REBAR_DumpBandInfo(const REBARBANDINFOW *pB)
TRACE(", clrF=0x%06x, clrB=0x%06x", pB->clrFore, pB->clrBack);
TRACE("\n");
- TRACE("band info: mask=0x%08x (%s)\n", pB->fMask,
REBAR_FmtMask(pB->fMask));
+ TRACE("band info: mask=0x%08x (%s)\n", pB->fMask, REBAR_FmtMask(buff,
pB->fMask));
if (pB->fMask & RBBIM_STYLE)
- TRACE("band info: style=0x%08x (%s)\n", pB->fStyle,
REBAR_FmtStyle(pB->fStyle));
+ TRACE("band info: style=0x%08x (%s)\n", pB->fStyle, REBAR_FmtStyle(buff,
pB->fStyle));
if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_HEADERSIZE |
RBBIM_LPARAM )) {
TRACE("band info:");
if (pB->fMask & RBBIM_SIZE)
@@ -372,6 +376,7 @@ REBAR_DumpBandInfo(const REBARBANDINFOW *pB)
static VOID
REBAR_DumpBand (const REBAR_INFO *iP)
{
+ char buff[300];
REBAR_BAND *pB;
UINT i;
@@ -397,10 +402,9 @@ REBAR_DumpBand (const REBAR_INFO *iP)
if (pB->fMask & RBBIM_COLORS)
TRACE(" clrF=0x%06x clrB=0x%06x", pB->clrFore, pB->clrBack);
TRACE("\n");
- TRACE("band # %u: mask=0x%08x (%s)\n", i, pB->fMask,
REBAR_FmtMask(pB->fMask));
+ TRACE("band # %u: mask=0x%08x (%s)\n", i, pB->fMask, REBAR_FmtMask(buff,
pB->fMask));
if (pB->fMask & RBBIM_STYLE)
- TRACE("band # %u: style=0x%08x (%s)\n",
- i, pB->fStyle, REBAR_FmtStyle(pB->fStyle));
+ TRACE("band # %u: style=0x%08x (%s)\n", i, pB->fStyle,
REBAR_FmtStyle(buff, pB->fStyle));
TRACE("band # %u: xHeader=%u",
i, pB->cxHeader);
if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_LPARAM )) {
@@ -1306,8 +1310,8 @@ static int REBAR_SetBandsHeight(const REBAR_INFO *infoPtr, INT
iBeginBand, INT i
REBAR_BAND *lpBand;
int yMaxHeight = 0;
int yPos = yStart;
- int row = REBAR_GetBand(infoPtr, iBeginBand)->iRow;
- int i;
+ int row, i;
+
for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
{
lpBand = REBAR_GetBand(infoPtr, i);
@@ -1316,6 +1320,8 @@ static int REBAR_SetBandsHeight(const REBAR_INFO *infoPtr, INT
iBeginBand, INT i
}
TRACE("Bands [%d; %d) height: %d\n", iBeginBand, iEndBand, yMaxHeight);
+ row = iBeginBand < iEndBand ? REBAR_GetBand(infoPtr, iBeginBand)->iRow : 0;
+
for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
{
lpBand = REBAR_GetBand(infoPtr, i);
@@ -2154,7 +2160,7 @@ REBAR_HandleUDDrag (REBAR_INFO *infoPtr, const POINT *ptsmove)
}
else
{
- /* Place the band in the prexisting row the mouse is hovering over */
+ /* Place the band in the preexisting row the mouse is hovering over */
iRowBegin = first_visible(infoPtr);
while(iRowBegin < infoPtr->uNumBands)
{
diff --git a/dll/win32/comctl32/static.c b/dll/win32/comctl32/static.c
index 1d2e39f84ee..c81db5d445a 100644
--- a/dll/win32/comctl32/static.c
+++ b/dll/win32/comctl32/static.c
@@ -18,11 +18,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* Notes:
- * - Windows XP introduced new behavior: The background of centered
- * icons and bitmaps is painted differently. This is only done if
- * a manifest is present.
- * Because it has not yet been decided how to implement the two
- * different modes in Wine, only the Windows XP mode is implemented.
* - Controls with SS_SIMPLE but without SS_NOPREFIX:
* The text should not be changed. Windows doesn't clear the
* client rectangle, so the new text must be larger than the old one.
@@ -730,7 +725,6 @@ static void STATIC_PaintBitmapfn(HWND hwnd, HDC hdc, DWORD style )
HBITMAP hBitmap, oldbitmap;
HBRUSH hbrush;
- /* message is still sent, even if the returned brush is not used */
hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
if ((hBitmap = (HBITMAP)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET ))
diff --git a/dll/win32/comctl32/status.c b/dll/win32/comctl32/status.c
index 34a299eb744..879b281840f 100644
--- a/dll/win32/comctl32/status.c
+++ b/dll/win32/comctl32/status.c
@@ -36,7 +36,6 @@
#include "windef.h"
#include "winbase.h"
-#include "wine/unicode.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
@@ -504,10 +503,10 @@ STATUSBAR_GetTextW (STATUS_INFO *infoPtr, INT nPart, LPWSTR buf)
if (part->style & SBT_OWNERDRAW)
result = (LRESULT)part->text;
else {
- result = part->text ? strlenW (part->text) : 0;
+ result = part->text ? lstrlenW (part->text) : 0;
result |= (part->style << 16);
if (part->text && buf)
- strcpyW (buf, part->text);
+ lstrcpyW (buf, part->text);
}
return result;
}
@@ -530,7 +529,7 @@ STATUSBAR_GetTextLength (STATUS_INFO *infoPtr, INT nPart)
part = &infoPtr->parts[nPart];
if ((~part->style & SBT_OWNERDRAW) && part->text)
- result = strlenW(part->text);
+ result = lstrlenW(part->text);
else
result = 0;
@@ -754,16 +753,16 @@ STATUSBAR_SetTextT (STATUS_INFO *infoPtr, INT nPart, WORD style,
if (!ntext) return FALSE;
MultiByteToWideChar( CP_ACP, 0, atxt, -1, ntext, len );
} else if (text) {
- ntext = Alloc( (strlenW(text) + 1)*sizeof(WCHAR) );
+ ntext = Alloc( (lstrlenW(text) + 1)*sizeof(WCHAR) );
if (!ntext) return FALSE;
- strcpyW (ntext, text);
+ lstrcpyW (ntext, text);
} else ntext = 0;
/* replace nonprintable characters with spaces */
if (ntext) {
idx = ntext;
while (*idx) {
- if(!isprintW(*idx))
+ if(!iswprint(*idx))
*idx = ' ';
idx++;
}
@@ -944,11 +943,11 @@ STATUSBAR_WMCreate (HWND hwnd, const CREATESTRUCTA *lpCreate)
OpenThemeData (hwnd, themeClass);
- if (lpCreate->lpszName && (len = strlenW
((LPCWSTR)lpCreate->lpszName)))
+ if (lpCreate->lpszName && (len = lstrlenW
((LPCWSTR)lpCreate->lpszName)))
{
infoPtr->parts[0].text = Alloc ((len + 1)*sizeof(WCHAR));
if (!infoPtr->parts[0].text) goto create_fail;
- strcpyW (infoPtr->parts[0].text, (LPCWSTR)lpCreate->lpszName);
+ lstrcpyW (infoPtr->parts[0].text, (LPCWSTR)lpCreate->lpszName);
}
dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
@@ -997,12 +996,12 @@ STATUSBAR_WMGetText (const STATUS_INFO *infoPtr, INT size, LPWSTR
buf)
if (!(infoPtr->parts[0].text))
return 0;
- len = strlenW (infoPtr->parts[0].text);
+ len = lstrlenW (infoPtr->parts[0].text);
if (!size)
return len;
else if (size > len) {
- strcpyW (buf, infoPtr->parts[0].text);
+ lstrcpyW (buf, infoPtr->parts[0].text);
return len;
}
else {
@@ -1083,10 +1082,10 @@ STATUSBAR_WMSetText (const STATUS_INFO *infoPtr, LPCSTR text)
Free (part->text);
part->text = 0;
- if (text && (len = strlenW((LPCWSTR)text))) {
+ if (text && (len = lstrlenW((LPCWSTR)text))) {
part->text = Alloc ((len+1)*sizeof(WCHAR));
if (!part->text) return FALSE;
- strcpyW (part->text, (LPCWSTR)text);
+ lstrcpyW (part->text, (LPCWSTR)text);
}
InvalidateRect(infoPtr->Self, &part->bound, FALSE);
diff --git a/dll/win32/comctl32/string.c b/dll/win32/comctl32/string.c
index 112d9d37b43..d5bc6d3577f 100644
--- a/dll/win32/comctl32/string.c
+++ b/dll/win32/comctl32/string.c
@@ -22,9 +22,6 @@
*
*/
-#include "config.h"
-#include "wine/port.h"
-
#include <stdarg.h>
#include <string.h>
#include <stdlib.h> /* atoi */
@@ -36,7 +33,6 @@
#include "comctl32.h"
-#include "wine/unicode.h"
#include "wine/debug.h"
@@ -208,7 +204,7 @@ INT WINAPI Str_GetPtrW (LPCWSTR lpSrc, LPWSTR lpDest, INT nMaxLen)
TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen);
if (!lpDest && lpSrc)
- return strlenW (lpSrc);
+ return lstrlenW (lpSrc);
if (nMaxLen == 0)
return 0;
@@ -218,7 +214,7 @@ INT WINAPI Str_GetPtrW (LPCWSTR lpSrc, LPWSTR lpDest, INT nMaxLen)
return 0;
}
- len = strlenW (lpSrc);
+ len = lstrlenW (lpSrc);
if (len >= nMaxLen)
len = nMaxLen - 1;
@@ -238,11 +234,11 @@ BOOL WINAPI Str_SetPtrW (LPWSTR *lppDest, LPCWSTR lpSrc)
TRACE("(%p %s)\n", lppDest, debugstr_w(lpSrc));
if (lpSrc) {
- INT len = strlenW (lpSrc) + 1;
+ INT len = lstrlenW (lpSrc) + 1;
LPWSTR ptr = ReAlloc (*lppDest, len * sizeof(WCHAR));
if (!ptr)
return FALSE;
- strcpyW (ptr, lpSrc);
+ lstrcpyW (ptr, lpSrc);
*lppDest = ptr;
}
else {
@@ -391,8 +387,8 @@ LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
if (!lpszStr || !lpszSearch || !*lpszSearch)
return NULL;
- iLen = strlenW(lpszSearch);
- end = lpszStr + strlenW(lpszStr);
+ iLen = lstrlenW(lpszSearch);
+ end = lpszStr + lstrlenW(lpszStr);
while (lpszStr + iLen <= end)
{
@@ -410,7 +406,7 @@ LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
*/
INT WINAPI StrToIntW (LPCWSTR lpString)
{
- return atoiW(lpString);
+ return wcstol(lpString, NULL, 10);
}
/*************************************************************************
@@ -472,7 +468,7 @@ LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
if (lpszStr)
- lpszRet = strchrW(lpszStr, ch);
+ lpszRet = wcschr(lpszStr, ch);
return lpszRet;
}
@@ -558,7 +554,7 @@ LPWSTR WINAPI StrRChrW(LPCWSTR str, LPCWSTR end, WORD ch)
WCHAR *ret = NULL;
if (!str) return NULL;
- if (!end) end = str + strlenW(str);
+ if (!end) end = str + lstrlenW(str);
while (str < end)
{
if (*str == ch) ret = (WCHAR *)str;
@@ -594,7 +590,7 @@ LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
{
if (!lpszStr || !lpszSearch) return NULL;
- return strstrW( lpszStr, lpszSearch );
+ return wcsstr( lpszStr, lpszSearch );
}
/*************************************************************************
@@ -638,10 +634,10 @@ LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
if (lpszStr)
{
- ch = toupperW(ch);
+ ch = towupper(ch);
while (*lpszStr)
{
- if (toupperW(*lpszStr) == ch)
+ if (towupper(*lpszStr) == ch)
return (LPWSTR)lpszStr;
lpszStr++;
}
@@ -713,10 +709,10 @@ LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR
lpszSearch)
if (!lpszStr || !lpszSearch || !*lpszSearch)
return NULL;
- iLen = strlenW(lpszSearch);
+ iLen = lstrlenW(lpszSearch);
if (!lpszEnd)
- lpszEnd = lpszStr + strlenW(lpszStr);
+ lpszEnd = lpszStr + lstrlenW(lpszStr);
else /* reproduce the broken behaviour on Windows */
lpszEnd += min(iLen - 1, lstrlenW(lpszEnd));
@@ -826,7 +822,7 @@ LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch)
WCHAR *ret = NULL;
if (!str) return NULL;
- if (!end) end = str + strlenW(str);
+ if (!end) end = str + lstrlenW(str);
while (str < end)
{
if (!COMCTL32_ChrCmpIW(*str, ch)) ret = (WCHAR *)str;
@@ -843,7 +839,7 @@ LPWSTR WINAPI StrRChrIW(LPCWSTR str, LPCWSTR end, WORD ch)
int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
{
if (!lpszStr || !lpszMatch) return 0;
- return strcspnW( lpszStr, lpszMatch );
+ return wcscspn( lpszStr, lpszMatch );
}
/*************************************************************************
diff --git a/dll/win32/comctl32/syslink.c b/dll/win32/comctl32/syslink.c
index 91796a32e44..a00ef9e4a3a 100644
--- a/dll/win32/comctl32/syslink.c
+++ b/dll/win32/comctl32/syslink.c
@@ -27,7 +27,6 @@
#include "winnls.h"
#include "commctrl.h"
#include "comctl32.h"
-#include "wine/unicode.h"
#include "wine/debug.h"
#include "wine/list.h"
@@ -124,7 +123,7 @@ static PDOC_ITEM SYSLINK_AppendDocItem (SYSLINK_INFO *infoPtr, LPCWSTR
Text, UIN
{
PDOC_ITEM Item;
- textlen = min(textlen, strlenW(Text));
+ textlen = min(textlen, lstrlenW(Text));
Item = Alloc(FIELD_OFFSET(DOC_ITEM, Text[textlen + 1]));
if(Item == NULL)
{
@@ -183,7 +182,7 @@ static UINT SYSLINK_ParseText (SYSLINK_INFO *infoPtr, LPCWSTR Text)
{
if(*current == '<')
{
- if(!strncmpiW(current, SL_LINKOPEN, ARRAY_SIZE(SL_LINKOPEN)) &&
(CurrentType == slText))
+ if(!wcsnicmp(current, SL_LINKOPEN, ARRAY_SIZE(SL_LINKOPEN)) &&
(CurrentType == slText))
{
BOOL ValidParam = FALSE, ValidLink = FALSE;
@@ -211,14 +210,14 @@ static UINT SYSLINK_ParseText (SYSLINK_INFO *infoPtr, LPCWSTR Text)
CheckParameter:
/* compare the current position with all known parameters */
- if(!strncmpiW(tmp, SL_HREF, ARRAY_SIZE(SL_HREF)))
+ if(!wcsnicmp(tmp, SL_HREF, ARRAY_SIZE(SL_HREF)))
{
taglen += 6;
ValidParam = TRUE;
CurrentParameter = &lpUrl;
CurrentParameterLen = &lenUrl;
}
- else if(!strncmpiW(tmp, SL_ID, ARRAY_SIZE(SL_ID)))
+ else if(!wcsnicmp(tmp, SL_ID, ARRAY_SIZE(SL_ID)))
{
taglen += 4;
ValidParam = TRUE;
@@ -292,7 +291,7 @@ CheckParameter:
}
}
}
- else if(!strncmpiW(current, SL_LINKCLOSE, ARRAY_SIZE(SL_LINKCLOSE))
&& (CurrentType == slLink) && firsttag)
+ else if(!wcsnicmp(current, SL_LINKCLOSE, ARRAY_SIZE(SL_LINKCLOSE)) &&
(CurrentType == slLink) && firsttag)
{
/* there's a <a...> tag opened, first add the previous text, if
present */
if(textstart != NULL && textlen > 0 && firsttag >
textstart)
@@ -330,7 +329,7 @@ CheckParameter:
/* Copy the tag parameters */
if(lpID != NULL)
{
- nc = min(lenId, strlenW(lpID));
+ nc = min(lenId, lstrlenW(lpID));
nc = min(nc, MAX_LINKID_TEXT - 1);
Last->u.Link.szID = Alloc((nc + 1) * sizeof(WCHAR));
if(Last->u.Link.szID != NULL)
@@ -342,7 +341,7 @@ CheckParameter:
Last->u.Link.szID = NULL;
if(lpUrl != NULL)
{
- nc = min(lenUrl, strlenW(lpUrl));
+ nc = min(lenUrl, lstrlenW(lpUrl));
nc = min(nc, L_MAX_URL_LENGTH - 1);
Last->u.Link.szUrl = Alloc((nc + 1) * sizeof(WCHAR));
if(Last->u.Link.szUrl != NULL)
@@ -408,7 +407,7 @@ CheckParameter:
/* Copy the tag parameters */
if(lpID != NULL)
{
- nc = min(lenId, strlenW(lpID));
+ nc = min(lenId, lstrlenW(lpID));
nc = min(nc, MAX_LINKID_TEXT - 1);
Last->u.Link.szID = Alloc((nc + 1) * sizeof(WCHAR));
if(Last->u.Link.szID != NULL)
@@ -420,7 +419,7 @@ CheckParameter:
Last->u.Link.szID = NULL;
if(lpUrl != NULL)
{
- nc = min(lenUrl, strlenW(lpUrl));
+ nc = min(lenUrl, lstrlenW(lpUrl));
nc = min(nc, L_MAX_URL_LENGTH - 1);
Last->u.Link.szUrl = Alloc((nc + 1) * sizeof(WCHAR));
if(Last->u.Link.szUrl != NULL)
@@ -566,12 +565,12 @@ static BOOL SYSLINK_WrapLine (LPWSTR Text, WCHAR BreakChar, int x,
int *LineLen,
{
int i;
- for (i = 0; i < nFit; i++) if (Text[i] == '\n') break;
+ for (i = 0; i < nFit; i++) if (Text[i] == '\r' || Text[i] == '\n')
break;
if (i == *LineLen) return FALSE;
/* check if we're in the middle of a word */
- if (Text[i] != '\n' && Text[i] != BreakChar)
+ if (Text[i] != '\r' && Text[i] != '\n' && Text[i] !=
BreakChar)
{
/* search for the beginning of the word */
while (i && Text[i - 1] != BreakChar) i--;
@@ -654,6 +653,12 @@ static VOID SYSLINK_Render (const SYSLINK_INFO *infoPtr, HDC hdc,
PRECT pRect)
/* skip break characters unless they're the first of the doc item */
if(tx != Current->Text || x == SL_LEFTMARGIN)
{
+ if (n && *tx == '\r')
+ {
+ tx++;
+ SkipChars++;
+ n--;
+ }
if (n && *tx == '\n')
{
tx++;
@@ -954,7 +959,7 @@ static LRESULT SYSLINK_SetText (SYSLINK_INFO *infoPtr, LPCWSTR Text)
/***********************************************************************
* SYSLINK_SetFocusLink
- * Updates the focus status bits and focusses the specified link.
+ * Updates the focus status bits and focuses the specified link.
* If no document item is specified, the focus bit will be removed from all links.
* Returns the previous focused item.
*/
diff --git a/dll/win32/comctl32/taskdialog.c b/dll/win32/comctl32/taskdialog.c
index 1ab9e133dac..3d98c644e84 100644
--- a/dll/win32/comctl32/taskdialog.c
+++ b/dll/win32/comctl32/taskdialog.c
@@ -2,6 +2,7 @@
* Task dialog control
*
* Copyright 2017 Fabian Maurer
+ * Copyright 2018 Zhiyi Zhang
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -34,286 +35,962 @@
#include "comctl32.h"
#include "wine/debug.h"
-#include "wine/list.h"
-#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(taskdialog);
-#define ALIGNED_LENGTH(_Len, _Align) (((_Len)+(_Align))&~(_Align))
-#define ALIGNED_POINTER(_Ptr, _Align) ((LPVOID)ALIGNED_LENGTH((ULONG_PTR)(_Ptr),
_Align))
-#define ALIGN_LENGTH(_Len, _Align) _Len = ALIGNED_LENGTH(_Len, _Align)
-#define ALIGN_POINTER(_Ptr, _Align) _Ptr = ALIGNED_POINTER(_Ptr, _Align)
-
static const UINT DIALOG_MIN_WIDTH = 240;
static const UINT DIALOG_SPACING = 5;
static const UINT DIALOG_BUTTON_WIDTH = 50;
static const UINT DIALOG_BUTTON_HEIGHT = 14;
+static const UINT DIALOG_EXPANDO_ICON_WIDTH = 10;
+static const UINT DIALOG_EXPANDO_ICON_HEIGHT = 10;
+static const UINT DIALOG_TIMER_MS = 200;
-static const UINT ID_MAIN_INSTRUCTION = 0xf000;
-static const UINT ID_CONTENT = 0xf001;
+static const UINT ID_TIMER = 1;
-struct taskdialog_control
+struct taskdialog_info
{
- struct list entry;
- DLGITEMTEMPLATE *template;
- unsigned int template_size;
+ HWND hwnd;
+ const TASKDIALOGCONFIG *taskconfig;
+ DWORD last_timer_tick;
+ HFONT font;
+ HFONT main_instruction_font;
+ /* Control handles */
+ HWND main_icon;
+ HWND main_instruction;
+ HWND content;
+ HWND progress_bar;
+ HWND *radio_buttons;
+ INT radio_button_count;
+ HWND *command_links;
+ INT command_link_count;
+ HWND expanded_info;
+ HWND expando_button;
+ HWND verification_box;
+ HWND footer_icon;
+ HWND footer_text;
+ HWND *buttons;
+ INT button_count;
+ HWND default_button;
+ /* Dialog metrics */
+ struct
+ {
+ LONG x_baseunit;
+ LONG y_baseunit;
+ LONG h_spacing;
+ LONG v_spacing;
+ } m;
+ INT selected_radio_id;
+ BOOL verification_checked;
+ BOOL expanded;
+ BOOL has_cancel;
+ WCHAR *expanded_text;
+ WCHAR *collapsed_text;
};
-struct taskdialog_button_desc
+struct button_layout_info
{
- int id;
- const WCHAR *text;
- unsigned int width;
- unsigned int line;
- HINSTANCE hinst;
+ LONG width;
+ LONG line;
};
-struct taskdialog_template_desc
+static HRESULT taskdialog_notify(struct taskdialog_info *dialog_info, UINT notification,
WPARAM wparam, LPARAM lparam);
+static void taskdialog_on_button_click(struct taskdialog_info *dialog_info, HWND hwnd,
WORD id);
+static void taskdialog_layout(struct taskdialog_info *dialog_info);
+
+static void taskdialog_du_to_px(struct taskdialog_info *dialog_info, LONG *width, LONG
*height)
{
- const TASKDIALOGCONFIG *taskconfig;
- unsigned int dialog_height;
- unsigned int dialog_width;
- struct list controls;
- WORD control_count;
- LONG x_baseunit;
- LONG y_baseunit;
- HFONT font;
- struct taskdialog_button_desc *default_button;
-};
+ if (width) *width = MulDiv(*width, dialog_info->m.x_baseunit, 4);
+ if (height) *height = MulDiv(*height, dialog_info->m.y_baseunit, 8);
+}
-struct taskdialog_info
+static void template_write_data(char **ptr, const void *src, unsigned int size)
{
- HWND hwnd;
- PFTASKDIALOGCALLBACK callback;
- LONG_PTR callback_data;
-};
+ memcpy(*ptr, src, size);
+ *ptr += size;
+}
-static void pixels_to_dialogunits(const struct taskdialog_template_desc *desc, LONG
*width, LONG *height)
+static unsigned int taskdialog_get_reference_rect(const TASKDIALOGCONFIG *taskconfig,
RECT *ret)
{
- if (width)
- *width = MulDiv(*width, 4, desc->x_baseunit);
- if (height)
- *height = MulDiv(*height, 8, desc->y_baseunit);
+ HMONITOR monitor = MonitorFromWindow(taskconfig->hwndParent ?
taskconfig->hwndParent : GetActiveWindow(),
+ MONITOR_DEFAULTTOPRIMARY);
+ MONITORINFO info;
+
+ info.cbSize = sizeof(info);
+ GetMonitorInfoW(monitor, &info);
+
+ if ((taskconfig->dwFlags & TDF_POSITION_RELATIVE_TO_WINDOW) &&
taskconfig->hwndParent)
+ GetWindowRect(taskconfig->hwndParent, ret);
+ else
+ *ret = info.rcWork;
+
+ return info.rcWork.right - info.rcWork.left;
}
-static void dialogunits_to_pixels(const struct taskdialog_template_desc *desc, LONG
*width, LONG *height)
+static WCHAR *taskdialog_get_exe_name(WCHAR *name, DWORD length)
{
- if (width)
- *width = MulDiv(*width, desc->x_baseunit, 4);
- if (height)
- *height = MulDiv(*height, desc->y_baseunit, 8);
+ DWORD len = GetModuleFileNameW(NULL, name, length);
+ if (len && len < length)
+ {
+ WCHAR *p;
+ if ((p = wcsrchr(name, '/'))) name = p + 1;
+ if ((p = wcsrchr(name, '\\'))) name = p + 1;
+ return name;
+ }
+ else
+ return NULL;
}
-static void template_write_data(char **ptr, const void *src, unsigned int size)
+static DLGTEMPLATE *create_taskdialog_template(const TASKDIALOGCONFIG *taskconfig)
{
- memcpy(*ptr, src, size);
- *ptr += size;
+ unsigned int size, title_size;
+ static const WORD fontsize = 0x7fff;
+ static const WCHAR emptyW[] = { 0 };
+ const WCHAR *titleW = NULL;
+ DLGTEMPLATE *template;
+ WCHAR pathW[MAX_PATH];
+ char *ptr;
+
+ /* Window title */
+ if (!taskconfig->pszWindowTitle)
+ titleW = taskdialog_get_exe_name(pathW, ARRAY_SIZE(pathW));
+ else if (IS_INTRESOURCE(taskconfig->pszWindowTitle))
+ {
+ if (!LoadStringW(taskconfig->hInstance, LOWORD(taskconfig->pszWindowTitle),
(WCHAR *)&titleW, 0))
+ titleW = taskdialog_get_exe_name(pathW, ARRAY_SIZE(pathW));
+ }
+ else
+ titleW = taskconfig->pszWindowTitle;
+ if (!titleW)
+ titleW = emptyW;
+ title_size = (lstrlenW(titleW) + 1) * sizeof(WCHAR);
+
+ size = sizeof(DLGTEMPLATE) + 2 * sizeof(WORD);
+ size += title_size;
+ size += 2; /* font size */
+
+ template = Alloc(size);
+ if (!template) return NULL;
+
+ template->style = DS_MODALFRAME | DS_SETFONT | WS_CAPTION | WS_VISIBLE |
WS_SYSMENU;
+ if (taskconfig->dwFlags & TDF_CAN_BE_MINIMIZED) template->style |=
WS_MINIMIZEBOX;
+ if (!(taskconfig->dwFlags & TDF_NO_SET_FOREGROUND)) template->style |=
DS_SETFOREGROUND;
+ if (taskconfig->dwFlags & TDF_RTL_LAYOUT) template->dwExtendedStyle =
WS_EX_LAYOUTRTL | WS_EX_RIGHT | WS_EX_RTLREADING;
+
+ ptr = (char *)(template + 1);
+ ptr += 2; /* menu */
+ ptr += 2; /* class */
+ template_write_data(&ptr, titleW, title_size);
+ template_write_data(&ptr, &fontsize, sizeof(fontsize));
+
+ return template;
}
-/* used to calculate size for the controls */
-static void taskdialog_get_text_extent(const struct taskdialog_template_desc *desc, const
WCHAR *text,
- BOOL user_resource, SIZE *sz)
+static HWND taskdialog_find_button(HWND *buttons, INT count, INT id)
+{
+ INT button_id;
+ INT i;
+
+ for (i = 0; i < count; i++)
+ {
+ button_id = GetWindowLongW(buttons[i], GWLP_ID);
+ if (button_id == id) return buttons[i];
+ }
+
+ return NULL;
+}
+
+static void taskdialog_enable_button(const struct taskdialog_info *dialog_info, INT id,
BOOL enable)
+{
+ HWND hwnd = taskdialog_find_button(dialog_info->command_links,
dialog_info->command_link_count, id);
+ if (!hwnd) hwnd = taskdialog_find_button(dialog_info->buttons,
dialog_info->button_count, id);
+ if (hwnd) EnableWindow(hwnd, enable);
+}
+
+static void taskdialog_click_button(struct taskdialog_info *dialog_info, INT id)
+{
+ if (taskdialog_notify(dialog_info, TDN_BUTTON_CLICKED, id, 0) == S_OK)
EndDialog(dialog_info->hwnd, id);
+}
+
+static void taskdialog_button_set_shield(const struct taskdialog_info *dialog_info, INT
id, BOOL elevate)
+{
+ HWND hwnd = taskdialog_find_button(dialog_info->command_links,
dialog_info->command_link_count, id);
+ if (!hwnd) hwnd = taskdialog_find_button(dialog_info->buttons,
dialog_info->button_count, id);
+ if (hwnd) SendMessageW(hwnd, BCM_SETSHIELD, 0, elevate);
+}
+
+static void taskdialog_enable_radio_button(const struct taskdialog_info *dialog_info, INT
id, BOOL enable)
+{
+ HWND hwnd = taskdialog_find_button(dialog_info->radio_buttons,
dialog_info->radio_button_count, id);
+ if (hwnd) EnableWindow(hwnd, enable);
+}
+
+static void taskdialog_click_radio_button(const struct taskdialog_info *dialog_info, INT
id)
+{
+ HWND hwnd = taskdialog_find_button(dialog_info->radio_buttons,
dialog_info->radio_button_count, id);
+ if (hwnd) SendMessageW(hwnd, BM_CLICK, 0, 0);
+}
+
+static HRESULT taskdialog_notify(struct taskdialog_info *dialog_info, UINT notification,
WPARAM wparam, LPARAM lparam)
+{
+ const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+ return taskconfig->pfCallback
+ ? taskconfig->pfCallback(dialog_info->hwnd, notification, wparam,
lparam, taskconfig->lpCallbackData)
+ : S_OK;
+}
+
+static void taskdialog_move_controls_vertically(HWND parent, HWND *controls, INT count,
INT offset)
+{
+ RECT rect;
+ POINT pt;
+ INT i;
+
+ for (i = 0; i < count; i++)
+ {
+ if (!controls[i]) continue;
+
+ GetWindowRect(controls[i], &rect);
+ pt.x = rect.left;
+ pt.y = rect.top;
+ MapWindowPoints(HWND_DESKTOP, parent, &pt, 1);
+ SetWindowPos(controls[i], 0, pt.x, pt.y + offset, 0, 0, SWP_NOSIZE |
SWP_NOZORDER);
+ }
+}
+
+static void taskdialog_toggle_expando_control(struct taskdialog_info *dialog_info)
+{
+ const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+ const WCHAR *text;
+ RECT info_rect, rect;
+ INT height, offset;
+
+ dialog_info->expanded = !dialog_info->expanded;
+ text = dialog_info->expanded ? dialog_info->expanded_text :
dialog_info->collapsed_text;
+ SendMessageW(dialog_info->expando_button, WM_SETTEXT, 0, (LPARAM)text);
+ ShowWindow(dialog_info->expanded_info, dialog_info->expanded ? SW_SHOWDEFAULT :
SW_HIDE);
+
+ GetWindowRect(dialog_info->expanded_info, &info_rect);
+ /* If expanded information starts up not expanded, call taskdialog_layout()
+ * to to set size for expanded information control at least once */
+ if (IsRectEmpty(&info_rect))
+ {
+ taskdialog_layout(dialog_info);
+ return;
+ }
+ height = info_rect.bottom - info_rect.top + dialog_info->m.v_spacing;
+ offset = dialog_info->expanded ? height : -height;
+
+ /* Update vertical layout, move all controls after expanded information */
+ /* Move dialog */
+ GetWindowRect(dialog_info->hwnd, &rect);
+ SetWindowPos(dialog_info->hwnd, 0, 0, 0, rect.right - rect.left, rect.bottom -
rect.top + offset,
+ SWP_NOMOVE | SWP_NOZORDER);
+ /* Move controls */
+ if (!(taskconfig->dwFlags & TDF_EXPAND_FOOTER_AREA))
+ {
+ taskdialog_move_controls_vertically(dialog_info->hwnd,
&dialog_info->progress_bar, 1, offset);
+ taskdialog_move_controls_vertically(dialog_info->hwnd,
&dialog_info->expando_button, 1, offset);
+ taskdialog_move_controls_vertically(dialog_info->hwnd,
&dialog_info->verification_box, 1, offset);
+ taskdialog_move_controls_vertically(dialog_info->hwnd,
&dialog_info->footer_icon, 1, offset);
+ taskdialog_move_controls_vertically(dialog_info->hwnd,
&dialog_info->footer_text, 1, offset);
+ taskdialog_move_controls_vertically(dialog_info->hwnd,
dialog_info->buttons, dialog_info->button_count, offset);
+ taskdialog_move_controls_vertically(dialog_info->hwnd,
dialog_info->radio_buttons,
+ dialog_info->radio_button_count, offset);
+ taskdialog_move_controls_vertically(dialog_info->hwnd,
dialog_info->command_links,
+ dialog_info->command_link_count, offset);
+ }
+}
+
+static void taskdialog_on_button_click(struct taskdialog_info *dialog_info, HWND hwnd,
WORD id)
+{
+ INT command_id;
+ HWND button, radio_button;
+
+ /* Prefer the id from hwnd because the id from WM_COMMAND is truncated to WORD */
+ command_id = hwnd ? GetWindowLongW(hwnd, GWLP_ID) : id;
+
+ if (hwnd && hwnd == dialog_info->expando_button)
+ {
+ taskdialog_toggle_expando_control(dialog_info);
+ taskdialog_notify(dialog_info, TDN_EXPANDO_BUTTON_CLICKED,
dialog_info->expanded, 0);
+ return;
+ }
+
+ if (hwnd && hwnd == dialog_info->verification_box)
+ {
+ dialog_info->verification_checked = !dialog_info->verification_checked;
+ taskdialog_notify(dialog_info, TDN_VERIFICATION_CLICKED,
dialog_info->verification_checked, 0);
+ return;
+ }
+
+ radio_button = taskdialog_find_button(dialog_info->radio_buttons,
dialog_info->radio_button_count, command_id);
+ if (radio_button)
+ {
+ dialog_info->selected_radio_id = command_id;
+ taskdialog_notify(dialog_info, TDN_RADIO_BUTTON_CLICKED, command_id, 0);
+ return;
+ }
+
+ button = taskdialog_find_button(dialog_info->command_links,
dialog_info->command_link_count, command_id);
+ if (!button) button = taskdialog_find_button(dialog_info->buttons,
dialog_info->button_count, command_id);
+ if (!button && command_id == IDOK)
+ {
+ button = dialog_info->command_link_count > 0 ?
dialog_info->command_links[0] : dialog_info->buttons[0];
+ command_id = GetWindowLongW(button, GWLP_ID);
+ }
+
+ if (button && taskdialog_notify(dialog_info, TDN_BUTTON_CLICKED, command_id,
0) == S_OK)
+ EndDialog(dialog_info->hwnd, command_id);
+}
+
+static WCHAR *taskdialog_gettext(struct taskdialog_info *dialog_info, BOOL user_resource,
const WCHAR *text)
{
- RECT rect = { 0, 0, desc->dialog_width - DIALOG_SPACING * 2, 0}; /* padding left
and right of the control */
const WCHAR *textW = NULL;
- static const WCHAR nulW;
- unsigned int length;
- HFONT oldfont;
- HDC hdc;
+ INT length;
+ WCHAR *ret;
if (IS_INTRESOURCE(text))
{
- if (!(length = LoadStringW(user_resource ? desc->taskconfig->hInstance :
COMCTL32_hModule,
- (UINT_PTR)text, (WCHAR *)&textW, 0)))
- {
- WARN("Failed to load text\n");
- textW = &nulW;
- length = 0;
- }
+ if (!(length = LoadStringW(user_resource ?
dialog_info->taskconfig->hInstance : COMCTL32_hModule,
+ (UINT_PTR)text, (WCHAR *)&textW, 0)))
+ return NULL;
}
else
{
textW = text;
- length = strlenW(textW);
+ length = lstrlenW(textW);
}
- hdc = GetDC(0);
- oldfont = SelectObject(hdc, desc->font);
+ ret = Alloc((length + 1) * sizeof(WCHAR));
+ if (ret) memcpy(ret, textW, length * sizeof(WCHAR));
- dialogunits_to_pixels(desc, &rect.right, NULL);
- DrawTextW(hdc, textW, length, &rect, DT_LEFT | DT_EXPANDTABS | DT_CALCRECT |
DT_WORDBREAK);
- pixels_to_dialogunits(desc, &rect.right, &rect.bottom);
+ return ret;
+}
- SelectObject(hdc, oldfont);
- ReleaseDC(0, hdc);
+static BOOL taskdialog_hyperlink_enabled(struct taskdialog_info *dialog_info)
+{
+ return dialog_info->taskconfig->dwFlags & TDF_ENABLE_HYPERLINKS;
+}
- sz->cx = rect.right - rect.left;
- sz->cy = rect.bottom - rect.top;
+static BOOL taskdialog_use_command_link(struct taskdialog_info *dialog_info)
+{
+ return dialog_info->taskconfig->dwFlags & (TDF_USE_COMMAND_LINKS |
TDF_USE_COMMAND_LINKS_NO_ICON);
}
-static unsigned int taskdialog_add_control(struct taskdialog_template_desc *desc, WORD
id, const WCHAR *class,
- HINSTANCE hInstance, const WCHAR *text, DWORD style, short x, short y, short cx,
short cy)
+static void taskdialog_get_label_size(struct taskdialog_info *dialog_info, HWND hwnd,
LONG max_width, SIZE *size,
+ BOOL syslink)
{
- struct taskdialog_control *control = Alloc(sizeof(*control));
- unsigned int size, class_size, text_size;
- DLGITEMTEMPLATE *template;
- static const WCHAR nulW;
- const WCHAR *textW;
- char *ptr;
+ DWORD style = DT_EXPANDTABS | DT_CALCRECT | DT_WORDBREAK;
+ HFONT hfont, old_hfont;
+ HDC hdc;
+ RECT rect = {0};
+ WCHAR *text;
+ INT text_length;
- class_size = (strlenW(class) + 1) * sizeof(WCHAR);
+ if (syslink)
+ {
+ SendMessageW(hwnd, LM_GETIDEALSIZE, max_width, (LPARAM)size);
+ return;
+ }
- if (IS_INTRESOURCE(text))
- text_size = LoadStringW(hInstance, (UINT_PTR)text, (WCHAR *)&textW, 0) *
sizeof(WCHAR);
+ if (dialog_info->taskconfig->dwFlags & TDF_RTL_LAYOUT)
+ style |= DT_RIGHT | DT_RTLREADING;
else
+ style |= DT_LEFT;
+
+ hfont = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0);
+ text_length = GetWindowTextLengthW(hwnd);
+ text = Alloc((text_length + 1) * sizeof(WCHAR));
+ if (!text)
{
- textW = text;
- text_size = strlenW(textW) * sizeof(WCHAR);
+ size->cx = 0;
+ size->cy = 0;
+ return;
}
+ GetWindowTextW(hwnd, text, text_length + 1);
+ hdc = GetDC(hwnd);
+ old_hfont = SelectObject(hdc, hfont);
+ rect.right = max_width;
+ size->cy = DrawTextW(hdc, text, text_length, &rect, style);
+ size->cx = min(max_width, rect.right - rect.left);
+ if (old_hfont) SelectObject(hdc, old_hfont);
+ ReleaseDC(hwnd, hdc);
+ Free(text);
+}
- size = sizeof(DLGITEMTEMPLATE);
- size += class_size;
- size += text_size + sizeof(WCHAR);
- size += sizeof(WORD); /* creation data */
+static void taskdialog_get_button_size(HWND hwnd, LONG max_width, SIZE *size)
+{
+ size->cx = max_width;
+ size->cy = 0;
+ SendMessageW(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)size);
+}
- control->template = template = Alloc(size);
- control->template_size = size;
+static void taskdialog_get_expando_size(struct taskdialog_info *dialog_info, HWND hwnd,
SIZE *size)
+{
+ DWORD style = DT_EXPANDTABS | DT_CALCRECT | DT_WORDBREAK;
+ HFONT hfont, old_hfont;
+ HDC hdc;
+ RECT rect = {0};
+ LONG icon_width, icon_height, text_offset;
+ LONG max_width, max_text_height;
- template->style = WS_VISIBLE | style;
- template->dwExtendedStyle = 0;
- template->x = x;
- template->y = y;
- template->cx = cx;
- template->cy = cy;
- template->id = id;
- ptr = (char *)(template + 1);
- template_write_data(&ptr, class, class_size);
- template_write_data(&ptr, textW, text_size);
- template_write_data(&ptr, &nulW, sizeof(nulW));
+ hdc = GetDC(hwnd);
+ hfont = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0);
+ old_hfont = SelectObject(hdc, hfont);
+
+ icon_width = DIALOG_EXPANDO_ICON_WIDTH;
+ icon_height = DIALOG_EXPANDO_ICON_HEIGHT;
+ taskdialog_du_to_px(dialog_info, &icon_width, &icon_height);
+
+ GetCharWidthW(hdc, '0', '0', &text_offset);
+ text_offset /= 2;
+
+ if (dialog_info->taskconfig->dwFlags & TDF_RTL_LAYOUT)
+ style |= DT_RIGHT | DT_RTLREADING;
+ else
+ style |= DT_LEFT;
+
+ max_width = DIALOG_MIN_WIDTH / 2;
+ taskdialog_du_to_px(dialog_info, &max_width, NULL);
- list_add_tail(&desc->controls, &control->entry);
- desc->control_count++;
- return ALIGNED_LENGTH(size, 3);
+ rect.right = max_width - icon_width - text_offset;
+ max_text_height = DrawTextW(hdc, dialog_info->expanded_text, -1, &rect,
style);
+ size->cy = max(max_text_height, icon_height);
+ size->cx = rect.right - rect.left;
+
+ rect.right = max_width - icon_width - text_offset;
+ max_text_height = DrawTextW(hdc, dialog_info->collapsed_text, -1, &rect,
style);
+ size->cy = max(size->cy, max_text_height);
+ size->cx = max(size->cx, rect.right - rect.left);
+ size->cx = min(size->cx, max_width);
+
+ if (old_hfont) SelectObject(hdc, old_hfont);
+ ReleaseDC(hwnd, hdc);
}
-static unsigned int taskdialog_add_static_label(struct taskdialog_template_desc *desc,
WORD id, const WCHAR *str)
+static ULONG_PTR taskdialog_get_standard_icon(LPCWSTR icon)
{
- unsigned int size;
- SIZE sz;
+ if (icon == TD_WARNING_ICON)
+ return IDI_WARNING;
+ else if (icon == TD_ERROR_ICON)
+ return IDI_ERROR;
+ else if (icon == TD_INFORMATION_ICON)
+ return IDI_INFORMATION;
+ else if (icon == TD_SHIELD_ICON)
+ return IDI_SHIELD;
+ else
+ return (ULONG_PTR)icon;
+}
- if (!str)
- return 0;
+static void taskdialog_set_icon(struct taskdialog_info *dialog_info, INT element, HICON
icon)
+{
+ DWORD flags = dialog_info->taskconfig->dwFlags;
+ INT cx = 0, cy = 0;
+ HICON hicon;
- taskdialog_get_text_extent(desc, str, TRUE, &sz);
+ if (!icon) return;
- desc->dialog_height += DIALOG_SPACING;
- size = taskdialog_add_control(desc, id, WC_STATICW,
desc->taskconfig->hInstance, str, 0, DIALOG_SPACING,
- desc->dialog_height, sz.cx, sz.cy);
- desc->dialog_height += sz.cy + DIALOG_SPACING;
- return size;
+ if (((flags & TDF_USE_HICON_MAIN) && element == TDIE_ICON_MAIN)
+ || ((flags & TDF_USE_HICON_FOOTER) && element == TDIE_ICON_FOOTER))
+ hicon = icon;
+ else
+ {
+ if (element == TDIE_ICON_FOOTER)
+ {
+ cx = GetSystemMetrics(SM_CXSMICON);
+ cy = GetSystemMetrics(SM_CYSMICON);
+ }
+ hicon = LoadImageW(dialog_info->taskconfig->hInstance, (LPCWSTR)icon,
IMAGE_ICON, cx, cy, LR_SHARED | LR_DEFAULTSIZE);
+ if (!hicon)
+ hicon = LoadImageW(NULL,
(LPCWSTR)taskdialog_get_standard_icon((LPCWSTR)icon), IMAGE_ICON, cx, cy,
+ LR_SHARED | LR_DEFAULTSIZE);
+ }
+
+ if (!hicon) return;
+
+ if (element == TDIE_ICON_MAIN)
+ {
+ SendMessageW(dialog_info->hwnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hicon);
+ SendMessageW(dialog_info->main_icon, STM_SETICON, (WPARAM)hicon, 0);
+ }
+ else if (element == TDIE_ICON_FOOTER)
+ SendMessageW(dialog_info->footer_icon, STM_SETICON, (WPARAM)hicon, 0);
+}
+
+static void taskdialog_set_element_text(struct taskdialog_info *dialog_info,
TASKDIALOG_ELEMENTS element,
+ const WCHAR *text)
+{
+ HWND hwnd = NULL;
+ WCHAR *textW;
+
+ if (element == TDE_CONTENT)
+ hwnd = dialog_info->content;
+ else if (element == TDE_EXPANDED_INFORMATION)
+ hwnd = dialog_info->expanded_info;
+ else if (element == TDE_FOOTER)
+ hwnd = dialog_info->footer_text;
+ else if (element == TDE_MAIN_INSTRUCTION)
+ hwnd = dialog_info->main_instruction;
+
+ if (!hwnd) return;
+
+ textW = taskdialog_gettext(dialog_info, TRUE, text);
+ SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)textW);
+ Free(textW);
}
-static unsigned int taskdialog_add_main_instruction(struct taskdialog_template_desc
*desc)
+static void taskdialog_check_default_radio_buttons(struct taskdialog_info *dialog_info)
{
- return taskdialog_add_static_label(desc, ID_MAIN_INSTRUCTION,
desc->taskconfig->pszMainInstruction);
+ const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+ HWND default_button;
+
+ if (!dialog_info->radio_button_count) return;
+
+ default_button = taskdialog_find_button(dialog_info->radio_buttons,
dialog_info->radio_button_count,
+ taskconfig->nDefaultRadioButton);
+
+ if (!default_button && !(taskconfig->dwFlags &
TDF_NO_DEFAULT_RADIO_BUTTON))
+ default_button = dialog_info->radio_buttons[0];
+
+ if (default_button)
+ {
+ SendMessageW(default_button, BM_SETCHECK, BST_CHECKED, 0);
+ taskdialog_on_button_click(dialog_info, default_button, 0);
+ }
}
-static unsigned int taskdialog_add_content(struct taskdialog_template_desc *desc)
+static void taskdialog_add_main_icon(struct taskdialog_info *dialog_info)
{
- return taskdialog_add_static_label(desc, ID_CONTENT,
desc->taskconfig->pszContent);
+ if (!dialog_info->taskconfig->u.hMainIcon) return;
+
+ dialog_info->main_icon =
+ CreateWindowW(WC_STATICW, NULL, WS_CHILD | WS_VISIBLE | SS_ICON, 0, 0, 0, 0,
dialog_info->hwnd, NULL, 0, NULL);
+ taskdialog_set_icon(dialog_info, TDIE_ICON_MAIN,
dialog_info->taskconfig->u.hMainIcon);
}
-static void taskdialog_init_button(struct taskdialog_button_desc *button, struct
taskdialog_template_desc *desc,
- int id, const WCHAR *text, BOOL custom_button)
+static HWND taskdialog_create_label(struct taskdialog_info *dialog_info, const WCHAR
*text, HFONT font, BOOL syslink)
{
- SIZE sz;
+ WCHAR *textW;
+ HWND hwnd;
+ const WCHAR *class;
+ DWORD style = WS_CHILD | WS_VISIBLE;
- taskdialog_get_text_extent(desc, text, custom_button, &sz);
+ if (!text) return NULL;
- button->id = id;
- button->text = text;
- button->width = max(DIALOG_BUTTON_WIDTH, sz.cx + DIALOG_SPACING * 2);
- button->line = 0;
- button->hinst = custom_button ? desc->taskconfig->hInstance :
COMCTL32_hModule;
+ class = syslink ? WC_LINK : WC_STATICW;
+ if (syslink) style |= WS_TABSTOP;
+ textW = taskdialog_gettext(dialog_info, TRUE, text);
+ hwnd = CreateWindowW(class, textW, style, 0, 0, 0, 0, dialog_info->hwnd, NULL, 0,
NULL);
+ Free(textW);
- if (id == desc->taskconfig->nDefaultButton)
- desc->default_button = button;
+ SendMessageW(hwnd, WM_SETFONT, (WPARAM)font, 0);
+ return hwnd;
}
-static void taskdialog_init_common_buttons(struct taskdialog_template_desc *desc, struct
taskdialog_button_desc *buttons,
- unsigned int *button_count)
+static void taskdialog_add_main_instruction(struct taskdialog_info *dialog_info)
{
- DWORD flags = desc->taskconfig->dwCommonButtons;
+ const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+ NONCLIENTMETRICSW ncm;
-#define TASKDIALOG_INIT_COMMON_BUTTON(id) \
- do { \
- taskdialog_init_button(&buttons[(*button_count)++], desc, ID##id,
MAKEINTRESOURCEW(IDS_BUTTON_##id), FALSE); \
- } while(0)
+ if (!taskconfig->pszMainInstruction) return;
- if (flags & TDCBF_OK_BUTTON)
- TASKDIALOG_INIT_COMMON_BUTTON(OK);
- if (flags & TDCBF_YES_BUTTON)
- TASKDIALOG_INIT_COMMON_BUTTON(YES);
- if (flags & TDCBF_NO_BUTTON)
- TASKDIALOG_INIT_COMMON_BUTTON(NO);
- if (flags & TDCBF_RETRY_BUTTON)
- TASKDIALOG_INIT_COMMON_BUTTON(RETRY);
- if (flags & TDCBF_CANCEL_BUTTON)
- TASKDIALOG_INIT_COMMON_BUTTON(CANCEL);
- if (flags & TDCBF_CLOSE_BUTTON)
- TASKDIALOG_INIT_COMMON_BUTTON(CLOSE);
+ ncm.cbSize = sizeof(ncm);
+ SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
+ /* 1.25 times the height */
+ ncm.lfMessageFont.lfHeight = ncm.lfMessageFont.lfHeight * 5 / 4;
+ ncm.lfMessageFont.lfWeight = FW_BOLD;
+ dialog_info->main_instruction_font = CreateFontIndirectW(&ncm.lfMessageFont);
-#undef TASKDIALOG_INIT_COMMON_BUTTON
+ dialog_info->main_instruction =
+ taskdialog_create_label(dialog_info, taskconfig->pszMainInstruction,
dialog_info->main_instruction_font, FALSE);
}
-static unsigned int taskdialog_add_buttons(struct taskdialog_template_desc *desc)
+static void taskdialog_add_content(struct taskdialog_info *dialog_info)
{
- unsigned int count = 0, buttons_size, i, line_count, size = 0;
- unsigned int location_x, *line_widths, alignment = ~0u;
- const TASKDIALOGCONFIG *taskconfig = desc->taskconfig;
- struct taskdialog_button_desc *buttons;
+ dialog_info->content = taskdialog_create_label(dialog_info,
dialog_info->taskconfig->pszContent, dialog_info->font,
+
taskdialog_hyperlink_enabled(dialog_info));
+}
+
+static void taskdialog_add_progress_bar(struct taskdialog_info *dialog_info)
+{
+ const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+ DWORD style = PBS_SMOOTH | PBS_SMOOTHREVERSE | WS_CHILD | WS_VISIBLE;
+
+ if (!(taskconfig->dwFlags & (TDF_SHOW_PROGRESS_BAR |
TDF_SHOW_MARQUEE_PROGRESS_BAR))) return;
+ if (taskconfig->dwFlags & TDF_SHOW_MARQUEE_PROGRESS_BAR) style |=
PBS_MARQUEE;
+ dialog_info->progress_bar =
+ CreateWindowW(PROGRESS_CLASSW, NULL, style, 0, 0, 0, 0, dialog_info->hwnd,
NULL, 0, NULL);
+}
+
+static void taskdialog_add_radio_buttons(struct taskdialog_info *dialog_info)
+{
+ const TASKDIALOGCONFIG *taskconfig = dialog_info->taskconfig;
+ static const DWORD style = BS_AUTORADIOBUTTON | BS_MULTILINE | BS_TOP | WS_CHILD |
WS_VISIBLE | WS_TABSTOP;
+ WCHAR *textW;
+ INT i;
+
+ if (!taskconfig->cRadioButtons || !taskconfig->pRadioButtons) return;
+
+ dialog_info->radio_buttons = Alloc(taskconfig->cRadioButtons *
sizeof(*dialog_info->radio_buttons));
+ if (!dialog_info->radio_buttons) return;
+
+ dialog_info->radio_button_count = taskconfig->cRadioButtons;
+ for (i = 0; i < dialog_info->radio_button_count; i++)
+ {
+ textW = taskdialog_gettext(dialog_info, TRUE,
taskconfig->pRadioButtons[i].pszButtonText);
... 3486 lines suppressed ...