📄 combo.c
字号:
/*
* In some circumstances (when the selection of the combobox
* is changed for example) we don't wans the EN_CHANGE notification
* to be forwarded to the parent of the combobox. This code
* checks a flag that is set in these occasions and ignores the
* notification.
*/
if (lphc->wState & CBF_NOLBSELECT)
{
lphc->wState &= ~CBF_NOLBSELECT;
}
else
{
CBUpdateLBox( lphc, lphc->wState & CBF_DROPPED );
}
if (!(lphc->wState & CBF_NOEDITNOTIFY))
CB_NOTIFY( lphc, CBN_EDITCHANGE );
break;
case (EN_UPDATE >> 8):
if (!(lphc->wState & CBF_NOEDITNOTIFY))
CB_NOTIFY( lphc, CBN_EDITUPDATE );
break;
case (EN_ERRSPACE >> 8):
CB_NOTIFY( lphc, CBN_ERRSPACE );
}
}
else if( lphc->hWndLBox == hWnd )
{
switch( (short)HIWORD(wParam) )
{
case LBN_ERRSPACE:
CB_NOTIFY( lphc, CBN_ERRSPACE );
break;
case LBN_DBLCLK:
CB_NOTIFY( lphc, CBN_DBLCLK );
break;
case LBN_SELCHANGE:
case LBN_SELCANCEL:
TRACE("[%p]: lbox selection change [%x]\n", lphc->self, lphc->wState );
if( HIWORD(wParam) == LBN_SELCHANGE)
{
if( lphc->wState & CBF_EDIT )
{
INT index = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
lphc->wState |= CBF_NOLBSELECT;
CBUpdateEdit( lphc, index );
/* select text in edit, as Windows does */
SendMessageW(lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1));
}
else
InvalidateRect(lphc->self, &lphc->textRect, TRUE);
}
/* do not roll up if selection is being tracked
* by arrowkeys in the dropdown listbox */
if( ((lphc->wState & CBF_DROPPED) && !(lphc->wState & CBF_NOROLLUP)) )
{
CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
}
else lphc->wState &= ~CBF_NOROLLUP;
CB_NOTIFY( lphc, CBN_SELCHANGE );
/* fall through */
case LBN_SETFOCUS:
case LBN_KILLFOCUS:
/* nothing to do here since ComboLBox always resets the focus to its
* combo/edit counterpart */
break;
}
}
return 0;
}
/***********************************************************************
* COMBO_ItemOp
*
* Fixup an ownerdrawn item operation and pass it up to the combobox owner.
*/
static LRESULT COMBO_ItemOp( LPHEADCOMBO lphc, UINT msg, LPARAM lParam )
{
HWND hWnd = lphc->self;
UINT id = (UINT)GetWindowLongPtrW( hWnd, GWLP_ID );
TRACE("[%p]: ownerdraw op %04x\n", lphc->self, msg );
switch( msg )
{
case WM_DELETEITEM:
{
DELETEITEMSTRUCT *lpIS = (DELETEITEMSTRUCT *)lParam;
lpIS->CtlType = ODT_COMBOBOX;
lpIS->CtlID = id;
lpIS->hwndItem = hWnd;
break;
}
case WM_DRAWITEM:
{
DRAWITEMSTRUCT *lpIS = (DRAWITEMSTRUCT *)lParam;
lpIS->CtlType = ODT_COMBOBOX;
lpIS->CtlID = id;
lpIS->hwndItem = hWnd;
break;
}
case WM_COMPAREITEM:
{
COMPAREITEMSTRUCT *lpIS = (COMPAREITEMSTRUCT *)lParam;
lpIS->CtlType = ODT_COMBOBOX;
lpIS->CtlID = id;
lpIS->hwndItem = hWnd;
break;
}
case WM_MEASUREITEM:
{
MEASUREITEMSTRUCT *lpIS = (MEASUREITEMSTRUCT *)lParam;
lpIS->CtlType = ODT_COMBOBOX;
lpIS->CtlID = id;
break;
}
}
return SendMessageW(lphc->owner, msg, id, lParam);
}
/***********************************************************************
* COMBO_GetTextW
*/
static LRESULT COMBO_GetTextW( LPHEADCOMBO lphc, INT count, LPWSTR buf )
{
INT length;
if( lphc->wState & CBF_EDIT )
return SendMessageW( lphc->hWndEdit, WM_GETTEXT, count, (LPARAM)buf );
/* get it from the listbox */
if (!count || !buf) return 0;
if( lphc->hWndLBox )
{
INT idx = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
if (idx == LB_ERR) goto error;
length = SendMessageW(lphc->hWndLBox, LB_GETTEXTLEN, idx, 0 );
if (length == LB_ERR) goto error;
/* 'length' is without the terminating character */
if (length >= count)
{
LPWSTR lpBuffer = HeapAlloc(GetProcessHeap(), 0, (length + 1) * sizeof(WCHAR));
if (!lpBuffer) goto error;
length = SendMessageW(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)lpBuffer);
/* truncate if buffer is too short */
if (length != LB_ERR)
{
lstrcpynW( buf, lpBuffer, count );
length = count;
}
HeapFree( GetProcessHeap(), 0, lpBuffer );
}
else length = SendMessageW(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)buf);
if (length == LB_ERR) return 0;
return length;
}
error: /* error - truncate string, return zero */
buf[0] = 0;
return 0;
}
/***********************************************************************
* COMBO_GetTextA
*
* NOTE! LB_GETTEXT does not count terminating \0, WM_GETTEXT does.
* also LB_GETTEXT might return values < 0, WM_GETTEXT doesn't.
*/
static LRESULT COMBO_GetTextA( LPHEADCOMBO lphc, INT count, LPSTR buf )
{
INT length;
if( lphc->wState & CBF_EDIT )
return SendMessageA( lphc->hWndEdit, WM_GETTEXT, count, (LPARAM)buf );
/* get it from the listbox */
if (!count || !buf) return 0;
if( lphc->hWndLBox )
{
INT idx = SendMessageW(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
if (idx == LB_ERR) goto error;
length = SendMessageA(lphc->hWndLBox, LB_GETTEXTLEN, idx, 0 );
if (length == LB_ERR) goto error;
/* 'length' is without the terminating character */
if (length >= count)
{
LPSTR lpBuffer = HeapAlloc(GetProcessHeap(), 0, (length + 1) );
if (!lpBuffer) goto error;
length = SendMessageA(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)lpBuffer);
/* truncate if buffer is too short */
if (length != LB_ERR)
{
lstrcpynA( buf, lpBuffer, count );
length = count;
}
HeapFree( GetProcessHeap(), 0, lpBuffer );
}
else length = SendMessageA(lphc->hWndLBox, LB_GETTEXT, idx, (LPARAM)buf);
if (length == LB_ERR) return 0;
return length;
}
error: /* error - truncate string, return zero */
buf[0] = 0;
return 0;
}
/***********************************************************************
* CBResetPos
*
* This function sets window positions according to the updated
* component placement struct.
*/
static void CBResetPos(
LPHEADCOMBO lphc,
LPRECT rectEdit,
LPRECT rectLB,
BOOL bRedraw)
{
BOOL bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
/* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
* sizing messages */
if( lphc->wState & CBF_EDIT )
SetWindowPos( lphc->hWndEdit, 0,
rectEdit->left, rectEdit->top,
rectEdit->right - rectEdit->left,
rectEdit->bottom - rectEdit->top,
SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
SetWindowPos( lphc->hWndLBox, 0,
rectLB->left, rectLB->top,
rectLB->right - rectLB->left,
rectLB->bottom - rectLB->top,
SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
if( bDrop )
{
if( lphc->wState & CBF_DROPPED )
{
lphc->wState &= ~CBF_DROPPED;
ShowWindow( lphc->hWndLBox, SW_HIDE );
}
if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
RedrawWindow( lphc->self, NULL, 0,
RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
}
}
/***********************************************************************
* COMBO_Size
*/
static void COMBO_Size( LPHEADCOMBO lphc, BOOL bRedraw )
{
CBCalcPlacement(lphc->self,
lphc,
&lphc->textRect,
&lphc->buttonRect,
&lphc->droppedRect);
CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, bRedraw );
}
/***********************************************************************
* COMBO_Font
*/
static void COMBO_Font( LPHEADCOMBO lphc, HFONT hFont, BOOL bRedraw )
{
/*
* Set the font
*/
lphc->hFont = hFont;
/*
* Propagate to owned windows.
*/
if( lphc->wState & CBF_EDIT )
SendMessageW(lphc->hWndEdit, WM_SETFONT, (WPARAM)hFont, bRedraw);
SendMessageW(lphc->hWndLBox, WM_SETFONT, (WPARAM)hFont, bRedraw);
/*
* Redo the layout of the control.
*/
if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
{
CBCalcPlacement(lphc->self,
lphc,
&lphc->textRect,
&lphc->buttonRect,
&lphc->droppedRect);
CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
}
else
{
CBForceDummyResize(lphc);
}
}
/***********************************************************************
* COMBO_SetItemHeight
*/
static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT index, INT height )
{
LRESULT lRet = CB_ERR;
if( index == -1 ) /* set text field height */
{
if( height < 32768 )
{
lphc->editHeight = height;
/*
* Redo the layout of the control.
*/
if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
{
CBCalcPlacement(lphc->self,
lphc,
&lphc->textRect,
&lphc->buttonRect,
&lphc->droppedRect);
CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
}
else
{
CBForceDummyResize(lphc);
}
lRet = height;
}
}
else if ( CB_OWNERDRAWN(lphc) ) /* set listbox item height */
lRet = SendMessageW(lphc->hWndLBox, LB_SETITEMHEIGHT,
(WPARAM)index, (LPARAM)height );
return lRet;
}
/***********************************************************************
* COMBO_SelectString
*/
static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT start, LPARAM pText, BOOL unicode )
{
INT index = unicode ? SendMessageW(lphc->hWndLBox, LB_SELECTSTRING, (WPARAM)start, pText) :
SendMessageA(lphc->hWndLBox, LB_SELECTSTRING, (WPARAM)start, pText);
if( index >= 0 )
{
if( lphc->wState & CBF_EDIT )
CBUpdateEdit( lphc, index );
else
{
InvalidateRect(lphc->self, &lphc->textRect, TRUE);
}
}
return (LRESULT)index;
}
/***********************************************************************
* COMBO_LButtonDown
*/
static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
{
POINT pt;
BOOL bButton;
HWND hWnd = lphc->self;
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
bButton = PtInRect(&lphc->buttonRect, pt);
if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
(bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
{
lphc->wState |= CBF_BUTTONDOWN;
if( lphc->wState & CBF_DROPPED )
{
/* got a click to cancel selection */
lphc->wState &= ~CBF_BUTTONDOWN;
CBRollUp( lphc, TRUE, FALSE );
if( !IsWindow( hWnd ) ) return;
if( lphc->wState & CBF_CAPTURE )
{
lphc->wState &= ~CBF_CAPTURE;
ReleaseCapture();
}
}
else
{
/* drop down the listbox and start tracking */
lphc->wState |= CBF_CAPTURE;
SetCapture( hWnd );
CBDropDown( lphc );
}
if( bButton ) CBRepaintButton( lphc );
}
}
/***********************************************************************
* COMBO_LButtonUp
*
* Release capture and stop tracking if needed.
*/
static void COMBO_LButtonUp( LPHEADCOMBO lphc )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -