- Sync to Wine: Listbox controls

- Implement NtUserGetListBoxInfo and GetListBoxInfo. Fix header entry.
- Add LB_GETLISTBOXINFO to psdk.

svn path=/trunk/; revision=29839
This commit is contained in:
James Tabor 2007-10-24 01:04:06 +00:00
parent 243774066b
commit 07c753c912
6 changed files with 149 additions and 64 deletions

View file

@ -16,12 +16,26 @@
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* NOTES
*
* This code was audited for completeness against the documented features
* of Comctl32.dll version 6.0 on Oct. 9, 2004, by Dimitrie O. Paun.
*
* Unless otherwise noted, we believe this code to be complete, as per
* the specification mentioned above.
* If you discover missing features, or bugs, please note them below.
*
* TODO:
* - GetListBoxInfo()
* - LB_GETLISTBOXINFO
* - LBS_NODATA
*/ */
#include <user32.h> #include <user32.h>
#include <wine/debug.h> #include <wine/debug.h>
WINE_DECLARE_DEBUG_CHANNEL(combo);
WINE_DEFAULT_DEBUG_CHANNEL(listbox); WINE_DEFAULT_DEBUG_CHANNEL(listbox);
/* Start of hack section -------------------------------- */ /* Start of hack section -------------------------------- */
@ -42,14 +56,6 @@ BOOL STDCALL KillSystemTimer(HWND,UINT_PTR);
/* End of hack section -------------------------------- */ /* End of hack section -------------------------------- */
/* Unimplemented yet:
* - LBS_USETABSTOPS
* - Locale handling
*
* Probably needs improvement:
* - LBS_NOSEL
*/
/* Items array granularity */ /* Items array granularity */
#define LB_ARRAY_GRANULARITY 16 #define LB_ARRAY_GRANULARITY 16
@ -341,10 +347,12 @@ static void LISTBOX_UpdateScroll( LB_DESCR *descr )
* *
* Set the top item of the listbox, scrolling up or down if necessary. * Set the top item of the listbox, scrolling up or down if necessary.
*/ */
static LRESULT LISTBOX_SetTopItem( LB_DESCR *descr, INT index, static LRESULT LISTBOX_SetTopItem( LB_DESCR *descr, INT index, BOOL scroll )
BOOL scroll )
{ {
INT max = LISTBOX_GetMaxTopIndex( descr ); INT max = LISTBOX_GetMaxTopIndex( descr );
TRACE("setting top item %d, scroll %d\n", index, scroll);
if (index > max) index = max; if (index > max) index = max;
if (index < 0) index = 0; if (index < 0) index = 0;
if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size; if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size;
@ -520,6 +528,8 @@ static LRESULT LISTBOX_GetItemRect( LB_DESCR *descr, INT index, RECT *rect )
rect->right += descr->horz_pos; rect->right += descr->horz_pos;
} }
TRACE("item %d, rect %s\n", index, wine_dbgstr_rect(rect));
return ((rect->left < descr->width) && (rect->right > 0) && return ((rect->left < descr->width) && (rect->right > 0) &&
(rect->top < descr->height) && (rect->bottom > 0)); (rect->top < descr->height) && (rect->bottom > 0));
} }
@ -704,8 +714,7 @@ static void LISTBOX_SetRedraw( LB_DESCR *descr, BOOL on )
* *
* Repaint a single item synchronously. * Repaint a single item synchronously.
*/ */
static void LISTBOX_RepaintItem( LB_DESCR *descr, INT index, static void LISTBOX_RepaintItem( LB_DESCR *descr, INT index, UINT action )
UINT action )
{ {
HDC hdc; HDC hdc;
RECT rect; RECT rect;
@ -735,6 +744,33 @@ static void LISTBOX_RepaintItem( LB_DESCR *descr, INT index,
} }
/***********************************************************************
* LISTBOX_DrawFocusRect
*/
static void LISTBOX_DrawFocusRect( LB_DESCR *descr, BOOL on )
{
HDC hdc;
RECT rect;
HFONT oldFont = 0;
/* Do not repaint the item if the item is not visible */
if (!IsWindowVisible(descr->self)) return;
if (descr->focus_item == -1) return;
if (!descr->caret_on || !descr->in_focus) return;
if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) != 1) return;
if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE ))) return;
if (descr->font) oldFont = SelectObject( hdc, descr->font );
if (!IsWindowEnabled(descr->self))
SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
LISTBOX_PaintItem( descr, hdc, &rect, descr->focus_item, ODA_FOCUS, on ? FALSE : TRUE );
if (oldFont) SelectObject( hdc, oldFont );
ReleaseDC( descr->self, hdc );
}
/*********************************************************************** /***********************************************************************
* LISTBOX_InitStorage * LISTBOX_InitStorage
*/ */
@ -767,8 +803,7 @@ static LRESULT LISTBOX_InitStorage( LB_DESCR *descr, INT nb_items )
/*********************************************************************** /***********************************************************************
* LISTBOX_SetTabStops * LISTBOX_SetTabStops
*/ */
static BOOL LISTBOX_SetTabStops( LB_DESCR *descr, INT count, static BOOL LISTBOX_SetTabStops( LB_DESCR *descr, INT count, LPINT tabs, BOOL short_ints )
LPINT tabs, BOOL short_ints )
{ {
INT i; INT i;
@ -1375,6 +1410,8 @@ static void LISTBOX_MakeItemVisible( LB_DESCR *descr, INT index,
{ {
INT top; INT top;
TRACE("current top item %d, index %d, fully %d\n", descr->top_item, index, fully);
if (index <= descr->top_item) top = index; if (index <= descr->top_item) top = index;
else if (descr->style & LBS_MULTICOLUMN) else if (descr->style & LBS_MULTICOLUMN)
{ {
@ -1413,16 +1450,17 @@ static LRESULT LISTBOX_SetCaretIndex( LB_DESCR *descr, INT index,
{ {
INT oldfocus = descr->focus_item; INT oldfocus = descr->focus_item;
TRACE("old focus %d, index %d\n", oldfocus, index);
if (descr->style & LBS_NOSEL) return LB_ERR; if (descr->style & LBS_NOSEL) return LB_ERR;
if ((index < 0) || (index >= descr->nb_items)) return LB_ERR; if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
if (index == oldfocus) return LB_OKAY; if (index == oldfocus) return LB_OKAY;
LISTBOX_DrawFocusRect( descr, FALSE );
descr->focus_item = index; descr->focus_item = index;
if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
LISTBOX_RepaintItem( descr, oldfocus, ODA_FOCUS );
LISTBOX_MakeItemVisible( descr, index, fully_visible ); LISTBOX_MakeItemVisible( descr, index, fully_visible );
if (descr->caret_on && (descr->in_focus)) LISTBOX_DrawFocusRect( descr, TRUE );
LISTBOX_RepaintItem( descr, index, ODA_FOCUS );
return LB_OKAY; return LB_OKAY;
} }
@ -1476,7 +1514,8 @@ static LRESULT LISTBOX_SelectItemRange( LB_DESCR *descr, INT first,
static LRESULT LISTBOX_SetSelection( LB_DESCR *descr, INT index, static LRESULT LISTBOX_SetSelection( LB_DESCR *descr, INT index,
BOOL on, BOOL send_notify ) BOOL on, BOOL send_notify )
{ {
TRACE( "index=%d notify=%s\n", index, send_notify ? "YES" : "NO" ); TRACE( "cur_sel=%d index=%d notify=%s\n",
descr->selected_item, index, send_notify ? "YES" : "NO" );
if (descr->style & LBS_NOSEL) if (descr->style & LBS_NOSEL)
{ {
@ -1497,8 +1536,8 @@ static LRESULT LISTBOX_SetSelection( LB_DESCR *descr, INT index,
if (index == oldsel) return LB_OKAY; if (index == oldsel) return LB_OKAY;
if (oldsel != -1) descr->items[oldsel].selected = FALSE; if (oldsel != -1) descr->items[oldsel].selected = FALSE;
if (index != -1) descr->items[index].selected = TRUE; if (index != -1) descr->items[index].selected = TRUE;
descr->selected_item = index;
if (oldsel != -1) LISTBOX_RepaintItem( descr, oldsel, ODA_SELECT ); if (oldsel != -1) LISTBOX_RepaintItem( descr, oldsel, ODA_SELECT );
descr->selected_item = index;
if (index != -1) LISTBOX_RepaintItem( descr, index, ODA_SELECT ); if (index != -1) LISTBOX_RepaintItem( descr, index, ODA_SELECT );
if (send_notify && descr->nb_items) SEND_NOTIFICATION( descr, if (send_notify && descr->nb_items) SEND_NOTIFICATION( descr,
(index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL ); (index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
@ -1518,7 +1557,7 @@ static LRESULT LISTBOX_SetSelection( LB_DESCR *descr, INT index,
static void LISTBOX_MoveCaret( LB_DESCR *descr, INT index, static void LISTBOX_MoveCaret( LB_DESCR *descr, INT index,
BOOL fully_visible ) BOOL fully_visible )
{ {
INT oldfocus = descr->focus_item; TRACE("old focus %d, index %d\n", descr->focus_item, index);
if ((index < 0) || (index >= descr->nb_items)) if ((index < 0) || (index >= descr->nb_items))
return; return;
@ -1531,9 +1570,7 @@ static void LISTBOX_MoveCaret( LB_DESCR *descr, INT index,
4. Set the focus to 'index' and repaint the item */ 4. Set the focus to 'index' and repaint the item */
/* 1. remove the focus and repaint the item */ /* 1. remove the focus and repaint the item */
descr->focus_item = -1; LISTBOX_DrawFocusRect( descr, FALSE );
if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
LISTBOX_RepaintItem( descr, oldfocus, ODA_FOCUS );
/* 2. then turn off the previous selection */ /* 2. then turn off the previous selection */
/* 3. repaint the new selected item */ /* 3. repaint the new selected item */
@ -1558,8 +1595,7 @@ static void LISTBOX_MoveCaret( LB_DESCR *descr, INT index,
/* 4. repaint the new item with the focus */ /* 4. repaint the new item with the focus */
descr->focus_item = index; descr->focus_item = index;
LISTBOX_MakeItemVisible( descr, index, fully_visible ); LISTBOX_MakeItemVisible( descr, index, fully_visible );
if (descr->caret_on && (descr->in_focus)) LISTBOX_DrawFocusRect( descr, TRUE );
LISTBOX_RepaintItem( descr, index, ODA_FOCUS );
} }
@ -1712,7 +1748,7 @@ static void LISTBOX_DeleteItem( LB_DESCR *descr, INT index )
dis.itemData = descr->items[index].data; dis.itemData = descr->items[index].data;
SendMessageW( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis ); SendMessageW( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis );
} }
if (HAS_STRINGS(descr) && descr->items[index].str) if (HAS_STRINGS(descr))
HeapFree( GetProcessHeap(), 0, descr->items[index].str ); HeapFree( GetProcessHeap(), 0, descr->items[index].str );
} }
@ -2066,7 +2102,10 @@ static LRESULT LISTBOX_HandleLButtonDown( LB_DESCR *descr,
DWORD keys, INT x, INT y ) DWORD keys, INT x, INT y )
{ {
INT index = LISTBOX_GetItemFromPoint( descr, x, y ); INT index = LISTBOX_GetItemFromPoint( descr, x, y );
TRACE("[%p]: lbuttondown %d,%d item %d\n", descr->self, x, y, index );
TRACE("[%p]: lbuttondown %d,%d item %d, focus item %d\n",
descr->self, x, y, index, descr->focus_item);
if (!descr->caret_on && (descr->in_focus)) return 0; if (!descr->caret_on && (descr->in_focus)) return 0;
if (!descr->in_focus) if (!descr->in_focus)
@ -2077,6 +2116,16 @@ static LRESULT LISTBOX_HandleLButtonDown( LB_DESCR *descr,
if (index == -1) return 0; if (index == -1) return 0;
if (!descr->lphc)
{
if (descr->style & LBS_NOTIFY )
SendMessageW( descr->owner, WM_LBTRACKPOINT, index,
MAKELPARAM( x, y ) );
}
descr->captured = TRUE;
SetCapture( descr->self );
if (descr->style & (LBS_EXTENDEDSEL | LBS_MULTIPLESEL)) if (descr->style & (LBS_EXTENDEDSEL | LBS_MULTIPLESEL))
{ {
/* we should perhaps make sure that all items are deselected /* we should perhaps make sure that all items are deselected
@ -2119,14 +2168,8 @@ static LRESULT LISTBOX_HandleLButtonDown( LB_DESCR *descr,
TRUE, (descr->style & LBS_NOTIFY) != 0 ); TRUE, (descr->style & LBS_NOTIFY) != 0 );
} }
descr->captured = TRUE;
SetCapture( descr->self );
if (!descr->lphc) if (!descr->lphc)
{ {
if (descr->style & LBS_NOTIFY )
SendMessageW( descr->owner, WM_LBTRACKPOINT, index,
MAKELPARAM( x, y ) );
if (GetWindowLongW( descr->self, GWL_EXSTYLE ) & WS_EX_DRAGDETECT) if (GetWindowLongW( descr->self, GWL_EXSTYLE ) & WS_EX_DRAGDETECT)
{ {
POINT pt; POINT pt;
@ -2147,7 +2190,7 @@ static LRESULT LISTBOX_HandleLButtonDown( LB_DESCR *descr,
* *
* Process LButtonDown message for the ComboListBox * Process LButtonDown message for the ComboListBox
* *
nn * PARAMS * PARAMS
* pWnd [I] The windows internal structure * pWnd [I] The windows internal structure
* pDescr [I] The ListBox internal structure * pDescr [I] The ListBox internal structure
* wParam [I] Key Flag (WM_LBUTTONDOWN doc for more info) * wParam [I] Key Flag (WM_LBUTTONDOWN doc for more info)
@ -2467,7 +2510,6 @@ static LRESULT LISTBOX_HandleKeyDown( LB_DESCR *descr, DWORD key )
} }
} }
return 0; return 0;
} }
@ -2614,8 +2656,8 @@ static LRESULT WINAPI ListBoxWndProc_common( HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam, BOOL unicode ) WPARAM wParam, LPARAM lParam, BOOL unicode )
{ {
LB_DESCR *descr = (LB_DESCR *)GetWindowLongPtrW( hwnd, 0 ); LB_DESCR *descr = (LB_DESCR *)GetWindowLongPtrW( hwnd, 0 );
LRESULT ret;
LPHEADCOMBO lphc = 0; LPHEADCOMBO lphc = 0;
LRESULT ret;
if (!descr) if (!descr)
{ {
@ -2625,8 +2667,7 @@ static LRESULT WINAPI ListBoxWndProc_common( HWND hwnd, UINT msg,
{ {
CREATESTRUCTW *lpcs = (CREATESTRUCTW *)lParam; CREATESTRUCTW *lpcs = (CREATESTRUCTW *)lParam;
if (lpcs->style & LBS_COMBOBOX) lphc = (LPHEADCOMBO)lpcs->lpCreateParams; if (lpcs->style & LBS_COMBOBOX) lphc = (LPHEADCOMBO)lpcs->lpCreateParams;
if (!LISTBOX_Create( hwnd, lphc )) if (!LISTBOX_Create( hwnd, lphc )) return -1;
return -1;
TRACE("creating wnd=%p descr=%lx\n", hwnd, GetWindowLongPtrW( hwnd, 0 ) ); TRACE("creating wnd=%p descr=%lx\n", hwnd, GetWindowLongPtrW( hwnd, 0 ) );
return 0; return 0;
} }
@ -2638,6 +2679,7 @@ static LRESULT WINAPI ListBoxWndProc_common( HWND hwnd, UINT msg,
TRACE("[%p]: msg %s wp %08x lp %08lx\n", TRACE("[%p]: msg %s wp %08x lp %08lx\n",
hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam ); hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam );
switch(msg) switch(msg)
{ {
#ifndef __REACTOS__ #ifndef __REACTOS__
@ -2843,16 +2885,38 @@ static LRESULT WINAPI ListBoxWndProc_common( HWND hwnd, UINT msg,
{ {
POINT pt; POINT pt;
RECT rect; RECT rect;
int index;
BOOL hit = TRUE;
pt.x = LOWORD(lParam); /* The hiword of the return value is not a client area
pt.y = HIWORD(lParam); hittest as suggested by MSDN, but rather a hittest on
rect.left = 0; the returned listbox item. */
rect.top = 0;
rect.right = descr->width;
rect.bottom = descr->height;
return MAKELONG( LISTBOX_GetItemFromPoint(descr, pt.x, pt.y), if(descr->nb_items == 0)
!PtInRect( &rect, pt ) ); return 0x1ffff; /* win9x returns 0x10000, we copy winnt */
pt.x = (short)LOWORD(lParam);
pt.y = (short)HIWORD(lParam);
SetRect(&rect, 0, 0, descr->width, descr->height);
if(!PtInRect(&rect, pt))
{
pt.x = min(pt.x, rect.right - 1);
pt.x = max(pt.x, 0);
pt.y = min(pt.y, rect.bottom - 1);
pt.y = max(pt.y, 0);
hit = FALSE;
}
index = LISTBOX_GetItemFromPoint(descr, pt.x, pt.y);
if(index == -1)
{
index = descr->nb_items - 1;
hit = FALSE;
}
return MAKELONG(index, hit ? 0 : 1);
} }
#ifndef __REACTOS__ #ifndef __REACTOS__
@ -3154,6 +3218,10 @@ static LRESULT WINAPI ListBoxWndProc_common( HWND hwnd, UINT msg,
LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS ); LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS );
return LB_OKAY; return LB_OKAY;
case LB_GETLISTBOXINFO:
FIXME("LB_GETLISTBOXINFO: stub!\n");
return 0;
case WM_DESTROY: case WM_DESTROY:
return LISTBOX_Destroy( descr ); return LISTBOX_Destroy( descr );
@ -3190,7 +3258,7 @@ static LRESULT WINAPI ListBoxWndProc_common( HWND hwnd, UINT msg,
descr->in_focus = TRUE; descr->in_focus = TRUE;
descr->caret_on = TRUE; descr->caret_on = TRUE;
if (descr->focus_item != -1) if (descr->focus_item != -1)
LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS ); LISTBOX_DrawFocusRect( descr, TRUE );
SEND_NOTIFICATION( descr, LBN_SETFOCUS ); SEND_NOTIFICATION( descr, LBN_SETFOCUS );
return 0; return 0;
case WM_KILLFOCUS: case WM_KILLFOCUS:
@ -3325,6 +3393,7 @@ static LRESULT WINAPI ListBoxWndProc_common( HWND hwnd, UINT msg,
if( lphc ) return 0; if( lphc ) return 0;
return unicode ? SendMessageW( descr->owner, msg, wParam, lParam ) : return unicode ? SendMessageW( descr->owner, msg, wParam, lParam ) :
SendMessageA( descr->owner, msg, wParam, lParam ); SendMessageA( descr->owner, msg, wParam, lParam );
case WM_NCDESTROY: case WM_NCDESTROY:
if( lphc && (lphc->dwStyle & CBS_DROPDOWNLIST) != CBS_SIMPLE ) if( lphc && (lphc->dwStyle & CBS_DROPDOWNLIST) != CBS_SIMPLE )
lphc->hWndLBox = 0; lphc->hWndLBox = 0;
@ -3364,12 +3433,11 @@ static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARA
} }
/*********************************************************************** /***********************************************************************
* GetListBoxInfo * GetListBoxInfo !REACTOS!
*/ */
DWORD STDCALL DWORD STDCALL
GetListBoxInfo(HWND hwnd) GetListBoxInfo(HWND hwnd)
{ {
UNIMPLEMENTED; return NtUserGetListBoxInfo(hwnd); // Do it right! Have the message org from kmode!
return 0;
} }

View file

@ -1847,6 +1847,7 @@ extern "C" {
#define LB_GETITEMDATA 409 #define LB_GETITEMDATA 409
#define LB_GETITEMHEIGHT 417 #define LB_GETITEMHEIGHT 417
#define LB_GETITEMRECT 408 #define LB_GETITEMRECT 408
#define LB_GETLISTBOXINFO 434
#define LB_GETLOCALE 422 #define LB_GETLOCALE 422
#define LB_GETSEL 391 #define LB_GETSEL 391
#define LB_GETSELCOUNT 400 #define LB_GETSELCOUNT 400

View file

@ -1161,7 +1161,7 @@ NtUserGetLayeredWindowAttributes(
DWORD DWORD
NTAPI NTAPI
NtUserGetListBoxInfo( NtUserGetListBoxInfo(
DWORD Unknown0); HWND hWnd);
typedef struct tagNTUSERGETMESSAGEINFO typedef struct tagNTUSERGETMESSAGEINFO
{ {

View file

@ -125,7 +125,7 @@ User32 -
reactos/dll/win32/user32/controls/combo.c # Synced at 20071022 reactos/dll/win32/user32/controls/combo.c # Synced at 20071022
reactos/dll/win32/user32/controls/edit.c # Synced at 20071022 reactos/dll/win32/user32/controls/edit.c # Synced at 20071022
reactos/dll/win32/user32/controls/icontitle.c # Synced at 20060617 reactos/dll/win32/user32/controls/icontitle.c # Synced at 20060617
reactos/dll/win32/user32/controls/listbox.c # Synced at 20060616 reactos/dll/win32/user32/controls/listbox.c # Synced at 20071023
reactos/dll/win32/user32/controls/scrollbar.c # Forked reactos/dll/win32/user32/controls/scrollbar.c # Forked
reactos/dll/win32/user32/controls/static.c # Synced at 20060908 reactos/dll/win32/user32/controls/static.c # Synced at 20060908

View file

@ -334,16 +334,6 @@ NtUserGetImeHotKey(
} }
DWORD
STDCALL
NtUserGetListBoxInfo(
DWORD Unknown0)
{
UNIMPLEMENTED
return 0;
}
DWORD DWORD
STDCALL STDCALL
NtUserGetMouseMovePointsEx( NtUserGetMouseMovePointsEx(

View file

@ -2872,6 +2872,32 @@ NtUserGetLastActivePopup(HWND hWnd)
#endif #endif
} }
DWORD
STDCALL
NtUserGetListBoxInfo(
HWND hWnd)
{
PWINDOW_OBJECT Wnd;
DECLARE_RETURN(DWORD);
DPRINT("Enter NtUserGetListBoxInfo\n");
UserEnterExclusive();
if (!(Wnd = UserGetWindowObject(hWnd)))
{
RETURN( 0 );
}
RETURN( (DWORD) co_IntSendMessage( Wnd->hSelf, LB_GETLISTBOXINFO, 0, 0 ));
CLEANUP:
DPRINT("Leave NtUserGetListBoxInfo, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/* /*
* NtUserGetParent * NtUserGetParent
* *