Release 951003
[wine/multimedia.git] / controls / combo.c
blobaab97f53932dd9f1286b7f7e254c1812f5dce3bb
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, (HMENU)1, WIN_GetWindowInstance(hwnd), 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, (HMENU)1, WIN_GetWindowInstance(hwnd), 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, WIN_GetWindowInstance(hwnd),
171 (SEGPTR)hwnd );
172 ShowWindow(lphc->hWndLBox, SW_HIDE);
173 dprintf_combo(stddeb,"Combo Creation LBox="NPFMT"!\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 #ifdef WINELIB32
224 hBrush = (HBRUSH) SendMessage(lphl->hParent, WM_CTLCOLORLISTBOX, (WPARAM)hdc,
225 (LPARAM)hwnd);
226 #else
227 hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
228 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
229 #endif
230 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
232 GetClientRect(hwnd, &rect);
233 rect.right -= (lphc->RectButton.right - lphc->RectButton.left);
234 FillRect(hdc, &rect, hBrush);
236 lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
237 if (lpls != NULL) {
238 height = lpls->mis.itemHeight;
239 rect.bottom = rect.top + height;
241 if (lphl->OwnerDrawn) {
242 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
243 } else {
244 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
246 if (GetFocus() == hwnd)
247 ListBoxDrawItem (hwnd,lphl, hdc, lpls, &rect, ODA_FOCUS, ODS_FOCUS);
249 SelectObject(hdc,hOldFont);
250 EndPaint(hwnd, &ps);
251 return 0;
254 /***********************************************************************
255 * CBGetDlgCode
257 static LONG CBGetDlgCode(HWND hwnd, WORD wParam, LONG lParam)
259 return DLGC_WANTARROWS | DLGC_WANTCHARS;
262 /***********************************************************************
263 * CBLButtonDown
265 static LONG CBLButtonDown(HWND hwnd, WORD wParam, LONG lParam)
267 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
268 SendMessage(hwnd,CB_SHOWDROPDOWN,!lphc->DropDownVisible,0);
269 return 0;
272 /***********************************************************************
273 * CBKeyDown
275 static LONG CBKeyDown(HWND hwnd, WORD wParam, LONG lParam)
277 LPHEADLIST lphl = ComboGetListHeader(hwnd);
278 WORD newFocused = lphl->ItemFocused;
280 switch(wParam) {
281 case VK_HOME:
282 newFocused = 0;
283 break;
284 case VK_END:
285 newFocused = lphl->ItemsCount - 1;
286 break;
287 case VK_UP:
288 if (newFocused > 0) newFocused--;
289 break;
290 case VK_DOWN:
291 newFocused++;
292 break;
293 default:
294 return 0;
297 if (newFocused >= lphl->ItemsCount)
298 newFocused = lphl->ItemsCount - 1;
300 ListBoxSetCurSel(lphl, newFocused);
301 ListBoxSendNotification(lphl, hwnd, CBN_SELCHANGE);
303 lphl->ItemFocused = newFocused;
304 ListBoxScrollToFocus(lphl);
305 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
306 InvalidateRect(hwnd, NULL, TRUE);
308 return 0;
311 /***********************************************************************
312 * CBChar
314 static LONG CBChar(HWND hwnd, WORD wParam, LONG lParam)
316 LPHEADLIST lphl = ComboGetListHeader(hwnd);
317 WORD newFocused;
319 newFocused = ListBoxFindNextMatch(lphl, wParam);
320 if (newFocused == (WORD)LB_ERR) return 0;
322 if (newFocused >= lphl->ItemsCount)
323 newFocused = lphl->ItemsCount - 1;
325 ListBoxSetCurSel(lphl, newFocused);
326 ListBoxSendNotification(lphl, hwnd, CBN_SELCHANGE);
327 lphl->ItemFocused = newFocused;
328 ListBoxScrollToFocus(lphl);
330 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
331 InvalidateRect(hwnd, NULL, TRUE);
333 return 0;
336 /***********************************************************************
337 * CBKillFocus
339 static LONG CBKillFocus(HWND hwnd, WORD wParam, LONG lParam)
341 return 0;
344 /***********************************************************************
345 * CBSetFocus
347 static LONG CBSetFocus(HWND hwnd, WORD wParam, LONG lParam)
349 return 0;
352 /***********************************************************************
353 * CBResetContent
355 static LONG CBResetContent(HWND hwnd, WORD wParam, LONG lParam)
357 LPHEADLIST lphl = ComboGetListHeader(hwnd);
358 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
360 ListBoxResetContent(lphl);
361 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
362 return 0;
365 /***********************************************************************
366 * CBDir
368 static LONG CBDir(HWND hwnd, WORD wParam, LONG lParam)
370 WORD wRet;
371 LPHEADLIST lphl = ComboGetListHeader(hwnd);
372 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
374 wRet = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
375 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
376 return wRet;
379 /***********************************************************************
380 * CBInsertString
382 static LONG CBInsertString(HWND hwnd, WORD wParam, LONG lParam)
384 WORD wRet;
385 LPHEADLIST lphl = ComboGetListHeader(hwnd);
386 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
388 if (lphl->HasStrings)
389 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
390 else
391 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)lParam);
393 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
394 return wRet;
397 /***********************************************************************
398 * CBAddString
400 static LONG CBAddString(HWND hwnd, WORD wParam, LONG lParam)
402 WORD wRet;
403 LPHEADLIST lphl = ComboGetListHeader(hwnd);
404 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
406 if (lphl->HasStrings)
407 wRet = ListBoxAddString(lphl, (LPSTR)PTR_SEG_TO_LIN(lParam));
408 else
409 wRet = ListBoxAddString(lphl, (LPSTR)lParam);
411 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
412 return wRet;
415 /***********************************************************************
416 * CBDeleteString
418 static LONG CBDeleteString(HWND hwnd, WORD wParam, LONG lParam)
420 LPHEADLIST lphl = ComboGetListHeader(hwnd);
421 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
422 LONG lRet = ListBoxDeleteString(lphl,wParam);
424 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
425 return lRet;
428 /***********************************************************************
429 * CBSelectString
431 static LONG CBSelectString(HWND hwnd, WORD wParam, LONG lParam)
433 LPHEADLIST lphl = ComboGetListHeader(hwnd);
434 WORD wRet;
436 wRet = ListBoxFindString(lphl, wParam, lParam);
438 /* XXX add functionality here */
440 return 0;
443 /***********************************************************************
444 * CBFindString
446 static LONG CBFindString(HWND hwnd, WORD wParam, LONG lParam)
448 LPHEADLIST lphl = ComboGetListHeader(hwnd);
449 return ListBoxFindString(lphl, wParam, lParam);
452 /***********************************************************************
453 * CBGetCount
455 static LONG CBGetCount(HWND hwnd, WORD wParam, LONG lParam)
457 LPHEADLIST lphl = ComboGetListHeader(hwnd);
458 return lphl->ItemsCount;
461 /***********************************************************************
462 * CBSetCurSel
464 static LONG CBSetCurSel(HWND hwnd, WORD wParam, LONG lParam)
466 LPHEADLIST lphl = ComboGetListHeader(hwnd);
467 WORD wRet;
469 wRet = ListBoxSetCurSel(lphl, wParam);
471 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
472 InvalidateRect(hwnd, NULL, TRUE);
474 return wRet;
477 /***********************************************************************
478 * CBGetCurSel
480 static LONG CBGetCurSel(HWND hwnd, WORD wParam, LONG lParam)
482 LPHEADLIST lphl = ComboGetListHeader(hwnd);
483 return lphl->ItemFocused;
486 /***********************************************************************
487 * CBGetItemHeight
489 static LONG CBGetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
491 LPHEADLIST lphl = ComboGetListHeader(hwnd);
492 LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
494 if (lpls == NULL) return LB_ERR;
495 return lpls->mis.itemHeight;
498 /***********************************************************************
499 * CBSetItemHeight
501 static LONG CBSetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
503 LPHEADLIST lphl = ComboGetListHeader(hwnd);
504 return ListBoxSetItemHeight(lphl, wParam, lParam);
507 /***********************************************************************
508 * CBSetRedraw
510 static LONG CBSetRedraw(HWND hwnd, WORD wParam, LONG lParam)
512 LPHEADLIST lphl = ComboGetListHeader(hwnd);
513 lphl->bRedrawFlag = wParam;
514 return 0;
517 /***********************************************************************
518 * CBSetFont
520 static LONG CBSetFont(HWND hwnd, WPARAM wParam, LPARAM lParam)
522 LPHEADLIST lphl = ComboGetListHeader(hwnd);
524 if (wParam == 0)
525 lphl->hFont = GetStockObject(SYSTEM_FONT);
526 else
527 lphl->hFont = (HFONT)wParam;
529 return 0;
532 /***********************************************************************
533 * CBGetLBTextLen
535 static LONG CBGetLBTextLen(HWND hwnd, WORD wParam, LONG lParam)
537 LPHEADLIST lphl = ComboGetListHeader(hwnd);
538 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
540 if (lpls == NULL || !lphl->HasStrings) return LB_ERR;
541 return strlen(lpls->itemText);
544 /***********************************************************************
545 * CBGetLBText
547 static LONG CBGetLBText(HWND hwnd, WORD wParam, LONG lParam)
549 LPHEADLIST lphl = ComboGetListHeader(hwnd);
550 return ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
553 /***********************************************************************
554 * CBGetItemData
556 static LONG CBGetItemData(HWND hwnd, WORD wParam, LONG lParam)
558 LPHEADLIST lphl = ComboGetListHeader(hwnd);
559 return ListBoxGetItemData(lphl, wParam);
562 /***********************************************************************
563 * CBSetItemData
565 static LONG CBSetItemData(HWND hwnd, WORD wParam, LONG lParam)
567 LPHEADLIST lphl = ComboGetListHeader(hwnd);
568 return ListBoxSetItemData(lphl, wParam, lParam);
571 /***********************************************************************
572 * CBShowDropDown
574 static LONG CBShowDropDown(HWND hwnd, WORD wParam, LONG lParam)
576 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
577 RECT rect;
579 if (lphc->dwStyle & 3 == CBS_SIMPLE) return LB_ERR;
581 wParam = !!wParam;
582 if (wParam != lphc->DropDownVisible) {
583 lphc->DropDownVisible = wParam;
584 GetWindowRect(hwnd,&rect);
585 SetWindowPos(lphc->hWndLBox, 0, rect.left, rect.top+lphc->LBoxTop, 0, 0,
586 SWP_NOSIZE | (wParam ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
587 if (!wParam) SetFocus(hwnd);
589 return 0;
593 /***********************************************************************
594 * ComboWndProc
596 LRESULT ComboBoxWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
598 switch(message) {
599 case WM_NCCREATE: return CBNCCreate(hwnd, wParam, lParam);
600 case WM_CREATE: return CBCreate(hwnd, wParam, lParam);
601 case WM_DESTROY: return CBDestroy(hwnd, wParam, lParam);
602 case WM_GETDLGCODE: return CBGetDlgCode(hwnd, wParam, lParam);
603 case WM_KEYDOWN: return CBKeyDown(hwnd, wParam, lParam);
604 case WM_CHAR: return CBChar(hwnd, wParam, lParam);
605 case WM_SETFONT: return CBSetFont(hwnd, wParam, lParam);
606 case WM_SETREDRAW: return CBSetRedraw(hwnd, wParam, lParam);
607 case WM_PAINT: return CBPaint(hwnd, wParam, lParam);
608 case WM_LBUTTONDOWN: return CBLButtonDown(hwnd, wParam, lParam);
609 case WM_SETFOCUS: return CBSetFocus(hwnd, wParam, lParam);
610 case WM_KILLFOCUS: return CBKillFocus(hwnd, wParam, lParam);
611 case CB_RESETCONTENT: return CBResetContent(hwnd, wParam, lParam);
612 case CB_DIR: return CBDir(hwnd, wParam, lParam);
613 case CB_ADDSTRING: return CBAddString(hwnd, wParam, lParam);
614 case CB_INSERTSTRING: return CBInsertString(hwnd, wParam, lParam);
615 case CB_DELETESTRING: return CBDeleteString(hwnd, wParam, lParam);
616 case CB_FINDSTRING: return CBFindString(hwnd, wParam, lParam);
617 case CB_GETCOUNT: return CBGetCount(hwnd, wParam, lParam);
618 case CB_GETCURSEL: return CBGetCurSel(hwnd, wParam, lParam);
619 case CB_GETITEMDATA: return CBGetItemData(hwnd, wParam, lParam);
620 case CB_GETITEMHEIGHT: return CBGetItemHeight(hwnd, wParam, lParam);
621 case CB_GETLBTEXT: return CBGetLBText(hwnd, wParam, lParam);
622 case CB_GETLBTEXTLEN: return CBGetLBTextLen(hwnd, wParam, lParam);
623 case CB_SELECTSTRING: return CBSelectString(hwnd, wParam, lParam);
624 case CB_SETITEMDATA: return CBSetItemData(hwnd, wParam, lParam);
625 case CB_SETCURSEL: return CBSetCurSel(hwnd, wParam, lParam);
626 case CB_SETITEMHEIGHT: return CBSetItemHeight(hwnd, wParam, lParam);
627 case CB_SHOWDROPDOWN: return CBShowDropDown(hwnd, wParam, lParam);
629 return DefWindowProc(hwnd, message, wParam, lParam);
632 /*--------------------------------------------------------------------*/
633 /* ComboLBox code starts here */
635 HWND CLBoxGetCombo(HWND hwnd)
637 #ifdef WINELIB32
638 return (HWND)GetWindowLong(hwnd,0);
639 #else
640 return (HWND)GetWindowWord(hwnd,0);
641 #endif
644 LPHEADLIST CLBoxGetListHeader(HWND hwnd)
646 return ComboGetListHeader(CLBoxGetCombo(hwnd));
649 /***********************************************************************
650 * CBLCreate
652 static LONG CBLCreate( HWND hwnd, WORD wParam, LONG lParam )
654 CREATESTRUCT *createStruct = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
655 SetWindowWord(hwnd,0,LOWORD(createStruct->lpCreateParams));
656 return 0;
659 /***********************************************************************
660 * CBLGetDlgCode
662 static LONG CBLGetDlgCode( HWND hwnd, WORD wParam, LONG lParam )
664 return DLGC_WANTARROWS | DLGC_WANTCHARS;
667 /***********************************************************************
668 * CBLKeyDown
670 static LONG CBLKeyDown( HWND hwnd, WORD wParam, LONG lParam )
672 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
673 WORD newFocused = lphl->ItemFocused;
675 switch(wParam) {
676 case VK_HOME:
677 newFocused = 0;
678 break;
679 case VK_END:
680 newFocused = lphl->ItemsCount - 1;
681 break;
682 case VK_UP:
683 if (newFocused > 0) newFocused--;
684 break;
685 case VK_DOWN:
686 newFocused++;
687 break;
688 case VK_PRIOR:
689 if (newFocused > lphl->ItemsVisible) {
690 newFocused -= lphl->ItemsVisible;
691 } else {
692 newFocused = 0;
694 break;
695 case VK_NEXT:
696 newFocused += lphl->ItemsVisible;
697 break;
698 default:
699 return 0;
702 if (newFocused >= lphl->ItemsCount)
703 newFocused = lphl->ItemsCount - 1;
705 ListBoxSetCurSel(lphl, newFocused);
706 ListBoxSendNotification(lphl, hwnd, CBN_SELCHANGE);
708 lphl->ItemFocused = newFocused;
709 ListBoxScrollToFocus(lphl);
710 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
711 InvalidateRect(hwnd, NULL, TRUE);
712 return 0;
715 /***********************************************************************
716 * CBLChar
718 static LONG CBLChar( HWND hwnd, WORD wParam, LONG lParam )
720 return 0;
723 /***********************************************************************
724 * CBLPaint
726 static LONG CBLPaint( HWND hwnd, WORD wParam, LONG lParam )
728 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
729 LPLISTSTRUCT lpls;
730 PAINTSTRUCT ps;
731 HBRUSH hBrush;
732 HFONT hOldFont;
733 HWND combohwnd = CLBoxGetCombo(hwnd);
734 HDC hdc;
735 RECT rect;
736 int i, top, height;
738 top = 0;
739 hdc = BeginPaint( hwnd, &ps );
741 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) {
742 EndPaint(hwnd, &ps);
743 return 0;
746 hOldFont = SelectObject(hdc, lphl->hFont);
747 #ifdef WINELIB32
748 hBrush = (HBRUSH) SendMessage(lphl->hParent, WM_CTLCOLORLISTBOX, (WPARAM)hdc,
749 (LPARAM)hwnd);
750 #else
751 hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
752 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
753 #endif
755 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
757 GetClientRect(hwnd, &rect);
758 FillRect(hdc, &rect, hBrush);
760 lpls = lphl->lpFirst;
762 lphl->ItemsVisible = 0;
763 for(i = 0; i < lphl->ItemsCount; i++) {
764 if (lpls == NULL) break;
766 if (i >= lphl->FirstVisible) {
767 height = lpls->mis.itemHeight;
769 if (top > rect.bottom) break;
770 lpls->itemRect.top = top;
771 lpls->itemRect.bottom = top + height;
772 lpls->itemRect.left = rect.left;
773 lpls->itemRect.right = rect.right;
775 dprintf_listbox(stddeb,"drawing item: %d %d %d %d %d\n",rect.left,top,rect.right,top+height,lpls->itemState);
776 if (lphl->OwnerDrawn) {
777 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, 0);
778 if (lpls->itemState)
779 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_SELECT, ODS_SELECTED);
780 } else {
781 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
782 lpls->itemState);
784 if ((lphl->ItemFocused == i) && GetFocus() == hwnd)
785 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, ODS_FOCUS);
787 top += height;
788 lphl->ItemsVisible++;
791 lpls = lpls->lpNext;
793 SelectObject(hdc,hOldFont);
794 EndPaint( hwnd, &ps );
795 return 0;
799 /***********************************************************************
800 * CBLKillFocus
802 static LONG CBLKillFocus( HWND hwnd, WORD wParam, LONG lParam )
804 /* SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);*/
805 return 0;
808 /***********************************************************************
809 * CBLActivate
811 static LONG CBLActivate( HWND hwnd, WORD wParam, LONG lParam )
813 if (wParam == WA_INACTIVE)
814 SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
815 return 0;
818 /***********************************************************************
819 * CBLLButtonDown
821 static LONG CBLLButtonDown( HWND hwnd, WORD wParam, LONG lParam )
823 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
824 int y;
825 RECT rectsel;
827 SetFocus(hwnd);
828 SetCapture(hwnd);
830 lphl->PrevFocused = lphl->ItemFocused;
832 y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
833 if (y == -1)
834 return 0;
836 ListBoxSetCurSel(lphl, y);
837 ListBoxGetItemRect(lphl, y, &rectsel);
839 InvalidateRect(hwnd, NULL, TRUE);
840 return 0;
843 /***********************************************************************
844 * CBLLButtonUp
846 static LONG CBLLButtonUp( HWND hwnd, WORD wParam, LONG lParam )
848 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
850 if (GetCapture() == hwnd) ReleaseCapture();
852 if(!lphl)
854 fprintf(stdnimp,"CBLLButtonUp: CLBoxGetListHeader returned NULL!\n");
856 else if (lphl->PrevFocused != lphl->ItemFocused)
858 SendMessage(CLBoxGetCombo(hwnd),CB_SETCURSEL,lphl->ItemFocused,0);
859 ListBoxSendNotification(lphl, CLBoxGetCombo(hwnd), CBN_SELCHANGE);
862 SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
864 return 0;
867 /***********************************************************************
868 * CBLMouseMove
870 static LONG CBLMouseMove( HWND hwnd, WORD wParam, LONG lParam )
872 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
873 int y;
874 WORD wRet;
875 RECT rect, rectsel; /* XXX Broken */
877 if ((wParam & MK_LBUTTON) != 0) {
878 y = SHIWORD(lParam);
879 if (y < 0) {
880 if (lphl->FirstVisible > 0) {
881 lphl->FirstVisible--;
882 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
883 InvalidateRect(hwnd, NULL, TRUE);
884 return 0;
887 GetClientRect(hwnd, &rect);
888 if (y >= rect.bottom) {
889 if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
890 lphl->FirstVisible++;
891 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
892 InvalidateRect(hwnd, NULL, TRUE);
893 return 0;
896 if ((y > 0) && (y < (rect.bottom - 4))) {
897 if ((y < rectsel.top) || (y > rectsel.bottom)) {
898 wRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
899 if (wRet == lphl->ItemFocused) return 0;
900 ListBoxSetCurSel(lphl, wRet);
901 ListBoxGetItemRect(lphl, wRet, &rectsel);
902 InvalidateRect(hwnd, NULL, TRUE);
907 return 0;
910 /***********************************************************************
911 * CBLVScroll
913 static LONG CBLVScroll( HWND hwnd, WORD wParam, LONG lParam )
915 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
916 int y;
918 y = lphl->FirstVisible;
920 switch(wParam) {
921 case SB_LINEUP:
922 if (lphl->FirstVisible > 0)
923 lphl->FirstVisible--;
924 break;
926 case SB_LINEDOWN:
927 lphl->FirstVisible++;
928 break;
930 case SB_PAGEUP:
931 if (lphl->FirstVisible > lphl->ItemsVisible) {
932 lphl->FirstVisible -= lphl->ItemsVisible;
933 } else {
934 lphl->FirstVisible = 0;
936 break;
938 case SB_PAGEDOWN:
939 lphl->FirstVisible += lphl->ItemsVisible;
940 break;
942 case SB_THUMBTRACK:
943 lphl->FirstVisible = LOWORD(lParam);
944 break;
947 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
948 lphl->FirstVisible = ListMaxFirstVisible(lphl);
950 if (y != lphl->FirstVisible) {
951 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
952 InvalidateRect(hwnd, NULL, TRUE);
955 return 0;
958 /***********************************************************************
959 * ComboLBoxWndProc
961 LRESULT ComboLBoxWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
963 switch(message) {
964 case WM_CREATE: return CBLCreate(hwnd, wParam, lParam);
965 case WM_GETDLGCODE: return CBLGetDlgCode(hwnd, wParam, lParam);
966 case WM_KEYDOWN: return CBLKeyDown(hwnd, wParam, lParam);
967 case WM_CHAR: return CBLChar(hwnd, wParam, lParam);
968 case WM_PAINT: return CBLPaint(hwnd, wParam, lParam);
969 case WM_KILLFOCUS: return CBLKillFocus(hwnd, wParam, lParam);
970 case WM_ACTIVATE: return CBLActivate(hwnd, wParam, lParam);
971 case WM_LBUTTONDOWN: return CBLLButtonDown(hwnd, wParam, lParam);
972 case WM_LBUTTONUP: return CBLLButtonUp(hwnd, wParam, lParam);
973 case WM_MOUSEMOVE: return CBLMouseMove(hwnd, wParam, lParam);
974 case WM_VSCROLL: return CBLVScroll(hwnd, wParam, lParam);
976 return DefWindowProc(hwnd, message, wParam, lParam);
979 /************************************************************************
980 * DlgDirSelectComboBox [USER.194]
982 BOOL DlgDirSelectComboBox(HWND hDlg, LPSTR lpStr, int nIDLBox)
984 fprintf(stdnimp,"DlgDirSelectComboBox("NPFMT", '%s', %d) \n",
985 hDlg, lpStr, nIDLBox);
986 return TRUE;
990 /************************************************************************
991 * DlgDirListComboBox [USER.195]
993 int DlgDirListComboBox(HWND hDlg, SEGPTR PathSpec,
994 int nIDLBox, int nIDStat, WORD wType)
996 HWND hWnd;
997 int ret;
998 LPSTR lpPathSpec = PTR_SEG_TO_LIN(PathSpec);
1000 dprintf_combo(stddeb,"DlgDirListComboBox("NPFMT", '%s', %d, %d, %04X) \n",
1001 hDlg, lpPathSpec, nIDLBox, nIDStat, wType);
1002 if (nIDLBox) {
1003 LPHEADLIST lphl;
1004 LPHEADCOMBO lphc;
1005 hWnd = GetDlgItem(hDlg, nIDLBox);
1006 lphl = ComboGetListHeader(hWnd);
1007 lphc = ComboGetStorageHeader(hWnd);
1008 ListBoxResetContent(lphl);
1009 ret = ListBoxDirectory(lphl, wType, lpPathSpec);
1010 ComboUpdateWindow(hWnd, lphl, lphc, TRUE);
1011 } else {
1012 ret = 0;
1014 if (nIDStat) {
1015 int drive;
1016 HANDLE hTemp;
1017 char *temp;
1018 drive = DOS_GetDefaultDrive();
1019 hTemp = USER_HEAP_ALLOC( 256 );
1020 temp = (char *) USER_HEAP_LIN_ADDR( hTemp );
1021 strcpy( temp+3, DOS_GetCurrentDir(drive) );
1022 if( temp[3] == '\\' ) {
1023 temp[1] = 'A'+drive;
1024 temp[2] = ':';
1025 SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
1026 (LPARAM)(USER_HEAP_SEG_ADDR(hTemp) + 1) );
1027 } else {
1028 temp[0] = 'A'+drive;
1029 temp[1] = ':';
1030 temp[2] = '\\';
1031 SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
1032 (LPARAM)USER_HEAP_SEG_ADDR(hTemp) );
1034 USER_HEAP_FREE( hTemp );
1036 return ret;