wine/controls/combo.c
Alexandre Julliard a69b88b2f2 Release 980315
Sun Mar 15 03:46:50 1998  Dimitrie O. Paun  <dimi@mail.cs.toronto.edu>

	* [*/*]
	Fixed some dprintf_ such that there is one and only one
	new line for each dprintf and that new line occurs at the end.
	Transformed some fprintfs into proper debug statements.
	Removed much redundancy from most of the debug statements. The
	redundancy appeared because now the component and function
	name is output automatically. Most debug statements also used to
	output the name of the function.
	All these changes prepared the source to switch completely to
	the new debugging interface.
	For more info, refer to ./documentation/debug-msg

Sat Mar 14 19:45:23 1997  Andreas Mohr <100.30936@germany.net>

	* [misc/shell.c] [if1632/kernel.spec]
	Changed parameters of FUNC004() to fix a crash.
	Not sure if this fix is correct (doc wanted).

	* [windows/user.c] [if1632/user.spec] [include/user.h]
	Implemented UserSeeUserDo.

	* [msdos/int21.c] [include/msdos.h]
	Added "GET LIST OF LISTS" (INT 21/52h).

Sat Mar 14 15:48:02 1998  Douglas Ridgway <ridgway@gmcl.com>

	* [include/windows.h] [relay32/gdi32.spec] [objects/enhmetafile.c]
	Beginnings of enhanced metafile support.

Fri Mar 13 20:53:09 1998  John Richardson <jrichard@zko.dec.com>

	* [win32/console.c]
	Restart interrupted console writes.

Fri Mar 13 18:59:24 1998  Matthew Becker <mbecker@glasscity.net>

	* [*/*.c]
	Updated documentation for API manpages.

	* [windows/dce.c]
	ReleaseDC16: Fixed cast.

	* [include/windows.h] [memory/virtual.c]
	VirtualQuery{Ex} should return DWORD instead of BOOL32.

