Release 960314
[wine/multimedia.git] / controls / combo.c
blob338c0c8887c8676d73ba7ae99934c6aa033966e0
1 /*
2 * Combo controls
3 *
4 * Copyright 1993 Martin Ayotte
5 * Copyright 1995 Bernd Schmidt
6 *
7 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
14 #include "windows.h"
15 #include "sysmetrics.h"
16 #include "combo.h"
17 #include "stackframe.h"
18 #include "user.h"
19 #include "win.h"
20 #include "graphics.h"
21 #include "listbox.h"
22 #include "dos_fs.h"
23 #include "drive.h"
24 #include "stddebug.h"
25 #include "debug.h"
26 #include "xmalloc.h"
29 * Note: Combos are probably implemented in a different way by Windows.
30 * Using a message spy for Windows, you can see some undocumented
31 * messages being passed between ComboBox and ComboLBox.
32 * I hope no programs rely on the implementation of combos.
35 #define CBLMM_EDGE 4 /* distance inside box which is same as moving mouse
36 outside box, to trigger scrolling of CBL */
38 static HBITMAP hComboBit = 0;
39 static WORD CBitHeight, CBitWidth;
41 static int COMBO_Init()
43 BITMAP bm;
45 dprintf_combo(stddeb, "COMBO_Init\n");
46 hComboBit = LoadBitmap(0, MAKEINTRESOURCE(OBM_COMBO));
47 GetObject(hComboBit, sizeof(BITMAP), (LPSTR)&bm);
48 CBitHeight = bm.bmHeight;
49 CBitWidth = bm.bmWidth;
50 return 0;
53 LPHEADCOMBO ComboGetStorageHeader(HWND hwnd)
55 return (LPHEADCOMBO)GetWindowLong(hwnd,4);
58 LPHEADLIST ComboGetListHeader(HWND hwnd)
60 return (LPHEADLIST)GetWindowLong(hwnd,0);
63 int CreateComboStruct(HWND hwnd, LONG style)
65 LPHEADCOMBO lphc;
67 lphc = (LPHEADCOMBO)xmalloc(sizeof(HEADCOMBO));
68 SetWindowLong(hwnd,4,(LONG)lphc);
69 lphc->hWndEdit = 0;
70 lphc->hWndLBox = 0;
71 lphc->dwState = 0;
72 lphc->LastSel = -1;
73 lphc->dwStyle = style;
74 lphc->DropDownVisible = FALSE;
75 return TRUE;
78 void ComboUpdateWindow(HWND hwnd, LPHEADLIST lphl, LPHEADCOMBO lphc, BOOL repaint)
80 SetScrollRange(lphc->hWndLBox, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
81 if (repaint && lphl->bRedrawFlag) {
82 InvalidateRect(hwnd, NULL, TRUE);
86 /***********************************************************************
87 * CBNCCreate
89 static LRESULT CBNCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
91 CREATESTRUCT *createStruct;
93 if (!hComboBit) COMBO_Init();
95 createStruct = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
96 createStruct->style &= ~(WS_VSCROLL | WS_HSCROLL);
97 SetWindowLong(hwnd, GWL_STYLE, createStruct->style);
99 dprintf_combo(stddeb,"ComboBox WM_NCCREATE!\n");
100 return DefWindowProc(hwnd, WM_NCCREATE, wParam, lParam);
104 /***********************************************************************
105 * CBCreate
107 static LRESULT CBCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
109 LPHEADLIST lphl;
110 LPHEADCOMBO lphc;
111 LONG style = 0;
112 LONG cstyle = GetWindowLong(hwnd,GWL_STYLE);
113 RECT rect,lboxrect;
114 char className[] = "COMBOLBOX"; /* Hack so that class names are > 0x10000 */
115 char editName[] = "EDIT";
117 /* translate combo into listbox styles */
118 if (cstyle & CBS_OWNERDRAWFIXED) style |= LBS_OWNERDRAWFIXED;
119 if (cstyle & CBS_OWNERDRAWVARIABLE) style |= LBS_OWNERDRAWVARIABLE;
120 if (cstyle & CBS_SORT) style |= LBS_SORT;
121 if (cstyle & CBS_HASSTRINGS) style |= LBS_HASSTRINGS;
122 style |= LBS_NOTIFY;
123 CreateListBoxStruct(hwnd, ODT_COMBOBOX, style, GetParent(hwnd));
124 CreateComboStruct(hwnd,cstyle);
125 lphl = ComboGetListHeader(hwnd);
126 lphc = ComboGetStorageHeader(hwnd);
128 GetClientRect(hwnd,&rect);
129 GetWindowRect(hwnd,&lboxrect);
130 /* FIXME: combos with edit controls are broken. */
131 switch(cstyle & 3) {
132 case CBS_SIMPLE: /* edit control, list always visible */
133 dprintf_combo(stddeb,"CBS_SIMPLE\n");
134 SetRectEmpty(&lphc->RectButton);
135 lphc->LBoxTop = lphl->StdItemHeight;
136 lphc->hWndEdit = CreateWindow(MAKE_SEGPTR(editName), (SEGPTR)0,
137 WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | SS_LEFT,
138 0, 0, rect.right, lphl->StdItemHeight,
139 hwnd, (HMENU)1, WIN_GetWindowInstance(hwnd), 0L);
140 break;
141 case CBS_DROPDOWN: /* edit control, dropdown listbox */
142 dprintf_combo(stddeb,"CBS_DROPDOWN\n");
143 lphc->RectButton = rect;
144 lphc->RectButton.left = lphc->RectButton.right - 6 - CBitWidth;
145 lphc->RectButton.bottom = lphc->RectButton.top + lphl->StdItemHeight;
146 lphc->LBoxTop = lphl->StdItemHeight;
147 SetWindowPos(hwnd, 0, 0, 0, rect.right - rect.left + 2*SYSMETRICS_CXBORDER,
148 lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER,
149 SWP_NOMOVE | SWP_NOZORDER);
150 lphc->hWndEdit = CreateWindow(MAKE_SEGPTR(editName), (SEGPTR)0,
151 WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | SS_LEFT,
152 0, 0, lphc->RectButton.left, lphl->StdItemHeight,
153 hwnd, (HMENU)1, WIN_GetWindowInstance(hwnd), 0L);
154 break;
155 case CBS_DROPDOWNLIST: /* static control, dropdown listbox */
156 dprintf_combo(stddeb,"CBS_DROPDOWNLIST\n");
157 lphc->RectButton = rect;
158 lphc->RectButton.left = lphc->RectButton.right - 6 - CBitWidth;
159 lphc->RectButton.bottom = lphc->RectButton.top + lphl->StdItemHeight;
160 lphc->LBoxTop = lphl->StdItemHeight;
161 SetWindowPos(hwnd, 0, 0, 0, rect.right - rect.left + 2*SYSMETRICS_CXBORDER,
162 lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER,
163 SWP_NOMOVE | SWP_NOZORDER);
164 break;
166 lboxrect.top += lphc->LBoxTop;
167 /* FIXME: WinSight says these should be CHILD windows with the TOPMOST flag
168 * set. Wine doesn't support TOPMOST, and simply setting the WS_CHILD
169 * flag doesn't work. */
170 lphc->hWndLBox = CreateWindow(MAKE_SEGPTR(className), (SEGPTR)0,
171 WS_POPUP | WS_BORDER | WS_VSCROLL,
172 lboxrect.left, lboxrect.top,
173 lboxrect.right - lboxrect.left,
174 lboxrect.bottom - lboxrect.top,
175 0, 0, WIN_GetWindowInstance(hwnd),
176 (SEGPTR)hwnd );
177 ShowWindow(lphc->hWndLBox, SW_HIDE);
178 dprintf_combo(stddeb,"Combo Creation LBox="NPFMT"!\n", lphc->hWndLBox);
179 return 0;
182 /***********************************************************************
183 * CBDestroy
185 static LRESULT CBDestroy(HWND hwnd, WPARAM wParam, LPARAM lParam)
187 LPHEADLIST lphl = ComboGetListHeader(hwnd);
189 ListBoxResetContent(lphl);
190 DestroyListBoxStruct(lphl);
191 dprintf_combo(stddeb,"Combo WM_DESTROY %p !\n", lphl);
192 return 0;
195 /***********************************************************************
196 * CBPaint
198 static LRESULT CBPaint(HWND hwnd, WPARAM wParam, LPARAM lParam)
200 LPHEADLIST lphl = ComboGetListHeader(hwnd);
201 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
202 LPLISTSTRUCT lpls;
203 PAINTSTRUCT ps;
204 HBRUSH hBrush;
205 HFONT hOldFont;
206 HDC hdc;
207 RECT rect;
208 int height;
210 hdc = BeginPaint(hwnd, &ps);
212 if (hComboBit != 0) {
213 GRAPH_DrawReliefRect(hdc, &lphc->RectButton, 2, 2, FALSE);
214 GRAPH_DrawBitmap(hdc, hComboBit,
215 lphc->RectButton.left + 3,lphc->RectButton.top + 2,
216 0, 0, CBitWidth, CBitHeight );
218 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag
219 || (lphc->dwStyle & 3) != CBS_DROPDOWNLIST)
221 /* we don't want to draw an entry when there is an edit control */
222 EndPaint(hwnd, &ps);
223 return 0;
226 hOldFont = SelectObject(hdc, lphl->hFont);
228 #ifdef WINELIB32
229 hBrush = (HBRUSH) SendMessage(lphl->hParent, WM_CTLCOLORLISTBOX, (WPARAM)hdc,
230 (LPARAM)hwnd);
231 #else
232 hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
233 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
234 #endif
235 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
237 GetClientRect(hwnd, &rect);
238 rect.right -= (lphc->RectButton.right - lphc->RectButton.left);
239 FillRect(hdc, &rect, hBrush);
241 lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
242 if (lpls != NULL) {
243 height = lpls->mis.itemHeight;
244 rect.bottom = rect.top + height;
246 if (lphl->OwnerDrawn) {
247 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
248 } else {
249 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
251 if (GetFocus() == hwnd)
252 ListBoxDrawItem (hwnd,lphl, hdc, lpls, &rect, ODA_FOCUS, ODS_FOCUS);
254 SelectObject(hdc,hOldFont);
255 EndPaint(hwnd, &ps);
256 return 0;
259 /***********************************************************************
260 * CBGetDlgCode
262 static LRESULT CBGetDlgCode(HWND hwnd, WPARAM wParam, LPARAM lParam)
264 return DLGC_WANTARROWS | DLGC_WANTCHARS;
267 /***********************************************************************
268 * CBLButtonDown
270 static LRESULT CBLButtonDown(HWND hwnd, WPARAM wParam, LPARAM lParam)
272 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
273 SendMessage(hwnd,CB_SHOWDROPDOWN,!lphc->DropDownVisible,0);
274 return 0;
277 /***********************************************************************
278 * CBKeyDown
280 static LRESULT CBKeyDown(HWND hwnd, WPARAM wParam, LPARAM lParam)
282 LPHEADLIST lphl = ComboGetListHeader(hwnd);
283 WORD newFocused = lphl->ItemFocused;
285 switch(wParam) {
286 case VK_HOME:
287 newFocused = 0;
288 break;
289 case VK_END:
290 newFocused = lphl->ItemsCount - 1;
291 break;
292 case VK_UP:
293 if (newFocused > 0) newFocused--;
294 break;
295 case VK_DOWN:
296 newFocused++;
297 break;
298 default:
299 return 0;
302 if (newFocused >= lphl->ItemsCount)
303 newFocused = lphl->ItemsCount - 1;
305 ListBoxSetCurSel(lphl, newFocused);
306 ListBoxSendNotification(lphl, CBN_SELCHANGE);
308 lphl->ItemFocused = newFocused;
309 ListBoxScrollToFocus(lphl);
310 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
311 InvalidateRect(hwnd, NULL, TRUE);
313 return 0;
316 /***********************************************************************
317 * CBChar
319 static LRESULT CBChar(HWND hwnd, WPARAM wParam, LPARAM lParam)
321 LPHEADLIST lphl = ComboGetListHeader(hwnd);
322 WORD newFocused;
324 newFocused = ListBoxFindNextMatch(lphl, wParam);
325 if (newFocused == (WORD)LB_ERR) return 0;
327 if (newFocused >= lphl->ItemsCount)
328 newFocused = lphl->ItemsCount - 1;
330 ListBoxSetCurSel(lphl, newFocused);
331 ListBoxSendNotification(lphl, CBN_SELCHANGE);
332 lphl->ItemFocused = newFocused;
333 ListBoxScrollToFocus(lphl);
335 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
336 InvalidateRect(hwnd, NULL, TRUE);
338 return 0;
341 /***********************************************************************
342 * CBKillFocus
344 static LRESULT CBKillFocus(HWND hwnd, WPARAM wParam, LPARAM lParam)
346 return 0;
349 /***********************************************************************
350 * CBSetFocus
352 static LRESULT CBSetFocus(HWND hwnd, WPARAM wParam, LPARAM lParam)
354 return 0;
357 /***********************************************************************
358 * CBResetContent
360 static LRESULT CBResetContent(HWND hwnd, WPARAM wParam, LPARAM lParam)
362 LPHEADLIST lphl = ComboGetListHeader(hwnd);
363 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
365 ListBoxResetContent(lphl);
366 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
367 return 0;
370 /***********************************************************************
371 * CBDir
373 static LRESULT CBDir(HWND hwnd, WPARAM wParam, LPARAM lParam)
375 WORD wRet;
376 LPHEADLIST lphl = ComboGetListHeader(hwnd);
377 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
379 wRet = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
380 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
381 return wRet;
384 /***********************************************************************
385 * CBInsertString
387 static LRESULT CBInsertString(HWND hwnd, WPARAM wParam, LPARAM lParam)
389 WORD wRet;
390 LPHEADLIST lphl = ComboGetListHeader(hwnd);
391 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
393 if (lphl->HasStrings)
394 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
395 else
396 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)lParam);
398 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
399 return wRet;
402 /***********************************************************************
403 * CBAddString
405 static LRESULT CBAddString(HWND hwnd, WPARAM wParam, LPARAM lParam)
407 WORD wRet;
408 LPHEADLIST lphl = ComboGetListHeader(hwnd);
409 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
411 if (lphl->HasStrings)
412 wRet = ListBoxAddString(lphl, (LPSTR)PTR_SEG_TO_LIN(lParam));
413 else
414 wRet = ListBoxAddString(lphl, (LPSTR)lParam);
416 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
417 return wRet;
420 /***********************************************************************
421 * CBDeleteString
423 static LRESULT CBDeleteString(HWND hwnd, WPARAM wParam, LPARAM lParam)
425 LPHEADLIST lphl = ComboGetListHeader(hwnd);
426 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
427 LONG lRet = ListBoxDeleteString(lphl,wParam);
429 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
430 return lRet;
433 /***********************************************************************
434 * CBSelectString
436 static LRESULT CBSelectString(HWND hwnd, WPARAM wParam, LPARAM lParam)
438 LPHEADLIST lphl = ComboGetListHeader(hwnd);
439 WORD wRet;
441 wRet = ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
443 /* XXX add functionality here */
445 return 0;
448 /***********************************************************************
449 * CBFindString
451 static LRESULT CBFindString(HWND hwnd, WPARAM wParam, LPARAM lParam)
453 LPHEADLIST lphl = ComboGetListHeader(hwnd);
454 return ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
457 /***********************************************************************
458 * CBGetCount
460 static LRESULT CBGetCount(HWND hwnd, WPARAM wParam, LPARAM lParam)
462 LPHEADLIST lphl = ComboGetListHeader(hwnd);
463 return lphl->ItemsCount;
466 /***********************************************************************
467 * CBSetCurSel
469 static LRESULT CBSetCurSel(HWND hwnd, WPARAM wParam, LPARAM lParam)
471 LPHEADLIST lphl = ComboGetListHeader(hwnd);
472 WORD wRet;
474 wRet = ListBoxSetCurSel(lphl, wParam);
476 dprintf_combo(stddeb,"CBSetCurSel: hwnd "NPFMT" wp %x lp %lx wRet %d\n",
477 hwnd,wParam,lParam,wRet);
478 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
479 InvalidateRect(hwnd, NULL, TRUE);
481 return wRet;
484 /***********************************************************************
485 * CBGetCurSel
487 static LRESULT CBGetCurSel(HWND hwnd, WPARAM wParam, LPARAM lParam)
489 LPHEADLIST lphl = ComboGetListHeader(hwnd);
490 return lphl->ItemFocused;
493 /***********************************************************************
494 * CBGetItemHeight
496 static LRESULT CBGetItemHeight(HWND hwnd, WPARAM wParam, LPARAM lParam)
498 LPHEADLIST lphl = ComboGetListHeader(hwnd);
499 LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
501 if (lpls == NULL) return LB_ERR;
502 return lpls->mis.itemHeight;
505 /***********************************************************************
506 * CBSetItemHeight
508 static LRESULT CBSetItemHeight(HWND hwnd, WPARAM wParam, LPARAM lParam)
510 LPHEADLIST lphl = ComboGetListHeader(hwnd);
511 return ListBoxSetItemHeight(lphl, wParam, lParam);
514 /***********************************************************************
515 * CBSetRedraw
517 static LRESULT CBSetRedraw(HWND hwnd, WPARAM wParam, LPARAM lParam)
519 LPHEADLIST lphl = ComboGetListHeader(hwnd);
520 lphl->bRedrawFlag = wParam;
521 return 0;
524 /***********************************************************************
525 * CBSetFont
527 static LRESULT CBSetFont(HWND hwnd, WPARAM wParam, LPARAM lParam)
529 LPHEADLIST lphl = ComboGetListHeader(hwnd);
531 if (wParam == 0)
532 lphl->hFont = GetStockObject(SYSTEM_FONT);
533 else
534 lphl->hFont = (HFONT)wParam;
536 return 0;
539 /***********************************************************************
540 * CBGetLBTextLen
542 static LRESULT CBGetLBTextLen(HWND hwnd, WPARAM wParam, LPARAM lParam)
544 LPHEADLIST lphl = ComboGetListHeader(hwnd);
545 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
547 if (lpls == NULL || !lphl->HasStrings) return LB_ERR;
548 return strlen(lpls->itemText);
551 /***********************************************************************
552 * CBGetLBText
554 static LRESULT CBGetLBText(HWND hwnd, WPARAM wParam, LPARAM lParam)
556 LPHEADLIST lphl = ComboGetListHeader(hwnd);
557 return ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
560 /***********************************************************************
561 * CBGetItemData
563 static LRESULT CBGetItemData(HWND hwnd, WPARAM wParam, LPARAM lParam)
565 LPHEADLIST lphl = ComboGetListHeader(hwnd);
566 return ListBoxGetItemData(lphl, wParam);
569 /***********************************************************************
570 * CBSetItemData
572 static LRESULT CBSetItemData(HWND hwnd, WPARAM wParam, LPARAM lParam)
574 LPHEADLIST lphl = ComboGetListHeader(hwnd);
575 return ListBoxSetItemData(lphl, wParam, lParam);
578 /***********************************************************************
579 * CBShowDropDown
581 static LRESULT CBShowDropDown(HWND hwnd, WPARAM wParam, LPARAM lParam)
583 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
584 RECT rect;
586 if ((lphc->dwStyle & 3) == CBS_SIMPLE) return LB_ERR;
588 wParam = !!wParam;
589 if (wParam != lphc->DropDownVisible) {
590 lphc->DropDownVisible = wParam;
591 GetWindowRect(hwnd,&rect);
592 SetWindowPos(lphc->hWndLBox, 0, rect.left, rect.top+lphc->LBoxTop, 0, 0,
593 SWP_NOSIZE | (wParam ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
594 if (!wParam) SetFocus(hwnd);
596 return 0;
600 /***********************************************************************
601 * ComboWndProc
603 LRESULT ComboBoxWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
605 switch(message) {
606 case WM_NCCREATE: return CBNCCreate(hwnd, wParam, lParam);
607 case WM_CREATE: return CBCreate(hwnd, wParam, lParam);
608 case WM_DESTROY: return CBDestroy(hwnd, wParam, lParam);
609 case WM_GETDLGCODE: return CBGetDlgCode(hwnd, wParam, lParam);
610 case WM_KEYDOWN: return CBKeyDown(hwnd, wParam, lParam);
611 case WM_CHAR: return CBChar(hwnd, wParam, lParam);
612 case WM_SETFONT: return CBSetFont(hwnd, wParam, lParam);
613 case WM_SETREDRAW: return CBSetRedraw(hwnd, wParam, lParam);
614 case WM_PAINT: return CBPaint(hwnd, wParam, lParam);
615 case WM_LBUTTONDOWN: return CBLButtonDown(hwnd, wParam, lParam);
616 case WM_SETFOCUS: return CBSetFocus(hwnd, wParam, lParam);
617 case WM_KILLFOCUS: return CBKillFocus(hwnd, wParam, lParam);
618 case CB_RESETCONTENT: return CBResetContent(hwnd, wParam, lParam);
619 case CB_DIR: return CBDir(hwnd, wParam, lParam);
620 case CB_ADDSTRING: return CBAddString(hwnd, wParam, lParam);
621 case CB_INSERTSTRING: return CBInsertString(hwnd, wParam, lParam);
622 case CB_DELETESTRING: return CBDeleteString(hwnd, wParam, lParam);
623 case CB_FINDSTRING: return CBFindString(hwnd, wParam, lParam);
624 case CB_GETCOUNT: return CBGetCount(hwnd, wParam, lParam);
625 case CB_GETCURSEL: return CBGetCurSel(hwnd, wParam, lParam);
626 case CB_GETITEMDATA: return CBGetItemData(hwnd, wParam, lParam);
627 case CB_GETITEMHEIGHT: return CBGetItemHeight(hwnd, wParam, lParam);
628 case CB_GETLBTEXT: return CBGetLBText(hwnd, wParam, lParam);
629 case CB_GETLBTEXTLEN: return CBGetLBTextLen(hwnd, wParam, lParam);
630 case CB_SELECTSTRING: return CBSelectString(hwnd, wParam, lParam);
631 case CB_SETITEMDATA: return CBSetItemData(hwnd, wParam, lParam);
632 case CB_SETCURSEL: return CBSetCurSel(hwnd, wParam, lParam);
633 case CB_SETITEMHEIGHT: return CBSetItemHeight(hwnd, wParam, lParam);
634 case CB_SHOWDROPDOWN: return CBShowDropDown(hwnd, wParam, lParam);
636 return DefWindowProc(hwnd, message, wParam, lParam);
639 /*--------------------------------------------------------------------*/
640 /* ComboLBox code starts here */
642 HWND CLBoxGetCombo(HWND hwnd)
644 #ifdef WINELIB32
645 return (HWND)GetWindowLong(hwnd,0);
646 #else
647 return (HWND)GetWindowWord(hwnd,0);
648 #endif
651 LPHEADLIST CLBoxGetListHeader(HWND hwnd)
653 return ComboGetListHeader(CLBoxGetCombo(hwnd));
656 /***********************************************************************
657 * CBLCreate
659 static LRESULT CBLCreate( HWND hwnd, WPARAM wParam, LPARAM lParam )
661 CREATESTRUCT *createStruct = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
662 #ifdef WINELIB32
663 SetWindowLong(hwnd,0,(LONG)createStruct->lpCreateParams);
664 #else
665 SetWindowWord(hwnd,0,LOWORD(createStruct->lpCreateParams));
666 #endif
667 return 0;
670 /***********************************************************************
671 * CBLGetDlgCode
673 static LRESULT CBLGetDlgCode( HWND hwnd, WPARAM wParam, LPARAM lParam )
675 return DLGC_WANTARROWS | DLGC_WANTCHARS;
678 /***********************************************************************
679 * CBLKeyDown
681 static LRESULT CBLKeyDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
683 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
684 WORD newFocused = lphl->ItemFocused;
686 switch(wParam) {
687 case VK_HOME:
688 newFocused = 0;
689 break;
690 case VK_END:
691 newFocused = lphl->ItemsCount - 1;
692 break;
693 case VK_UP:
694 if (newFocused > 0) newFocused--;
695 break;
696 case VK_DOWN:
697 newFocused++;
698 break;
699 case VK_PRIOR:
700 if (newFocused > lphl->ItemsVisible) {
701 newFocused -= lphl->ItemsVisible;
702 } else {
703 newFocused = 0;
705 break;
706 case VK_NEXT:
707 newFocused += lphl->ItemsVisible;
708 break;
709 default:
710 return 0;
713 if (newFocused >= lphl->ItemsCount)
714 newFocused = lphl->ItemsCount - 1;
716 ListBoxSetCurSel(lphl, newFocused);
717 ListBoxSendNotification(lphl, CBN_SELCHANGE);
719 lphl->ItemFocused = newFocused;
720 ListBoxScrollToFocus(lphl);
721 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
722 InvalidateRect(hwnd, NULL, TRUE);
723 return 0;
726 /***********************************************************************
727 * CBLChar
729 static LRESULT CBLChar( HWND hwnd, WPARAM wParam, LPARAM lParam )
731 return 0;
734 /***********************************************************************
735 * CBLPaint
737 static LRESULT CBLPaint( HWND hwnd, WPARAM wParam, LPARAM lParam )
739 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
740 LPLISTSTRUCT lpls;
741 PAINTSTRUCT ps;
742 HBRUSH hBrush;
743 HFONT hOldFont;
744 HWND combohwnd = CLBoxGetCombo(hwnd);
745 HDC hdc;
746 RECT rect;
747 int i, top, height;
749 top = 0;
750 hdc = BeginPaint( hwnd, &ps );
752 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) {
753 EndPaint(hwnd, &ps);
754 return 0;
757 hOldFont = SelectObject(hdc, lphl->hFont);
758 #ifdef WINELIB32
759 hBrush = (HBRUSH) SendMessage(lphl->hParent, WM_CTLCOLORLISTBOX, (WPARAM)hdc,
760 (LPARAM)hwnd);
761 #else
762 hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
763 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
764 #endif
766 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
768 GetClientRect(hwnd, &rect);
769 FillRect(hdc, &rect, hBrush);
771 lpls = lphl->lpFirst;
773 lphl->ItemsVisible = 0;
774 for(i = 0; i < lphl->ItemsCount; i++) {
775 if (lpls == NULL) break;
777 if (i >= lphl->FirstVisible) {
778 height = lpls->mis.itemHeight;
780 if (top > rect.bottom) break;
781 lpls->itemRect.top = top;
782 lpls->itemRect.bottom = top + height;
783 lpls->itemRect.left = rect.left;
784 lpls->itemRect.right = rect.right;
786 dprintf_listbox(stddeb,"drawing item: %ld %d %ld %d %d\n",(LONG)rect.left,top,(LONG)rect.right,top+height,lpls->itemState);
787 if (lphl->OwnerDrawn) {
788 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, 0);
789 if (lpls->itemState)
790 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_SELECT, ODS_SELECTED);
791 } else {
792 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
793 lpls->itemState);
795 if ((lphl->ItemFocused == i) && GetFocus() == hwnd)
796 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, ODS_FOCUS);
798 top += height;
799 lphl->ItemsVisible++;
802 lpls = lpls->lpNext;
804 SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
805 SelectObject(hdc,hOldFont);
806 EndPaint( hwnd, &ps );
807 return 0;
811 /***********************************************************************
812 * CBLKillFocus
814 static LRESULT CBLKillFocus( HWND hwnd, WPARAM wParam, LPARAM lParam )
816 /* SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);*/
817 return 0;
820 /***********************************************************************
821 * CBLActivate
823 static LRESULT CBLActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
825 if (wParam == WA_INACTIVE)
826 SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
827 return 0;
830 /***********************************************************************
831 * CBLLButtonDown
833 static LRESULT CBLLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
835 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
836 int y;
837 RECT rectsel;
839 SetFocus(hwnd);
840 SetCapture(hwnd);
842 lphl->PrevFocused = lphl->ItemFocused;
844 y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
845 if (y == -1)
846 return 0;
848 ListBoxSetCurSel(lphl, y);
849 ListBoxGetItemRect(lphl, y, &rectsel);
851 InvalidateRect(hwnd, NULL, TRUE);
852 return 0;
855 /***********************************************************************
856 * CBLLButtonUp
858 static LRESULT CBLLButtonUp( HWND hwnd, WPARAM wParam, LPARAM lParam )
860 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
862 if (GetCapture() == hwnd) ReleaseCapture();
864 if(!lphl)
866 fprintf(stdnimp,"CBLLButtonUp: CLBoxGetListHeader returned NULL!\n");
868 else if (lphl->PrevFocused != lphl->ItemFocused)
870 SendMessage(CLBoxGetCombo(hwnd),CB_SETCURSEL,lphl->ItemFocused,0);
871 ListBoxSendNotification(lphl, CBN_SELCHANGE);
874 SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
876 return 0;
879 /***********************************************************************
880 * CBLMouseMove
882 static LRESULT CBLMouseMove( HWND hwnd, WPARAM wParam, LPARAM lParam )
884 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
885 short y;
886 WORD wRet;
887 RECT rect, rectsel;
889 y = SHIWORD(lParam);
890 wRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
891 ListBoxGetItemRect(lphl, wRet, &rectsel);
892 GetClientRect(hwnd, &rect);
894 dprintf_combo(stddeb,"CBLMouseMove: hwnd "NPFMT" wp %x lp %lx y %d if %d wret %d %d,%d-%d,%d\n",
895 hwnd,wParam,lParam,y,lphl->ItemFocused,wRet,rectsel.left,rectsel.top,rectsel.right,rectsel.bottom);
897 if ((wParam & MK_LBUTTON) != 0) {
898 if (y < CBLMM_EDGE) {
899 if (lphl->FirstVisible > 0) {
900 lphl->FirstVisible--;
901 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
902 ListBoxSetCurSel(lphl, wRet);
903 InvalidateRect(hwnd, NULL, TRUE);
904 return 0;
907 else if (y >= (rect.bottom-CBLMM_EDGE)) {
908 if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
909 lphl->FirstVisible++;
910 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
911 ListBoxSetCurSel(lphl, wRet);
912 InvalidateRect(hwnd, NULL, TRUE);
913 return 0;
916 else {
917 if ((short) wRet == lphl->ItemFocused) return 0;
918 ListBoxSetCurSel(lphl, wRet);
919 InvalidateRect(hwnd, NULL, TRUE);
923 return 0;
926 /***********************************************************************
927 * CBLVScroll
929 static LRESULT CBLVScroll( HWND hwnd, WPARAM wParam, LPARAM lParam )
931 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
932 int y;
934 y = lphl->FirstVisible;
936 switch(wParam) {
937 case SB_LINEUP:
938 if (lphl->FirstVisible > 0)
939 lphl->FirstVisible--;
940 break;
942 case SB_LINEDOWN:
943 lphl->FirstVisible++;
944 break;
946 case SB_PAGEUP:
947 if (lphl->FirstVisible > lphl->ItemsVisible) {
948 lphl->FirstVisible -= lphl->ItemsVisible;
949 } else {
950 lphl->FirstVisible = 0;
952 break;
954 case SB_PAGEDOWN:
955 lphl->FirstVisible += lphl->ItemsVisible;
956 break;
958 case SB_THUMBTRACK:
959 lphl->FirstVisible = LOWORD(lParam);
960 break;
963 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
964 lphl->FirstVisible = ListMaxFirstVisible(lphl);
966 if (y != lphl->FirstVisible) {
967 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
968 InvalidateRect(hwnd, NULL, TRUE);
971 return 0;
974 /***********************************************************************
975 * ComboLBoxWndProc
977 LRESULT ComboLBoxWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
979 switch(message) {
980 case WM_CREATE: return CBLCreate(hwnd, wParam, lParam);
981 case WM_GETDLGCODE: return CBLGetDlgCode(hwnd, wParam, lParam);
982 case WM_KEYDOWN: return CBLKeyDown(hwnd, wParam, lParam);
983 case WM_CHAR: return CBLChar(hwnd, wParam, lParam);
984 case WM_PAINT: return CBLPaint(hwnd, wParam, lParam);
985 case WM_KILLFOCUS: return CBLKillFocus(hwnd, wParam, lParam);
986 case WM_ACTIVATE: return CBLActivate(hwnd, wParam, lParam);
987 case WM_LBUTTONDOWN: return CBLLButtonDown(hwnd, wParam, lParam);
988 case WM_LBUTTONUP: return CBLLButtonUp(hwnd, wParam, lParam);
989 case WM_MOUSEMOVE: return CBLMouseMove(hwnd, wParam, lParam);
990 case WM_VSCROLL: return CBLVScroll(hwnd, wParam, lParam);
992 return DefWindowProc(hwnd, message, wParam, lParam);
995 /************************************************************************
996 * DlgDirSelectComboBox [USER.194]
998 BOOL DlgDirSelectComboBox(HWND hDlg, LPSTR lpStr, INT nIDLBox)
1000 fprintf(stdnimp,"DlgDirSelectComboBox("NPFMT", '%s', %d) \n",
1001 hDlg, lpStr, nIDLBox);
1002 return TRUE;
1006 /************************************************************************
1007 * DlgDirListComboBox [USER.195]
1009 INT DlgDirListComboBox( HWND hDlg, SEGPTR path, INT idCBox,
1010 INT idStatic, UINT wType )
1012 INT ret = 0;
1014 dprintf_combo( stddeb,"DlgDirListComboBox("NPFMT",%08lx,%d,%d,%04X) \n",
1015 hDlg, (DWORD)path, idCBox, idStatic, wType );
1017 if (idCBox)
1019 SendDlgItemMessage( hDlg, idCBox, CB_RESETCONTENT, 0, 0 );
1020 ret = (SendDlgItemMessage( hDlg, idCBox, CB_DIR, wType, path ) >= 0);
1022 if (idStatic)
1024 char temp[256];
1025 int drive = DRIVE_GetCurrentDrive();
1026 strcpy( temp, "A:\\" );
1027 temp[0] += drive;
1028 lstrcpyn( temp+3, DRIVE_GetDosCwd(drive), 253 );
1029 SendDlgItemMessage( hDlg, idStatic, WM_SETTEXT,
1030 0, (LPARAM)MAKE_SEGPTR(temp) );
1032 return ret;