/* * Combo controls * * Copyright 1997 Alex Korobka * * FIXME: roll up in Netscape 3.01. */ #include #include "windows.h" #include "sysmetrics.h" #include "win.h" #include "spy.h" #include "user.h" #include "graphics.h" #include "heap.h" #include "combo.h" #include "drive.h" #include "debug.h" /* bits in the dwKeyData */ #define KEYDATA_ALT 0x2000 #define KEYDATA_PREVSTATE 0x4000 /* * Additional combo box definitions */ #define CB_GETPTR( wnd ) (*(LPHEADCOMBO*)((wnd)->wExtra)) #define CB_NOTIFY( lphc, code ) \ (SendMessage32A( (lphc)->owner, WM_COMMAND, \ MAKEWPARAM((lphc)->self->wIDmenu, (code)), (lphc)->self->hwndSelf)) #define CB_GETEDITTEXTLENGTH( lphc ) \ (SendMessage32A( (lphc)->hWndEdit, WM_GETTEXTLENGTH, 0, 0 )) static HBITMAP32 hComboBmp = 0; static UINT32 CBitHeight, CBitWidth; static UINT32 CBitOffset = 8; /*********************************************************************** * COMBO_Init * * Load combo button bitmap. */ static BOOL32 COMBO_Init() { HDC32 hDC; if( hComboBmp ) return TRUE; if( (hDC = CreateCompatibleDC32(0)) ) { BOOL32 bRet = FALSE; if( (hComboBmp = LoadBitmap32A(0, MAKEINTRESOURCE32A(OBM_COMBO))) ) { BITMAP32 bm; HBITMAP32 hPrevB; RECT32 r; GetObject32A( hComboBmp, sizeof(bm), &bm ); CBitHeight = bm.bmHeight; CBitWidth = bm.bmWidth; TRACE(combo, "combo bitmap [%i,%i]\n", CBitWidth, CBitHeight ); hPrevB = SelectObject16( hDC, hComboBmp); SetRect32( &r, 0, 0, CBitWidth, CBitHeight ); InvertRect32( hDC, &r ); SelectObject32( hDC, hPrevB ); bRet = TRUE; } DeleteDC32( hDC ); return bRet; } return FALSE; } /*********************************************************************** * COMBO_NCCreate */ static LRESULT COMBO_NCCreate(WND* wnd, LPARAM lParam) { LPHEADCOMBO lphc; if ( wnd && COMBO_Init() && (lphc = HeapAlloc(GetProcessHeap(), 0, sizeof(HEADCOMBO))) ) { LPCREATESTRUCT32A lpcs = (CREATESTRUCT32A*)lParam; memset( lphc, 0, sizeof(HEADCOMBO) ); *(LPHEADCOMBO*)wnd->wExtra = lphc; /* some braindead apps do try to use scrollbar/border flags */ lphc->dwStyle = (lpcs->style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL)); wnd->dwStyle &= ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL); if( !(lpcs->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) ) lphc->dwStyle |= CBS_HASSTRINGS; if( !(wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) ) lphc->wState |= CBF_NOTIFY; TRACE(combo, "[0x%08x], style = %08x\n", (UINT32)lphc, lphc->dwStyle ); return (LRESULT)(UINT32)wnd->hwndSelf; } return (LRESULT)FALSE; } /*********************************************************************** * COMBO_NCDestroy */ static LRESULT COMBO_NCDestroy( LPHEADCOMBO lphc ) { if( lphc ) { WND* wnd = lphc->self; TRACE(combo,"[%04x]: freeing storage\n", CB_HWND(lphc)); if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox ) DestroyWindow32( lphc->hWndLBox ); HeapFree( GetProcessHeap(), 0, lphc ); wnd->wExtra[0] = 0; } return 0; } /*********************************************************************** * CBGetDefaultTextHeight */ static void CBGetDefaultTextHeight( LPHEADCOMBO lphc, LPSIZE32 lpSize ) { if( lphc->editHeight ) /* explicitly set height */ lpSize->cy = lphc->editHeight; else { HDC32 hDC = GetDC32( lphc->self->hwndSelf ); HFONT32 hPrevFont = 0; if( lphc->hFont ) hPrevFont = SelectObject32( hDC, lphc->hFont ); GetTextExtentPoint32A( hDC, "0", 1, lpSize); lpSize->cy += lpSize->cy / 4 + 4 * SYSMETRICS_CYBORDER; if( hPrevFont ) SelectObject32( hDC, hPrevFont ); ReleaseDC32( lphc->self->hwndSelf, hDC ); } lpSize->cx = lphc->RectCombo.right - lphc->RectCombo.left; } /*********************************************************************** * CBCalcPlacement * * Set up component coordinates given valid lphc->RectCombo. */ static void CBCalcPlacement( LPHEADCOMBO lphc, LPRECT32 lprEdit, LPRECT32 lprButton, LPRECT32 lprLB ) { RECT32 rect = lphc->RectCombo; SIZE32 size; /* get combo height and width */ if( CB_OWNERDRAWN(lphc) ) { UINT32 u = lphc->RectEdit.bottom - lphc->RectEdit.top; if( lphc->wState & CBF_MEASUREITEM ) /* first initialization */ { MEASUREITEMSTRUCT32 mi32; /* calculate defaults before sending WM_MEASUREITEM */ CBGetDefaultTextHeight( lphc, &size ); lphc->wState &= ~CBF_MEASUREITEM; mi32.CtlType = ODT_COMBOBOX; mi32.CtlID = lphc->self->wIDmenu; mi32.itemID = -1; mi32.itemWidth = size.cx; mi32.itemHeight = size.cy - 6; /* ownerdrawn cb is taller */ mi32.itemData = 0; SendMessage32A(lphc->owner, WM_MEASUREITEM, (WPARAM32)mi32.CtlID, (LPARAM)&mi32); u = 6 + (UINT16)mi32.itemHeight; } else size.cx = rect.right - rect.left; size.cy = u; } else CBGetDefaultTextHeight( lphc, &size ); /* calculate text and button placement */ lprEdit->left = lprEdit->top = lprButton->top = 0; if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* no button */ lprButton->left = lprButton->right = lprButton->bottom = 0; else { INT32 i = size.cx - CBitWidth - 10; /* seems ok */ lprButton->right = size.cx; lprButton->left = (INT16)i; lprButton->bottom = lprButton->top + size.cy; if( i < 0 ) size.cx = 0; else size.cx = i; } if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) { size.cx -= CBitOffset; if( size.cx < 0 ) size.cx = 0; } lprEdit->right = size.cx; lprEdit->bottom = size.cy; /* listbox placement */ lprLB->left = ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset; lprLB->top = lprEdit->bottom - SYSMETRICS_CYBORDER; lprLB->right = rect.right - rect.left; lprLB->bottom = rect.bottom - rect.top; if( lphc->droppedWidth > (lprLB->right - lprLB->left) ) lprLB->right = lprLB->left + lphc->droppedWidth; TRACE(combo,"[%04x]: (%i,%i-%i,%i) placement\n", CB_HWND(lphc), lphc->RectCombo.left, lphc->RectCombo.top, lphc->RectCombo.right, lphc->RectCombo.bottom); TRACE(combo,"\ttext\t= (%i,%i-%i,%i)\n", lprEdit->left, lprEdit->top, lprEdit->right, lprEdit->bottom); TRACE(combo,"\tbutton\t= (%i,%i-%i,%i)\n", lprButton->left, lprButton->top, lprButton->right, lprButton->bottom); TRACE(combo,"\tlbox\t= (%i,%i-%i,%i)\n", lprLB->left, lprLB->top, lprLB->right, lprLB->bottom ); } /*********************************************************************** * CBGetDroppedControlRect32 */ static void CBGetDroppedControlRect32( LPHEADCOMBO lphc, LPRECT32 lpRect) { lpRect->left = lphc->RectCombo.left + (lphc->wState & CBF_EDIT) ? CBitOffset : 0; lpRect->top = lphc->RectCombo.top + lphc->RectEdit.bottom - SYSMETRICS_CYBORDER; lpRect->right = lphc->RectCombo.right; lpRect->bottom = lphc->RectCombo.bottom - SYSMETRICS_CYBORDER; } /*********************************************************************** * COMBO_Create */ static LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam) { static char clbName[] = "ComboLBox"; static char editName[] = "Edit"; LPCREATESTRUCT32A lpcs = (CREATESTRUCT32A*)lParam; if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE; else if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT; lphc->self = wnd; lphc->owner = lpcs->hwndParent; /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */ if( lphc->owner || !(lpcs->style & WS_VISIBLE) ) { UINT32 lbeStyle; RECT32 editRect, btnRect, lbRect; GetWindowRect32( wnd->hwndSelf, &lphc->RectCombo ); lphc->wState |= CBF_MEASUREITEM; CBCalcPlacement( lphc, &editRect, &btnRect, &lbRect ); lphc->RectButton = btnRect; lphc->droppedWidth = lphc->editHeight = 0; /* create listbox popup */ lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS) | (lpcs->style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)); if( lphc->dwStyle & CBS_SORT ) lbeStyle |= LBS_SORT; if( lphc->dwStyle & CBS_HASSTRINGS ) lbeStyle |= LBS_HASSTRINGS; if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT ) lbeStyle |= LBS_NOINTEGRALHEIGHT; if( lphc->dwStyle & CBS_DISABLENOSCROLL ) lbeStyle |= LBS_DISABLENOSCROLL; if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* child listbox */ lbeStyle |= WS_CHILD | WS_VISIBLE; else /* popup listbox */ { lbeStyle |= WS_POPUP; OffsetRect32( &lbRect, lphc->RectCombo.left, lphc->RectCombo.top ); } /* Dropdown ComboLBox is not a child window and we cannot pass * ID_CB_LISTBOX directly because it will be treated as a menu handle. */ lphc->hWndLBox = CreateWindowEx32A( 0, clbName, NULL, lbeStyle, lbRect.left + SYSMETRICS_CXBORDER, lbRect.top + SYSMETRICS_CYBORDER, lbRect.right - lbRect.left - 2 * SYSMETRICS_CXBORDER, lbRect.bottom - lbRect.top - 2 * SYSMETRICS_CYBORDER, lphc->self->hwndSelf, (lphc->dwStyle & CBS_DROPDOWN)? (HMENU32)0 : (HMENU32)ID_CB_LISTBOX, lphc->self->hInstance, (LPVOID)lphc ); if( lphc->hWndLBox ) { BOOL32 bEdit = TRUE; lbeStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NOHIDESEL | ES_LEFT; if( lphc->wState & CBF_EDIT ) { if( lphc->dwStyle & CBS_OEMCONVERT ) lbeStyle |= ES_OEMCONVERT; if( lphc->dwStyle & CBS_AUTOHSCROLL ) lbeStyle |= ES_AUTOHSCROLL; if( lphc->dwStyle & CBS_LOWERCASE ) lbeStyle |= ES_LOWERCASE; else if( lphc->dwStyle & CBS_UPPERCASE ) lbeStyle |= ES_UPPERCASE; lphc->hWndEdit = CreateWindowEx32A( 0, editName, NULL, lbeStyle, editRect.left, editRect.top, editRect.right - editRect.left, editRect.bottom - editRect.top, lphc->self->hwndSelf, (HMENU32)ID_CB_EDIT, lphc->self->hInstance, NULL ); if( !lphc->hWndEdit ) bEdit = FALSE; } if( bEdit ) { lphc->RectEdit = editRect; if( CB_GETTYPE(lphc) != CBS_SIMPLE ) { lphc->wState |= CBF_NORESIZE; SetWindowPos32( wnd->hwndSelf, 0, 0, 0, lphc->RectCombo.right - lphc->RectCombo.left, lphc->RectEdit.bottom - lphc->RectEdit.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE ); lphc->wState &= ~CBF_NORESIZE; } TRACE(combo,"init done\n"); return wnd->hwndSelf; } ERR(combo, "edit control failure.\n"); } else ERR(combo, "listbox failure.\n"); } else ERR(combo, "no owner for visible combo.\n"); /* CreateWindow() will send WM_NCDESTROY to cleanup */ return -1; } /*********************************************************************** * CBPaintButton * * Paint combo button (normal, pressed, and disabled states). */ static void CBPaintButton(LPHEADCOMBO lphc, HDC32 hdc) { RECT32 r; HBRUSH32 hPrevBrush; UINT32 x, y; BOOL32 bBool; if( lphc->wState & CBF_NOREDRAW ) return; hPrevBrush = (HBRUSH32)SelectObject32(hdc, GetSysColorBrush32(COLOR_BTNFACE)); CONV_RECT16TO32( &lphc->RectButton, &r ); Rectangle32(hdc, r.left, r.top, r.right, r.bottom ); InflateRect32( &r, -1, -1 ); if( (bBool = lphc->wState & CBF_BUTTONDOWN) ) { GRAPH_DrawReliefRect(hdc, &r, 1, 0, TRUE); OffsetRect32( &r, 1, 1 ); } else GRAPH_DrawReliefRect(hdc, &r, 1, 2, FALSE); x = (r.left + r.right - CBitWidth) >> 1; y = (r.top + r.bottom - CBitHeight) >> 1; InflateRect32( &r, -3, -3 ); if( (bBool = CB_DISABLED(lphc)) ) { GRAPH_SelectClipMask(hdc, hComboBmp, x + 1, y + 1 ); FillRect32(hdc, &r, (HBRUSH32)GetStockObject32(WHITE_BRUSH)); } GRAPH_SelectClipMask(hdc, hComboBmp, x, y ); FillRect32(hdc, &r, (HBRUSH32)GetStockObject32((bBool) ? GRAY_BRUSH : BLACK_BRUSH)); GRAPH_SelectClipMask(hdc, (HBITMAP32)0, 0, 0); SelectObject32( hdc, hPrevBrush ); } /*********************************************************************** * CBPaintText * * Paint CBS_DROPDOWNLIST text field / update edit control contents. */ static void CBPaintText(LPHEADCOMBO lphc, HDC32 hdc) { INT32 id, size = 0; LPSTR pText = NULL; if( lphc->wState & CBF_NOREDRAW ) return; /* follow Windows combobox that sends a bunch of text * inquiries to its listbox while processing WM_PAINT. */ if( (id = SendMessage32A(lphc->hWndLBox, LB_GETCURSEL32, 0, 0) ) != LB_ERR ) { size = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, id, 0); if( (pText = HeapAlloc( GetProcessHeap(), 0, size + 1)) ) { SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, (WPARAM32)id, (LPARAM)pText ); pText[size] = '\0'; /* just in case */ } else return; } if( lphc->wState & CBF_EDIT ) { if( CB_HASSTRINGS(lphc) ) SetWindowText32A( lphc->hWndEdit, pText ? pText : "" ); if( lphc->wState & CBF_FOCUSED ) SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1)); } else /* paint text field ourselves */ { HBRUSH32 hPrevBrush = 0; HDC32 hDC = hdc; if( !hDC ) { if ((hDC = GetDC32(lphc->self->hwndSelf))) { HBRUSH32 hBrush = SendMessage32A( lphc->owner, WM_CTLCOLORLISTBOX, hDC, lphc->self->hwndSelf ); hPrevBrush = SelectObject32( hDC, (hBrush) ? hBrush : GetStockObject32(WHITE_BRUSH) ); } } if( hDC ) { RECT32 rect; UINT32 itemState; HFONT32 hPrevFont = (lphc->hFont) ? SelectObject32(hDC, lphc->hFont) : 0; PatBlt32( hDC, (rect.left = lphc->RectEdit.left + SYSMETRICS_CXBORDER), (rect.top = lphc->RectEdit.top + SYSMETRICS_CYBORDER), (rect.right = lphc->RectEdit.right - SYSMETRICS_CXBORDER), (rect.bottom = lphc->RectEdit.bottom - SYSMETRICS_CYBORDER) - 1, PATCOPY ); InflateRect32( &rect, -1, -1 ); if( lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED) ) { /* highlight */ FillRect32( hDC, &rect, GetSysColorBrush32(COLOR_HIGHLIGHT) ); SetBkColor32( hDC, GetSysColor32( COLOR_HIGHLIGHT ) ); SetTextColor32( hDC, GetSysColor32( COLOR_HIGHLIGHTTEXT ) ); itemState = ODS_SELECTED | ODS_FOCUS; } else itemState = 0; if( CB_OWNERDRAWN(lphc) ) { DRAWITEMSTRUCT32 dis; if( lphc->self->dwStyle & WS_DISABLED ) itemState |= ODS_DISABLED; dis.CtlType = ODT_COMBOBOX; dis.CtlID = lphc->self->wIDmenu; dis.hwndItem = lphc->self->hwndSelf; dis.itemAction = ODA_DRAWENTIRE; dis.itemID = id; dis.itemState = itemState; dis.hDC = hDC; dis.rcItem = rect; dis.itemData = SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32, (WPARAM32)id, 0 ); SendMessage32A( lphc->owner, WM_DRAWITEM, lphc->self->wIDmenu, (LPARAM)&dis ); } else { ExtTextOut32A( hDC, rect.left + 1, rect.top + 1, ETO_OPAQUE | ETO_CLIPPED, &rect, pText ? pText : "" , size, NULL ); if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED)) DrawFocusRect32( hDC, &rect ); } if( hPrevFont ) SelectObject32(hDC, hPrevFont ); if( !hdc ) { if( hPrevBrush ) SelectObject32( hDC, hPrevBrush ); ReleaseDC32( lphc->self->hwndSelf, hDC ); } } } if (pText) HeapFree( GetProcessHeap(), 0, pText ); } /*********************************************************************** * COMBO_Paint */ static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC32 hParamDC) { PAINTSTRUCT32 ps; HDC32 hDC; hDC = (hParamDC) ? hParamDC : BeginPaint32( lphc->self->hwndSelf, &ps); if( hDC && !(lphc->wState & CBF_NOREDRAW) ) { HBRUSH32 hPrevBrush, hBkgBrush; hBkgBrush = SendMessage32A( lphc->owner, WM_CTLCOLORLISTBOX, hDC, lphc->self->hwndSelf ); if( !hBkgBrush ) hBkgBrush = GetStockObject32(WHITE_BRUSH); hPrevBrush = SelectObject32( hDC, hBkgBrush ); if( !IsRectEmpty32(&lphc->RectButton) ) { /* paint everything to the right of the text field */ PatBlt32( hDC, lphc->RectEdit.right, lphc->RectEdit.top, lphc->RectButton.right - lphc->RectEdit.right, lphc->RectEdit.bottom - lphc->RectEdit.top, PATCOPY ); CBPaintButton( lphc, hDC ); } if( !(lphc->wState & CBF_EDIT) ) { /* paint text field */ GRAPH_DrawRectangle( hDC, lphc->RectEdit.left, lphc->RectEdit.top, lphc->RectEdit.right - lphc->RectEdit.left, lphc->RectButton.bottom - lphc->RectButton.top, GetSysColorPen32(COLOR_WINDOWFRAME) ); CBPaintText( lphc, hDC ); } if( hPrevBrush ) SelectObject32( hDC, hPrevBrush ); } if( !hParamDC ) EndPaint32(lphc->self->hwndSelf, &ps); return 0; } /*********************************************************************** * CBUpdateLBox * * Select listbox entry according to the contents of the edit control. */ static INT32 CBUpdateLBox( LPHEADCOMBO lphc ) { INT32 length, idx, ret; LPSTR pText = NULL; idx = ret = LB_ERR; length = CB_GETEDITTEXTLENGTH( lphc ); if( length > 0 ) pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1); TRACE(combo,"\t edit text length %i\n", length ); if( pText ) { if( length ) GetWindowText32A( lphc->hWndEdit, pText, length + 1); else pText[0] = '\0'; idx = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32, (WPARAM32)(-1), (LPARAM)pText ); if( idx == LB_ERR ) idx = 0; /* select first item */ else ret = idx; HeapFree( GetProcessHeap(), 0, pText ); } /* select entry */ SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, (WPARAM32)idx, 0 ); if( idx >= 0 ) { SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)idx, 0 ); /* probably superfluous but Windows sends this too */ SendMessage32A( lphc->hWndLBox, LB_SETCARETINDEX32, (WPARAM32)idx, 0 ); } return ret; } /*********************************************************************** * CBUpdateEdit * * Copy a listbox entry to the edit control. */ static void CBUpdateEdit( LPHEADCOMBO lphc , INT32 index ) { INT32 length; LPSTR pText = NULL; TRACE(combo,"\t %i\n", index ); if( index == -1 ) { length = CB_GETEDITTEXTLENGTH( lphc ); if( length ) { if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) ) { GetWindowText32A( lphc->hWndEdit, pText, length + 1 ); index = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32, (WPARAM32)(-1), (LPARAM)pText ); HeapFree( GetProcessHeap(), 0, pText ); } } } if( index >= 0 ) /* got an entry */ { length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, (WPARAM32)index, 0); if( length ) { if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) ) { SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, (WPARAM32)index, (LPARAM)pText ); SendMessage32A( lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)pText ); SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) ); HeapFree( GetProcessHeap(), 0, pText ); } } } } /*********************************************************************** * CBDropDown * * Show listbox popup. */ static void CBDropDown( LPHEADCOMBO lphc ) { INT32 index; RECT32 rect; LPRECT32 pRect = NULL; TRACE(combo,"[%04x]: drop down\n", CB_HWND(lphc)); CB_NOTIFY( lphc, CBN_DROPDOWN ); /* set selection */ lphc->wState |= CBF_DROPPED; if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) { index = CBUpdateLBox( lphc ); if( !(lphc->wState & CBF_CAPTURE) ) CBUpdateEdit( lphc, index ); } else { index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 ); if( index == LB_ERR ) index = 0; SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)index, 0 ); SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 ); pRect = &lphc->RectEdit; } /* now set popup position */ GetWindowRect32( lphc->self->hwndSelf, &rect ); rect.top += lphc->RectEdit.bottom - lphc->RectEdit.top - SYSMETRICS_CYBORDER; rect.bottom = rect.top + lphc->RectCombo.bottom - lphc->RectCombo.top - SYSMETRICS_CYBORDER; rect.right = rect.left + lphc->RectCombo.right - lphc->RectCombo.left; rect.left += ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset; SetWindowPos32( lphc->hWndLBox, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOREDRAW); if( !(lphc->wState & CBF_NOREDRAW) ) if( pRect ) RedrawWindow32( lphc->self->hwndSelf, pRect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN ); ShowWindow32( lphc->hWndLBox, SW_SHOWNA ); } /*********************************************************************** * CBRollUp * * Hide listbox popup. */ static void CBRollUp( LPHEADCOMBO lphc, BOOL32 ok, BOOL32 bButton ) { HWND32 hWnd = lphc->self->hwndSelf; CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL ); if( IsWindow32( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE ) { TRACE(combo,"[%04x]: roll up [%i]\n", CB_HWND(lphc), (INT32)ok ); /* always send WM_LBUTTONUP? */ SendMessage32A( lphc->hWndLBox, WM_LBUTTONUP, 0, (LPARAM)(-1) ); if( lphc->wState & CBF_DROPPED ) { RECT32 rect; lphc->wState &= ~CBF_DROPPED; ShowWindow32( lphc->hWndLBox, SW_HIDE ); if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) { INT32 index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 ); CBUpdateEdit( lphc, index ); rect = lphc->RectButton; } else { if( bButton ) UnionRect32( &rect, &lphc->RectButton, &lphc->RectEdit ); else rect = lphc->RectEdit; bButton = TRUE; } if( bButton && !(lphc->wState & CBF_NOREDRAW) ) RedrawWindow32( hWnd, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN ); CB_NOTIFY( lphc, CBN_CLOSEUP ); } } } /*********************************************************************** * COMBO_FlipListbox * * Used by the ComboLBox to show/hide itself in response to VK_F4, etc... */ BOOL32 COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL32 bRedrawButton ) { if( lphc->wState & CBF_DROPPED ) { CBRollUp( lphc, TRUE, bRedrawButton ); return FALSE; } CBDropDown( lphc ); return TRUE; } /*********************************************************************** * COMBO_GetLBWindow * * Edit control helper. */ HWND32 COMBO_GetLBWindow( WND* pWnd ) { LPHEADCOMBO lphc = CB_GETPTR(pWnd); if( lphc ) return lphc->hWndLBox; return 0; } /*********************************************************************** * CBRepaintButton */ static void CBRepaintButton( LPHEADCOMBO lphc ) { HDC32 hDC = GetDC32( lphc->self->hwndSelf ); if( hDC ) { CBPaintButton( lphc, hDC ); ReleaseDC32( lphc->self->hwndSelf, hDC ); } } /*********************************************************************** * COMBO_SetFocus */ static void COMBO_SetFocus( LPHEADCOMBO lphc ) { if( !(lphc->wState & CBF_FOCUSED) ) { if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 ); if( lphc->wState & CBF_EDIT ) SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) ); lphc->wState |= CBF_FOCUSED; if( !(lphc->wState & CBF_EDIT) ) CBPaintText( lphc, 0 ); CB_NOTIFY( lphc, CBN_SETFOCUS ); } } /*********************************************************************** * COMBO_KillFocus */ static void COMBO_KillFocus( LPHEADCOMBO lphc ) { HWND32 hWnd = lphc->self->hwndSelf; if( lphc->wState & CBF_FOCUSED ) { SendMessage32A( hWnd, WM_LBUTTONUP, 0, (LPARAM)(-1) ); CBRollUp( lphc, FALSE, TRUE ); if( IsWindow32( hWnd ) ) { if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) SendMessage32A( lphc->hWndLBox, LB_CARETOFF32, 0, 0 ); lphc->wState &= ~CBF_FOCUSED; /* redraw text */ if( lphc->wState & CBF_EDIT ) SendMessage32A( lphc->hWndEdit, EM_SETSEL32, (WPARAM32)(-1), 0 ); else CBPaintText( lphc, 0 ); CB_NOTIFY( lphc, CBN_KILLFOCUS ); } } } /*********************************************************************** * COMBO_Command */ static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM32 wParam, HWND32 hWnd ) { if( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd ) { /* ">> 8" makes gcc generate jump-table instead of cmp ladder */ switch( HIWORD(wParam) >> 8 ) { case (EN_SETFOCUS >> 8): TRACE(combo,"[%04x]: edit [%04x] got focus\n", CB_HWND(lphc), lphc->hWndEdit ); if( !(lphc->wState & CBF_FOCUSED) ) COMBO_SetFocus( lphc ); break; case (EN_KILLFOCUS >> 8): TRACE(combo,"[%04x]: edit [%04x] lost focus\n", CB_HWND(lphc), lphc->hWndEdit ); /* NOTE: it seems that Windows' edit control sends an * undocumented message WM_USER + 0x1B instead of this * notification (only when it happens to be a part of * the combo). ?? - AK. */ COMBO_KillFocus( lphc ); break; case (EN_CHANGE >> 8): CB_NOTIFY( lphc, CBN_EDITCHANGE ); CBUpdateLBox( lphc ); break; case (EN_UPDATE >> 8): CB_NOTIFY( lphc, CBN_EDITUPDATE ); break; case (EN_ERRSPACE >> 8): CB_NOTIFY( lphc, CBN_ERRSPACE ); } } else if( lphc->hWndLBox == hWnd ) { switch( 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(combo,"[%04x]: lbox selection change [%04x]\n", CB_HWND(lphc), lphc->wState ); /* 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 ); CBPaintText( lphc, 0 ); /* 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_ItemOp32( LPHEADCOMBO lphc, UINT32 msg, WPARAM32 wParam, LPARAM lParam ) { HWND32 hWnd = lphc->self->hwndSelf; TRACE(combo,"[%04x]: ownerdraw op %04x\n", CB_HWND(lphc), msg ); #define lpIS ((LPDELETEITEMSTRUCT32)lParam) /* two first items are the same in all 4 structs */ lpIS->CtlType = ODT_COMBOBOX; lpIS->CtlID = lphc->self->wIDmenu; switch( msg ) /* patch window handle */ { case WM_DELETEITEM: lpIS->hwndItem = hWnd; #undef lpIS break; case WM_DRAWITEM: #define lpIS ((LPDRAWITEMSTRUCT32)lParam) lpIS->hwndItem = hWnd; #undef lpIS break; case WM_COMPAREITEM: #define lpIS ((LPCOMPAREITEMSTRUCT32)lParam) lpIS->hwndItem = hWnd; #undef lpIS break; } return SendMessage32A( lphc->owner, msg, lphc->self->wIDmenu, lParam ); } /*********************************************************************** * COMBO_GetText */ static LRESULT COMBO_GetText( LPHEADCOMBO lphc, UINT32 N, LPSTR lpText) { if( lphc->wState & CBF_EDIT ) return SendMessage32A( lphc->hWndEdit, WM_GETTEXT, (WPARAM32)N, (LPARAM)lpText ); /* get it from the listbox */ if( lphc->hWndLBox ) { INT32 idx = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 ); if( idx != LB_ERR ) { LPSTR lpBuffer; INT32 length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, (WPARAM32)idx, 0 ); /* 'length' is without the terminating character */ if( length >= N ) lpBuffer = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1 ); else lpBuffer = lpText; if( lpBuffer ) { INT32 n = SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, (WPARAM32)idx, (LPARAM)lpBuffer ); /* truncate if buffer is too short */ if( length >= N ) { if (N && lpText) { if( n != LB_ERR ) memcpy( lpText, lpBuffer, (N>n) ? n+1 : N-1 ); lpText[N - 1] = '\0'; } HeapFree( GetProcessHeap(), 0, lpBuffer ); } return (LRESULT)n; } } } return 0; } /*********************************************************************** * CBResetPos * * This function sets window positions according to the updated * component placement struct. */ static void CBResetPos( LPHEADCOMBO lphc, LPRECT32 lbRect, BOOL32 bRedraw ) { BOOL32 bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE); /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of * sizing messages */ if( lphc->wState & CBF_EDIT ) SetWindowPos32( lphc->hWndEdit, 0, lphc->RectEdit.left, lphc->RectEdit.top, lphc->RectEdit.right - lphc->RectEdit.left, lphc->RectEdit.bottom - lphc->RectEdit.top, SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) ); if( bDrop ) OffsetRect32( lbRect, lphc->RectCombo.left, lphc->RectCombo.top ); lbRect->right -= lbRect->left; /* convert to width */ lbRect->bottom -= lbRect->top; SetWindowPos32( lphc->hWndLBox, 0, lbRect->left, lbRect->top, lbRect->right, lbRect->bottom, SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) ); if( bDrop ) { if( lphc->wState & CBF_DROPPED ) { lphc->wState &= ~CBF_DROPPED; ShowWindow32( lphc->hWndLBox, SW_HIDE ); } lphc->wState |= CBF_NORESIZE; SetWindowPos32( lphc->self->hwndSelf, 0, 0, 0, lphc->RectCombo.right - lphc->RectCombo.left, lphc->RectEdit.bottom - lphc->RectEdit.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW ); lphc->wState &= ~CBF_NORESIZE; if( bRedraw && !(lphc->wState & CBF_NOREDRAW) ) RedrawWindow32( lphc->self->hwndSelf, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW ); } } /*********************************************************************** * COMBO_Size */ static void COMBO_Size( LPHEADCOMBO lphc ) { RECT32 rect; INT32 w, h; GetWindowRect32( lphc->self->hwndSelf, &rect ); w = rect.right - rect.left; h = rect.bottom - rect.top; TRACE(combo,"w = %i, h = %i\n", w, h ); /* CreateWindow() may send a bogus WM_SIZE, ignore it */ if( w == (lphc->RectCombo.right - lphc->RectCombo.left) ) { if( (CB_GETTYPE(lphc) == CBS_SIMPLE) && (h == (lphc->RectCombo.bottom - lphc->RectCombo.top)) ) return; else if( (lphc->dwStyle & CBS_DROPDOWN) && (h == (lphc->RectEdit.bottom - lphc->RectEdit.top)) ) return; } lphc->RectCombo = rect; CBCalcPlacement( lphc, &lphc->RectEdit, &lphc->RectButton, &rect ); CBResetPos( lphc, &rect, TRUE ); } /*********************************************************************** * COMBO_Font */ static void COMBO_Font( LPHEADCOMBO lphc, HFONT32 hFont, BOOL32 bRedraw ) { RECT32 rect; lphc->hFont = hFont; if( lphc->wState & CBF_EDIT ) SendMessage32A( lphc->hWndEdit, WM_SETFONT, (WPARAM32)hFont, bRedraw ); SendMessage32A( lphc->hWndLBox, WM_SETFONT, (WPARAM32)hFont, bRedraw ); GetWindowRect32( lphc->self->hwndSelf, &rect ); OffsetRect32( &lphc->RectCombo, rect.left - lphc->RectCombo.left, rect.top - lphc->RectCombo.top ); CBCalcPlacement( lphc, &lphc->RectEdit, &lphc->RectButton, &rect ); CBResetPos( lphc, &rect, bRedraw ); } /*********************************************************************** * COMBO_SetItemHeight */ static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT32 index, INT32 height ) { LRESULT lRet = CB_ERR; if( index == -1 ) /* set text field height */ { if( height < 32768 ) { RECT32 rect; lphc->editHeight = height; GetWindowRect32( lphc->self->hwndSelf, &rect ); OffsetRect32( &lphc->RectCombo, rect.left - lphc->RectCombo.left, rect.top - lphc->RectCombo.top ); CBCalcPlacement( lphc, &lphc->RectEdit, &lphc->RectButton, &rect ); CBResetPos( lphc, &rect, TRUE ); lRet = height; } } else if ( CB_OWNERDRAWN(lphc) ) /* set listbox item height */ lRet = SendMessage32A( lphc->hWndLBox, LB_SETITEMHEIGHT32, (WPARAM32)index, (LPARAM)height ); return lRet; } /*********************************************************************** * COMBO_SelectString */ static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT32 start, LPCSTR pText ) { INT32 index = SendMessage32A( lphc->hWndLBox, LB_SELECTSTRING32, (WPARAM32)start, (LPARAM)pText ); if( index >= 0 ) { if( lphc->wState & CBF_EDIT ) CBUpdateEdit( lphc, index ); else CBPaintText( lphc, 0 ); } return (LRESULT)index; } /*********************************************************************** * COMBO_LButtonDown */ static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam ) { POINT32 pt = { LOWORD(lParam), HIWORD(lParam) }; BOOL32 bButton = PtInRect32(&lphc->RectButton, pt); HWND32 hWnd = lphc->self->hwndSelf; 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 */ CBRollUp( lphc, TRUE, FALSE ); if( !IsWindow32( hWnd ) ) return; if( lphc->wState & CBF_CAPTURE ) { lphc->wState &= ~CBF_CAPTURE; ReleaseCapture(); } lphc->wState &= ~CBF_BUTTONDOWN; } else { /* drop down the listbox and start tracking */ lphc->wState |= CBF_CAPTURE; CBDropDown( lphc ); SetCapture32( hWnd ); } if( bButton ) CBRepaintButton( lphc ); } } /*********************************************************************** * COMBO_LButtonUp * * Release capture and stop tracking if needed. */ static void COMBO_LButtonUp( LPHEADCOMBO lphc, LPARAM lParam ) { if( lphc->wState & CBF_CAPTURE ) { lphc->wState &= ~CBF_CAPTURE; if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) { INT32 index = CBUpdateLBox( lphc ); CBUpdateEdit( lphc, index ); } ReleaseCapture(); } if( lphc->wState & CBF_BUTTONDOWN ) { lphc->wState &= ~CBF_BUTTONDOWN; CBRepaintButton( lphc ); } } /*********************************************************************** * COMBO_MouseMove * * Two things to do - track combo button and release capture when * pointer goes into the listbox. */ static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM32 wParam, LPARAM lParam ) { POINT32 pt = { LOWORD(lParam), HIWORD(lParam) }; RECT32 lbRect; if( lphc->wState & CBF_BUTTONDOWN ) { BOOL32 bButton = PtInRect32(&lphc->RectButton, pt); if( !bButton ) { lphc->wState &= ~CBF_BUTTONDOWN; CBRepaintButton( lphc ); } } GetClientRect32( lphc->hWndLBox, &lbRect ); MapWindowPoints32( lphc->self->hwndSelf, lphc->hWndLBox, &pt, 1 ); if( PtInRect32(&lbRect, pt) ) { lphc->wState &= ~CBF_CAPTURE; ReleaseCapture(); if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc ); /* hand over pointer tracking */ SendMessage32A( lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam ); } } /*********************************************************************** * ComboWndProc * * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm */ LRESULT WINAPI ComboWndProc( HWND32 hwnd, UINT32 message, WPARAM32 wParam, LPARAM lParam ) { WND* pWnd = WIN_FindWndPtr(hwnd); if( pWnd ) { LPHEADCOMBO lphc = CB_GETPTR(pWnd); TRACE(combo, "[%04x]: msg %s wp %08x lp %08lx\n", pWnd->hwndSelf, SPY_GetMsgName(message), wParam, lParam ); if( lphc || message == WM_NCCREATE ) switch(message) { /* System messages */ case WM_NCCREATE: return COMBO_NCCreate(pWnd, lParam); case WM_NCDESTROY: COMBO_NCDestroy(lphc); break; case WM_CREATE: return COMBO_Create(lphc, pWnd, lParam); case WM_PAINT: /* wParam may contain a valid HDC! */ return COMBO_Paint(lphc, wParam); case WM_ERASEBKGND: return TRUE; case WM_GETDLGCODE: return (LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS); case WM_SIZE: if( lphc->hWndLBox && !(lphc->wState & CBF_NORESIZE) ) COMBO_Size( lphc ); return TRUE; case WM_SETFONT: COMBO_Font( lphc, (HFONT16)wParam, (BOOL32)lParam ); return TRUE; case WM_GETFONT: return (LRESULT)lphc->hFont; case WM_SETFOCUS: if( lphc->wState & CBF_EDIT ) SetFocus32( lphc->hWndEdit ); else COMBO_SetFocus( lphc ); return TRUE; case WM_KILLFOCUS: #define hwndFocus ((HWND16)wParam) if( !hwndFocus || (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox )) COMBO_KillFocus( lphc ); #undef hwndFocus return TRUE; case WM_COMMAND: return COMBO_Command( lphc, wParam, (HWND32)lParam ); case WM_GETTEXT: return COMBO_GetText( lphc, (UINT32)wParam, (LPSTR)lParam ); case WM_SETTEXT: case WM_GETTEXTLENGTH: case WM_CLEAR: case WM_CUT: case WM_PASTE: case WM_COPY: if( lphc->wState & CBF_EDIT ) return SendMessage32A( lphc->hWndEdit, message, wParam, lParam ); return CB_ERR; case WM_DRAWITEM: case WM_DELETEITEM: case WM_COMPAREITEM: case WM_MEASUREITEM: return COMBO_ItemOp32( lphc, message, wParam, lParam ); case WM_ENABLE: if( lphc->wState & CBF_EDIT ) EnableWindow32( lphc->hWndEdit, (BOOL32)wParam ); EnableWindow32( lphc->hWndLBox, (BOOL32)wParam ); return TRUE; case WM_SETREDRAW: if( wParam ) lphc->wState &= ~CBF_NOREDRAW; else lphc->wState |= CBF_NOREDRAW; if( lphc->wState & CBF_EDIT ) SendMessage32A( lphc->hWndEdit, message, wParam, lParam ); SendMessage32A( lphc->hWndLBox, message, wParam, lParam ); return 0; case WM_SYSKEYDOWN: if( KEYDATA_ALT & HIWORD(lParam) ) if( wParam == VK_UP || wParam == VK_DOWN ) COMBO_FlipListbox( lphc, TRUE ); break; case WM_CHAR: case WM_KEYDOWN: if( lphc->wState & CBF_EDIT ) return SendMessage32A( lphc->hWndEdit, message, wParam, lParam ); else return SendMessage32A( lphc->hWndLBox, message, wParam, lParam ); case WM_LBUTTONDOWN: if( !(lphc->wState & CBF_FOCUSED) ) SetFocus32( lphc->self->hwndSelf ); if( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam ); return TRUE; case WM_LBUTTONUP: COMBO_LButtonUp( lphc, lParam ); return TRUE; case WM_MOUSEMOVE: if( lphc->wState & CBF_CAPTURE ) COMBO_MouseMove( lphc, wParam, lParam ); return TRUE; /* Combo messages */ case CB_ADDSTRING16: if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam); case CB_ADDSTRING32: return SendMessage32A( lphc->hWndLBox, LB_ADDSTRING32, 0, lParam); case CB_INSERTSTRING16: wParam = (INT32)(INT16)wParam; if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam); case CB_INSERTSTRING32: return SendMessage32A( lphc->hWndLBox, LB_INSERTSTRING32, wParam, lParam); case CB_DELETESTRING16: case CB_DELETESTRING32: return SendMessage32A( lphc->hWndLBox, LB_DELETESTRING32, wParam, 0); case CB_SELECTSTRING16: wParam = (INT32)(INT16)wParam; if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam); case CB_SELECTSTRING32: return COMBO_SelectString( lphc, (INT32)wParam, (LPSTR)lParam ); case CB_FINDSTRING16: wParam = (INT32)(INT16)wParam; if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam); case CB_FINDSTRING32: return SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32, wParam, lParam); case CB_FINDSTRINGEXACT16: wParam = (INT32)(INT16)wParam; if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam); case CB_FINDSTRINGEXACT32: return SendMessage32A( lphc->hWndLBox, LB_FINDSTRINGEXACT32, wParam, lParam ); case CB_SETITEMHEIGHT16: wParam = (INT32)(INT16)wParam; /* signed integer */ case CB_SETITEMHEIGHT32: return COMBO_SetItemHeight( lphc, (INT32)wParam, (INT32)lParam); case CB_GETITEMHEIGHT16: wParam = (INT32)(INT16)wParam; case CB_GETITEMHEIGHT32: if( (INT32)wParam >= 0 ) /* listbox item */ return SendMessage32A( lphc->hWndLBox, LB_GETITEMHEIGHT32, wParam, 0); return (lphc->RectEdit.bottom - lphc->RectEdit.top); case CB_RESETCONTENT16: case CB_RESETCONTENT32: SendMessage32A( lphc->hWndLBox, LB_RESETCONTENT32, 0, 0 ); CBPaintText( lphc, 0 ); return TRUE; case CB_INITSTORAGE32: return SendMessage32A( lphc->hWndLBox, LB_INITSTORAGE32, wParam, lParam); case CB_GETHORIZONTALEXTENT32: return SendMessage32A( lphc->hWndLBox, LB_GETHORIZONTALEXTENT32, 0, 0); case CB_SETHORIZONTALEXTENT32: return SendMessage32A( lphc->hWndLBox, LB_SETHORIZONTALEXTENT32, wParam, 0); case CB_GETTOPINDEX32: return SendMessage32A( lphc->hWndLBox, LB_GETTOPINDEX32, 0, 0); case CB_GETLOCALE32: return SendMessage32A( lphc->hWndLBox, LB_GETLOCALE32, 0, 0); case CB_SETLOCALE32: return SendMessage32A( lphc->hWndLBox, LB_SETLOCALE32, wParam, 0); case CB_GETDROPPEDWIDTH32: if( lphc->droppedWidth ) return lphc->droppedWidth; return lphc->RectCombo.right - lphc->RectCombo.left - (lphc->wState & CBF_EDIT) ? CBitOffset : 0; case CB_SETDROPPEDWIDTH32: if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && (INT32)wParam < 32768 ) lphc->droppedWidth = (INT32)wParam; return CB_ERR; case CB_GETDROPPEDCONTROLRECT16: lParam = (LPARAM)PTR_SEG_TO_LIN(lParam); if( lParam ) { RECT32 r; CBGetDroppedControlRect32( lphc, &r ); CONV_RECT32TO16( &r, (LPRECT16)lParam ); } return CB_OKAY; case CB_GETDROPPEDCONTROLRECT32: if( lParam ) CBGetDroppedControlRect32(lphc, (LPRECT32)lParam ); return CB_OKAY; case CB_GETDROPPEDSTATE16: case CB_GETDROPPEDSTATE32: return (lphc->wState & CBF_DROPPED) ? TRUE : FALSE; case CB_DIR16: lParam = (LPARAM)PTR_SEG_TO_LIN(lParam); /* fall through */ case CB_DIR32: return COMBO_Directory( lphc, (UINT32)wParam, (LPSTR)lParam, (message == CB_DIR32)); case CB_SHOWDROPDOWN16: case CB_SHOWDROPDOWN32: if( CB_GETTYPE(lphc) != CBS_SIMPLE ) { if( wParam ) { if( !(lphc->wState & CBF_DROPPED) ) CBDropDown( lphc ); } else if( lphc->wState & CBF_DROPPED ) CBRollUp( lphc, FALSE, TRUE ); } return TRUE; case CB_GETCOUNT16: case CB_GETCOUNT32: return SendMessage32A( lphc->hWndLBox, LB_GETCOUNT32, 0, 0); case CB_GETCURSEL16: case CB_GETCURSEL32: return SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0); case CB_SETCURSEL16: wParam = (INT32)(INT16)wParam; case CB_SETCURSEL32: return SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, wParam, 0); case CB_GETLBTEXT16: wParam = (INT32)(INT16)wParam; lParam = (LPARAM)PTR_SEG_TO_LIN(lParam); case CB_GETLBTEXT32: return SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, wParam, lParam); case CB_GETLBTEXTLEN16: wParam = (INT32)(INT16)wParam; case CB_GETLBTEXTLEN32: return SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, wParam, 0); case CB_GETITEMDATA16: wParam = (INT32)(INT16)wParam; case CB_GETITEMDATA32: return SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32, wParam, 0); case CB_SETITEMDATA16: wParam = (INT32)(INT16)wParam; case CB_SETITEMDATA32: return SendMessage32A( lphc->hWndLBox, LB_SETITEMDATA32, wParam, lParam); case CB_GETEDITSEL16: wParam = lParam = 0; /* just in case */ case CB_GETEDITSEL32: if( lphc->wState & CBF_EDIT ) { INT32 a, b; return SendMessage32A( lphc->hWndEdit, EM_GETSEL32, (wParam) ? wParam : (WPARAM32)&a, (lParam) ? lParam : (LPARAM)&b ); } return CB_ERR; case CB_SETEDITSEL16: case CB_SETEDITSEL32: if( lphc->wState & CBF_EDIT ) return SendMessage32A( lphc->hWndEdit, EM_SETSEL32, (INT32)(INT16)LOWORD(lParam), (INT32)(INT16)HIWORD(lParam) ); return CB_ERR; case CB_SETEXTENDEDUI16: case CB_SETEXTENDEDUI32: if( CB_GETTYPE(lphc) == CBS_SIMPLE ) return CB_ERR; if( wParam ) lphc->wState |= CBF_EUI; else lphc->wState &= ~CBF_EUI; return CB_OKAY; case CB_GETEXTENDEDUI16: case CB_GETEXTENDEDUI32: return (lphc->wState & CBF_EUI) ? TRUE : FALSE; case (WM_USER + 0x1B): WARN(combo, "[%04x]: undocumented msg!\n", hwnd ); } return DefWindowProc32A(hwnd, message, wParam, lParam); } return CB_ERR; }