Fri Mar 13 13:03:06 1998  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>

	* [README][documentation/status/]
	README updated, added lzexpand,version and multimedia
	status notes to new documentation/status directory.

	* [ole/*.c][if1632/typelib.spec]
	Added typelib stubs, several small additions and fixes.

	* [loader/pe_image.c]
	Fixed a small bug (fixup_imports got passed the wrong hModule in a
	remapcase).

	* [loader/signal.c][if1632/signal.c][misc/winsock_dns.c]
	  [loader/module.c]
	Fixed some recursive debugger crashes (caused by invalid FS).

	* [misc/registry.c]
	Two bugs fixed.

Fri Mar 13 04:55:01 1998  David Lee Lambert <lamber45@egr.msu.edu>

	* [include/winnt.h] [include/winnls.h]
	Moved LANG_xxx flags to winnls.h

	* [include/winnls.h]
	Added flags for GetDateFormat(); fixed validity of
	LOCALE_SYSTEM_DEFAULT.

	* [include/windows.h] 
	Added GetTimeFormat() prototypes.

	* [ole/ole2nls.c]
	Implemented ASCII date- and time-functions,  using an
	optimized common core;  added stubs for Unicode versions;  
	started work on a Unicode core.

	* [AUTHORS]
	Added my name.

Mon Mar  9 20:10:15 1998  Eric Kohl <ekohl@abo.rhein-zeitung.de>

	* [relay32/comctl32.spec] [include/imagelist.h]
	  [include/commctrl.h] [misc/imagelist.c] [misc/Makefile.in]
	First attempt at implementing ImageLists.

Sun Mar  8 20:19:49 1998  Uwe Bonnes  <bon@elektron.ikp.physik.tu-darmstadt.de>

	* [files/dos_fs.c] [configure.in]
	Try to get FileTimeToLocalFileTime,FileTimeToSystemTime and
	SystemTimeToFileTime right.
	Use timegm() where available.

	* [misc/lstr.c]
	Fix an off by one error in FormatMessage and handle the case 
	when args = NULL (used by programs to get the length of the 
	string).

	* [win32/console.c]
	Actual display a per-process Title string, better working
	attempt for WriteConsole32W and ReadConsole32W.

Fri Mar  6 20:33:45 1998  Slaven Rezic  <eserte@cs.tu-berlin.de>

	* [include/config.h.in][configure.in][multimedia/audio.c]
	  [multimedia/dsound.c]
	Added check for FreeBSD sound system.

Sun Mar  1 17:40:10 1998  Jason Schonberg <schon@mti.sgi.com>

	* [controls/edit.c] [include/ole.h] [include/shlobj.h]
	Removed final commas in enum types.

Mon Feb 23 07:52:18 1998  Luiz Otavio L. Zorzella  <zorzella@nr.conexware.com>

	* [multimedia/time.c]
	Workaround to avoid infinite recursion inside timeGetTime.

	* [multimedia/audio.c]
	WODM_GETNUMDEVS and WIDM_GETNUMDEVS only return 1 now if the
	SOUND_DEV can be opened, or if it's busy.
1998-03-15 20:29:56 +00:00

1574 lines
44 KiB
C

/*
* Combo controls
*
* Copyright 1997 Alex Korobka
*
* FIXME: roll up in Netscape 3.01.
*/
#include <stdio.h>
#include <string.h>
#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 HBITMAP16 hComboBmp = 0;
static UINT16 CBitHeight, CBitWidth;
static UINT16 CBitOffset = 8;
/***********************************************************************
* COMBO_Init
*
* Load combo button bitmap.
*/
static BOOL32 COMBO_Init()
{
HDC16 hDC;
if( hComboBmp ) return TRUE;
if( (hDC = CreateCompatibleDC16(0)) )
{
BOOL32 bRet = FALSE;
if( (hComboBmp = LoadBitmap16(0, MAKEINTRESOURCE(OBM_COMBO))) )
{
BITMAP16 bm;
HBITMAP16 hPrevB;
RECT16 r;
GetObject16( hComboBmp, sizeof(bm), &bm );
CBitHeight = bm.bmHeight;
CBitWidth = bm.bmWidth;
TRACE(combo, "combo bitmap [%i,%i]\n", CBitWidth, CBitHeight );
hPrevB = SelectObject16( hDC, hComboBmp);
SetRect16( &r, 0, 0, CBitWidth, CBitHeight );
InvertRect16( hDC, &r );
SelectObject16( hDC, hPrevB );
bRet = TRUE;
}
DeleteDC16( 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;
}
/***********************************************************************
* CBCalcPlacement
*
* Set up component coordinates given valid lphc->RectCombo.
*/
static void CBCalcPlacement( LPHEADCOMBO lphc,
LPRECT16 lprEdit, LPRECT16 lprButton, LPRECT16 lprLB )
{
RECT16 rect = lphc->RectCombo;
SIZE16 size;
/* get combo height and width */
if( lphc->editHeight )
size.cy = (INT16)lphc->editHeight;
else
{
HDC16 hDC = GetDC16( lphc->self->hwndSelf );
HFONT16 hPrevFont = (HFONT16)0;
if( lphc->hFont ) hPrevFont = SelectObject16( hDC, lphc->hFont );
GetTextExtentPoint16( hDC, "0", 1, &size);
size.cy += size.cy / 4 + 4 * SYSMETRICS_CYBORDER;
if( hPrevFont ) SelectObject16( hDC, hPrevFont );
ReleaseDC16( lphc->self->hwndSelf, hDC );
}
size.cx = rect.right - rect.left;
if( CB_OWNERDRAWN(lphc) )
{
UINT16 u = lphc->RectEdit.bottom - lphc->RectEdit.top;
if( lphc->wState & CBF_MEASUREITEM ) /* first initialization */
{
MEASUREITEMSTRUCT32 mi32;
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;
}
size.cy = u;
}
/* 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 = (INT16)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 + (INT16)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;
RECT16 editRect, btnRect, lbRect;
GetWindowRect16( 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;
OffsetRect16( &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, HDC16 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, HDC16 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 );
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;
UINT16 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 );
}
}
}
HeapFree( GetProcessHeap(), 0, pText );
}
/***********************************************************************
* COMBO_Paint
*/
static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC16 hParamDC)
{
PAINTSTRUCT16 ps;
HDC16 hDC;
hDC = (hParamDC) ? hParamDC
: BeginPaint16( 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( !IsRectEmpty16(&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 ) EndPaint16(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;
RECT16 rect;
LPRECT16 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 */
GetWindowRect16( 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 )
RedrawWindow16( 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 )
{
RECT16 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 )
UnionRect16( &rect, &lphc->RectButton,
&lphc->RectEdit );
else
rect = lphc->RectEdit;
bButton = TRUE;
}
if( bButton && !(lphc->wState & CBF_NOREDRAW) )
RedrawWindow16( 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, (HDC16)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), (HWND16)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), (HWND16)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), (UINT16)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)lpText );
/* truncate if buffer is too short */
if( length >= N )
{
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, LPRECT16 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 )
OffsetRect16( 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 )
{
RECT16 rect;
INT16 w, h;
GetWindowRect16( 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, HFONT16 hFont, BOOL32 bRedraw )
{
RECT16 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 );
GetWindowRect16( lphc->self->hwndSelf, &rect );
OffsetRect16( &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 )
{
RECT16 rect;
lphc->editHeight = height;
GetWindowRect16( lphc->self->hwndSelf, &rect );
OffsetRect16( &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 )
{
BOOL32 bButton = PtInRect16(&lphc->RectButton, MAKEPOINT16(lParam));
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 )
{
RECT16 lbRect;
if( lphc->wState & CBF_BUTTONDOWN )
{
BOOL32 bButton = PtInRect16(&lphc->RectButton, MAKEPOINT16(lParam));
if( !bButton )
{
lphc->wState &= ~CBF_BUTTONDOWN;
CBRepaintButton( lphc );
}
}
GetClientRect16( lphc->hWndLBox, &lbRect );
MapWindowPoints16( lphc->self->hwndSelf,
lphc->hWndLBox, (LPPOINT16)&lParam, 1 );
if( PtInRect16(&lbRect, MAKEPOINT16(lParam)) )
{
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, (HDC16)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;
case CB_SETITEMHEIGHT32:
return COMBO_SetItemHeight( lphc, (INT32)wParam, (INT32)lParam);
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", (HWND16)hwnd );
}
return DefWindowProc32A(hwnd, message, wParam, lParam);
}
return CB_ERR;
}