📄 comboex.c
字号:
static LRESULT COMBOEX_NotifyFormat (COMBOEX_INFO *infoPtr, LPARAM lParam)
{
if (lParam == NF_REQUERY) {
INT i = SendMessageW(infoPtr->hwndNotify,
WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY);
infoPtr->NtfUnicode = (i == NFR_UNICODE) ? 1 : 0;
}
return infoPtr->NtfUnicode ? NFR_UNICODE : NFR_ANSI;
}
static LRESULT COMBOEX_Size (COMBOEX_INFO *infoPtr, INT width, INT height)
{
TRACE("(width=%d, height=%d)\n", width, height);
MoveWindow (infoPtr->hwndCombo, 0, 0, width, height, TRUE);
COMBOEX_AdjustEditPos (infoPtr);
return 0;
}
static LRESULT COMBOEX_WindowPosChanging (COMBOEX_INFO *infoPtr, WINDOWPOS *wp)
{
RECT cbx_wrect, cbx_crect, cb_wrect;
INT width, height;
GetWindowRect (infoPtr->hwndSelf, &cbx_wrect);
GetClientRect (infoPtr->hwndSelf, &cbx_crect);
GetWindowRect (infoPtr->hwndCombo, &cb_wrect);
/* width is winpos value + border width of comboex */
width = wp->cx
+ (cbx_wrect.right-cbx_wrect.left)
- (cbx_crect.right-cbx_crect.left);
TRACE("winpos=(%d,%d %dx%d) flags=0x%08x\n",
wp->x, wp->y, wp->cx, wp->cy, wp->flags);
TRACE("EX window=(%d,%d)-(%d,%d), client=(%d,%d)-(%d,%d)\n",
cbx_wrect.left, cbx_wrect.top, cbx_wrect.right, cbx_wrect.bottom,
cbx_crect.left, cbx_crect.top, cbx_crect.right, cbx_crect.bottom);
TRACE("CB window=(%d,%d)-(%d,%d), EX setting=(0,0)-(%d,%d)\n",
cb_wrect.left, cb_wrect.top, cb_wrect.right, cb_wrect.bottom,
width, cb_wrect.bottom-cb_wrect.top);
if (width) SetWindowPos (infoPtr->hwndCombo, HWND_TOP, 0, 0,
width,
cb_wrect.bottom-cb_wrect.top,
SWP_NOACTIVATE);
GetWindowRect (infoPtr->hwndCombo, &cb_wrect);
/* height is combo window height plus border width of comboex */
height = (cb_wrect.bottom-cb_wrect.top)
+ (cbx_wrect.bottom-cbx_wrect.top)
- (cbx_crect.bottom-cbx_crect.top);
if (wp->cy < height) wp->cy = height;
if (infoPtr->hwndEdit) {
COMBOEX_AdjustEditPos (infoPtr);
InvalidateRect (infoPtr->hwndCombo, 0, TRUE);
}
return 0;
}
static LRESULT WINAPI
COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HWND hwndComboex = (HWND)GetPropW(hwnd, COMBOEX_SUBCLASS_PROP);
COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwndComboex);
NMCBEENDEDITW cbeend;
WCHAR edit_text[260];
COLORREF obkc;
HDC hDC;
RECT rect;
LRESULT lret;
TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx, info_ptr=%p\n",
hwnd, uMsg, wParam, lParam, infoPtr);
if (!infoPtr) return 0;
switch (uMsg)
{
case WM_CHAR:
/* handle (ignore) the return character */
if (wParam == VK_RETURN) return 0;
/* all other characters pass into the real Edit */
return CallWindowProcW (infoPtr->prevEditWndProc,
hwnd, uMsg, wParam, lParam);
case WM_ERASEBKGND:
/*
* The following was determined by traces of the native
*/
hDC = (HDC) wParam;
obkc = SetBkColor (hDC, GetSysColor (COLOR_WINDOW));
GetClientRect (hwnd, &rect);
TRACE("erasing (%d,%d)-(%d,%d)\n",
rect.left, rect.top, rect.right, rect.bottom);
ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0);
SetBkColor (hDC, obkc);
return CallWindowProcW (infoPtr->prevEditWndProc,
hwnd, uMsg, wParam, lParam);
case WM_KEYDOWN: {
INT oldItem, selected, step = 1;
CBE_ITEMDATA *item;
switch ((INT)wParam)
{
case VK_ESCAPE:
/* native version seems to do following for COMBOEX */
/*
* GetWindowTextW(Edit,&?, 0x104) x
* CB_GETCURSEL to Combo rets -1 x
* WM_NOTIFY to COMBOEX parent (rebar) x
* (CBEN_ENDEDIT{A|W}
* fChanged = FALSE x
* inewSelection = -1 x
* txt="www.hoho" x
* iWhy = 3 x
* CB_GETCURSEL to Combo rets -1 x
* InvalidateRect(Combo, 0) x
* WM_SETTEXT to Edit x
* EM_SETSEL to Edit (0,0) x
* EM_SETSEL to Edit (0,-1) x
* RedrawWindow(Combo, 0, 0, 5) x
*/
TRACE("special code for VK_ESCAPE\n");
GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
cbeend.fChanged = FALSE;
cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
CB_GETCURSEL, 0, 0);
cbeend.iWhy = CBENF_ESCAPE;
if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) return 0;
oldItem = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
InvalidateRect (infoPtr->hwndCombo, 0, 0);
if (!(item = COMBOEX_FindItem(infoPtr, oldItem))) {
ERR("item %d not found. Problem!\n", oldItem);
break;
}
infoPtr->selected = oldItem;
COMBOEX_SetEditText (infoPtr, item);
RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE |
RDW_INVALIDATE);
break;
case VK_RETURN:
/* native version seems to do following for COMBOEX */
/*
* GetWindowTextW(Edit,&?, 0x104) x
* CB_GETCURSEL to Combo rets -1 x
* CB_GETCOUNT to Combo rets 0
* if >0 loop
* CB_GETITEMDATA to match
* *** above 3 lines simulated by FindItem x
* WM_NOTIFY to COMBOEX parent (rebar) x
* (CBEN_ENDEDIT{A|W} x
* fChanged = TRUE (-1) x
* iNewSelection = -1 or selected x
* txt= x
* iWhy = 2 (CBENF_RETURN) x
* CB_GETCURSEL to Combo rets -1 x
* if -1 send CB_SETCURSEL to Combo -1 x
* InvalidateRect(Combo, 0, 0) x
* SetFocus(Edit) x
* CallWindowProc(406615a8, Edit, 0x100, 0xd, 0x1c0001)
*/
TRACE("special code for VK_RETURN\n");
GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
selected = SendMessageW (infoPtr->hwndCombo,
CB_GETCURSEL, 0, 0);
if (selected != -1) {
cmp_func_t cmptext = get_cmp_func(infoPtr);
item = COMBOEX_FindItem (infoPtr, selected);
TRACE("handling VK_RETURN, selected = %d, selected_text=%s\n",
selected, debugstr_txt(item->pszText));
TRACE("handling VK_RETURN, edittext=%s\n",
debugstr_w(edit_text));
if (cmptext (COMBOEX_GetText(infoPtr, item), edit_text)) {
/* strings not equal -- indicate edit has changed */
selected = -1;
}
}
cbeend.iNewSelection = selected;
cbeend.fChanged = TRUE;
cbeend.iWhy = CBENF_RETURN;
if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) {
/* abort the change, restore previous */
TRACE("Notify requested abort of change\n");
COMBOEX_SetEditText (infoPtr, infoPtr->edit);
RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE |
RDW_INVALIDATE);
return 0;
}
oldItem = SendMessageW (infoPtr->hwndCombo,CB_GETCURSEL, 0, 0);
if (oldItem != -1) {
/* if something is selected, then deselect it */
SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL,
(WPARAM)-1, 0);
}
InvalidateRect (infoPtr->hwndCombo, 0, 0);
SetFocus(infoPtr->hwndEdit);
break;
case VK_UP:
step = -1;
case VK_DOWN:
/* by default, step is 1 */
oldItem = SendMessageW (infoPtr->hwndSelf, CB_GETCURSEL, 0, 0);
if (oldItem >= 0 && oldItem + step >= 0)
SendMessageW (infoPtr->hwndSelf, CB_SETCURSEL, oldItem + step, 0);
return 0;
default:
return CallWindowProcW (infoPtr->prevEditWndProc,
hwnd, uMsg, wParam, lParam);
}
return 0;
}
case WM_SETFOCUS:
/* remember the focus to set state of icon */
lret = CallWindowProcW (infoPtr->prevEditWndProc,
hwnd, uMsg, wParam, lParam);
infoPtr->flags |= WCBE_EDITFOCUSED;
return lret;
case WM_KILLFOCUS:
/*
* do NOTIFY CBEN_ENDEDIT with CBENF_KILLFOCUS
*/
infoPtr->flags &= ~WCBE_EDITFOCUSED;
if (infoPtr->flags & WCBE_ACTEDIT) {
infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
cbeend.fChanged = FALSE;
cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
CB_GETCURSEL, 0, 0);
cbeend.iWhy = CBENF_KILLFOCUS;
COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text);
}
/* fall through */
default:
return CallWindowProcW (infoPtr->prevEditWndProc,
hwnd, uMsg, wParam, lParam);
}
}
static LRESULT WINAPI
COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HWND hwndComboex = (HWND)GetPropW(hwnd, COMBOEX_SUBCLASS_PROP);
COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwndComboex);
NMCBEENDEDITW cbeend;
NMMOUSE nmmse;
COLORREF obkc;
HDC hDC;
HWND focusedhwnd;
RECT rect;
POINT pt;
WCHAR edit_text[260];
TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx, info_ptr=%p\n",
hwnd, uMsg, wParam, lParam, infoPtr);
if (!infoPtr) return 0;
switch (uMsg)
{
case WM_DRAWITEM:
/*
* The only way this message should come is from the
* child Listbox issuing the message. Flag this so
* that ComboEx knows this is listbox.
*/
((DRAWITEMSTRUCT *)lParam)->itemState |= ODS_COMBOEXLBOX;
return CallWindowProcW (infoPtr->prevComboWndProc,
hwnd, uMsg, wParam, lParam);
case WM_ERASEBKGND:
/*
* The following was determined by traces of the native
*/
hDC = (HDC) wParam;
obkc = SetBkColor (hDC, GetSysColor (COLOR_WINDOW));
GetClientRect (hwnd, &rect);
TRACE("erasing (%d,%d)-(%d,%d)\n",
rect.left, rect.top, rect.right, rect.bottom);
ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0);
SetBkColor (hDC, obkc);
return CallWindowProcW (infoPtr->prevComboWndProc,
hwnd, uMsg, wParam, lParam);
case WM_SETCURSOR:
/*
* WM_NOTIFY to comboex parent (rebar)
* with NM_SETCURSOR with extra words of 0,0,0,0,0x02010001
* CallWindowProc (previous)
*/
nmmse.dwItemSpec = 0;
nmmse.dwItemData = 0;
nmmse.pt.x = 0;
nmmse.pt.y = 0;
nmmse.dwHitInfo = lParam;
COMBOEX_Notify (infoPtr, NM_SETCURSOR, (NMHDR *)&nmmse);
return CallWindowProcW (infoPtr->prevComboWndProc,
hwnd, uMsg, wParam, lParam);
case WM_LBUTTONDOWN:
GetClientRect (hwnd, &rect);
rect.bottom = rect.top + SendMessageW(infoPtr->hwndSelf,
CB_GETITEMHEIGHT, -1, 0);
rect.left = rect.right - GetSystemMetrics(SM_CXVSCROLL);
pt.x = (short)LOWORD(lParam);
pt.y = (short)HIWORD(lParam);
if (PtInRect(&rect, pt))
return CallWindowProcW (infoPtr->prevComboWndProc,
hwnd, uMsg, wParam, lParam);
infoPtr->flags |= WCBE_MOUSECAPTURED;
SetCapture(hwnd);
break;
case WM_LBUTTONUP:
if (!(infoPtr->flags & WCBE_MOUSECAPTURED))
return CallWindowProcW (infoPtr->prevComboWndProc,
hwnd, uMsg, wParam, lParam);
ReleaseCapture();
infoPtr->flags &= ~WCBE_MOUSECAPTURED;
if (infoPtr->flags & WCBE_MOUSEDRAGGED) {
infoPtr->flags &= ~WCBE_MOUSEDRAGGED;
} else {
SendMessageW(hwnd, CB_SHOWDROPDOWN, TRUE, 0);
}
break;
case WM_MOUSEMOVE:
if ( (infoPtr->flags & WCBE_MOUSECAPTURED) &&
!(infoPtr->flags & WCBE_MOUSEDRAGGED)) {
GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
COMBOEX_NotifyDragBegin(infoPtr, edit_text);
infoPtr->flags |= WCBE_MOUSEDRAGGED;
}
return CallWindowProcW (infoPtr->prevComboWndProc,
hwnd, uMsg, wParam, lParam);
case WM_COMMAND:
switch (HIWORD(wParam)) {
case EN_UPDATE:
/* traces show that COMBOEX does not issue CBN_EDITUPDATE
* on the EN_UPDATE
*/
return 0;
case EN_KILLFOCUS:
/*
* Native does:
*
* GetFocus() retns AA
* GetWindowTextW(Edit)
* CB_GETCURSEL(Combo) (got -1)
* WM_NOTIFY(CBEN_ENDEDITA) with CBENF_KILLFOCUS
* CB_GETCURSEL(Combo) (got -1)
* InvalidateRect(Combo, 0, 0)
* WM_KILLFOCUS(Combo, AA)
* return 0;
*/
focusedhwnd = GetFocus();
if (infoPtr->flags & WCBE_ACTEDIT) {
GetWindowTextW (infoPtr->hwndEdit, edit_text, 260);
cbeend.fChanged = (infoPtr->flags & WCBE_EDITCHG);
cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo,
CB_GETCURSEL, 0, 0);
cbeend.iWhy = CBENF_KILLFOCUS;
infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG);
if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) return 0;
}
/* possible CB_GETCURSEL */
InvalidateRect (infoPtr->hwndCombo, 0, 0);
if (focusedhwnd)
SendMessageW (infoPtr->hwndCombo, WM_KILLFOCUS,
(WPARAM)focusedhwnd, 0);
return 0;
case EN_SETFOCUS: {
/*
* For EN_SETFOCUS this issues the same calls
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -