Release 950918
[wine.git] / controls / combo.c
blob77374cd82be72ff682e385e4aced8c36721f090b
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 "stddebug.h"
24 #include "debug.h"
27 * Note: Combos are probably implemented in a different way by Windows.
28 * Using a message spy for Windows, you can see some undocumented
29 * messages being passed between ComboBox and ComboLBox.
30 * I hope no programs rely on the implementation of combos.
33 static HBITMAP hComboBit = 0;
34 static WORD CBitHeight, CBitWidth;
36 static int COMBO_Init()
38 BITMAP bm;
40 dprintf_combo(stddeb, "COMBO_Init\n");
41 hComboBit = LoadBitmap(0, MAKEINTRESOURCE(OBM_COMBO));
42 GetObject(hComboBit, sizeof(BITMAP), (LPSTR)&bm);
43 CBitHeight = bm.bmHeight;
44 CBitWidth = bm.bmWidth;
45 return 0;
48 LPHEADCOMBO ComboGetStorageHeader(HWND hwnd)
50 return (LPHEADCOMBO)GetWindowLong(hwnd,4);
53 LPHEADLIST ComboGetListHeader(HWND hwnd)
55 return (LPHEADLIST)GetWindowLong(hwnd,0);
58 int CreateComboStruct(HWND hwnd, LONG style)
60 LPHEADCOMBO lphc;
62 lphc = (LPHEADCOMBO)malloc(sizeof(HEADCOMBO));
63 SetWindowLong(hwnd,4,(LONG)lphc);
64 lphc->hWndEdit = 0;
65 lphc->hWndLBox = 0;
66 lphc->dwState = 0;
67 lphc->LastSel = -1;
68 lphc->dwStyle = style;
69 lphc->DropDownVisible = FALSE;
70 return TRUE;
73 void ComboUpdateWindow(HWND hwnd, LPHEADLIST lphl, LPHEADCOMBO lphc, BOOL repaint)
75 SetScrollRange(lphc->hWndLBox, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
76 if (repaint && lphl->bRedrawFlag) {
77 InvalidateRect(hwnd, NULL, TRUE);
81 /***********************************************************************
82 * CBNCCreate
84 static LONG CBNCCreate(HWND hwnd, WORD wParam, LONG lParam)
86 CREATESTRUCT *createStruct;
88 if (!hComboBit) COMBO_Init();
90 createStruct = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
91 createStruct->style &= ~(WS_VSCROLL | WS_HSCROLL);
92 SetWindowLong(hwnd, GWL_STYLE, createStruct->style);
94 dprintf_combo(stddeb,"ComboBox WM_NCCREATE!\n");
95 return DefWindowProc(hwnd, WM_NCCREATE, wParam, lParam);
99 /***********************************************************************
100 * CBCreate
102 static LONG CBCreate(HWND hwnd, WORD wParam, LONG lParam)
104 LPHEADLIST lphl;
105 LPHEADCOMBO lphc;
106 LONG style = 0;
107 LONG cstyle = GetWindowLong(hwnd,GWL_STYLE);
108 RECT rect,lboxrect;
109 char className[] = "COMBOLBOX"; /* Hack so that class names are > 0x10000 */
110 char editName[] = "EDIT";
112 /* translate combo into listbox styles */
113 if (cstyle & CBS_OWNERDRAWFIXED) style |= LBS_OWNERDRAWFIXED;
114 if (cstyle & CBS_OWNERDRAWVARIABLE) style |= LBS_OWNERDRAWVARIABLE;
115 if (cstyle & CBS_SORT) style |= LBS_SORT;
116 if (cstyle & CBS_HASSTRINGS) style |= LBS_HASSTRINGS;
117 style |= LBS_NOTIFY;
118 CreateListBoxStruct(hwnd, ODT_COMBOBOX, style, GetParent(hwnd));
119 CreateComboStruct(hwnd,cstyle);
120 lphl = ComboGetListHeader(hwnd);
121 lphc = ComboGetStorageHeader(hwnd);
123 GetClientRect(hwnd,&rect);
124 GetWindowRect(hwnd,&lboxrect);
125 /* FIXME: combos with edit controls are broken. */
126 switch(cstyle & 3) {
127 case CBS_SIMPLE: /* edit control, list always visible */
128 dprintf_combo(stddeb,"CBS_SIMPLE\n");
129 SetRectEmpty(&lphc->RectButton);
130 lphc->LBoxTop = lphl->StdItemHeight;
131 lphc->hWndEdit = CreateWindow(MAKE_SEGPTR(editName), (SEGPTR)0,
132 WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | SS_LEFT,
133 0, 0, rect.right, lphl->StdItemHeight,
134 hwnd, 1, GetWindowWord(hwnd,GWW_HINSTANCE), 0L);
135 break;
136 case CBS_DROPDOWN: /* edit control, dropdown listbox */
137 dprintf_combo(stddeb,"CBS_DROPDOWN\n");
138 lphc->RectButton = rect;
139 lphc->RectButton.left = lphc->RectButton.right - 6 - CBitWidth;
140 lphc->RectButton.bottom = lphc->RectButton.top + lphl->StdItemHeight;
141 lphc->LBoxTop = lphl->StdItemHeight;
142 SetWindowPos(hwnd, 0, 0, 0, rect.right - rect.left + 2*SYSMETRICS_CXBORDER,
143 lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER,
144 SWP_NOMOVE | SWP_NOZORDER);
145 lphc->hWndEdit = CreateWindow(MAKE_SEGPTR(editName), (SEGPTR)0,
146 WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | SS_LEFT,
147 0, 0, lphc->RectButton.left, lphl->StdItemHeight,
148 hwnd, 1, GetWindowWord(hwnd,GWW_HINSTANCE), 0L);
149 break;
150 case CBS_DROPDOWNLIST: /* static control, downdown listbox */
151 dprintf_combo(stddeb,"CBS_DROPDOWNLIST\n");
152 lphc->RectButton = rect;
153 lphc->RectButton.left = lphc->RectButton.right - 6 - CBitWidth;
154 lphc->RectButton.bottom = lphc->RectButton.top + lphl->StdItemHeight;
155 lphc->LBoxTop = lphl->StdItemHeight;
156 SetWindowPos(hwnd, 0, 0, 0, rect.right - rect.left + 2*SYSMETRICS_CXBORDER,
157 lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER,
158 SWP_NOMOVE | SWP_NOZORDER);
159 break;
161 lboxrect.top += lphc->LBoxTop;
162 /* FIXME: WinSight says these should be CHILD windows with the TOPMOST flag
163 * set. Wine doesn't support TOPMOST, and simply setting the WS_CHILD
164 * flag doesn't work. */
165 lphc->hWndLBox = CreateWindow(MAKE_SEGPTR(className), (SEGPTR)0,
166 WS_POPUP | WS_BORDER | WS_VSCROLL,
167 lboxrect.left, lboxrect.top,
168 lboxrect.right - lboxrect.left,
169 lboxrect.bottom - lboxrect.top,
170 0, 0, GetWindowWord(hwnd,GWW_HINSTANCE),
171 (SEGPTR)MAKELONG(hwnd, hwnd));
172 ShowWindow(lphc->hWndLBox, SW_HIDE);
173 dprintf_combo(stddeb,"Combo Creation LBox=%X!\n", lphc->hWndLBox);
174 return 0;
177 /***********************************************************************
178 * CBDestroy
180 static LONG CBDestroy(HWND hwnd, WORD wParam, LONG lParam)
182 LPHEADLIST lphl = ComboGetListHeader(hwnd);
184 ListBoxResetContent(lphl);
185 DestroyListBoxStruct(lphl);
186 dprintf_combo(stddeb,"Combo WM_DESTROY %p !\n", lphl);
187 return 0;
190 /***********************************************************************
191 * CBPaint
193 static LONG CBPaint(HWND hwnd, WORD wParam, LONG lParam)
195 LPHEADLIST lphl = ComboGetListHeader(hwnd);
196 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
197 LPLISTSTRUCT lpls;
198 PAINTSTRUCT ps;
199 HBRUSH hBrush;
200 HFONT hOldFont;
201 HDC hdc;
202 RECT rect;
203 int height;
205 hdc = BeginPaint(hwnd, &ps);
207 if (hComboBit != 0) {
208 GRAPH_DrawReliefRect(hdc, &lphc->RectButton, 2, 2, FALSE);
209 GRAPH_DrawBitmap(hdc, hComboBit,
210 lphc->RectButton.left + 3,lphc->RectButton.top + 2,
211 0, 0, CBitWidth, CBitHeight );
213 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag
214 || (lphc->dwStyle & 3) != CBS_DROPDOWNLIST)
216 /* we don't want to draw an entry when there is an edit control */
217 EndPaint(hwnd, &ps);
218 return 0;
221 hOldFont = SelectObject(hdc, lphl->hFont);
223 hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
224 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
225 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
227 GetClientRect(hwnd, &rect);
228 rect.right -= (lphc->RectButton.right - lphc->RectButton.left);
229 FillRect(hdc, &rect, hBrush);
231 lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
232 if (lpls != NULL) {
233 height = lpls->mis.itemHeight;
234 rect.bottom = rect.top + height;
236 if (lphl->OwnerDrawn) {
237 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
238 } else {
239 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
241 if (GetFocus() == hwnd)
242 ListBoxDrawItem (hwnd,lphl, hdc, lpls, &rect, ODA_FOCUS, ODS_FOCUS);
244 SelectObject(hdc,hOldFont);
245 EndPaint(hwnd, &ps);
246 return 0;
249 /***********************************************************************
250 * CBGetDlgCode
252 static LONG CBGetDlgCode(HWND hwnd, WORD wParam, LONG lParam)
254 return DLGC_WANTARROWS | DLGC_WANTCHARS;
257 /***********************************************************************
258 * CBLButtonDown
260 static LONG CBLButtonDown(HWND hwnd, WORD wParam, LONG lParam)
262 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
263 SendMessage(hwnd,CB_SHOWDROPDOWN,!lphc->DropDownVisible,0);
264 return 0;
267 /***********************************************************************
268 * CBKeyDown
270 static LONG CBKeyDown(HWND hwnd, WORD wParam, LONG lParam)
272 LPHEADLIST lphl = ComboGetListHeader(hwnd);
273 WORD newFocused = lphl->ItemFocused;
275 switch(wParam) {
276 case VK_HOME:
277 newFocused = 0;
278 break;
279 case VK_END:
280 newFocused = lphl->ItemsCount - 1;
281 break;
282 case VK_UP:
283 if (newFocused > 0) newFocused--;
284 break;
285 case VK_DOWN:
286 newFocused++;
287 break;
288 default:
289 return 0;
292 if (newFocused >= lphl->ItemsCount)
293 newFocused = lphl->ItemsCount - 1;
295 ListBoxSetCurSel(lphl, newFocused);
296 ListBoxSendNotification(lphl, hwnd, CBN_SELCHANGE);
298 lphl->ItemFocused = newFocused;
299 ListBoxScrollToFocus(lphl);
300 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
301 InvalidateRect(hwnd, NULL, TRUE);
303 return 0;
306 /***********************************************************************
307 * CBChar
309 static LONG CBChar(HWND hwnd, WORD wParam, LONG lParam)
311 LPHEADLIST lphl = ComboGetListHeader(hwnd);
312 WORD newFocused;
314 newFocused = ListBoxFindNextMatch(lphl, wParam);
315 if (newFocused == (WORD)LB_ERR) return 0;
317 if (newFocused >= lphl->ItemsCount)
318 newFocused = lphl->ItemsCount - 1;
320 ListBoxSetCurSel(lphl, newFocused);
321 ListBoxSendNotification(lphl, hwnd, CBN_SELCHANGE);
322 lphl->ItemFocused = newFocused;
323 ListBoxScrollToFocus(lphl);
325 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
326 InvalidateRect(hwnd, NULL, TRUE);
328 return 0;
331 /***********************************************************************
332 * CBKillFocus
334 static LONG CBKillFocus(HWND hwnd, WORD wParam, LONG lParam)
336 return 0;
339 /***********************************************************************
340 * CBSetFocus
342 static LONG CBSetFocus(HWND hwnd, WORD wParam, LONG lParam)
344 return 0;
347 /***********************************************************************
348 * CBResetContent
350 static LONG CBResetContent(HWND hwnd, WORD wParam, LONG lParam)
352 LPHEADLIST lphl = ComboGetListHeader(hwnd);
353 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
355 ListBoxResetContent(lphl);
356 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
357 return 0;
360 /***********************************************************************
361 * CBDir
363 static LONG CBDir(HWND hwnd, WORD wParam, LONG lParam)
365 WORD wRet;
366 LPHEADLIST lphl = ComboGetListHeader(hwnd);
367 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
369 wRet = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
370 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
371 return wRet;
374 /***********************************************************************
375 * CBInsertString
377 static LONG CBInsertString(HWND hwnd, WORD wParam, LONG lParam)
379 WORD wRet;
380 LPHEADLIST lphl = ComboGetListHeader(hwnd);
381 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
383 if (lphl->HasStrings)
384 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
385 else
386 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)lParam);
388 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
389 return wRet;
392 /***********************************************************************
393 * CBAddString
395 static LONG CBAddString(HWND hwnd, WORD wParam, LONG lParam)
397 WORD wRet;
398 LPHEADLIST lphl = ComboGetListHeader(hwnd);
399 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
401 if (lphl->HasStrings)
402 wRet = ListBoxAddString(lphl, (LPSTR)PTR_SEG_TO_LIN(lParam));
403 else
404 wRet = ListBoxAddString(lphl, (LPSTR)lParam);
406 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
407 return wRet;
410 /***********************************************************************
411 * CBDeleteString
413 static LONG CBDeleteString(HWND hwnd, WORD wParam, LONG lParam)
415 LPHEADLIST lphl = ComboGetListHeader(hwnd);
416 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
417 LONG lRet = ListBoxDeleteString(lphl,wParam);
419 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
420 return lRet;
423 /***********************************************************************
424 * CBSelectString
426 static LONG CBSelectString(HWND hwnd, WORD wParam, LONG lParam)
428 LPHEADLIST lphl = ComboGetListHeader(hwnd);
429 WORD wRet;
431 wRet = ListBoxFindString(lphl, wParam, lParam);
433 /* XXX add functionality here */
435 return 0;
438 /***********************************************************************
439 * CBFindString
441 static LONG CBFindString(HWND hwnd, WORD wParam, LONG lParam)
443 LPHEADLIST lphl = ComboGetListHeader(hwnd);
444 return ListBoxFindString(lphl, wParam, lParam);
447 /***********************************************************************
448 * CBGetCount
450 static LONG CBGetCount(HWND hwnd, WORD wParam, LONG lParam)
452 LPHEADLIST lphl = ComboGetListHeader(hwnd);
453 return lphl->ItemsCount;
456 /***********************************************************************
457 * CBSetCurSel
459 static LONG CBSetCurSel(HWND hwnd, WORD wParam, LONG lParam)
461 LPHEADLIST lphl = ComboGetListHeader(hwnd);
462 WORD wRet;
464 wRet = ListBoxSetCurSel(lphl, wParam);
466 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
467 InvalidateRect(hwnd, NULL, TRUE);
469 return wRet;
472 /***********************************************************************
473 * CBGetCurSel
475 static LONG CBGetCurSel(HWND hwnd, WORD wParam, LONG lParam)
477 LPHEADLIST lphl = ComboGetListHeader(hwnd);
478 return lphl->ItemFocused;
481 /***********************************************************************
482 * CBGetItemHeight
484 static LONG CBGetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
486 LPHEADLIST lphl = ComboGetListHeader(hwnd);
487 LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
489 if (lpls == NULL) return LB_ERR;
490 return lpls->mis.itemHeight;
493 /***********************************************************************
494 * CBSetItemHeight
496 static LONG CBSetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
498 LPHEADLIST lphl = ComboGetListHeader(hwnd);
499 return ListBoxSetItemHeight(lphl, wParam, lParam);
502 /***********************************************************************
503 * CBSetRedraw
505 static LONG CBSetRedraw(HWND hwnd, WORD wParam, LONG lParam)
507 LPHEADLIST lphl = ComboGetListHeader(hwnd);
508 lphl->bRedrawFlag = wParam;
509 return 0;
512 /***********************************************************************
513 * CBSetFont
515 static LONG CBSetFont(HWND hwnd, WORD wParam, LONG lParam)
517 LPHEADLIST lphl = ComboGetListHeader(hwnd);
519 if (wParam == 0)
520 lphl->hFont = GetStockObject(SYSTEM_FONT);
521 else
522 lphl->hFont = wParam;
524 return 0;
527 /***********************************************************************
528 * CBGetLBTextLen
530 static LONG CBGetLBTextLen(HWND hwnd, WORD wParam, LONG lParam)
532 LPHEADLIST lphl = ComboGetListHeader(hwnd);
533 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
535 if (lpls == NULL || !lphl->HasStrings) return LB_ERR;
536 return strlen(lpls->itemText);
539 /***********************************************************************
540 * CBGetLBText
542 static LONG CBGetLBText(HWND hwnd, WORD wParam, LONG lParam)
544 LPHEADLIST lphl = ComboGetListHeader(hwnd);
545 return ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
548 /***********************************************************************
549 * CBGetItemData
551 static LONG CBGetItemData(HWND hwnd, WORD wParam, LONG lParam)
553 LPHEADLIST lphl = ComboGetListHeader(hwnd);
554 return ListBoxGetItemData(lphl, wParam);
557 /***********************************************************************
558 * CBSetItemData
560 static LONG CBSetItemData(HWND hwnd, WORD wParam, LONG lParam)
562 LPHEADLIST lphl = ComboGetListHeader(hwnd);
563 return ListBoxSetItemData(lphl, wParam, lParam);
566 /***********************************************************************
567 * CBShowDropDown
569 static LONG CBShowDropDown(HWND hwnd, WORD wParam, LONG lParam)
571 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
572 RECT rect;
574 if (lphc->dwStyle & 3 == CBS_SIMPLE) return LB_ERR;
576 wParam = !!wParam;
577 if (wParam != lphc->DropDownVisible) {
578 lphc->DropDownVisible = wParam;
579 GetWindowRect(hwnd,&rect);
580 SetWindowPos(lphc->hWndLBox, 0, rect.left, rect.top+lphc->LBoxTop, 0, 0,
581 SWP_NOSIZE | (wParam ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
582 if (!wParam) SetFocus(hwnd);
584 return 0;
588 /***********************************************************************
589 * ComboWndProc
591 LONG ComboBoxWndProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
593 switch(message) {
594 case WM_NCCREATE: return CBNCCreate(hwnd, wParam, lParam);
595 case WM_CREATE: return CBCreate(hwnd, wParam, lParam);
596 case WM_DESTROY: return CBDestroy(hwnd, wParam, lParam);
597 case WM_GETDLGCODE: return CBGetDlgCode(hwnd, wParam, lParam);
598 case WM_KEYDOWN: return CBKeyDown(hwnd, wParam, lParam);
599 case WM_CHAR: return CBChar(hwnd, wParam, lParam);
600 case WM_SETFONT: return CBSetFont(hwnd, wParam, lParam);
601 case WM_SETREDRAW: return CBSetRedraw(hwnd, wParam, lParam);
602 case WM_PAINT: return CBPaint(hwnd, wParam, lParam);
603 case WM_LBUTTONDOWN: return CBLButtonDown(hwnd, wParam, lParam);
604 case WM_SETFOCUS: return CBSetFocus(hwnd, wParam, lParam);
605 case WM_KILLFOCUS: return CBKillFocus(hwnd, wParam, lParam);
606 case CB_RESETCONTENT: return CBResetContent(hwnd, wParam, lParam);
607 case CB_DIR: return CBDir(hwnd, wParam, lParam);
608 case CB_ADDSTRING: return CBAddString(hwnd, wParam, lParam);
609 case CB_INSERTSTRING: return CBInsertString(hwnd, wParam, lParam);
610 case CB_DELETESTRING: return CBDeleteString(hwnd, wParam, lParam);
611 case CB_FINDSTRING: return CBFindString(hwnd, wParam, lParam);
612 case CB_GETCOUNT: return CBGetCount(hwnd, wParam, lParam);
613 case CB_GETCURSEL: return CBGetCurSel(hwnd, wParam, lParam);
614 case CB_GETITEMDATA: return CBGetItemData(hwnd, wParam, lParam);
615 case CB_GETITEMHEIGHT: return CBGetItemHeight(hwnd, wParam, lParam);
616 case CB_GETLBTEXT: return CBGetLBText(hwnd, wParam, lParam);
617 case CB_GETLBTEXTLEN: return CBGetLBTextLen(hwnd, wParam, lParam);
618 case CB_SELECTSTRING: return CBSelectString(hwnd, wParam, lParam);
619 case CB_SETITEMDATA: return CBSetItemData(hwnd, wParam, lParam);
620 case CB_SETCURSEL: return CBSetCurSel(hwnd, wParam, lParam);
621 case CB_SETITEMHEIGHT: return CBSetItemHeight(hwnd, wParam, lParam);
622 case CB_SHOWDROPDOWN: return CBShowDropDown(hwnd, wParam, lParam);
624 return DefWindowProc(hwnd, message, wParam, lParam);
627 /*--------------------------------------------------------------------*/
628 /* ComboLBox code starts here */
630 HWND CLBoxGetCombo(HWND hwnd)
632 return GetWindowWord(hwnd,0);
635 LPHEADLIST CLBoxGetListHeader(HWND hwnd)
637 return ComboGetListHeader(CLBoxGetCombo(hwnd));
640 /***********************************************************************
641 * CBLCreate
643 static LONG CBLCreate( HWND hwnd, WORD wParam, LONG lParam )
645 CREATESTRUCT *createStruct = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
646 SetWindowWord(hwnd,0,LOWORD(createStruct->lpCreateParams));
647 return 0;
650 /***********************************************************************
651 * CBLGetDlgCode
653 static LONG CBLGetDlgCode( HWND hwnd, WORD wParam, LONG lParam )
655 return DLGC_WANTARROWS | DLGC_WANTCHARS;
658 /***********************************************************************
659 * CBLKeyDown
661 static LONG CBLKeyDown( HWND hwnd, WORD wParam, LONG lParam )
663 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
664 WORD newFocused = lphl->ItemFocused;
666 switch(wParam) {
667 case VK_HOME:
668 newFocused = 0;
669 break;
670 case VK_END:
671 newFocused = lphl->ItemsCount - 1;
672 break;
673 case VK_UP:
674 if (newFocused > 0) newFocused--;
675 break;
676 case VK_DOWN:
677 newFocused++;
678 break;
679 case VK_PRIOR:
680 if (newFocused > lphl->ItemsVisible) {
681 newFocused -= lphl->ItemsVisible;
682 } else {
683 newFocused = 0;
685 break;
686 case VK_NEXT:
687 newFocused += lphl->ItemsVisible;
688 break;
689 default:
690 return 0;
693 if (newFocused >= lphl->ItemsCount)
694 newFocused = lphl->ItemsCount - 1;
696 ListBoxSetCurSel(lphl, newFocused);
697 ListBoxSendNotification(lphl, hwnd, CBN_SELCHANGE);
699 lphl->ItemFocused = newFocused;
700 ListBoxScrollToFocus(lphl);
701 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
702 InvalidateRect(hwnd, NULL, TRUE);
703 return 0;
706 /***********************************************************************
707 * CBLChar
709 static LONG CBLChar( HWND hwnd, WORD wParam, LONG lParam )
711 return 0;
714 /***********************************************************************
715 * CBLPaint
717 static LONG CBLPaint( HWND hwnd, WORD wParam, LONG lParam )
719 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
720 LPLISTSTRUCT lpls;
721 PAINTSTRUCT ps;
722 HBRUSH hBrush;
723 HFONT hOldFont;
724 HWND combohwnd = CLBoxGetCombo(hwnd);
725 HDC hdc;
726 RECT rect;
727 int i, top, height;
729 top = 0;
730 hdc = BeginPaint( hwnd, &ps );
732 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) {
733 EndPaint(hwnd, &ps);
734 return 0;
737 hOldFont = SelectObject(hdc, lphl->hFont);
738 hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
739 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
741 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
743 GetClientRect(hwnd, &rect);
744 FillRect(hdc, &rect, hBrush);
746 lpls = lphl->lpFirst;
748 lphl->ItemsVisible = 0;
749 for(i = 0; i < lphl->ItemsCount; i++) {
750 if (lpls == NULL) break;
752 if (i >= lphl->FirstVisible) {
753 height = lpls->mis.itemHeight;
755 if (top > rect.bottom) break;
756 lpls->itemRect.top = top;
757 lpls->itemRect.bottom = top + height;
758 lpls->itemRect.left = rect.left;
759 lpls->itemRect.right = rect.right;
761 dprintf_listbox(stddeb,"drawing item: %d %d %d %d %d\n",rect.left,top,rect.right,top+height,lpls->itemState);
762 if (lphl->OwnerDrawn) {
763 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, 0);
764 if (lpls->itemState)
765 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_SELECT, ODS_SELECTED);
766 } else {
767 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
768 lpls->itemState);
770 if ((lphl->ItemFocused == i) && GetFocus() == hwnd)
771 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, ODS_FOCUS);
773 top += height;
774 lphl->ItemsVisible++;
777 lpls = lpls->lpNext;
779 SelectObject(hdc,hOldFont);
780 EndPaint( hwnd, &ps );
781 return 0;
785 /***********************************************************************
786 * CBLKillFocus
788 static LONG CBLKillFocus( HWND hwnd, WORD wParam, LONG lParam )
790 /* SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);*/
791 return 0;
794 /***********************************************************************
795 * CBLActivate
797 static LONG CBLActivate( HWND hwnd, WORD wParam, LONG lParam )
799 if (wParam == WA_INACTIVE)
800 SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
801 return 0;
804 /***********************************************************************
805 * CBLLButtonDown
807 static LONG CBLLButtonDown( HWND hwnd, WORD wParam, LONG lParam )
809 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
810 int y;
811 RECT rectsel;
813 SetFocus(hwnd);
814 SetCapture(hwnd);
816 lphl->PrevFocused = lphl->ItemFocused;
818 y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
819 if (y == -1)
820 return 0;
822 ListBoxSetCurSel(lphl, y);
823 ListBoxGetItemRect(lphl, y, &rectsel);
825 InvalidateRect(hwnd, NULL, TRUE);
826 return 0;
829 /***********************************************************************
830 * CBLLButtonUp
832 static LONG CBLLButtonUp( HWND hwnd, WORD wParam, LONG lParam )
834 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
836 if (GetCapture() == hwnd) ReleaseCapture();
838 if (lphl->PrevFocused != lphl->ItemFocused) {
839 SendMessage(CLBoxGetCombo(hwnd),CB_SETCURSEL,lphl->ItemFocused,0);
840 ListBoxSendNotification(lphl, CLBoxGetCombo(hwnd), CBN_SELCHANGE);
842 SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
844 return 0;
847 /***********************************************************************
848 * CBLMouseMove
850 static LONG CBLMouseMove( HWND hwnd, WORD wParam, LONG lParam )
852 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
853 int y;
854 WORD wRet;
855 RECT rect, rectsel; /* XXX Broken */
857 if ((wParam & MK_LBUTTON) != 0) {
858 y = SHIWORD(lParam);
859 if (y < 0) {
860 if (lphl->FirstVisible > 0) {
861 lphl->FirstVisible--;
862 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
863 InvalidateRect(hwnd, NULL, TRUE);
864 return 0;
867 GetClientRect(hwnd, &rect);
868 if (y >= rect.bottom) {
869 if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
870 lphl->FirstVisible++;
871 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
872 InvalidateRect(hwnd, NULL, TRUE);
873 return 0;
876 if ((y > 0) && (y < (rect.bottom - 4))) {
877 if ((y < rectsel.top) || (y > rectsel.bottom)) {
878 wRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
879 if (wRet == lphl->ItemFocused) return 0;
880 ListBoxSetCurSel(lphl, wRet);
881 ListBoxGetItemRect(lphl, wRet, &rectsel);
882 InvalidateRect(hwnd, NULL, TRUE);
887 return 0;
890 /***********************************************************************
891 * CBLVScroll
893 static LONG CBLVScroll( HWND hwnd, WORD wParam, LONG lParam )
895 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
896 int y;
898 y = lphl->FirstVisible;
900 switch(wParam) {
901 case SB_LINEUP:
902 if (lphl->FirstVisible > 0)
903 lphl->FirstVisible--;
904 break;
906 case SB_LINEDOWN:
907 lphl->FirstVisible++;
908 break;
910 case SB_PAGEUP:
911 if (lphl->FirstVisible > lphl->ItemsVisible) {
912 lphl->FirstVisible -= lphl->ItemsVisible;
913 } else {
914 lphl->FirstVisible = 0;
916 break;
918 case SB_PAGEDOWN:
919 lphl->FirstVisible += lphl->ItemsVisible;
920 break;
922 case SB_THUMBTRACK:
923 lphl->FirstVisible = LOWORD(lParam);
924 break;
927 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
928 lphl->FirstVisible = ListMaxFirstVisible(lphl);
930 if (y != lphl->FirstVisible) {
931 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
932 InvalidateRect(hwnd, NULL, TRUE);
935 return 0;
938 /***********************************************************************
939 * ComboLBoxWndProc
941 LONG ComboLBoxWndProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
943 switch(message) {
944 case WM_CREATE: return CBLCreate(hwnd, wParam, lParam);
945 case WM_GETDLGCODE: return CBLGetDlgCode(hwnd, wParam, lParam);
946 case WM_KEYDOWN: return CBLKeyDown(hwnd, wParam, lParam);
947 case WM_CHAR: return CBLChar(hwnd, wParam, lParam);
948 case WM_PAINT: return CBLPaint(hwnd, wParam, lParam);
949 case WM_KILLFOCUS: return CBLKillFocus(hwnd, wParam, lParam);
950 case WM_ACTIVATE: return CBLActivate(hwnd, wParam, lParam);
951 case WM_LBUTTONDOWN: return CBLLButtonDown(hwnd, wParam, lParam);
952 case WM_LBUTTONUP: return CBLLButtonUp(hwnd, wParam, lParam);
953 case WM_MOUSEMOVE: return CBLMouseMove(hwnd, wParam, lParam);
954 case WM_VSCROLL: return CBLVScroll(hwnd, wParam, lParam);
956 return DefWindowProc(hwnd, message, wParam, lParam);
959 /************************************************************************
960 * DlgDirSelectComboBox [USER.194]
962 BOOL DlgDirSelectComboBox(HWND hDlg, LPSTR lpStr, int nIDLBox)
964 fprintf(stdnimp,"DlgDirSelectComboBox(%04X, '%s', %d) \n",
965 hDlg, lpStr, nIDLBox);
966 return TRUE;
970 /************************************************************************
971 * DlgDirListComboBox [USER.195]
973 int DlgDirListComboBox(HWND hDlg, SEGPTR PathSpec,
974 int nIDLBox, int nIDStat, WORD wType)
976 HWND hWnd;
977 int ret;
978 LPSTR lpPathSpec = PTR_SEG_TO_LIN(PathSpec);
980 dprintf_combo(stddeb,"DlgDirListComboBox(%04X, '%s', %d, %d, %04X) \n",
981 hDlg, lpPathSpec, nIDLBox, nIDStat, wType);
982 if (nIDLBox) {
983 LPHEADLIST lphl;
984 LPHEADCOMBO lphc;
985 hWnd = GetDlgItem(hDlg, nIDLBox);
986 lphl = ComboGetListHeader(hWnd);
987 lphc = ComboGetStorageHeader(hWnd);
988 ListBoxResetContent(lphl);
989 ret = ListBoxDirectory(lphl, wType, lpPathSpec);
990 ComboUpdateWindow(hWnd, lphl, lphc, TRUE);
991 } else {
992 ret = 0;
994 if (nIDStat) {
995 int drive;
996 HANDLE hTemp;
997 char *temp;
998 drive = DOS_GetDefaultDrive();
999 hTemp = USER_HEAP_ALLOC( 256 );
1000 temp = (char *) USER_HEAP_LIN_ADDR( hTemp );
1001 strcpy( temp+3, DOS_GetCurrentDir(drive) );
1002 if( temp[3] == '\\' ) {
1003 temp[1] = 'A'+drive;
1004 temp[2] = ':';
1005 SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
1006 USER_HEAP_SEG_ADDR(hTemp) + 1 );
1007 } else {
1008 temp[0] = 'A'+drive;
1009 temp[1] = ':';
1010 temp[2] = '\\';
1011 SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
1012 USER_HEAP_SEG_ADDR(hTemp) );
1014 USER_HEAP_FREE( hTemp );
1016 return ret;