Release 950817
[wine/multimedia.git] / controls / combo.c
blob1600a23639ddeb92da402fd24fecb054c58947a3
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 "user.h"
18 #include "win.h"
19 #include "stddebug.h"
20 #include "debug.h"
21 #include "graphics.h"
22 #include "listbox.h"
23 #include "dos_fs.h"
26 * Note: Combos are probably implemented in a different way by Windows.
27 * Using a message spy for Windows, you can see some undocumented
28 * messages being passed between ComboBox and ComboLBox.
29 * I hope no programs rely on the implementation of combos.
32 static HBITMAP hComboBit = 0;
33 static WORD CBitHeight, CBitWidth;
35 static int COMBO_Init()
37 BITMAP bm;
39 dprintf_combo(stddeb, "COMBO_Init\n");
40 hComboBit = LoadBitmap(0, MAKEINTRESOURCE(OBM_COMBO));
41 GetObject(hComboBit, sizeof(BITMAP), (LPSTR)&bm);
42 CBitHeight = bm.bmHeight;
43 CBitWidth = bm.bmWidth;
44 return 0;
47 LPHEADCOMBO ComboGetStorageHeader(HWND hwnd)
49 return (LPHEADCOMBO)GetWindowLong(hwnd,4);
52 LPHEADLIST ComboGetListHeader(HWND hwnd)
54 return (LPHEADLIST)GetWindowLong(hwnd,0);
57 int CreateComboStruct(HWND hwnd, LONG style)
59 LPHEADCOMBO lphc;
61 lphc = (LPHEADCOMBO)malloc(sizeof(HEADCOMBO));
62 SetWindowLong(hwnd,4,(LONG)lphc);
63 lphc->hWndEdit = 0;
64 lphc->hWndLBox = 0;
65 lphc->dwState = 0;
66 lphc->LastSel = -1;
67 lphc->dwStyle = style;
68 lphc->DropDownVisible = FALSE;
69 return TRUE;
72 void ComboUpdateWindow(HWND hwnd, LPHEADLIST lphl, LPHEADCOMBO lphc, BOOL repaint)
74 SetScrollRange(lphc->hWndLBox, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
75 if (repaint && lphl->bRedrawFlag) {
76 InvalidateRect(hwnd, NULL, TRUE);
80 /***********************************************************************
81 * CBNCCreate
83 static LONG CBNCCreate(HWND hwnd, WORD wParam, LONG lParam)
85 CREATESTRUCT *createStruct;
87 if (!hComboBit) COMBO_Init();
89 createStruct = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
90 createStruct->style &= ~(WS_VSCROLL | WS_HSCROLL);
91 SetWindowLong(hwnd, GWL_STYLE, createStruct->style);
93 dprintf_combo(stddeb,"ComboBox WM_NCCREATE!\n");
94 return DefWindowProc(hwnd, WM_NCCREATE, wParam, lParam);
98 /***********************************************************************
99 * CBCreate
101 static LONG CBCreate(HWND hwnd, WORD wParam, LONG lParam)
103 LPHEADLIST lphl;
104 LPHEADCOMBO lphc;
105 LONG style = 0;
106 LONG cstyle = GetWindowLong(hwnd,GWL_STYLE);
107 RECT rect,lboxrect;
108 char className[] = "COMBOLBOX"; /* Hack so that class names are > 0x10000 */
109 char editName[] = "EDIT";
111 /* translate combo into listbox styles */
112 if (cstyle & CBS_OWNERDRAWFIXED) style |= LBS_OWNERDRAWFIXED;
113 if (cstyle & CBS_OWNERDRAWVARIABLE) style |= LBS_OWNERDRAWVARIABLE;
114 if (cstyle & CBS_SORT) style |= LBS_SORT;
115 if (cstyle & CBS_HASSTRINGS) style |= LBS_HASSTRINGS;
116 style |= LBS_NOTIFY;
117 CreateListBoxStruct(hwnd, ODT_COMBOBOX, style, GetParent(hwnd));
118 CreateComboStruct(hwnd,cstyle);
119 lphl = ComboGetListHeader(hwnd);
120 lphc = ComboGetStorageHeader(hwnd);
122 GetClientRect(hwnd,&rect);
123 GetWindowRect(hwnd,&lboxrect);
124 /* FIXME: combos with edit controls are broken. */
125 switch(cstyle & 3) {
126 case CBS_SIMPLE: /* edit control, list always visible */
127 dprintf_combo(stddeb,"CBS_SIMPLE\n");
128 SetRectEmpty(&lphc->RectButton);
129 lphc->LBoxTop = lphl->StdItemHeight;
130 lphc->hWndEdit = CreateWindow(editName, "",
131 WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | SS_LEFT,
132 0, 0, rect.right, lphl->StdItemHeight,
133 hwnd, 1, GetWindowWord(hwnd,GWW_HINSTANCE), 0L);
134 break;
135 case CBS_DROPDOWN: /* edit control, dropdown listbox */
136 dprintf_combo(stddeb,"CBS_DROPDOWN\n");
137 lphc->RectButton = rect;
138 lphc->RectButton.left = lphc->RectButton.right - 6 - CBitWidth;
139 lphc->RectButton.bottom = lphc->RectButton.top + lphl->StdItemHeight;
140 lphc->LBoxTop = lphl->StdItemHeight;
141 SetWindowPos(hwnd, 0, 0, 0, rect.right - rect.left + 2*SYSMETRICS_CXBORDER,
142 lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER,
143 SWP_NOMOVE | SWP_NOZORDER);
144 lphc->hWndEdit = CreateWindow(editName, "",
145 WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | SS_LEFT,
146 0, 0, lphc->RectButton.left, lphl->StdItemHeight,
147 hwnd, 1, GetWindowWord(hwnd,GWW_HINSTANCE), 0L);
148 break;
149 case CBS_DROPDOWNLIST: /* static control, downdown listbox */
150 dprintf_combo(stddeb,"CBS_DROPDOWNLIST\n");
151 lphc->RectButton = rect;
152 lphc->RectButton.left = lphc->RectButton.right - 6 - CBitWidth;
153 lphc->RectButton.bottom = lphc->RectButton.top + lphl->StdItemHeight;
154 lphc->LBoxTop = lphl->StdItemHeight;
155 SetWindowPos(hwnd, 0, 0, 0, rect.right - rect.left + 2*SYSMETRICS_CXBORDER,
156 lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER,
157 SWP_NOMOVE | SWP_NOZORDER);
158 break;
160 lboxrect.top += lphc->LBoxTop;
161 /* FIXME: WinSight says these should be CHILD windows with the TOPMOST flag
162 * set. Wine doesn't support TOPMOST, and simply setting the WS_CHILD
163 * flag doesn't work. */
164 lphc->hWndLBox = CreateWindow(className, "",
165 WS_POPUP | WS_BORDER | WS_VSCROLL,
166 lboxrect.left, lboxrect.top,
167 lboxrect.right - lboxrect.left,
168 lboxrect.bottom - lboxrect.top,
169 0, 0, GetWindowWord(hwnd,GWW_HINSTANCE),
170 (SEGPTR)MAKELONG(hwnd, hwnd));
171 ShowWindow(lphc->hWndLBox, SW_HIDE);
172 dprintf_combo(stddeb,"Combo Creation LBox=%X!\n", lphc->hWndLBox);
173 return 0;
176 /***********************************************************************
177 * CBDestroy
179 static LONG CBDestroy(HWND hwnd, WORD wParam, LONG lParam)
181 LPHEADLIST lphl = ComboGetListHeader(hwnd);
183 ListBoxResetContent(lphl);
184 DestroyListBoxStruct(lphl);
185 dprintf_combo(stddeb,"Combo WM_DESTROY %p !\n", lphl);
186 return 0;
189 /***********************************************************************
190 * CBPaint
192 static LONG CBPaint(HWND hwnd, WORD wParam, LONG lParam)
194 LPHEADLIST lphl = ComboGetListHeader(hwnd);
195 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
196 LPLISTSTRUCT lpls;
197 PAINTSTRUCT ps;
198 HBRUSH hBrush;
199 HFONT hOldFont;
200 HDC hdc;
201 RECT rect;
202 int height;
204 hdc = BeginPaint(hwnd, &ps);
206 if (hComboBit != 0) {
207 GRAPH_DrawReliefRect(hdc, &lphc->RectButton, 2, 2, FALSE);
208 GRAPH_DrawBitmap(hdc, hComboBit,
209 lphc->RectButton.left + 3,lphc->RectButton.top + 2,
210 0, 0, CBitWidth, CBitHeight );
212 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag
213 || (lphc->dwStyle & 3) != CBS_DROPDOWNLIST)
215 /* we don't want to draw an entry when there is an edit control */
216 EndPaint(hwnd, &ps);
217 return 0;
220 hOldFont = SelectObject(hdc, lphl->hFont);
222 hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
223 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
224 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
226 GetClientRect(hwnd, &rect);
227 rect.right -= (lphc->RectButton.right - lphc->RectButton.left);
228 FillRect(hdc, &rect, hBrush);
230 lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
231 if (lpls != NULL) {
232 height = lpls->mis.itemHeight;
233 rect.bottom = rect.top + height;
235 if (lphl->OwnerDrawn) {
236 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
237 } else {
238 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
240 if (GetFocus() == hwnd)
241 ListBoxDrawItem (hwnd,lphl, hdc, lpls, &rect, ODA_FOCUS, ODS_FOCUS);
243 SelectObject(hdc,hOldFont);
244 EndPaint(hwnd, &ps);
245 return 0;
248 /***********************************************************************
249 * CBGetDlgCode
251 static LONG CBGetDlgCode(HWND hwnd, WORD wParam, LONG lParam)
253 return DLGC_WANTARROWS | DLGC_WANTCHARS;
256 /***********************************************************************
257 * CBLButtonDown
259 static LONG CBLButtonDown(HWND hwnd, WORD wParam, LONG lParam)
261 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
262 SendMessage(hwnd,CB_SHOWDROPDOWN,!lphc->DropDownVisible,0);
263 return 0;
266 /***********************************************************************
267 * CBKeyDown
269 static LONG CBKeyDown(HWND hwnd, WORD wParam, LONG lParam)
271 LPHEADLIST lphl = ComboGetListHeader(hwnd);
272 WORD newFocused = lphl->ItemFocused;
274 switch(wParam) {
275 case VK_HOME:
276 newFocused = 0;
277 break;
278 case VK_END:
279 newFocused = lphl->ItemsCount - 1;
280 break;
281 case VK_UP:
282 if (newFocused > 0) newFocused--;
283 break;
284 case VK_DOWN:
285 newFocused++;
286 break;
287 default:
288 return 0;
291 if (newFocused >= lphl->ItemsCount)
292 newFocused = lphl->ItemsCount - 1;
294 ListBoxSetCurSel(lphl, newFocused);
295 ListBoxSendNotification(lphl, hwnd, CBN_SELCHANGE);
297 lphl->ItemFocused = newFocused;
298 ListBoxScrollToFocus(lphl);
299 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
300 InvalidateRect(hwnd, NULL, TRUE);
302 return 0;
305 /***********************************************************************
306 * CBChar
308 static LONG CBChar(HWND hwnd, WORD wParam, LONG lParam)
310 LPHEADLIST lphl = ComboGetListHeader(hwnd);
311 WORD newFocused;
313 newFocused = ListBoxFindNextMatch(lphl, wParam);
314 if (newFocused == (WORD)LB_ERR) return 0;
316 if (newFocused >= lphl->ItemsCount)
317 newFocused = lphl->ItemsCount - 1;
319 ListBoxSetCurSel(lphl, newFocused);
320 ListBoxSendNotification(lphl, hwnd, CBN_SELCHANGE);
321 lphl->ItemFocused = newFocused;
322 ListBoxScrollToFocus(lphl);
324 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
325 InvalidateRect(hwnd, NULL, TRUE);
327 return 0;
330 /***********************************************************************
331 * CBKillFocus
333 static LONG CBKillFocus(HWND hwnd, WORD wParam, LONG lParam)
335 return 0;
338 /***********************************************************************
339 * CBSetFocus
341 static LONG CBSetFocus(HWND hwnd, WORD wParam, LONG lParam)
343 return 0;
346 /***********************************************************************
347 * CBResetContent
349 static LONG CBResetContent(HWND hwnd, WORD wParam, LONG lParam)
351 LPHEADLIST lphl = ComboGetListHeader(hwnd);
352 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
354 ListBoxResetContent(lphl);
355 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
356 return 0;
359 /***********************************************************************
360 * CBDir
362 static LONG CBDir(HWND hwnd, WORD wParam, LONG lParam)
364 WORD wRet;
365 LPHEADLIST lphl = ComboGetListHeader(hwnd);
366 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
368 wRet = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
369 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
370 return wRet;
373 /***********************************************************************
374 * CBInsertString
376 static LONG CBInsertString(HWND hwnd, WORD wParam, LONG lParam)
378 WORD wRet;
379 LPHEADLIST lphl = ComboGetListHeader(hwnd);
380 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
382 if (lphl->HasStrings)
383 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
384 else
385 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)lParam);
387 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
388 return wRet;
391 /***********************************************************************
392 * CBAddString
394 static LONG CBAddString(HWND hwnd, WORD wParam, LONG lParam)
396 WORD wRet;
397 LPHEADLIST lphl = ComboGetListHeader(hwnd);
398 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
400 if (lphl->HasStrings)
401 wRet = ListBoxAddString(lphl, (LPSTR)PTR_SEG_TO_LIN(lParam));
402 else
403 wRet = ListBoxAddString(lphl, (LPSTR)lParam);
405 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
406 return wRet;
409 /***********************************************************************
410 * CBDeleteString
412 static LONG CBDeleteString(HWND hwnd, WORD wParam, LONG lParam)
414 LPHEADLIST lphl = ComboGetListHeader(hwnd);
415 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
416 LONG lRet = ListBoxDeleteString(lphl,wParam);
418 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
419 return lRet;
422 /***********************************************************************
423 * CBSelectString
425 static LONG CBSelectString(HWND hwnd, WORD wParam, LONG lParam)
427 LPHEADLIST lphl = ComboGetListHeader(hwnd);
428 WORD wRet;
430 wRet = ListBoxFindString(lphl, wParam, lParam);
432 /* XXX add functionality here */
434 return 0;
437 /***********************************************************************
438 * CBFindString
440 static LONG CBFindString(HWND hwnd, WORD wParam, LONG lParam)
442 LPHEADLIST lphl = ComboGetListHeader(hwnd);
443 return ListBoxFindString(lphl, wParam, lParam);
446 /***********************************************************************
447 * CBGetCount
449 static LONG CBGetCount(HWND hwnd, WORD wParam, LONG lParam)
451 LPHEADLIST lphl = ComboGetListHeader(hwnd);
452 return lphl->ItemsCount;
455 /***********************************************************************
456 * CBSetCurSel
458 static LONG CBSetCurSel(HWND hwnd, WORD wParam, LONG lParam)
460 LPHEADLIST lphl = ComboGetListHeader(hwnd);
461 WORD wRet;
463 wRet = ListBoxSetCurSel(lphl, wParam);
465 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
466 InvalidateRect(hwnd, NULL, TRUE);
468 return wRet;
471 /***********************************************************************
472 * CBGetCurSel
474 static LONG CBGetCurSel(HWND hwnd, WORD wParam, LONG lParam)
476 LPHEADLIST lphl = ComboGetListHeader(hwnd);
477 return lphl->ItemFocused;
480 /***********************************************************************
481 * CBGetItemHeight
483 static LONG CBGetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
485 LPHEADLIST lphl = ComboGetListHeader(hwnd);
486 LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
488 if (lpls == NULL) return LB_ERR;
489 return lpls->mis.itemHeight;
492 /***********************************************************************
493 * CBSetItemHeight
495 static LONG CBSetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
497 LPHEADLIST lphl = ComboGetListHeader(hwnd);
498 return ListBoxSetItemHeight(lphl, wParam, lParam);
501 /***********************************************************************
502 * CBSetRedraw
504 static LONG CBSetRedraw(HWND hwnd, WORD wParam, LONG lParam)
506 LPHEADLIST lphl = ComboGetListHeader(hwnd);
507 lphl->bRedrawFlag = wParam;
508 return 0;
511 /***********************************************************************
512 * CBSetFont
514 static LONG CBSetFont(HWND hwnd, WORD wParam, LONG lParam)
516 LPHEADLIST lphl = ComboGetListHeader(hwnd);
518 if (wParam == 0)
519 lphl->hFont = GetStockObject(SYSTEM_FONT);
520 else
521 lphl->hFont = wParam;
523 return 0;
526 /***********************************************************************
527 * CBGetLBTextLen
529 static LONG CBGetLBTextLen(HWND hwnd, WORD wParam, LONG lParam)
531 LPHEADLIST lphl = ComboGetListHeader(hwnd);
532 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
534 if (lpls == NULL || !lphl->HasStrings) return LB_ERR;
535 return strlen(lpls->itemText);
538 /***********************************************************************
539 * CBGetLBText
541 static LONG CBGetLBText(HWND hwnd, WORD wParam, LONG lParam)
543 LPHEADLIST lphl = ComboGetListHeader(hwnd);
544 return ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
547 /***********************************************************************
548 * CBGetItemData
550 static LONG CBGetItemData(HWND hwnd, WORD wParam, LONG lParam)
552 LPHEADLIST lphl = ComboGetListHeader(hwnd);
553 return ListBoxGetItemData(lphl, wParam);
556 /***********************************************************************
557 * CBSetItemData
559 static LONG CBSetItemData(HWND hwnd, WORD wParam, LONG lParam)
561 LPHEADLIST lphl = ComboGetListHeader(hwnd);
562 return ListBoxSetItemData(lphl, wParam, lParam);
565 /***********************************************************************
566 * CBShowDropDown
568 static LONG CBShowDropDown(HWND hwnd, WORD wParam, LONG lParam)
570 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
571 RECT rect;
573 if (lphc->dwStyle & 3 == CBS_SIMPLE) return LB_ERR;
575 wParam = !!wParam;
576 if (wParam != lphc->DropDownVisible) {
577 lphc->DropDownVisible = wParam;
578 GetWindowRect(hwnd,&rect);
579 SetWindowPos(lphc->hWndLBox, 0, rect.left, rect.top+lphc->LBoxTop, 0, 0,
580 SWP_NOSIZE | (wParam ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
581 if (!wParam) SetFocus(hwnd);
583 return 0;
587 /***********************************************************************
588 * ComboWndProc
590 LONG ComboBoxWndProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
592 switch(message) {
593 case WM_NCCREATE: return CBNCCreate(hwnd, wParam, lParam);
594 case WM_CREATE: return CBCreate(hwnd, wParam, lParam);
595 case WM_DESTROY: return CBDestroy(hwnd, wParam, lParam);
596 case WM_GETDLGCODE: return CBGetDlgCode(hwnd, wParam, lParam);
597 case WM_KEYDOWN: return CBKeyDown(hwnd, wParam, lParam);
598 case WM_CHAR: return CBChar(hwnd, wParam, lParam);
599 case WM_SETFONT: return CBSetFont(hwnd, wParam, lParam);
600 case WM_SETREDRAW: return CBSetRedraw(hwnd, wParam, lParam);
601 case WM_PAINT: return CBPaint(hwnd, wParam, lParam);
602 case WM_LBUTTONDOWN: return CBLButtonDown(hwnd, wParam, lParam);
603 case WM_SETFOCUS: return CBSetFocus(hwnd, wParam, lParam);
604 case WM_KILLFOCUS: return CBKillFocus(hwnd, wParam, lParam);
605 case CB_RESETCONTENT: return CBResetContent(hwnd, wParam, lParam);
606 case CB_DIR: return CBDir(hwnd, wParam, lParam);
607 case CB_ADDSTRING: return CBAddString(hwnd, wParam, lParam);
608 case CB_INSERTSTRING: return CBInsertString(hwnd, wParam, lParam);
609 case CB_DELETESTRING: return CBDeleteString(hwnd, wParam, lParam);
610 case CB_FINDSTRING: return CBFindString(hwnd, wParam, lParam);
611 case CB_GETCOUNT: return CBGetCount(hwnd, wParam, lParam);
612 case CB_GETCURSEL: return CBGetCurSel(hwnd, wParam, lParam);
613 case CB_GETITEMDATA: return CBGetItemData(hwnd, wParam, lParam);
614 case CB_GETITEMHEIGHT: return CBGetItemHeight(hwnd, wParam, lParam);
615 case CB_GETLBTEXT: return CBGetLBText(hwnd, wParam, lParam);
616 case CB_GETLBTEXTLEN: return CBGetLBTextLen(hwnd, wParam, lParam);
617 case CB_SELECTSTRING: return CBSelectString(hwnd, wParam, lParam);
618 case CB_SETITEMDATA: return CBSetItemData(hwnd, wParam, lParam);
619 case CB_SETCURSEL: return CBSetCurSel(hwnd, wParam, lParam);
620 case CB_SETITEMHEIGHT: return CBSetItemHeight(hwnd, wParam, lParam);
621 case CB_SHOWDROPDOWN: return CBShowDropDown(hwnd, wParam, lParam);
623 return DefWindowProc(hwnd, message, wParam, lParam);
626 /*--------------------------------------------------------------------*/
627 /* ComboLBox code starts here */
629 HWND CLBoxGetCombo(HWND hwnd)
631 return GetWindowWord(hwnd,0);
634 LPHEADLIST CLBoxGetListHeader(HWND hwnd)
636 return ComboGetListHeader(CLBoxGetCombo(hwnd));
639 /***********************************************************************
640 * CBLCreate
642 static LONG CBLCreate( HWND hwnd, WORD wParam, LONG lParam )
644 CREATESTRUCT *createStruct = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
645 SetWindowWord(hwnd,0,LOWORD(createStruct->lpCreateParams));
646 return 0;
649 /***********************************************************************
650 * CBLGetDlgCode
652 static LONG CBLGetDlgCode( HWND hwnd, WORD wParam, LONG lParam )
654 return DLGC_WANTARROWS | DLGC_WANTCHARS;
657 /***********************************************************************
658 * CBLKeyDown
660 static LONG CBLKeyDown( HWND hwnd, WORD wParam, LONG lParam )
662 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
663 WORD newFocused = lphl->ItemFocused;
665 switch(wParam) {
666 case VK_HOME:
667 newFocused = 0;
668 break;
669 case VK_END:
670 newFocused = lphl->ItemsCount - 1;
671 break;
672 case VK_UP:
673 if (newFocused > 0) newFocused--;
674 break;
675 case VK_DOWN:
676 newFocused++;
677 break;
678 case VK_PRIOR:
679 if (newFocused > lphl->ItemsVisible) {
680 newFocused -= lphl->ItemsVisible;
681 } else {
682 newFocused = 0;
684 break;
685 case VK_NEXT:
686 newFocused += lphl->ItemsVisible;
687 break;
688 default:
689 return 0;
692 if (newFocused >= lphl->ItemsCount)
693 newFocused = lphl->ItemsCount - 1;
695 ListBoxSetCurSel(lphl, newFocused);
696 ListBoxSendNotification(lphl, hwnd, CBN_SELCHANGE);
698 lphl->ItemFocused = newFocused;
699 ListBoxScrollToFocus(lphl);
700 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
701 InvalidateRect(hwnd, NULL, TRUE);
702 return 0;
705 /***********************************************************************
706 * CBLChar
708 static LONG CBLChar( HWND hwnd, WORD wParam, LONG lParam )
710 return 0;
713 /***********************************************************************
714 * CBLPaint
716 static LONG CBLPaint( HWND hwnd, WORD wParam, LONG lParam )
718 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
719 LPLISTSTRUCT lpls;
720 PAINTSTRUCT ps;
721 HBRUSH hBrush;
722 HFONT hOldFont;
723 HWND combohwnd = CLBoxGetCombo(hwnd);
724 HDC hdc;
725 RECT rect;
726 int i, top, height;
728 top = 0;
729 hdc = BeginPaint( hwnd, &ps );
731 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) {
732 EndPaint(hwnd, &ps);
733 return 0;
736 hOldFont = SelectObject(hdc, lphl->hFont);
737 hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
738 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
740 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
742 GetClientRect(hwnd, &rect);
743 FillRect(hdc, &rect, hBrush);
745 lpls = lphl->lpFirst;
747 lphl->ItemsVisible = 0;
748 for(i = 0; i < lphl->ItemsCount; i++) {
749 if (lpls == NULL) break;
751 if (i >= lphl->FirstVisible) {
752 height = lpls->mis.itemHeight;
754 if (top > rect.bottom) break;
755 lpls->itemRect.top = top;
756 lpls->itemRect.bottom = top + height;
757 lpls->itemRect.left = rect.left;
758 lpls->itemRect.right = rect.right;
760 dprintf_listbox(stddeb,"drawing item: %d %d %d %d %d\n",rect.left,top,rect.right,top+height,lpls->itemState);
761 if (lphl->OwnerDrawn) {
762 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, 0);
763 if (lpls->itemState)
764 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_SELECT, ODS_SELECTED);
765 } else {
766 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
767 lpls->itemState);
769 if ((lphl->ItemFocused == i) && GetFocus() == hwnd)
770 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, ODS_FOCUS);
772 top += height;
773 lphl->ItemsVisible++;
776 lpls = lpls->lpNext;
778 SelectObject(hdc,hOldFont);
779 EndPaint( hwnd, &ps );
780 return 0;
784 /***********************************************************************
785 * CBLKillFocus
787 static LONG CBLKillFocus( HWND hwnd, WORD wParam, LONG lParam )
789 /* SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);*/
790 return 0;
793 /***********************************************************************
794 * CBLActivate
796 static LONG CBLActivate( HWND hwnd, WORD wParam, LONG lParam )
798 if (wParam == WA_INACTIVE)
799 SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
800 return 0;
803 /***********************************************************************
804 * CBLLButtonDown
806 static LONG CBLLButtonDown( HWND hwnd, WORD wParam, LONG lParam )
808 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
809 int y;
810 RECT rectsel;
812 SetFocus(hwnd);
813 SetCapture(hwnd);
815 lphl->PrevFocused = lphl->ItemFocused;
817 y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
818 if (y == -1)
819 return 0;
821 ListBoxSetCurSel(lphl, y);
822 ListBoxGetItemRect(lphl, y, &rectsel);
824 InvalidateRect(hwnd, NULL, TRUE);
825 return 0;
828 /***********************************************************************
829 * CBLLButtonUp
831 static LONG CBLLButtonUp( HWND hwnd, WORD wParam, LONG lParam )
833 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
835 if (GetCapture() == hwnd) ReleaseCapture();
837 if (lphl->PrevFocused != lphl->ItemFocused) {
838 SendMessage(CLBoxGetCombo(hwnd),CB_SETCURSEL,lphl->ItemFocused,0);
839 ListBoxSendNotification(lphl, CLBoxGetCombo(hwnd), CBN_SELCHANGE);
841 SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
843 return 0;
846 /***********************************************************************
847 * CBLMouseMove
849 static LONG CBLMouseMove( HWND hwnd, WORD wParam, LONG lParam )
851 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
852 int y;
853 WORD wRet;
854 RECT rect, rectsel; /* XXX Broken */
856 if ((wParam & MK_LBUTTON) != 0) {
857 y = SHIWORD(lParam);
858 if (y < 0) {
859 if (lphl->FirstVisible > 0) {
860 lphl->FirstVisible--;
861 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
862 InvalidateRect(hwnd, NULL, TRUE);
863 return 0;
866 GetClientRect(hwnd, &rect);
867 if (y >= rect.bottom) {
868 if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
869 lphl->FirstVisible++;
870 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
871 InvalidateRect(hwnd, NULL, TRUE);
872 return 0;
875 if ((y > 0) && (y < (rect.bottom - 4))) {
876 if ((y < rectsel.top) || (y > rectsel.bottom)) {
877 wRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
878 if (wRet == lphl->ItemFocused) return 0;
879 ListBoxSetCurSel(lphl, wRet);
880 ListBoxGetItemRect(lphl, wRet, &rectsel);
881 InvalidateRect(hwnd, NULL, TRUE);
886 return 0;
889 /***********************************************************************
890 * CBLVScroll
892 static LONG CBLVScroll( HWND hwnd, WORD wParam, LONG lParam )
894 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
895 int y;
897 y = lphl->FirstVisible;
899 switch(wParam) {
900 case SB_LINEUP:
901 if (lphl->FirstVisible > 0)
902 lphl->FirstVisible--;
903 break;
905 case SB_LINEDOWN:
906 lphl->FirstVisible++;
907 break;
909 case SB_PAGEUP:
910 if (lphl->FirstVisible > lphl->ItemsVisible) {
911 lphl->FirstVisible -= lphl->ItemsVisible;
912 } else {
913 lphl->FirstVisible = 0;
915 break;
917 case SB_PAGEDOWN:
918 lphl->FirstVisible += lphl->ItemsVisible;
919 break;
921 case SB_THUMBTRACK:
922 lphl->FirstVisible = LOWORD(lParam);
923 break;
926 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
927 lphl->FirstVisible = ListMaxFirstVisible(lphl);
929 if (y != lphl->FirstVisible) {
930 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
931 InvalidateRect(hwnd, NULL, TRUE);
934 return 0;
937 /***********************************************************************
938 * ComboLBoxWndProc
940 LONG ComboLBoxWndProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
942 switch(message) {
943 case WM_CREATE: return CBLCreate(hwnd, wParam, lParam);
944 case WM_GETDLGCODE: return CBLGetDlgCode(hwnd, wParam, lParam);
945 case WM_KEYDOWN: return CBLKeyDown(hwnd, wParam, lParam);
946 case WM_CHAR: return CBLChar(hwnd, wParam, lParam);
947 case WM_PAINT: return CBLPaint(hwnd, wParam, lParam);
948 case WM_KILLFOCUS: return CBLKillFocus(hwnd, wParam, lParam);
949 case WM_ACTIVATE: return CBLActivate(hwnd, wParam, lParam);
950 case WM_LBUTTONDOWN: return CBLLButtonDown(hwnd, wParam, lParam);
951 case WM_LBUTTONUP: return CBLLButtonUp(hwnd, wParam, lParam);
952 case WM_MOUSEMOVE: return CBLMouseMove(hwnd, wParam, lParam);
953 case WM_VSCROLL: return CBLVScroll(hwnd, wParam, lParam);
955 return DefWindowProc(hwnd, message, wParam, lParam);
958 /************************************************************************
959 * DlgDirSelectComboBox [USER.194]
961 BOOL DlgDirSelectComboBox(HWND hDlg, LPSTR lpStr, int nIDLBox)
963 fprintf(stdnimp,"DlgDirSelectComboBox(%04X, '%s', %d) \n",
964 hDlg, lpStr, nIDLBox);
965 return TRUE;
969 /************************************************************************
970 * DlgDirListComboBox [USER.195]
972 int DlgDirListComboBox(HWND hDlg, SEGPTR PathSpec,
973 int nIDLBox, int nIDStat, WORD wType)
975 HWND hWnd;
976 int ret;
977 LPSTR lpPathSpec = PTR_SEG_TO_LIN(PathSpec);
979 dprintf_combo(stddeb,"DlgDirListComboBox(%04X, '%s', %d, %d, %04X) \n",
980 hDlg, lpPathSpec, nIDLBox, nIDStat, wType);
981 if (nIDLBox) {
982 LPHEADLIST lphl;
983 LPHEADCOMBO lphc;
984 hWnd = GetDlgItem(hDlg, nIDLBox);
985 lphl = ComboGetListHeader(hWnd);
986 lphc = ComboGetStorageHeader(hWnd);
987 ListBoxResetContent(lphl);
988 ret = ListBoxDirectory(lphl, wType, lpPathSpec);
989 ComboUpdateWindow(hWnd, lphl, lphc, TRUE);
990 } else {
991 ret = 0;
993 if (nIDStat) {
994 int drive;
995 HANDLE hTemp;
996 char *temp;
997 drive = DOS_GetDefaultDrive();
998 hTemp = USER_HEAP_ALLOC( 256 );
999 temp = (char *) USER_HEAP_LIN_ADDR( hTemp );
1000 strcpy( temp+3, DOS_GetCurrentDir(drive) );
1001 if( temp[3] == '\\' ) {
1002 temp[1] = 'A'+drive;
1003 temp[2] = ':';
1004 SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
1005 USER_HEAP_SEG_ADDR(hTemp) + 1 );
1006 } else {
1007 temp[0] = 'A'+drive;
1008 temp[1] = ':';
1009 temp[2] = '\\';
1010 SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
1011 USER_HEAP_SEG_ADDR(hTemp) );
1013 USER_HEAP_FREE( hTemp );
1015 return ret;