updated listbox control from wine 0.9.2 fixes 36 listbox tests Modified: trunk/reactos/lib/user32/controls/combo.c Modified: trunk/reactos/lib/user32/controls/listbox.c Modified: trunk/reactos/lib/user32/include/user32.h Modified: trunk/reactos/w32api/include/winuser.h _____
Modified: trunk/reactos/lib/user32/controls/combo.c --- trunk/reactos/lib/user32/controls/combo.c 2005-12-04 14:17:13 UTC (rev 19864) +++ trunk/reactos/lib/user32/controls/combo.c 2005-12-04 14:19:05 UTC (rev 19865) @@ -548,7 +548,7 @@
/* create listbox popup */
- lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS | WS_CHILD) | + lbeStyle = (LBS_NOTIFY | LBS_COMBOBOX | WS_BORDER | WS_CLIPSIBLINGS | WS_CHILD) | (style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
if( lphc->dwStyle & CBS_SORT ) _____
Modified: trunk/reactos/lib/user32/controls/listbox.c --- trunk/reactos/lib/user32/controls/listbox.c 2005-12-04 14:17:13 UTC (rev 19864) +++ trunk/reactos/lib/user32/controls/listbox.c 2005-12-04 14:19:05 UTC (rev 19865) @@ -34,7 +34,6 @@
#define WM_LBTRACKPOINT 0x0131 #define WS_EX_DRAGDETECT 0x00000002L #define WM_BEGINDRAG 0x022C -#define WM_SYSTIMER 280
UINT STDCALL SetSystemTimer(HWND,UINT_PTR,UINT,TIMERPROC); BOOL STDCALL KillSystemTimer(HWND,UINT_PTR); @@ -73,6 +72,7 @@ /* Listbox structure */ typedef struct { + HWND self; /* Our own window handle */ HWND owner; /* Owner window to send notifications to */ UINT style; /* Window style */ INT width; /* Window width */ @@ -90,6 +90,7 @@ INT horz_pos; /* Horizontal position */ INT nb_tabs; /* Number of tabs in array */ INT *tabs; /* Array of tabs */ + INT avg_char_width; /* Average width of characters */ BOOL caret_on; /* Is caret on? */ BOOL captured; /* Is mouse captured? */ BOOL in_focus; @@ -107,11 +108,12 @@
#define IS_MULTISELECT(descr) \ - ((descr)->style & LBS_MULTIPLESEL || ((descr)->style & LBS_EXTENDEDSEL)) + ((descr)->style & (LBS_MULTIPLESEL|LBS_EXTENDEDSEL) && \ + !((descr)->style & LBS_NOSEL))
-#define SEND_NOTIFICATION(hwnd,descr,code) \ +#define SEND_NOTIFICATION(descr,code) \ (SendMessageW( (descr)->owner, WM_COMMAND, \ - MAKEWPARAM( GetWindowLongA((hwnd),GWL_ID), (code)), (LPARAM)(hwnd) )) + MAKEWPARAM( GetWindowLongPtrW((descr->self),GWLP_ID), (code)), (LPARAM)(descr->self) ))
#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
@@ -127,8 +129,6 @@
static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
-static LRESULT WINAPI ComboLBWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ); -static LRESULT WINAPI ComboLBWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ); static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ); static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
@@ -167,16 +167,16 @@ #ifdef __REACTOS__ L"ComboLBox", /* name */ CS_DBLCLKS | CS_SAVEBITS, /* style */ - (WNDPROC)ComboLBWndProcW, /* procW */ - (WNDPROC)ComboLBWndProcA, /* procA */ + (WNDPROC)ListBoxWndProcW, /* procW */ + (WNDPROC)ListBoxWndProcA, /* procA */ sizeof(LB_DESCR *), /* extra */ (LPCWSTR) IDC_ARROW, /* cursor */ 0 /* brush */ #else "ComboLBox", /* name */ CS_DBLCLKS | CS_SAVEBITS, /* style */ - ComboLBWndProcA, /* procA */ - ComboLBWndProcW, /* procW */ + ListBoxWndProcA, /* procA */ + ListBoxWndProcW, /* procW */ sizeof(LB_DESCR *), /* extra */ IDC_ARROW, /* cursor */ 0 /* brush */ @@ -267,7 +267,7 @@ * Update the scrollbars. Should be called whenever the content * of the listbox changes. */ -static void LISTBOX_UpdateScroll( HWND hwnd, LB_DESCR *descr ) +static void LISTBOX_UpdateScroll( LB_DESCR *descr ) { SCROLLINFO info;
@@ -300,11 +300,11 @@ if (descr->style & LBS_DISABLENOSCROLL) info.fMask |= SIF_DISABLENOSCROLL; if (descr->style & WS_HSCROLL) - SetScrollInfo( hwnd, SB_HORZ, &info, TRUE ); + SetScrollInfo( descr->self, SB_HORZ, &info, TRUE ); info.nMax = 0; info.fMask = SIF_RANGE; if (descr->style & WS_VSCROLL) - SetScrollInfo( hwnd, SB_VERT, &info, TRUE ); + SetScrollInfo( descr->self, SB_VERT, &info, TRUE ); } else { @@ -316,7 +316,7 @@ if (descr->style & LBS_DISABLENOSCROLL) info.fMask |= SIF_DISABLENOSCROLL; if (descr->style & WS_VSCROLL) - SetScrollInfo( hwnd, SB_VERT, &info, TRUE ); + SetScrollInfo( descr->self, SB_VERT, &info, TRUE );
if (descr->horz_extent) { @@ -328,7 +328,7 @@ if (descr->style & LBS_DISABLENOSCROLL) info.fMask |= SIF_DISABLENOSCROLL; if (descr->style & WS_HSCROLL) - SetScrollInfo( hwnd, SB_HORZ, &info, TRUE ); + SetScrollInfo( descr->self, SB_HORZ, &info, TRUE ); } } } @@ -339,7 +339,7 @@ * * Set the top item of the listbox, scrolling up or down if necessary. */ -static LRESULT LISTBOX_SetTopItem( HWND hwnd, LB_DESCR *descr, INT index, +static LRESULT LISTBOX_SetTopItem( LB_DESCR *descr, INT index, BOOL scroll ) { INT max = LISTBOX_GetMaxTopIndex( descr ); @@ -351,7 +351,7 @@ { INT diff = (descr->top_item - index) / descr->page_size * descr->column_width; if (scroll && (abs(diff) < descr->width)) - ScrollWindowEx( hwnd, diff, 0, NULL, NULL, 0, NULL, + ScrollWindowEx( descr->self, diff, 0, NULL, NULL, 0, NULL, SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
else @@ -379,14 +379,14 @@ diff = (descr->top_item - index) * descr->item_height;
if (abs(diff) < descr->height) - ScrollWindowEx( hwnd, 0, diff, NULL, NULL, 0, NULL, + ScrollWindowEx( descr->self, 0, diff, NULL, NULL, 0, NULL, SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN ); else scroll = FALSE; } - if (!scroll) InvalidateRect( hwnd, NULL, TRUE ); + if (!scroll) InvalidateRect( descr->self, NULL, TRUE ); descr->top_item = index; - LISTBOX_UpdateScroll( hwnd, descr ); + LISTBOX_UpdateScroll( descr ); return LB_OKAY; }
@@ -397,7 +397,7 @@ * Update the page size. Should be called when the size of * the client area or the item height changes. */ -static void LISTBOX_UpdatePage( HWND hwnd, LB_DESCR *descr ) +static void LISTBOX_UpdatePage( LB_DESCR *descr ) { INT page_size;
@@ -406,8 +406,8 @@ if (page_size == descr->page_size) return; descr->page_size = page_size; if (descr->style & LBS_MULTICOLUMN) - InvalidateRect( hwnd, NULL, TRUE ); - LISTBOX_SetTopItem( hwnd, descr, descr->top_item, FALSE ); + InvalidateRect( descr->self, NULL, TRUE ); + LISTBOX_SetTopItem( descr, descr->top_item, FALSE ); }
@@ -417,11 +417,11 @@ * Update the size of the listbox. Should be called when the size of * the client area changes. */ -static void LISTBOX_UpdateSize( HWND hwnd, LB_DESCR *descr ) +static void LISTBOX_UpdateSize( LB_DESCR *descr ) { RECT rect;
- GetClientRect( hwnd, &rect ); + GetClientRect( descr->self, &rect ); descr->width = rect.right - rect.left; descr->height = rect.bottom - rect.top; if (!(descr->style & LBS_NOINTEGRALHEIGHT) && !(descr->style & LBS_OWNERDRAWVARIABLE)) @@ -429,7 +429,7 @@ INT remaining; RECT rect;
- GetWindowRect( hwnd, &rect ); + GetWindowRect( descr->self, &rect ); if(descr->item_height != 0) remaining = descr->height % descr->item_height; else @@ -447,21 +447,21 @@ } #endif TRACE("[%p]: changing height %d -> %d\n", - hwnd, descr->height, descr->height - remaining ); - SetWindowPos( hwnd, 0, 0, 0, rect.right - rect.left, + descr->self, descr->height, descr->height - remaining ); + SetWindowPos( descr->self, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top - remaining, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE ); return; } } - TRACE("[%p]: new size = %d,%d\n", hwnd, descr->width, descr->height ); - LISTBOX_UpdatePage( hwnd, descr ); - LISTBOX_UpdateScroll( hwnd, descr ); + TRACE("[%p]: new size = %d,%d\n", descr->self, descr->width, descr->height ); + LISTBOX_UpdatePage( descr ); + LISTBOX_UpdateScroll( descr );
/* Invalidate the focused item so it will be repainted correctly */ if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1) { - InvalidateRect( hwnd, &rect, FALSE ); + InvalidateRect( descr->self, &rect, FALSE ); } }
@@ -475,7 +475,12 @@ static LRESULT LISTBOX_GetItemRect( LB_DESCR *descr, INT index, RECT *rect ) { /* Index <= 0 is legal even on empty listboxes */ - if (index && (index >= descr->nb_items)) return -1; + if (index && (index >= descr->nb_items)) + { + memset(rect, 0, sizeof(*rect)); + SetLastError(ERROR_INVALID_INDEX); + return LB_ERR; + } SetRect( rect, 0, 0, descr->width, descr->height ); if (descr->style & LBS_MULTICOLUMN) { @@ -570,7 +575,7 @@ * * Paint an item. */ -static void LISTBOX_PaintItem( HWND hwnd, LB_DESCR *descr, HDC hdc, +static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT *rect, INT index, UINT action, BOOL ignoreFocus ) { LB_ITEMDATA *item = NULL; @@ -581,7 +586,6 @@ DRAWITEMSTRUCT dis; RECT r; HRGN hrgn; - UINT id = GetWindowLongA( hwnd, GWL_ID );
if (!item) { @@ -596,14 +600,14 @@ drawing the item, *and* restore the previous region after they are done, so a region has better to exist else everything ends clipped */ - GetClientRect(hwnd, &r); + GetClientRect(descr->self, &r); hrgn = CreateRectRgnIndirect(&r); SelectClipRgn( hdc, hrgn); DeleteObject( hrgn );
dis.CtlType = ODT_LISTBOX; - dis.CtlID = id; - dis.hwndItem = hwnd; + dis.CtlID = GetWindowLongPtrW( descr->self, GWLP_ID ); + dis.hwndItem = descr->self; dis.itemAction = action; dis.hDC = hdc; dis.itemID = index; @@ -612,13 +616,13 @@ if (!ignoreFocus && (descr->focus_item == index) && (descr->caret_on) && (descr->in_focus)) dis.itemState |= ODS_FOCUS; - if (!IsWindowEnabled(hwnd)) dis.itemState |= ODS_DISABLED; + if (!IsWindowEnabled(descr->self)) dis.itemState |= ODS_DISABLED; dis.itemData = item ? item->data : 0; dis.rcItem = *rect; TRACE("[%p]: drawitem %d (%s) action=%02x state=%02x rect=%ld,%ld-%ld,%ld\n", - hwnd, index, item ? debugstr_w(item->str) : "", action, + descr->self, index, item ? debugstr_w(item->str) : "", action, dis.itemState, rect->left, rect->top, rect->right, rect->bottom ); - SendMessageW(descr->owner, WM_DRAWITEM, id, (LPARAM)&dis); + SendMessageW(descr->owner, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis); } else { @@ -636,7 +640,7 @@ }
TRACE("[%p]: painting %d (%s) action=%02x rect=%ld,%ld-%ld,%ld\n", - hwnd, index, item ? debugstr_w(item->str) : "", action, + descr->self, index, item ? debugstr_w(item->str) : "", action, rect->left, rect->top, rect->right, rect->bottom ); if (!item) ExtTextOutW( hdc, rect->left + 1, rect->top, @@ -671,7 +675,7 @@ * * Change the redraw flag. */ -static void LISTBOX_SetRedraw( HWND hwnd, LB_DESCR *descr, BOOL on ) +static void LISTBOX_SetRedraw( LB_DESCR *descr, BOOL on ) { if (on) { @@ -679,7 +683,7 @@ descr->style &= ~LBS_NOREDRAW; if (descr->style & LBS_DISPLAYCHANGED) { /* page was changed while setredraw false, refresh automatically */ - InvalidateRect(hwnd, NULL, TRUE); + InvalidateRect(descr->self, NULL, TRUE); if ((descr->top_item + descr->page_size) > descr->nb_items) { /* reset top of page if less than number of items/page */ descr->top_item = descr->nb_items - descr->page_size; @@ -687,7 +691,7 @@ } descr->style &= ~LBS_DISPLAYCHANGED; } - LISTBOX_UpdateScroll( hwnd, descr ); + LISTBOX_UpdateScroll( descr ); } else descr->style |= LBS_NOREDRAW; } @@ -698,7 +702,7 @@ * * Repaint a single item synchronously. */ -static void LISTBOX_RepaintItem( HWND hwnd, LB_DESCR *descr, INT index, +static void LISTBOX_RepaintItem( LB_DESCR *descr, INT index, UINT action ) { HDC hdc; @@ -707,32 +711,32 @@ HBRUSH hbrush, oldBrush = 0;
/* Do not repaint the item if the item is not visible */ - if (!IsWindowVisible(hwnd)) return; + if (!IsWindowVisible(descr->self)) return; if (descr->style & LBS_NOREDRAW) { descr->style |= LBS_DISPLAYCHANGED; return; } if (LISTBOX_GetItemRect( descr, index, &rect ) != 1) return; - if (!(hdc = GetDCEx( hwnd, 0, DCX_CACHE ))) return; + if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE ))) return; if (descr->font) oldFont = SelectObject( hdc, descr->font ); hbrush = (HBRUSH)SendMessageW( descr->owner, WM_CTLCOLORLISTBOX, - (WPARAM)hdc, (LPARAM)hwnd ); + (WPARAM)hdc, (LPARAM)descr->self ); if (hbrush) oldBrush = SelectObject( hdc, hbrush ); - if (!IsWindowEnabled(hwnd)) + if (!IsWindowEnabled(descr->self)) SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) ); SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL ); - LISTBOX_PaintItem( hwnd, descr, hdc, &rect, index, action, FALSE ); + LISTBOX_PaintItem( descr, hdc, &rect, index, action, FALSE ); if (oldFont) SelectObject( hdc, oldFont ); if (oldBrush) SelectObject( hdc, oldBrush ); - ReleaseDC( hwnd, hdc ); + ReleaseDC( descr->self, hdc ); }
/*********************************************************************** * LISTBOX_InitStorage */ -static LRESULT LISTBOX_InitStorage( HWND hwnd, LB_DESCR *descr, INT nb_items ) +static LRESULT LISTBOX_InitStorage( LB_DESCR *descr, INT nb_items ) { LB_ITEMDATA *item;
@@ -750,7 +754,7 @@
if (!item) { - SEND_NOTIFICATION( hwnd, descr, LBN_ERRSPACE ); + SEND_NOTIFICATION( descr, LBN_ERRSPACE ); return LB_ERRSPACE; } descr->items = item; @@ -761,19 +765,25 @@
/*********************************************************************** * LISTBOX_SetTabStops */ -static BOOL LISTBOX_SetTabStops( HWND hwnd, LB_DESCR *descr, INT count, +static BOOL LISTBOX_SetTabStops( LB_DESCR *descr, INT count, LPINT tabs, BOOL short_ints ) { - if (!(descr->style & LBS_USETABSTOPS)) return TRUE; - if (descr->tabs) HeapFree( GetProcessHeap(), 0, descr->tabs ); + INT i; + + if (!(descr->style & LBS_USETABSTOPS)) + { + SetLastError(ERROR_LB_WITHOUT_TABSTOPS); + return FALSE; + } + + HeapFree( GetProcessHeap(), 0, descr->tabs ); if (!(descr->nb_tabs = count)) { descr->tabs = NULL; return TRUE; } - /* FIXME: count = 1 */ - if (!(descr->tabs = (INT *)HeapAlloc( GetProcessHeap(), 0, - descr->nb_tabs * sizeof(INT) ))) + if (!(descr->tabs = HeapAlloc( GetProcessHeap(), 0, + descr->nb_tabs * sizeof(INT) ))) return FALSE; #ifndef __REACTOS__ if (short_ints) @@ -792,7 +802,11 @@ #else memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) ); #endif - /* FIXME: repaint the window? */ + + /* convert into "dialog units"*/ + for (i = 0; i < descr->nb_tabs; i++) + descr->tabs[i] = MulDiv(descr->tabs[i], descr->avg_char_width, 4); + return TRUE; }
@@ -800,34 +814,53 @@
/*********************************************************************** * LISTBOX_GetText */ -static LRESULT LISTBOX_GetText( LB_DESCR *descr, INT index, LPARAM lParam, BOOL unicode ) +static LRESULT LISTBOX_GetText( LB_DESCR *descr, INT index, LPWSTR buffer, BOOL unicode ) { - if ((index < 0) || (index >= descr->nb_items)) return LB_ERR; + if ((index < 0) || (index >= descr->nb_items)) + { + SetLastError(ERROR_INVALID_INDEX); + return LB_ERR; + } if (HAS_STRINGS(descr)) { - if (!lParam) - return strlenW(descr->items[index].str); + if (!buffer) + { + DWORD len = strlenW(descr->items[index].str); + if( unicode ) + return len; + return WideCharToMultiByte( CP_ACP, 0, descr->items[index].str, len, + NULL, 0, NULL, NULL ); + }
TRACE("index %d (0x%04x) %s\n", index, index, debugstr_w(descr->items[index].str));
if(unicode) { - LPWSTR buffer = (LPWSTR)lParam; strcpyW( buffer, descr->items[index].str ); return strlenW(buffer); } else { - LPSTR buffer = (LPSTR)lParam; - return WideCharToMultiByte(CP_ACP, 0, descr->items[index].str, -1, buffer, 0x7FFFFFFF, NULL, NULL) - 1; + return WideCharToMultiByte(CP_ACP, 0, descr->items[index].str, -1, (LPSTR)buffer, 0x7FFFFFFF, NULL, NULL) - 1; } } else { - if (lParam) - *((LPDWORD)lParam)=*(LPDWORD)(&descr->items[index].data); + if (buffer) + *((LPDWORD)buffer)=*(LPDWORD)(&descr->items[index].data); return sizeof(DWORD); } }
+static inline INT LISTBOX_lstrcmpiW( LCID lcid, LPCWSTR str1, LPCWSTR str2 ) +{ + INT ret = CompareStringW( lcid, NORM_IGNORECASE, str1, -1, str2, -1 ); + if (ret == CSTR_LESS_THAN) + return -1; + if (ret == CSTR_EQUAL) + return 0; + if (ret == CSTR_GREATER_THAN) + return 1; + return -1; +}
/*********************************************************************** * LISTBOX_FindStringPos @@ -835,8 +868,7 @@ * Find the nearest string located before a given string in sort order. * If 'exact' is TRUE, return an error if we don't get an exact match. */ -static INT LISTBOX_FindStringPos( HWND hwnd, LB_DESCR *descr, LPCWSTR str, - BOOL exact ) +static INT LISTBOX_FindStringPos( LB_DESCR *descr, LPCWSTR str, BOOL exact ) { INT index, min, max, res = -1;
@@ -847,15 +879,15 @@ { index = (min + max) / 2; if (HAS_STRINGS(descr)) - res = lstrcmpiW( str, descr->items[index].str); + res = LISTBOX_lstrcmpiW( descr->locale, str, descr->items[index].str); else { COMPAREITEMSTRUCT cis; - UINT id = GetWindowLongA( hwnd, GWL_ID ); + UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
cis.CtlType = ODT_LISTBOX; cis.CtlID = id; - cis.hwndItem = hwnd; + cis.hwndItem = descr->self; /* note that some application (MetaStock) expects the second item * to be in the listbox */ cis.itemID1 = -1; @@ -872,19 +904,18 @@ return exact ? -1 : max; }
-
/*********************************************************************** * LISTBOX_FindFileStrPos * * Find the nearest string located before a given string in directory * sort order (i.e. first files, then directories, then drives). */ -static INT LISTBOX_FindFileStrPos( HWND hwnd, LB_DESCR *descr, LPCWSTR str ) +static INT LISTBOX_FindFileStrPos( LB_DESCR *descr, LPCWSTR str ) { INT min, max, res = -1;
if (!HAS_STRINGS(descr)) - return LISTBOX_FindStringPos( hwnd, descr, str, FALSE ); + return LISTBOX_FindStringPos( descr, str, FALSE ); min = 0; max = descr->nb_items; while (min != max) @@ -902,13 +933,13 @@ else /* directory */ { if (str[1] == '-') res = 1; - else res = lstrcmpiW( str, p ); + else res = LISTBOX_lstrcmpiW( descr->locale, str, p ); } } else /* filename */ { if (*str == '[') res = 1; - else res = lstrcmpiW( str, p ); + else res = LISTBOX_lstrcmpiW( descr->locale, str, p ); } if (!res) return index; if (res < 0) max = index; @@ -923,8 +954,7 @@ * * Find the item beginning with a given string. */ -static INT LISTBOX_FindString( HWND hwnd, LB_DESCR *descr, INT start, - LPCWSTR str, BOOL exact ) +static INT LISTBOX_FindString( LB_DESCR *descr, INT start, LPCWSTR str, BOOL exact ) { INT i; LB_ITEMDATA *item; @@ -937,9 +967,9 @@ if (exact) { for (i = start + 1; i < descr->nb_items; i++, item++) - if (!lstrcmpiW( str, item->str )) return i; + if (!LISTBOX_lstrcmpiW( descr->locale, str, item->str )) return i; for (i = 0, item = descr->items; i <= start; i++, item++) - if (!lstrcmpiW( str, item->str )) return i; + if (!LISTBOX_lstrcmpiW( descr->locale, str, item->str )) return i; } else { @@ -970,13 +1000,13 @@ { if (exact && (descr->style & LBS_SORT)) /* If sorted, use a WM_COMPAREITEM binary search */ - return LISTBOX_FindStringPos( hwnd, descr, str, TRUE ); + return LISTBOX_FindStringPos( descr, str, TRUE );
/* Otherwise use a linear search */ for (i = start + 1; i < descr->nb_items; i++, item++) - if (item->data == (DWORD)str) return i; + if (item->data == (ULONG_PTR)str) return i; for (i = 0, item = descr->items; i <= start; i++, item++) - if (item->data == (DWORD)str) return i; + if (item->data == (ULONG_PTR)str) return i; } return LB_ERR; } @@ -990,7 +1020,9 @@ INT i, count; LB_ITEMDATA *item = descr->items;
- if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR; + 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++; return count; @@ -1032,7 +1064,7 @@
/*********************************************************************** * LISTBOX_Paint */ -static LRESULT LISTBOX_Paint( HWND hwnd, LB_DESCR *descr, HDC hdc ) +static LRESULT LISTBOX_Paint( LB_DESCR *descr, HDC hdc ) { INT i, col_pos = descr->page_size - 1; RECT rect; @@ -1053,16 +1085,18 @@
if (descr->font) oldFont = SelectObject( hdc, descr->font ); hbrush = (HBRUSH)SendMessageW( descr->owner, WM_CTLCOLORLISTBOX, - (WPARAM)hdc, (LPARAM)hwnd ); + (WPARAM)hdc, (LPARAM)descr->self ); if (hbrush) oldBrush = SelectObject( hdc, hbrush ); - if (!IsWindowEnabled(hwnd)) SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) ); + if (!IsWindowEnabled(descr->self)) SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on && (descr->in_focus)) { /* Special case for empty listbox: paint focus rect */ rect.bottom = rect.top + descr->item_height; - LISTBOX_PaintItem( hwnd, descr, hdc, &rect, descr->focus_item, + ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED, + &rect, NULL, 0, NULL ); + LISTBOX_PaintItem( descr, hdc, &rect, descr->focus_item, ODA_FOCUS, FALSE ); rect.top = rect.bottom; } @@ -1085,7 +1119,7 @@ focusRect.top = rect.top; focusRect.bottom = rect.bottom; } - LISTBOX_PaintItem( hwnd, descr, hdc, &rect, i, ODA_DRAWENTIRE, TRUE ); + LISTBOX_PaintItem( descr, hdc, &rect, i, ODA_DRAWENTIRE, TRUE ); rect.top = rect.bottom;
if ((descr->style & LBS_MULTICOLUMN) && !col_pos) @@ -1115,8 +1149,9 @@ }
/* Paint the focus item now */ - if (focusRect.top != focusRect.bottom && descr->caret_on) - LISTBOX_PaintItem( hwnd, descr, hdc, &focusRect, descr->focus_item, ODA_FOCUS, FALSE ); + if (focusRect.top != focusRect.bottom && + descr->caret_on && descr->in_focus) + LISTBOX_PaintItem( descr, hdc, &focusRect, descr->focus_item, ODA_FOCUS, FALSE );
if (!IS_OWNERDRAW(descr)) { @@ -1149,7 +1184,7 @@ * Invalidate all items from a given item. If the specified item is not * visible, nothing happens. */ -static void LISTBOX_InvalidateItems( HWND hwnd, LB_DESCR *descr, INT index ) +static void LISTBOX_InvalidateItems( LB_DESCR *descr, INT index ) { RECT rect;
@@ -1161,24 +1196,24 @@ return; } rect.bottom = descr->height; - InvalidateRect( hwnd, &rect, TRUE ); + InvalidateRect( descr->self, &rect, TRUE ); if (descr->style & LBS_MULTICOLUMN) { /* Repaint the other columns */ rect.left = rect.right; rect.right = descr->width; rect.top = 0; - InvalidateRect( hwnd, &rect, TRUE ); + InvalidateRect( descr->self, &rect, TRUE ); } } }
-static void LISTBOX_InvalidateItemRect( HWND hwnd, LB_DESCR *descr, INT index ) +static void LISTBOX_InvalidateItemRect( LB_DESCR *descr, INT index ) { RECT rect;
if (LISTBOX_GetItemRect( descr, index, &rect ) == 1) - InvalidateRect( hwnd, &rect, TRUE ); + InvalidateRect( descr->self, &rect, TRUE ); }
/*********************************************************************** @@ -1188,7 +1223,11 @@ { if (descr->style & LBS_OWNERDRAWVARIABLE) { - if ((index < 0) || (index >= descr->nb_items)) return LB_ERR; + if ((index < 0) || (index >= descr->nb_items)) + { + SetLastError(ERROR_INVALID_INDEX); + return LB_ERR; + } return descr->items[index].height; } else return descr->item_height; @@ -1198,28 +1237,32 @@
/*********************************************************************** * LISTBOX_SetItemHeight */ -static LRESULT LISTBOX_SetItemHeight( HWND hwnd, LB_DESCR *descr, INT index, +static LRESULT LISTBOX_SetItemHeight( LB_DESCR *descr, INT index, INT height, BOOL repaint ) { if (!height) height = 1;
if (descr->style & LBS_OWNERDRAWVARIABLE) { - if ((index < 0) || (index >= descr->nb_items)) return LB_ERR; - TRACE("[%p]: item %d height = %d\n", hwnd, index, height ); + if ((index < 0) || (index >= descr->nb_items)) + { + SetLastError(ERROR_INVALID_INDEX); + return LB_ERR; + } + TRACE("[%p]: item %d height = %d\n", descr->self, index, height ); descr->items[index].height = height; - LISTBOX_UpdateScroll( hwnd, descr ); + LISTBOX_UpdateScroll( descr ); if (repaint) - LISTBOX_InvalidateItems( hwnd, descr, index ); + LISTBOX_InvalidateItems( descr, index ); } else if (height != descr->item_height) { - TRACE("[%p]: new height = %d\n", hwnd, height ); + TRACE("[%p]: new height = %d\n", descr->self, height ); descr->item_height = height; - LISTBOX_UpdatePage( hwnd, descr ); - LISTBOX_UpdateScroll( hwnd, descr ); + LISTBOX_UpdatePage( descr ); + LISTBOX_UpdateScroll( descr ); if (repaint) - InvalidateRect( hwnd, 0, TRUE ); + InvalidateRect( descr->self, 0, TRUE ); } return LB_OKAY; } @@ -1228,7 +1271,7 @@
/*********************************************************************** * LISTBOX_SetHorizontalPos */ -static void LISTBOX_SetHorizontalPos( HWND hwnd, LB_DESCR *descr, INT pos ) +static void LISTBOX_SetHorizontalPos( LB_DESCR *descr, INT pos ) { INT diff;
@@ -1236,39 +1279,39 @@ pos = descr->horz_extent - descr->width; if (pos < 0) pos = 0; if (!(diff = descr->horz_pos - pos)) return; - TRACE("[%p]: new horz pos = %d\n", hwnd, pos ); + TRACE("[%p]: new horz pos = %d\n", descr->self, pos ); descr->horz_pos = pos; - LISTBOX_UpdateScroll( hwnd, descr ); + LISTBOX_UpdateScroll( descr ); if (abs(diff) < descr->width) { RECT rect; /* Invalidate the focused item so it will be repainted correctly */ if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1) - InvalidateRect( hwnd, &rect, TRUE ); - ScrollWindowEx( hwnd, diff, 0, NULL, NULL, 0, NULL, + InvalidateRect( descr->self, &rect, TRUE ); + ScrollWindowEx( descr->self, diff, 0, NULL, NULL, 0, NULL, SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN ); } else - InvalidateRect( hwnd, NULL, TRUE ); + InvalidateRect( descr->self, NULL, TRUE ); }
/*********************************************************************** * LISTBOX_SetHorizontalExtent */ -static LRESULT LISTBOX_SetHorizontalExtent( HWND hwnd, LB_DESCR *descr, +static LRESULT LISTBOX_SetHorizontalExtent( LB_DESCR *descr, INT extent ) { if (!descr->horz_extent || (descr->style & LBS_MULTICOLUMN)) return LB_OKAY; if (extent <= 0) extent = 1; if (extent == descr->horz_extent) return LB_OKAY; - TRACE("[%p]: new horz extent = %d\n", hwnd, extent ); + TRACE("[%p]: new horz extent = %d\n", descr->self, extent ); descr->horz_extent = extent; if (descr->horz_pos > extent - descr->width) - LISTBOX_SetHorizontalPos( hwnd, descr, extent - descr->width ); + LISTBOX_SetHorizontalPos( descr, extent - descr->width ); else - LISTBOX_UpdateScroll( hwnd, descr ); + LISTBOX_UpdateScroll( descr ); return LB_OKAY; }
@@ -1276,12 +1319,12 @@
/*********************************************************************** * LISTBOX_SetColumnWidth */ -static LRESULT LISTBOX_SetColumnWidth( HWND hwnd, LB_DESCR *descr, INT width) +static LRESULT LISTBOX_SetColumnWidth( LB_DESCR *descr, INT width) { if (width == descr->column_width) return LB_OKAY; - TRACE("[%p]: new column width = %d\n", hwnd, width ); + TRACE("[%p]: new column width = %d\n", descr->self, width ); descr->column_width = width; - LISTBOX_UpdatePage( hwnd, descr ); + LISTBOX_UpdatePage( descr ); return LB_OKAY; }
@@ -1291,26 +1334,29 @@ * * Returns the item height. */ -static INT LISTBOX_SetFont( HWND hwnd, LB_DESCR *descr, HFONT font ) +static INT LISTBOX_SetFont( LB_DESCR *descr, HFONT font ) { HDC hdc; HFONT oldFont = 0; - TEXTMETRICW tm; + const char *alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + SIZE sz;
descr->font = font;
- if (!(hdc = GetDCEx( hwnd, 0, DCX_CACHE ))) + if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE ))) { ERR("unable to get DC.\n" ); return 16; } if (font) oldFont = SelectObject( hdc, font ); - GetTextMetricsW( hdc, &tm ); + GetTextExtentPointA( hdc, alphabet, 52, &sz); if (oldFont) SelectObject( hdc, oldFont ); - ReleaseDC( hwnd, hdc ); + ReleaseDC( descr->self, hdc ); + + descr->avg_char_width = (sz.cx / 26 + 1) / 2; if (!IS_OWNERDRAW(descr)) - LISTBOX_SetItemHeight( hwnd, descr, 0, tm.tmHeight, FALSE ); - return tm.tmHeight ; + LISTBOX_SetItemHeight( descr, 0, sz.cy, FALSE ); + return sz.cy; }
@@ -1319,7 +1365,7 @@ * * Make sure that a given item is partially or fully visible. */ -static void LISTBOX_MakeItemVisible( HWND hwnd, LB_DESCR *descr, INT index, +static void LISTBOX_MakeItemVisible( LB_DESCR *descr, INT index, BOOL fully ) { INT top; @@ -1347,7 +1393,7 @@ (descr->height > (descr->page_size * descr->item_height))) return; top = index - descr->page_size + 1; } - LISTBOX_SetTopItem( hwnd, descr, top, TRUE ); + LISTBOX_SetTopItem( descr, top, TRUE ); }
/*********************************************************************** @@ -1357,7 +1403,7 @@ * index must be between 0 and descr->nb_items-1, or LB_ERR is returned. * */ -static LRESULT LISTBOX_SetCaretIndex( HWND hwnd, LB_DESCR *descr, INT index, +static LRESULT LISTBOX_SetCaretIndex( LB_DESCR *descr, INT index, BOOL fully_visible ) { INT oldfocus = descr->focus_item; @@ -1367,11 +1413,11 @@ if (index == oldfocus) return LB_OKAY; descr->focus_item = index; if ((oldfocus != -1) && descr->caret_on && (descr->in_focus)) - LISTBOX_RepaintItem( hwnd, descr, oldfocus, ODA_FOCUS ); + LISTBOX_RepaintItem( descr, oldfocus, ODA_FOCUS );
- LISTBOX_MakeItemVisible( hwnd, descr, index, fully_visible ); + LISTBOX_MakeItemVisible( descr, index, fully_visible ); if (descr->caret_on && (descr->in_focus)) - LISTBOX_RepaintItem( hwnd, descr, index, ODA_FOCUS ); + LISTBOX_RepaintItem( descr, index, ODA_FOCUS );
return LB_OKAY; } @@ -1382,7 +1428,7 @@ * * Select a range of items. Should only be used on a MULTIPLESEL listbox. */ -static LRESULT LISTBOX_SelectItemRange( HWND hwnd, LB_DESCR *descr, INT first, +static LRESULT LISTBOX_SelectItemRange( LB_DESCR *descr, INT first, INT last, BOOL on ) { INT i; @@ -1395,8 +1441,6 @@ if (last == -1) last = descr->nb_items - 1; if ((first < 0) || (first >= descr->nb_items)) return LB_ERR; if ((last < 0) || (last >= descr->nb_items)) return LB_ERR; - /* selected_item reflects last selected/unselected item on multiple sel */ - descr->selected_item = last;
if (on) /* Turn selection on */ { @@ -1404,9 +1448,8 @@ { if (descr->items[i].selected) continue; descr->items[i].selected = TRUE; - LISTBOX_InvalidateItemRect(hwnd, descr, i); + LISTBOX_InvalidateItemRect(descr, i); } - LISTBOX_SetCaretIndex( hwnd, descr, last, TRUE ); } else /* Turn selection off */ { @@ -1414,7 +1457,7 @@ { if (!descr->items[i].selected) continue; descr->items[i].selected = FALSE; - LISTBOX_InvalidateItemRect(hwnd, descr, i); + LISTBOX_InvalidateItemRect(descr, i); } } return LB_OKAY; @@ -1423,19 +1466,23 @@
/*********************************************************************** * LISTBOX_SetSelection */ -static LRESULT LISTBOX_SetSelection( HWND hwnd, LB_DESCR *descr, INT index, +static LRESULT LISTBOX_SetSelection( LB_DESCR *descr, INT index, BOOL on, BOOL send_notify ) { TRACE( "index=%d notify=%s\n", index, send_notify ? "YES" : "NO" );
- if (descr->style & LBS_NOSEL) return LB_ERR; + if (descr->style & LBS_NOSEL) + { + descr->selected_item = index; + return LB_ERR; + } if ((index < -1) || (index >= descr->nb_items)) return LB_ERR; if (descr->style & LBS_MULTIPLESEL) { if (index == -1) /* Select all items */ - return LISTBOX_SelectItemRange( hwnd, descr, 0, -1, on ); + return LISTBOX_SelectItemRange( descr, 0, -1, on ); else /* Only one item */ - return LISTBOX_SelectItemRange( hwnd, descr, index, index, on ); + return LISTBOX_SelectItemRange( descr, index, index, on ); } else { @@ -1444,9 +1491,9 @@ if (oldsel != -1) descr->items[oldsel].selected = FALSE; if (index != -1) descr->items[index].selected = TRUE; descr->selected_item = index; - if (oldsel != -1) LISTBOX_RepaintItem( hwnd, descr, oldsel, ODA_SELECT ); - if (index != -1) LISTBOX_RepaintItem( hwnd, descr, index, ODA_SELECT ); - if (send_notify && descr->nb_items) SEND_NOTIFICATION( hwnd, descr, + 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 ); else if( descr->lphc ) /* set selection change flag for parent combo */ @@ -1461,7 +1508,7 @@ * * Change the caret position and extend the selection to the new caret. [truncated at 1000 lines; 1662 more skipped]