Release 960331
[wine.git] / controls / combo.c
blob8ac780f58d67fde32829fc092b716f85b16f2c5d
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=%04x\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 = SendMessage(lphl->hParent, WM_CTLCOLORLISTBOX, hdc, hwnd);
230 #else
231 hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
232 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
233 #endif
234 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
236 GetClientRect(hwnd, &rect);
237 rect.right -= (lphc->RectButton.right - lphc->RectButton.left);
239 lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
240 if (lpls != NULL) {
241 height = lpls->mis.itemHeight;
242 rect.bottom = rect.top + height;
243 FillRect(hdc, &rect, hBrush);
244 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
245 if (GetFocus() == hwnd)
246 ListBoxDrawItem (hwnd,lphl, hdc, lpls, &rect, ODA_FOCUS, ODS_FOCUS);
248 else FillRect(hdc, &rect, hBrush);
249 SelectObject(hdc,hOldFont);
250 EndPaint(hwnd, &ps);
251 return 0;
254 /***********************************************************************
255 * CBGetDlgCode
257 static LRESULT CBGetDlgCode(HWND hwnd, WPARAM wParam, LPARAM lParam)
259 return DLGC_WANTARROWS | DLGC_WANTCHARS;
262 /***********************************************************************
263 * CBLButtonDown
265 static LRESULT CBLButtonDown(HWND hwnd, WPARAM wParam, LPARAM lParam)
267 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
268 SendMessage(hwnd,CB_SHOWDROPDOWN,!lphc->DropDownVisible,0);
269 return 0;
272 /***********************************************************************
273 * CBKeyDown
275 static LRESULT CBKeyDown(HWND hwnd, WPARAM wParam, LPARAM 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, 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 LRESULT CBChar(HWND hwnd, WPARAM wParam, LPARAM 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, 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 LRESULT CBKillFocus(HWND hwnd, WPARAM wParam, LPARAM lParam)
341 return 0;
344 /***********************************************************************
345 * CBSetFocus
347 static LRESULT CBSetFocus(HWND hwnd, WPARAM wParam, LPARAM lParam)
349 return 0;
352 /***********************************************************************
353 * CBResetContent
355 static LRESULT CBResetContent(HWND hwnd, WPARAM wParam, LPARAM 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 LRESULT CBDir(HWND hwnd, WPARAM wParam, LPARAM 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 LRESULT CBInsertString(HWND hwnd, WPARAM wParam, LPARAM 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 LRESULT CBAddString(HWND hwnd, WPARAM wParam, LPARAM 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 LRESULT CBDeleteString(HWND hwnd, WPARAM wParam, LPARAM 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 LRESULT CBSelectString(HWND hwnd, WPARAM wParam, LPARAM lParam)
433 LPHEADLIST lphl = ComboGetListHeader(hwnd);
434 WORD wRet;
436 wRet = ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
438 /* XXX add functionality here */
440 return 0;
443 /***********************************************************************
444 * CBFindString
446 static LRESULT CBFindString(HWND hwnd, WPARAM wParam, LPARAM lParam)
448 LPHEADLIST lphl = ComboGetListHeader(hwnd);
449 return ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
452 /***********************************************************************
453 * CBGetCount
455 static LRESULT CBGetCount(HWND hwnd, WPARAM wParam, LPARAM lParam)
457 LPHEADLIST lphl = ComboGetListHeader(hwnd);
458 return lphl->ItemsCount;
461 /***********************************************************************
462 * CBSetCurSel
464 static LRESULT CBSetCurSel(HWND hwnd, WPARAM wParam, LPARAM lParam)
466 LPHEADLIST lphl = ComboGetListHeader(hwnd);
467 WORD wRet;
469 wRet = ListBoxSetCurSel(lphl, wParam);
471 dprintf_combo(stddeb,"CBSetCurSel: hwnd %04x wp %x lp %lx wRet %d\n",
472 hwnd,wParam,lParam,wRet);
473 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
474 InvalidateRect(hwnd, NULL, TRUE);
476 return wRet;
479 /***********************************************************************
480 * CBGetCurSel
482 static LRESULT CBGetCurSel(HWND hwnd, WPARAM wParam, LPARAM lParam)
484 LPHEADLIST lphl = ComboGetListHeader(hwnd);
485 return lphl->ItemFocused;
488 /***********************************************************************
489 * CBGetItemHeight
491 static LRESULT CBGetItemHeight(HWND hwnd, WPARAM wParam, LPARAM lParam)
493 LPHEADLIST lphl = ComboGetListHeader(hwnd);
494 LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
496 if (lpls == NULL) return LB_ERR;
497 return lpls->mis.itemHeight;
500 /***********************************************************************
501 * CBSetItemHeight
503 static LRESULT CBSetItemHeight(HWND hwnd, WPARAM wParam, LPARAM lParam)
505 LPHEADLIST lphl = ComboGetListHeader(hwnd);
506 return ListBoxSetItemHeight(lphl, wParam, lParam);
509 /***********************************************************************
510 * CBSetRedraw
512 static LRESULT CBSetRedraw(HWND hwnd, WPARAM wParam, LPARAM lParam)
514 LPHEADLIST lphl = ComboGetListHeader(hwnd);
515 lphl->bRedrawFlag = wParam;
516 return 0;
519 /***********************************************************************
520 * CBSetFont
522 static LRESULT CBSetFont(HWND hwnd, WPARAM wParam, LPARAM lParam)
524 LPHEADLIST lphl = ComboGetListHeader(hwnd);
526 if (wParam == 0)
527 lphl->hFont = GetStockObject(SYSTEM_FONT);
528 else
529 lphl->hFont = (HFONT)wParam;
531 return 0;
534 /***********************************************************************
535 * CBGetLBTextLen
537 static LRESULT CBGetLBTextLen(HWND hwnd, WPARAM wParam, LPARAM lParam)
539 LPHEADLIST lphl = ComboGetListHeader(hwnd);
540 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
542 if (lpls == NULL || !lphl->HasStrings) return LB_ERR;
543 return strlen(lpls->itemText);
546 /***********************************************************************
547 * CBGetLBText
549 static LRESULT CBGetLBText(HWND hwnd, WPARAM wParam, LPARAM lParam)
551 LPHEADLIST lphl = ComboGetListHeader(hwnd);
552 return ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
555 /***********************************************************************
556 * CBGetItemData
558 static LRESULT CBGetItemData(HWND hwnd, WPARAM wParam, LPARAM lParam)
560 LPHEADLIST lphl = ComboGetListHeader(hwnd);
561 return ListBoxGetItemData(lphl, wParam);
564 /***********************************************************************
565 * CBSetItemData
567 static LRESULT CBSetItemData(HWND hwnd, WPARAM wParam, LPARAM lParam)
569 LPHEADLIST lphl = ComboGetListHeader(hwnd);
570 return ListBoxSetItemData(lphl, wParam, lParam);
573 /***********************************************************************
574 * CBShowDropDown
576 static LRESULT CBShowDropDown(HWND hwnd, WPARAM wParam, LPARAM lParam)
578 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
579 RECT rect;
581 if ((lphc->dwStyle & 3) == CBS_SIMPLE) return LB_ERR;
583 wParam = !!wParam;
584 if (wParam != lphc->DropDownVisible) {
585 lphc->DropDownVisible = wParam;
586 GetWindowRect(hwnd,&rect);
587 SetWindowPos(lphc->hWndLBox, 0, rect.left, rect.top+lphc->LBoxTop, 0, 0,
588 SWP_NOSIZE | (wParam ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
589 if (!wParam) SetFocus(hwnd);
591 return 0;
595 /***********************************************************************
596 * ComboWndProc
598 LRESULT ComboBoxWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
600 switch(message) {
601 case WM_NCCREATE: return CBNCCreate(hwnd, wParam, lParam);
602 case WM_CREATE: return CBCreate(hwnd, wParam, lParam);
603 case WM_DESTROY: return CBDestroy(hwnd, wParam, lParam);
604 case WM_GETDLGCODE: return CBGetDlgCode(hwnd, wParam, lParam);
605 case WM_KEYDOWN: return CBKeyDown(hwnd, wParam, lParam);
606 case WM_CHAR: return CBChar(hwnd, wParam, lParam);
607 case WM_SETFONT: return CBSetFont(hwnd, wParam, lParam);
608 case WM_SETREDRAW: return CBSetRedraw(hwnd, wParam, lParam);
609 case WM_PAINT: return CBPaint(hwnd, wParam, lParam);
610 case WM_LBUTTONDOWN: return CBLButtonDown(hwnd, wParam, lParam);
611 case WM_SETFOCUS: return CBSetFocus(hwnd, wParam, lParam);
612 case WM_KILLFOCUS: return CBKillFocus(hwnd, wParam, lParam);
613 case CB_RESETCONTENT: return CBResetContent(hwnd, wParam, lParam);
614 case CB_DIR: return CBDir(hwnd, wParam, lParam);
615 case CB_ADDSTRING: return CBAddString(hwnd, wParam, lParam);
616 case CB_INSERTSTRING: return CBInsertString(hwnd, wParam, lParam);
617 case CB_DELETESTRING: return CBDeleteString(hwnd, wParam, lParam);
618 case CB_FINDSTRING: return CBFindString(hwnd, wParam, lParam);
619 case CB_GETCOUNT: return CBGetCount(hwnd, wParam, lParam);
620 case CB_GETCURSEL: return CBGetCurSel(hwnd, wParam, lParam);
621 case CB_GETITEMDATA: return CBGetItemData(hwnd, wParam, lParam);
622 case CB_GETITEMHEIGHT: return CBGetItemHeight(hwnd, wParam, lParam);
623 case CB_GETLBTEXT: return CBGetLBText(hwnd, wParam, lParam);
624 case CB_GETLBTEXTLEN: return CBGetLBTextLen(hwnd, wParam, lParam);
625 case CB_SELECTSTRING: return CBSelectString(hwnd, wParam, lParam);
626 case CB_SETITEMDATA: return CBSetItemData(hwnd, wParam, lParam);
627 case CB_SETCURSEL: return CBSetCurSel(hwnd, wParam, lParam);
628 case CB_SETITEMHEIGHT: return CBSetItemHeight(hwnd, wParam, lParam);
629 case CB_SHOWDROPDOWN: return CBShowDropDown(hwnd, wParam, lParam);
631 return DefWindowProc(hwnd, message, wParam, lParam);
634 /*--------------------------------------------------------------------*/
635 /* ComboLBox code starts here */
637 HWND CLBoxGetCombo(HWND hwnd)
639 #ifdef WINELIB32
640 return (HWND)GetWindowLong(hwnd,0);
641 #else
642 return (HWND)GetWindowWord(hwnd,0);
643 #endif
646 LPHEADLIST CLBoxGetListHeader(HWND hwnd)
648 return ComboGetListHeader(CLBoxGetCombo(hwnd));
651 /***********************************************************************
652 * CBLCreate
654 static LRESULT CBLCreate( HWND hwnd, WPARAM wParam, LPARAM lParam )
656 CREATESTRUCT *createStruct = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
657 #ifdef WINELIB32
658 SetWindowLong(hwnd,0,(LONG)createStruct->lpCreateParams);
659 #else
660 SetWindowWord(hwnd,0,LOWORD(createStruct->lpCreateParams));
661 #endif
662 return 0;
665 /***********************************************************************
666 * CBLGetDlgCode
668 static LRESULT CBLGetDlgCode( HWND hwnd, WPARAM wParam, LPARAM lParam )
670 return DLGC_WANTARROWS | DLGC_WANTCHARS;
673 /***********************************************************************
674 * CBLKeyDown
676 static LRESULT CBLKeyDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
678 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
679 WORD newFocused = lphl->ItemFocused;
681 switch(wParam) {
682 case VK_HOME:
683 newFocused = 0;
684 break;
685 case VK_END:
686 newFocused = lphl->ItemsCount - 1;
687 break;
688 case VK_UP:
689 if (newFocused > 0) newFocused--;
690 break;
691 case VK_DOWN:
692 newFocused++;
693 break;
694 case VK_PRIOR:
695 if (newFocused > lphl->ItemsVisible) {
696 newFocused -= lphl->ItemsVisible;
697 } else {
698 newFocused = 0;
700 break;
701 case VK_NEXT:
702 newFocused += lphl->ItemsVisible;
703 break;
704 default:
705 return 0;
708 if (newFocused >= lphl->ItemsCount)
709 newFocused = lphl->ItemsCount - 1;
711 ListBoxSetCurSel(lphl, newFocused);
712 ListBoxSendNotification(lphl, CBN_SELCHANGE);
714 lphl->ItemFocused = newFocused;
715 ListBoxScrollToFocus(lphl);
716 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
717 InvalidateRect(hwnd, NULL, TRUE);
718 return 0;
721 /***********************************************************************
722 * CBLChar
724 static LRESULT CBLChar( HWND hwnd, WPARAM wParam, LPARAM lParam )
726 return 0;
729 /***********************************************************************
730 * CBLPaint
732 static LRESULT CBLPaint( HWND hwnd, WPARAM wParam, LPARAM lParam )
734 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
735 LPLISTSTRUCT lpls;
736 PAINTSTRUCT ps;
737 HBRUSH hBrush;
738 HFONT hOldFont;
739 HWND combohwnd = CLBoxGetCombo(hwnd);
740 HDC hdc;
741 RECT rect;
742 int i, top, height;
744 top = 0;
745 hdc = BeginPaint( hwnd, &ps );
747 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) {
748 EndPaint(hwnd, &ps);
749 return 0;
752 hOldFont = SelectObject(hdc, lphl->hFont);
753 #ifdef WINELIB32
754 hBrush = SendMessage(lphl->hParent, WM_CTLCOLORLISTBOX, hdc, hwnd);
755 #else
756 hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
757 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
758 #endif
760 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
762 GetClientRect(hwnd, &rect);
763 FillRect(hdc, &rect, hBrush);
765 lpls = lphl->lpFirst;
767 lphl->ItemsVisible = 0;
768 for(i = 0; i < lphl->ItemsCount; i++) {
769 if (lpls == NULL) break;
771 if (i >= lphl->FirstVisible) {
772 height = lpls->mis.itemHeight;
773 /* must have enough room to draw entire item */
774 if (top > (rect.bottom-height+1)) break;
776 lpls->itemRect.top = top;
777 lpls->itemRect.bottom = top + height;
778 lpls->itemRect.left = rect.left;
779 lpls->itemRect.right = rect.right;
781 dprintf_listbox(stddeb,"drawing item: %d %d %d %d %d\n",
782 rect.left,top,rect.right,top+height,lpls->itemState);
783 if (lphl->OwnerDrawn) {
784 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, 0);
785 if (lpls->itemState)
786 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_SELECT, ODS_SELECTED);
787 } else {
788 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
789 lpls->itemState);
791 if ((lphl->ItemFocused == i) && GetFocus() == hwnd)
792 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, ODS_FOCUS);
794 top += height;
795 lphl->ItemsVisible++;
798 lpls = lpls->lpNext;
800 SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
801 SelectObject(hdc,hOldFont);
802 EndPaint( hwnd, &ps );
803 return 0;
807 /***********************************************************************
808 * CBLKillFocus
810 static LRESULT CBLKillFocus( HWND hwnd, WPARAM wParam, LPARAM lParam )
812 /* SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);*/
813 return 0;
816 /***********************************************************************
817 * CBLActivate
819 static LRESULT CBLActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
821 if (wParam == WA_INACTIVE)
822 SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
823 return 0;
826 /***********************************************************************
827 * CBLLButtonDown
829 static LRESULT CBLLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
831 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
832 int y;
833 RECT rectsel;
835 SetFocus(hwnd);
836 SetCapture(hwnd);
838 lphl->PrevFocused = lphl->ItemFocused;
840 y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
841 if (y == -1)
842 return 0;
844 ListBoxSetCurSel(lphl, y);
845 ListBoxGetItemRect(lphl, y, &rectsel);
847 InvalidateRect(hwnd, NULL, TRUE);
848 return 0;
851 /***********************************************************************
852 * CBLLButtonUp
854 static LRESULT CBLLButtonUp( HWND hwnd, WPARAM wParam, LPARAM lParam )
856 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
858 if (GetCapture() == hwnd) ReleaseCapture();
860 if(!lphl)
862 fprintf(stdnimp,"CBLLButtonUp: CLBoxGetListHeader returned NULL!\n");
864 else if (lphl->PrevFocused != lphl->ItemFocused)
866 SendMessage(CLBoxGetCombo(hwnd),CB_SETCURSEL,lphl->ItemFocused,0);
867 ListBoxSendNotification(lphl, CBN_SELCHANGE);
870 SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
872 return 0;
875 /***********************************************************************
876 * CBLMouseMove
878 static LRESULT CBLMouseMove( HWND hwnd, WPARAM wParam, LPARAM lParam )
880 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
881 short y;
882 WORD wRet;
883 RECT rect, rectsel;
885 y = SHIWORD(lParam);
886 wRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
887 ListBoxGetItemRect(lphl, wRet, &rectsel);
888 GetClientRect(hwnd, &rect);
890 dprintf_combo(stddeb,"CBLMouseMove: hwnd %04x wp %x lp %lx y %d if %d wret %d %d,%d-%d,%d\n",
891 hwnd,wParam,lParam,y,lphl->ItemFocused,wRet,rectsel.left,rectsel.top,rectsel.right,rectsel.bottom);
893 if ((wParam & MK_LBUTTON) != 0) {
894 if (y < CBLMM_EDGE) {
895 if (lphl->FirstVisible > 0) {
896 lphl->FirstVisible--;
897 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
898 ListBoxSetCurSel(lphl, wRet);
899 InvalidateRect(hwnd, NULL, TRUE);
900 return 0;
903 else if (y >= (rect.bottom-CBLMM_EDGE)) {
904 if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
905 lphl->FirstVisible++;
906 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
907 ListBoxSetCurSel(lphl, wRet);
908 InvalidateRect(hwnd, NULL, TRUE);
909 return 0;
912 else {
913 if ((short) wRet == lphl->ItemFocused) return 0;
914 ListBoxSetCurSel(lphl, wRet);
915 InvalidateRect(hwnd, NULL, TRUE);
919 return 0;
922 /***********************************************************************
923 * CBLVScroll
925 static LRESULT CBLVScroll( HWND hwnd, WPARAM wParam, LPARAM lParam )
927 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
928 int y;
930 y = lphl->FirstVisible;
932 switch(wParam) {
933 case SB_LINEUP:
934 if (lphl->FirstVisible > 0)
935 lphl->FirstVisible--;
936 break;
938 case SB_LINEDOWN:
939 lphl->FirstVisible++;
940 break;
942 case SB_PAGEUP:
943 if (lphl->FirstVisible > lphl->ItemsVisible) {
944 lphl->FirstVisible -= lphl->ItemsVisible;
945 } else {
946 lphl->FirstVisible = 0;
948 break;
950 case SB_PAGEDOWN:
951 lphl->FirstVisible += lphl->ItemsVisible;
952 break;
954 case SB_THUMBTRACK:
955 lphl->FirstVisible = LOWORD(lParam);
956 break;
959 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
960 lphl->FirstVisible = ListMaxFirstVisible(lphl);
962 if (y != lphl->FirstVisible) {
963 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
964 InvalidateRect(hwnd, NULL, TRUE);
967 return 0;
970 /***********************************************************************
971 * ComboLBoxWndProc
973 LRESULT ComboLBoxWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
975 switch(message) {
976 case WM_CREATE: return CBLCreate(hwnd, wParam, lParam);
977 case WM_GETDLGCODE: return CBLGetDlgCode(hwnd, wParam, lParam);
978 case WM_KEYDOWN: return CBLKeyDown(hwnd, wParam, lParam);
979 case WM_CHAR: return CBLChar(hwnd, wParam, lParam);
980 case WM_PAINT: return CBLPaint(hwnd, wParam, lParam);
981 case WM_KILLFOCUS: return CBLKillFocus(hwnd, wParam, lParam);
982 case WM_ACTIVATE: return CBLActivate(hwnd, wParam, lParam);
983 case WM_LBUTTONDOWN: return CBLLButtonDown(hwnd, wParam, lParam);
984 case WM_LBUTTONUP: return CBLLButtonUp(hwnd, wParam, lParam);
985 case WM_MOUSEMOVE: return CBLMouseMove(hwnd, wParam, lParam);
986 case WM_VSCROLL: return CBLVScroll(hwnd, wParam, lParam);
988 return DefWindowProc(hwnd, message, wParam, lParam);
991 /************************************************************************
992 * DlgDirSelectComboBox [USER.194]
994 BOOL DlgDirSelectComboBox(HWND hDlg, LPSTR lpStr, INT nIDLBox)
996 fprintf(stdnimp,"DlgDirSelectComboBox(%04x, '%s', %d) \n",
997 hDlg, lpStr, nIDLBox);
998 return TRUE;
1002 /************************************************************************
1003 * DlgDirListComboBox [USER.195]
1005 INT DlgDirListComboBox( HWND hDlg, SEGPTR path, INT idCBox,
1006 INT idStatic, UINT wType )
1008 INT ret = 0;
1010 dprintf_combo( stddeb,"DlgDirListComboBox(%04x,%08lx,%d,%d,%04X) \n",
1011 hDlg, (DWORD)path, idCBox, idStatic, wType );
1013 if (idCBox)
1015 SendDlgItemMessage( hDlg, idCBox, CB_RESETCONTENT, 0, 0 );
1016 ret = (SendDlgItemMessage( hDlg, idCBox, CB_DIR, wType, path ) >= 0);
1018 if (idStatic)
1020 char temp[256];
1021 int drive = DRIVE_GetCurrentDrive();
1022 strcpy( temp, "A:\\" );
1023 temp[0] += drive;
1024 lstrcpyn( temp+3, DRIVE_GetDosCwd(drive), 253 );
1025 SendDlgItemMessage( hDlg, idStatic, WM_SETTEXT,
1026 0, (LPARAM)MAKE_SEGPTR(temp) );
1028 return ret;