Release 950620
[wine/multimedia.git] / controls / combo.c
blobabf7abbbba9fcdfc3095d333777cfd906e5db805
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 LONG CBNCCreate( HWND hwnd, WORD message, WORD wParam, LONG lParam );
33 static LONG CBCreate( HWND hwnd, WORD message, WORD wParam, LONG lParam );
34 static LONG CBGetDlgCode( HWND hwnd, WORD message, WORD wParam, LONG lParam );
35 static LONG CBDestroy( HWND hwnd, WORD message, WORD wParam, LONG lParam );
36 static LONG CBPaint( HWND hwnd, WORD message, WORD wParam, LONG lParam );
37 static LONG CBKeyDown( HWND hwnd, WORD message, WORD wParam, LONG lParam );
38 static LONG CBChar( HWND hwnd, WORD message, WORD wParam, LONG lParam );
39 static LONG CBSetFont( HWND hwnd, WORD message, WORD wParam, LONG lParam );
40 static LONG CBSetRedraw( HWND hwnd, WORD message, WORD wParam, LONG lParam );
41 static LONG CBLButtonDown( HWND hwnd, WORD message, WORD wParam, LONG lParam );
42 static LONG CBSetFocus( HWND hwnd, WORD message, WORD wParam, LONG lParam );
43 static LONG CBKillFocus( HWND hwnd, WORD message, WORD wParam, LONG lParam );
44 static LONG CBResetContent( HWND hwnd, WORD message, WORD wParam, LONG lParam );
45 static LONG CBDir( HWND hwnd, WORD message, WORD wParam, LONG lParam );
46 static LONG CBAddString( HWND hwnd, WORD message, WORD wParam, LONG lParam );
47 static LONG CBGetLBText( HWND hwnd, WORD message, WORD wParam, LONG lParam );
48 static LONG CBInsertString( HWND hwnd, WORD message, WORD wParam, LONG lParam );
49 static LONG CBDeleteString( HWND hwnd, WORD message, WORD wParam, LONG lParam );
50 static LONG CBFindString( HWND hwnd, WORD message, WORD wParam, LONG lParam );
51 static LONG CBGetCount( HWND hwnd, WORD message, WORD wParam, LONG lParam );
52 static LONG CBGetCurSel( HWND hwnd, WORD message, WORD wParam, LONG lParam );
53 static LONG CBGetItemData( HWND hwnd, WORD message, WORD wParam, LONG lParam );
54 static LONG CBGetItemHeight( HWND hwnd, WORD message, WORD wParam, LONG lParam );
55 static LONG CBGetLBTextLen( HWND hwnd, WORD message, WORD wParam, LONG lParam );
56 static LONG CBSelectString( HWND hwnd, WORD message, WORD wParam, LONG lParam );
57 static LONG CBSetItemData( HWND hwnd, WORD message, WORD wParam, LONG lParam );
58 static LONG CBSetCurSel( HWND hwnd, WORD message, WORD wParam, LONG lParam );
59 static LONG CBSetItemHeight( HWND hwnd, WORD message, WORD wParam, LONG lParam );
60 static LONG CBShowDropDown( HWND hwnd, WORD message, WORD wParam, LONG lParam );
62 static LONG CBLCreate( HWND hwnd, WORD message, WORD wParam, LONG lParam );
63 static LONG CBLGetDlgCode( HWND hwnd, WORD message, WORD wParam, LONG lParam );
64 static LONG CBLKeyDown( HWND hwnd, WORD message, WORD wParam, LONG lParam );
65 static LONG CBLChar( HWND hwnd, WORD message, WORD wParam, LONG lParam );
66 static LONG CBLPaint( HWND hwnd, WORD message, WORD wParam, LONG lParam );
67 static LONG CBLKillFocus( HWND hwnd, WORD message, WORD wParam, LONG lParam );
68 static LONG CBLActivate( HWND hwnd, WORD message, WORD wParam, LONG lParam );
69 static LONG CBLLButtonDown( HWND hwnd, WORD message, WORD wParam, LONG lParam );
70 static LONG CBLLButtonUp( HWND hwnd, WORD message, WORD wParam, LONG lParam );
71 static LONG CBLMouseMove( HWND hwnd, WORD message, WORD wParam, LONG lParam );
72 static LONG CBLVScroll( HWND hwnd, WORD message, WORD wParam, LONG lParam );
74 typedef struct {
75 WORD message;
76 LONG (*handler)(HWND, WORD, WPARAM, LPARAM);
77 } msg_tbl;
79 static msg_tbl combo_tbl[] = {
80 {WM_NCCREATE, CBNCCreate},
81 {WM_CREATE, CBCreate},
82 {WM_DESTROY, CBDestroy},
83 {WM_GETDLGCODE, CBGetDlgCode},
84 {WM_KEYDOWN, CBKeyDown},
85 {WM_CHAR, CBChar},
86 {WM_SETFONT, CBSetFont},
87 {WM_SETREDRAW, CBSetRedraw},
88 {WM_PAINT, CBPaint},
89 {WM_LBUTTONDOWN, CBLButtonDown},
90 {WM_SETFOCUS, CBSetFocus},
91 {WM_KILLFOCUS, CBKillFocus},
92 {CB_RESETCONTENT, CBResetContent},
93 {CB_DIR, CBDir},
94 {CB_ADDSTRING, CBAddString},
95 {CB_INSERTSTRING, CBInsertString},
96 {CB_DELETESTRING, CBDeleteString},
97 {CB_FINDSTRING, CBFindString},
98 {CB_GETCOUNT, CBGetCount},
99 {CB_GETCURSEL, CBGetCurSel},
100 {CB_GETITEMDATA, CBGetItemData},
101 {CB_GETITEMHEIGHT, CBGetItemHeight},
102 {CB_GETLBTEXT, CBGetLBText},
103 {CB_GETLBTEXTLEN, CBGetLBTextLen},
104 {CB_SELECTSTRING, CBSelectString},
105 {CB_SETITEMDATA, CBSetItemData},
106 {CB_SETCURSEL, CBSetCurSel},
107 {CB_SETITEMHEIGHT, CBSetItemHeight},
108 {CB_SHOWDROPDOWN, CBShowDropDown}
112 static msg_tbl clbox_tbl[] = {
113 {WM_CREATE, CBLCreate},
114 {WM_GETDLGCODE, CBLGetDlgCode},
115 {WM_KEYDOWN, CBLKeyDown},
116 {WM_CHAR, CBLChar},
117 {WM_PAINT, CBLPaint},
118 {WM_KILLFOCUS, CBLKillFocus},
119 {WM_ACTIVATE, CBLActivate},
120 {WM_LBUTTONDOWN, CBLLButtonDown},
121 {WM_LBUTTONUP, CBLLButtonUp},
122 {WM_MOUSEMOVE, CBLMouseMove},
123 {WM_VSCROLL, CBLVScroll}
126 static HBITMAP hComboBit = 0;
127 static WORD CBitHeight, CBitWidth;
129 static int COMBO_Init()
131 BITMAP bm;
133 dprintf_combo(stddeb, "COMBO_Init\n");
134 hComboBit = LoadBitmap(0, MAKEINTRESOURCE(OBM_COMBO));
135 GetObject(hComboBit, sizeof(BITMAP), (LPSTR)&bm);
136 CBitHeight = bm.bmHeight;
137 CBitWidth = bm.bmWidth;
138 return 0;
141 LPHEADCOMBO ComboGetStorageHeader(HWND hwnd)
143 return (LPHEADCOMBO)GetWindowLong(hwnd,4);
146 LPHEADLIST ComboGetListHeader(HWND hwnd)
148 return (LPHEADLIST)GetWindowLong(hwnd,0);
151 int CreateComboStruct(HWND hwnd, LONG style)
153 LPHEADCOMBO lphc;
155 lphc = (LPHEADCOMBO)malloc(sizeof(HEADCOMBO));
156 SetWindowLong(hwnd,4,(LONG)lphc);
157 lphc->hWndEdit = 0;
158 lphc->hWndLBox = 0;
159 lphc->dwState = 0;
160 lphc->LastSel = -1;
161 lphc->dwStyle = style;
162 lphc->DropDownVisible = FALSE;
163 return TRUE;
166 void ComboUpdateWindow(HWND hwnd, LPHEADLIST lphl, LPHEADCOMBO lphc, BOOL repaint)
168 SetScrollRange(lphc->hWndLBox, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
169 if (repaint && lphl->bRedrawFlag) {
170 InvalidateRect(hwnd, NULL, TRUE);
174 /***********************************************************************
175 * CBNCCreate
177 static LONG CBNCCreate(HWND hwnd, WORD message, WORD wParam, LONG lParam)
179 CREATESTRUCT *createStruct;
181 if (!hComboBit) COMBO_Init();
183 createStruct = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
184 createStruct->style &= ~(WS_VSCROLL | WS_HSCROLL);
185 SetWindowLong(hwnd, GWL_STYLE, createStruct->style);
187 dprintf_combo(stddeb,"ComboBox WM_NCCREATE!\n");
188 return DefWindowProc(hwnd, message, wParam, lParam);
192 /***********************************************************************
193 * CBCreate
195 static LONG CBCreate(HWND hwnd, WORD message, WORD wParam, LONG lParam)
197 LPHEADLIST lphl;
198 LPHEADCOMBO lphc;
199 LONG style = 0;
200 LONG cstyle = GetWindowLong(hwnd,GWL_STYLE);
201 RECT rect,lboxrect;
203 /* translate combo into listbox styles */
204 if (cstyle & CBS_OWNERDRAWFIXED) style |= LBS_OWNERDRAWFIXED;
205 if (cstyle & CBS_OWNERDRAWVARIABLE) style |= LBS_OWNERDRAWVARIABLE;
206 if (cstyle & CBS_SORT) style |= LBS_SORT;
207 if (cstyle & CBS_HASSTRINGS) style |= LBS_HASSTRINGS;
208 style |= LBS_NOTIFY;
209 CreateListBoxStruct(hwnd, ODT_COMBOBOX, style, GetParent(hwnd));
210 CreateComboStruct(hwnd,cstyle);
211 lphl = ComboGetListHeader(hwnd);
212 lphc = ComboGetStorageHeader(hwnd);
214 GetClientRect(hwnd,&rect);
215 GetWindowRect(hwnd,&lboxrect);
216 /* FIXME: combos with edit controls are broken. */
217 switch(cstyle & 3) {
218 case CBS_SIMPLE: /* edit control, list always visible */
219 dprintf_combo(stddeb,"CBS_SIMPLE\n");
220 SetRectEmpty(&lphc->RectButton);
221 lphc->LBoxTop = lphl->StdItemHeight;
222 lphc->hWndEdit = CreateWindow("EDIT", "",
223 WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | SS_LEFT,
224 0, 0, rect.right, lphl->StdItemHeight,
225 hwnd, 1, GetWindowWord(hwnd,GWW_HINSTANCE), 0L);
226 break;
227 case CBS_DROPDOWN: /* edit control, dropdown listbox */
228 dprintf_combo(stddeb,"CBS_DROPDOWN\n");
229 lphc->RectButton = rect;
230 lphc->RectButton.left = lphc->RectButton.right - 6 - CBitWidth;
231 lphc->RectButton.bottom = lphc->RectButton.top + lphl->StdItemHeight;
232 lphc->LBoxTop = lphl->StdItemHeight;
233 SetWindowPos(hwnd, 0, 0, 0, rect.right - rect.left + 2*SYSMETRICS_CXBORDER,
234 lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER,
235 SWP_NOMOVE | SWP_NOZORDER);
236 lphc->hWndEdit = CreateWindow("EDIT", "",
237 WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | SS_LEFT,
238 0, 0, lphc->RectButton.left, lphl->StdItemHeight,
239 hwnd, 1, GetWindowWord(hwnd,GWW_HINSTANCE), 0L);
240 break;
241 case CBS_DROPDOWNLIST: /* static control, downdown listbox */
242 dprintf_combo(stddeb,"CBS_DROPDOWNLIST\n");
243 lphc->RectButton = rect;
244 lphc->RectButton.left = lphc->RectButton.right - 6 - CBitWidth;
245 lphc->RectButton.bottom = lphc->RectButton.top + lphl->StdItemHeight;
246 lphc->LBoxTop = lphl->StdItemHeight;
247 SetWindowPos(hwnd, 0, 0, 0, rect.right - rect.left + 2*SYSMETRICS_CXBORDER,
248 lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER,
249 SWP_NOMOVE | SWP_NOZORDER);
250 break;
252 lboxrect.top += lphc->LBoxTop;
253 /* FIXME: WinSight says these should be CHILD windows with the TOPMOST flag
254 * set. Wine doesn't support TOPMOST, and simply setting the WS_CHILD
255 * flag doesn't work. */
256 lphc->hWndLBox = CreateWindow("COMBOLBOX", "",
257 WS_POPUP | WS_BORDER | WS_VSCROLL,
258 lboxrect.left, lboxrect.top,
259 lboxrect.right - lboxrect.left,
260 lboxrect.bottom - lboxrect.top,
261 0, 0, GetWindowWord(hwnd,GWW_HINSTANCE),
262 (SEGPTR)MAKELONG(hwnd, hwnd));
263 ShowWindow(lphc->hWndLBox, SW_HIDE);
264 dprintf_combo(stddeb,"Combo Creation LBox=%X!\n", lphc->hWndLBox);
265 return 0;
268 /***********************************************************************
269 * CBDestroy
271 static LONG CBDestroy(HWND hwnd, WORD message, WORD wParam, LONG lParam)
273 LPHEADLIST lphl = ComboGetListHeader(hwnd);
275 ListBoxResetContent(lphl);
276 DestroyListBoxStruct(lphl);
277 dprintf_combo(stddeb,"Combo WM_DESTROY %p !\n", lphl);
278 return 0;
281 /***********************************************************************
282 * CBPaint
284 static LONG CBPaint(HWND hwnd, WORD message, WORD wParam, LONG lParam)
286 LPHEADLIST lphl = ComboGetListHeader(hwnd);
287 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
288 LPLISTSTRUCT lpls;
289 PAINTSTRUCT ps;
290 HBRUSH hBrush;
291 HFONT hOldFont;
292 HDC hdc;
293 RECT rect;
294 int height;
296 hdc = BeginPaint(hwnd, &ps);
298 if (hComboBit != 0) {
299 GRAPH_DrawReliefRect(hdc, &lphc->RectButton, 2, 2, FALSE);
300 GRAPH_DrawBitmap(hdc, hComboBit,
301 lphc->RectButton.left + 3,lphc->RectButton.top + 2,
302 0, 0, CBitWidth, CBitHeight );
304 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag
305 || (lphc->dwStyle & 3) != CBS_DROPDOWNLIST)
307 /* we don't want to draw an entry when there is an edit control */
308 EndPaint(hwnd, &ps);
309 return 0;
312 hOldFont = SelectObject(hdc, lphl->hFont);
314 hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
315 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
316 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
318 GetClientRect(hwnd, &rect);
319 rect.right -= (lphc->RectButton.right - lphc->RectButton.left);
320 FillRect(hdc, &rect, hBrush);
322 lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
323 if (lpls != NULL) {
324 height = lpls->mis.itemHeight;
325 rect.bottom = rect.top + height;
327 if (OWNER_DRAWN(lphl)) {
328 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
329 } else {
330 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
332 if (GetFocus() == hwnd)
333 ListBoxDrawItem (hwnd,lphl, hdc, lpls, &rect, ODA_FOCUS, ODS_FOCUS);
335 SelectObject(hdc,hOldFont);
336 EndPaint(hwnd, &ps);
337 return 0;
340 /***********************************************************************
341 * CBGetDlgCode
343 static LONG CBGetDlgCode(HWND hwnd, WORD message, WORD wParam, LONG lParam)
345 return DLGC_WANTARROWS | DLGC_WANTCHARS;
348 /***********************************************************************
349 * CBLButtonDown
351 static LONG CBLButtonDown(HWND hwnd, WORD message, WORD wParam, LONG lParam)
353 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
354 SendMessage(hwnd,CB_SHOWDROPDOWN,!lphc->DropDownVisible,0);
355 return 0;
358 /***********************************************************************
359 * CBKeyDown
361 static LONG CBKeyDown(HWND hwnd, WORD message, WORD wParam, LONG lParam)
363 LPHEADLIST lphl = ComboGetListHeader(hwnd);
364 WORD newFocused = lphl->ItemFocused;
366 switch(wParam) {
367 case VK_HOME:
368 newFocused = 0;
369 break;
370 case VK_END:
371 newFocused = lphl->ItemsCount - 1;
372 break;
373 case VK_UP:
374 if (newFocused > 0) newFocused--;
375 break;
376 case VK_DOWN:
377 newFocused++;
378 break;
379 default:
380 return 0;
383 if (newFocused >= lphl->ItemsCount)
384 newFocused = lphl->ItemsCount - 1;
386 ListBoxSetCurSel(lphl, newFocused);
387 ListBoxSendNotification(lphl, hwnd, CBN_SELCHANGE);
389 lphl->ItemFocused = newFocused;
390 ListBoxScrollToFocus(lphl);
391 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
392 InvalidateRect(hwnd, NULL, TRUE);
394 return 0;
397 /***********************************************************************
398 * CBChar
400 static LONG CBChar(HWND hwnd, WORD message, WORD wParam, LONG lParam)
402 LPHEADLIST lphl = ComboGetListHeader(hwnd);
403 WORD newFocused;
405 newFocused = ListBoxFindNextMatch(lphl, wParam);
406 if (newFocused == (WORD)LB_ERR) return 0;
408 if (newFocused >= lphl->ItemsCount)
409 newFocused = lphl->ItemsCount - 1;
411 ListBoxSetCurSel(lphl, newFocused);
412 ListBoxSendNotification(lphl, hwnd, CBN_SELCHANGE);
413 lphl->ItemFocused = newFocused;
414 ListBoxScrollToFocus(lphl);
416 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
417 InvalidateRect(hwnd, NULL, TRUE);
419 return 0;
422 /***********************************************************************
423 * CBKillFocus
425 static LONG CBKillFocus(HWND hwnd, WORD message, WORD wParam, LONG lParam)
427 return 0;
430 /***********************************************************************
431 * CBSetFocus
433 static LONG CBSetFocus(HWND hwnd, WORD message, WORD wParam, LONG lParam)
435 return 0;
438 /***********************************************************************
439 * CBResetContent
441 static LONG CBResetContent(HWND hwnd, WORD message, WORD wParam, LONG lParam)
443 LPHEADLIST lphl = ComboGetListHeader(hwnd);
444 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
446 ListBoxResetContent(lphl);
447 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
448 return 0;
451 /***********************************************************************
452 * CBDir
454 static LONG CBDir(HWND hwnd, WORD message, WORD wParam, LONG lParam)
456 WORD wRet;
457 LPHEADLIST lphl = ComboGetListHeader(hwnd);
458 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
460 wRet = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
461 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
462 return wRet;
465 /***********************************************************************
466 * CBInsertString
468 static LONG CBInsertString(HWND hwnd, WORD message, WORD wParam, LONG lParam)
470 WORD wRet;
471 LPHEADLIST lphl = ComboGetListHeader(hwnd);
472 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
474 if (HasStrings(lphl))
475 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
476 else
477 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)lParam);
479 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
480 return wRet;
483 /***********************************************************************
484 * CBAddString
486 static LONG CBAddString(HWND hwnd, WORD message, WORD wParam, LONG lParam)
488 WORD wRet;
489 LPHEADLIST lphl = ComboGetListHeader(hwnd);
490 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
492 if (HasStrings(lphl))
493 wRet = ListBoxAddString(lphl, (LPSTR)PTR_SEG_TO_LIN(lParam));
494 else
495 wRet = ListBoxAddString(lphl, (LPSTR)lParam);
497 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
498 return wRet;
501 /***********************************************************************
502 * CBDeleteString
504 static LONG CBDeleteString(HWND hwnd, WORD message, WORD wParam, LONG lParam)
506 LPHEADLIST lphl = ComboGetListHeader(hwnd);
507 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
508 LONG lRet = ListBoxDeleteString(lphl,wParam);
510 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
511 return lRet;
514 /***********************************************************************
515 * CBSelectString
517 static LONG CBSelectString(HWND hwnd, WORD message, WORD wParam, LONG lParam)
519 LPHEADLIST lphl = ComboGetListHeader(hwnd);
520 WORD wRet;
522 wRet = ListBoxFindString(lphl, wParam, lParam);
524 /* XXX add functionality here */
526 return 0;
529 /***********************************************************************
530 * CBFindString
532 static LONG CBFindString(HWND hwnd, WORD message, WORD wParam, LONG lParam)
534 LPHEADLIST lphl = ComboGetListHeader(hwnd);
535 return ListBoxFindString(lphl, wParam, lParam);
538 /***********************************************************************
539 * CBGetCount
541 static LONG CBGetCount(HWND hwnd, WORD message, WORD wParam, LONG lParam)
543 LPHEADLIST lphl = ComboGetListHeader(hwnd);
544 return lphl->ItemsCount;
547 /***********************************************************************
548 * CBSetCurSel
550 static LONG CBSetCurSel(HWND hwnd, WORD message, WORD wParam, LONG lParam)
552 LPHEADLIST lphl = ComboGetListHeader(hwnd);
553 WORD wRet;
555 wRet = ListBoxSetCurSel(lphl, wParam);
557 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
558 InvalidateRect(hwnd, NULL, TRUE);
560 return wRet;
563 /***********************************************************************
564 * CBGetCurSel
566 static LONG CBGetCurSel(HWND hwnd, WORD message, WORD wParam, LONG lParam)
568 LPHEADLIST lphl = ComboGetListHeader(hwnd);
569 return lphl->ItemFocused;
572 /***********************************************************************
573 * CBGetItemHeight
575 static LONG CBGetItemHeight(HWND hwnd, WORD message, WORD wParam, LONG lParam)
577 LPHEADLIST lphl = ComboGetListHeader(hwnd);
578 LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
580 if (lpls == NULL) return LB_ERR;
581 return lpls->mis.itemHeight;
584 /***********************************************************************
585 * CBSetItemHeight
587 static LONG CBSetItemHeight(HWND hwnd, WORD message, WORD wParam, LONG lParam)
589 LPHEADLIST lphl = ComboGetListHeader(hwnd);
590 return ListBoxSetItemHeight(lphl, wParam, lParam);
593 /***********************************************************************
594 * CBSetRedraw
596 static LONG CBSetRedraw(HWND hwnd, WORD message, WORD wParam, LONG lParam)
598 LPHEADLIST lphl = ComboGetListHeader(hwnd);
599 lphl->bRedrawFlag = wParam;
600 return 0;
603 /***********************************************************************
604 * CBSetFont
606 static LONG CBSetFont(HWND hwnd, WORD message, WORD wParam, LONG lParam)
608 LPHEADLIST lphl = ComboGetListHeader(hwnd);
610 if (wParam == 0)
611 lphl->hFont = GetStockObject(SYSTEM_FONT);
612 else
613 lphl->hFont = wParam;
615 return 0;
618 /***********************************************************************
619 * CBGetLBTextLen
621 static LONG CBGetLBTextLen(HWND hwnd, WORD message, WORD wParam, LONG lParam)
623 LPHEADLIST lphl = ComboGetListHeader(hwnd);
624 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
626 if (lpls == NULL || !HasStrings(lphl)) return LB_ERR;
627 return strlen(lpls->itemText);
630 /***********************************************************************
631 * CBGetLBText
633 static LONG CBGetLBText(HWND hwnd, WORD message, WORD wParam, LONG lParam)
635 LPHEADLIST lphl = ComboGetListHeader(hwnd);
636 return ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
639 /***********************************************************************
640 * CBGetItemData
642 static LONG CBGetItemData(HWND hwnd, WORD message, WORD wParam, LONG lParam)
644 LPHEADLIST lphl = ComboGetListHeader(hwnd);
645 return ListBoxGetItemData(lphl, wParam);
648 /***********************************************************************
649 * CBSetItemData
651 static LONG CBSetItemData(HWND hwnd, WORD message, WORD wParam, LONG lParam)
653 LPHEADLIST lphl = ComboGetListHeader(hwnd);
654 return ListBoxSetItemData(lphl, wParam, lParam);
657 /***********************************************************************
658 * CBShowDropDown
660 static LONG CBShowDropDown(HWND hwnd, WORD message, WORD wParam, LONG lParam)
662 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
663 RECT rect;
665 if (lphc->dwStyle & 3 == CBS_SIMPLE) return LB_ERR;
667 wParam = !!wParam;
668 if (wParam != lphc->DropDownVisible) {
669 lphc->DropDownVisible = wParam;
670 GetWindowRect(hwnd,&rect);
671 SetWindowPos(lphc->hWndLBox, 0, rect.left, rect.top+lphc->LBoxTop, 0, 0,
672 SWP_NOSIZE | (wParam ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
673 if (!wParam) SetFocus(hwnd);
675 return 0;
679 /***********************************************************************
680 * ComboWndProc
682 LONG ComboBoxWndProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
684 int idx = 0;
685 int table_size = sizeof (combo_tbl) / sizeof (msg_tbl);
687 while (idx < table_size) {
688 if (message == combo_tbl[idx].message) {
689 return (*(combo_tbl[idx].handler))(hwnd, message, wParam, lParam);
691 idx++;
693 return DefWindowProc (hwnd, message, wParam, lParam);
696 /*--------------------------------------------------------------------*/
697 /* ComboLBox code starts here */
699 HWND CLBoxGetCombo(HWND hwnd)
701 return GetWindowWord(hwnd,0);
704 LPHEADLIST CLBoxGetListHeader(HWND hwnd)
706 return ComboGetListHeader(CLBoxGetCombo(hwnd));
709 /***********************************************************************
710 * CBLCreate
712 static LONG CBLCreate( HWND hwnd, WORD message, WORD wParam, LONG lParam )
714 CREATESTRUCT *createStruct = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
715 SetWindowWord(hwnd,0,LOWORD(createStruct->lpCreateParams));
716 return 0;
719 /***********************************************************************
720 * CBLGetDlgCode
722 static LONG CBLGetDlgCode( HWND hwnd, WORD message, WORD wParam, LONG lParam )
724 return DLGC_WANTARROWS | DLGC_WANTCHARS;
727 /***********************************************************************
728 * CBLKeyDown
730 static LONG CBLKeyDown( HWND hwnd, WORD message, WORD wParam, LONG lParam )
732 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
733 WORD newFocused = lphl->ItemFocused;
735 switch(wParam) {
736 case VK_HOME:
737 newFocused = 0;
738 break;
739 case VK_END:
740 newFocused = lphl->ItemsCount - 1;
741 break;
742 case VK_UP:
743 if (newFocused > 0) newFocused--;
744 break;
745 case VK_DOWN:
746 newFocused++;
747 break;
748 case VK_PRIOR:
749 if (newFocused > lphl->ItemsVisible) {
750 newFocused -= lphl->ItemsVisible;
751 } else {
752 newFocused = 0;
754 break;
755 case VK_NEXT:
756 newFocused += lphl->ItemsVisible;
757 break;
758 default:
759 return 0;
762 if (newFocused >= lphl->ItemsCount)
763 newFocused = lphl->ItemsCount - 1;
765 ListBoxSetCurSel(lphl, newFocused);
766 ListBoxSendNotification(lphl, hwnd, CBN_SELCHANGE);
768 lphl->ItemFocused = newFocused;
769 ListBoxScrollToFocus(lphl);
770 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
771 InvalidateRect(hwnd, NULL, TRUE);
772 return 0;
775 /***********************************************************************
776 * CBLChar
778 static LONG CBLChar( HWND hwnd, WORD message, WORD wParam, LONG lParam )
780 return 0;
783 /***********************************************************************
784 * CBLPaint
786 static LONG CBLPaint( HWND hwnd, WORD message, WORD wParam, LONG lParam )
788 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
789 LPLISTSTRUCT lpls;
790 PAINTSTRUCT ps;
791 HBRUSH hBrush;
792 HFONT hOldFont;
793 HWND combohwnd = CLBoxGetCombo(hwnd);
794 HDC hdc;
795 RECT rect;
796 int i, top, height;
798 top = 0;
799 hdc = BeginPaint( hwnd, &ps );
801 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) {
802 EndPaint(hwnd, &ps);
803 return 0;
806 hOldFont = SelectObject(hdc, lphl->hFont);
807 hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
808 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
810 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
812 GetClientRect(hwnd, &rect);
813 FillRect(hdc, &rect, hBrush);
815 lpls = lphl->lpFirst;
817 lphl->ItemsVisible = 0;
818 for(i = 0; i < lphl->ItemsCount; i++) {
819 if (lpls == NULL) break;
821 if (i >= lphl->FirstVisible) {
822 height = lpls->mis.itemHeight;
824 if (top > rect.bottom) break;
825 lpls->itemRect.top = top;
826 lpls->itemRect.bottom = top + height;
827 lpls->itemRect.left = rect.left;
828 lpls->itemRect.right = rect.right;
830 dprintf_listbox(stddeb,"drawing item: %d %d %d %d %d\n",rect.left,top,rect.right,top+height,lpls->itemState);
831 if (OWNER_DRAWN(lphl)) {
832 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, 0);
833 if (lpls->itemState)
834 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_SELECT, ODS_SELECTED);
835 } else {
836 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
837 lpls->itemState);
839 if ((lphl->ItemFocused == i) && GetFocus() == hwnd)
840 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, ODS_FOCUS);
842 top += height;
843 lphl->ItemsVisible++;
846 lpls = lpls->lpNext;
848 SelectObject(hdc,hOldFont);
849 EndPaint( hwnd, &ps );
850 return 0;
854 /***********************************************************************
855 * CBLKillFocus
857 static LONG CBLKillFocus( HWND hwnd, WORD message, WORD wParam, LONG lParam )
859 /* SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);*/
860 return 0;
863 /***********************************************************************
864 * CBLActivate
866 static LONG CBLActivate( HWND hwnd, WORD message, WORD wParam, LONG lParam )
868 if (wParam == WA_INACTIVE)
869 SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
870 return 0;
873 /***********************************************************************
874 * CBLLButtonDown
876 static LONG CBLLButtonDown( HWND hwnd, WORD message, WORD wParam, LONG lParam )
878 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
879 int y;
880 RECT rectsel;
882 SetFocus(hwnd);
883 SetCapture(hwnd);
885 lphl->PrevFocused = lphl->ItemFocused;
887 y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
888 if (y == -1)
889 return 0;
891 ListBoxSetCurSel(lphl, y);
892 ListBoxGetItemRect(lphl, y, &rectsel);
894 InvalidateRect(hwnd, NULL, TRUE);
895 return 0;
898 /***********************************************************************
899 * CBLLButtonUp
901 static LONG CBLLButtonUp( HWND hwnd, WORD message, WORD wParam, LONG lParam )
903 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
905 if (GetCapture() == hwnd) ReleaseCapture();
907 if (lphl->PrevFocused != lphl->ItemFocused) {
908 SendMessage(CLBoxGetCombo(hwnd),CB_SETCURSEL,lphl->ItemFocused,0);
909 ListBoxSendNotification(lphl, CLBoxGetCombo(hwnd), CBN_SELCHANGE);
911 SendMessage(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
913 return 0;
916 /***********************************************************************
917 * CBLMouseMove
919 static LONG CBLMouseMove( HWND hwnd, WORD message, WORD wParam, LONG lParam )
921 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
922 int y;
923 WORD wRet;
924 RECT rect, rectsel; /* XXX Broken */
926 if ((wParam & MK_LBUTTON) != 0) {
927 y = SHIWORD(lParam);
928 if (y < 0) {
929 if (lphl->FirstVisible > 0) {
930 lphl->FirstVisible--;
931 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
932 InvalidateRect(hwnd, NULL, TRUE);
933 return 0;
936 GetClientRect(hwnd, &rect);
937 if (y >= rect.bottom) {
938 if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
939 lphl->FirstVisible++;
940 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
941 InvalidateRect(hwnd, NULL, TRUE);
942 return 0;
945 if ((y > 0) && (y < (rect.bottom - 4))) {
946 if ((y < rectsel.top) || (y > rectsel.bottom)) {
947 wRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
948 if (wRet == lphl->ItemFocused) return 0;
949 ListBoxSetCurSel(lphl, wRet);
950 ListBoxGetItemRect(lphl, wRet, &rectsel);
951 InvalidateRect(hwnd, NULL, TRUE);
956 return 0;
959 /***********************************************************************
960 * CBLVScroll
962 static LONG CBLVScroll( HWND hwnd, WORD message, WORD wParam, LONG lParam )
964 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
965 int y;
967 y = lphl->FirstVisible;
969 switch(wParam) {
970 case SB_LINEUP:
971 if (lphl->FirstVisible > 0)
972 lphl->FirstVisible--;
973 break;
975 case SB_LINEDOWN:
976 lphl->FirstVisible++;
977 break;
979 case SB_PAGEUP:
980 if (lphl->FirstVisible > lphl->ItemsVisible) {
981 lphl->FirstVisible -= lphl->ItemsVisible;
982 } else {
983 lphl->FirstVisible = 0;
985 break;
987 case SB_PAGEDOWN:
988 lphl->FirstVisible += lphl->ItemsVisible;
989 break;
991 case SB_THUMBTRACK:
992 lphl->FirstVisible = LOWORD(lParam);
993 break;
996 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
997 lphl->FirstVisible = ListMaxFirstVisible(lphl);
999 if (y != lphl->FirstVisible) {
1000 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1001 InvalidateRect(hwnd, NULL, TRUE);
1004 return 0;
1007 /***********************************************************************
1008 * ComboLBoxWndProc
1010 LONG ComboLBoxWndProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
1012 int idx = 0;
1013 int table_size = sizeof (clbox_tbl) / sizeof (msg_tbl);
1015 while (idx < table_size) {
1016 if (message == clbox_tbl[idx].message) {
1017 return (*(clbox_tbl[idx].handler))(hwnd, message, wParam, lParam);
1019 idx++;
1021 return DefWindowProc (hwnd, message, wParam, lParam);
1024 /************************************************************************
1025 * DlgDirSelectComboBox [USER.194]
1027 BOOL DlgDirSelectComboBox(HWND hDlg, LPSTR lpStr, int nIDLBox)
1029 fprintf(stdnimp,"DlgDirSelectComboBox(%04X, '%s', %d) \n",
1030 hDlg, lpStr, nIDLBox);
1031 return TRUE;
1035 /************************************************************************
1036 * DlgDirListComboBox [USER.195]
1038 int DlgDirListComboBox(HWND hDlg, SEGPTR PathSpec,
1039 int nIDLBox, int nIDStat, WORD wType)
1041 HWND hWnd;
1042 int ret;
1043 LPSTR lpPathSpec = PTR_SEG_TO_LIN(PathSpec);
1045 dprintf_combo(stddeb,"DlgDirListComboBox(%04X, '%s', %d, %d, %04X) \n",
1046 hDlg, lpPathSpec, nIDLBox, nIDStat, wType);
1047 if (nIDLBox) {
1048 LPHEADLIST lphl;
1049 LPHEADCOMBO lphc;
1050 hWnd = GetDlgItem(hDlg, nIDLBox);
1051 lphl = ComboGetListHeader(hWnd);
1052 lphc = ComboGetStorageHeader(hWnd);
1053 ListBoxResetContent(lphl);
1054 ret = ListBoxDirectory(lphl, wType, lpPathSpec);
1055 ComboUpdateWindow(hWnd, lphl, lphc, TRUE);
1056 } else {
1057 ret = 0;
1059 if (nIDStat) {
1060 int drive;
1061 HANDLE hTemp;
1062 char *temp;
1063 drive = DOS_GetDefaultDrive();
1064 hTemp = USER_HEAP_ALLOC( 256 );
1065 temp = (char *) USER_HEAP_LIN_ADDR( hTemp );
1066 strcpy( temp+3, DOS_GetCurrentDir(drive) );
1067 if( temp[3] == '\\' ) {
1068 temp[1] = 'A'+drive;
1069 temp[2] = ':';
1070 SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
1071 USER_HEAP_SEG_ADDR(hTemp) + 1 );
1072 } else {
1073 temp[0] = 'A'+drive;
1074 temp[1] = ':';
1075 temp[2] = '\\';
1076 SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
1077 USER_HEAP_SEG_ADDR(hTemp) );
1079 USER_HEAP_FREE( hTemp );
1081 return ret;