Release 951003
[wine/multimedia.git] / controls / listbox.c
blob393f497c06a06589aa613cfb5268f687c5be53dc
1 /*
2 * Listbox controls
3 *
4 * Copyright Martin Ayotte, 1993
5 * Copyright Constantine Sapuntzakis, 1995
6 *
7 */
9 /*
10 * TODO:
11 * - check if multi-column listboxes work
12 * - implement more messages and styles
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include "windows.h"
20 #include "user.h"
21 #include "win.h"
22 #include "msdos.h"
23 #include "listbox.h"
24 #include "dos_fs.h"
25 #include "stddebug.h"
26 #include "debug.h"
28 #if 0
29 #define LIST_HEAP_ALLOC(lphl,f,size) ((int)HEAP_Alloc(&lphl->Heap,f,size) & 0xffff)
30 #define LIST_HEAP_FREE(lphl,handle) (HEAP_Free(&lphl->Heap,LIST_HEAP_ADDR(lphl,handle)))
31 #define LIST_HEAP_ADDR(lphl,handle) \
32 ((void *)((handle) ? ((handle) | ((int)lphl->Heap & 0xffff0000)) : 0))
33 #else
34 /* FIXME: shouldn't each listbox have its own heap? */
35 #define LIST_HEAP_ALLOC(lphl,f,size) USER_HEAP_ALLOC(size)
36 #define LIST_HEAP_FREE(lphl,handle) USER_HEAP_FREE(handle)
37 #define LIST_HEAP_ADDR(lphl,handle) USER_HEAP_LIN_ADDR(handle)
38 #define LIST_HEAP_SEG_ADDR(lphl,handle) USER_HEAP_SEG_ADDR(handle)
39 #endif
41 #define LIST_HEAP_SIZE 0x10000
43 static void ListBoxInitialize(LPHEADLIST lphl)
45 lphl->lpFirst = NULL;
46 lphl->ItemsCount = 0;
47 lphl->ItemsVisible = 0;
48 lphl->FirstVisible = 0;
49 lphl->ColumnsVisible = 1;
50 lphl->ItemsPerColumn = 0;
51 lphl->ItemFocused = -1;
52 lphl->PrevFocused = -1;
55 void CreateListBoxStruct(HWND hwnd, WORD CtlType, LONG styles, HWND parent)
57 LPHEADLIST lphl;
59 lphl = (LPHEADLIST)malloc(sizeof(HEADLIST));
60 SetWindowLong(hwnd, 0, (LONG)lphl);
61 if (lphl == NULL) {
62 fprintf(stderr,"malloc failed in CreateListBoxStruct()\n");
63 exit(1); /* Things won't get better */
66 ListBoxInitialize(lphl);
67 lphl->DrawCtlType = CtlType;
68 lphl->CtlID = GetWindowWord(hwnd,GWW_ID);
69 lphl->bRedrawFlag = TRUE;
70 lphl->iNumStops = 0;
71 lphl->TabStops = NULL;
72 lphl->hFont = GetStockObject(SYSTEM_FONT);
73 lphl->hParent = parent;
74 lphl->StdItemHeight = 15; /* FIXME: should get the font height */
75 lphl->dwStyle = styles;
76 lphl->OwnerDrawn = styles & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE);
77 lphl->HasStrings = (styles & LBS_HASSTRINGS) || !lphl->OwnerDrawn;
79 if (lphl->OwnerDrawn) {
80 LISTSTRUCT dummyls;
82 lphl->hDrawItemStruct = USER_HEAP_ALLOC(sizeof(DRAWITEMSTRUCT));
83 lphl->needMeasure = TRUE;
84 dummyls.mis.CtlType = lphl->DrawCtlType;
85 dummyls.mis.CtlID = lphl->CtlID;
86 dummyls.mis.itemID = -1;
87 dummyls.mis.itemWidth = 0; /* ignored */
88 dummyls.mis.itemData = 0;
90 ListBoxAskMeasure(lphl,&dummyls);
91 } else {
92 lphl->hDrawItemStruct = 0;
95 #if 0
96 HeapHandle = GlobalAlloc(GMEM_FIXED, LIST_HEAP_SIZE);
97 HeapBase = GlobalLock(HeapHandle);
98 HEAP_Init(&lphl->Heap, HeapBase, LIST_HEAP_SIZE);
99 #endif
102 void DestroyListBoxStruct(LPHEADLIST lphl)
104 if (lphl->hDrawItemStruct)
105 USER_HEAP_FREE(lphl->hDrawItemStruct);
107 /* XXX need to free lphl->Heap */
108 free(lphl);
111 static LPHEADLIST ListBoxGetStorageHeader(HWND hwnd)
113 return (LPHEADLIST)GetWindowLong(hwnd,0);
116 /* Send notification "code" as part of a WM_COMMAND-message if hwnd
117 has the LBS_NOTIFY style */
118 void ListBoxSendNotification(LPHEADLIST lphl, HWND hwnd, WORD code)
120 if (lphl->dwStyle & LBS_NOTIFY)
121 #ifdef WINELIB32
122 SendMessage(lphl->hParent, WM_COMMAND,
123 MAKEWPARAM(lphl->CtlID,code), (LPARAM)hwnd);
124 #else
125 SendMessage(lphl->hParent, WM_COMMAND,
126 lphl->CtlID, MAKELONG(hwnd, code));
127 #endif
131 /* get the maximum value of lphl->FirstVisible */
132 int ListMaxFirstVisible(LPHEADLIST lphl)
134 int m = lphl->ItemsCount-lphl->ItemsVisible;
135 return (m < 0) ? 0 : m;
139 void ListBoxUpdateWindow(HWND hwnd, LPHEADLIST lphl, BOOL repaint)
141 SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
142 if (lphl->ItemsPerColumn != 0) {
143 SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible /
144 lphl->ItemsPerColumn + 1, TRUE);
146 if (repaint && lphl->bRedrawFlag) {
147 InvalidateRect(hwnd, NULL, TRUE);
151 /* Returns: 0 if nothing needs to be changed */
152 /* 1 if FirstVisible changed */
154 int ListBoxScrollToFocus(LPHEADLIST lphl)
156 short end;
158 if (lphl->ItemsCount == 0) return 0;
159 if (lphl->ItemFocused == -1) return 0;
161 end = lphl->FirstVisible + lphl->ItemsVisible - 1;
163 if (lphl->ItemFocused < lphl->FirstVisible ) {
164 lphl->FirstVisible = lphl->ItemFocused;
165 return 1;
166 } else {
167 if (lphl->ItemFocused > end) {
168 WORD maxFirstVisible = ListMaxFirstVisible(lphl);
170 lphl->FirstVisible = lphl->ItemFocused;
172 if (lphl->FirstVisible > maxFirstVisible) {
173 lphl->FirstVisible = maxFirstVisible;
175 return 1;
178 return 0;
182 LPLISTSTRUCT ListBoxGetItem(LPHEADLIST lphl, UINT uIndex)
184 LPLISTSTRUCT lpls;
185 UINT Count = 0;
187 if (uIndex >= lphl->ItemsCount) return NULL;
189 lpls = lphl->lpFirst;
190 while (Count++ < uIndex) lpls = lpls->lpNext;
191 return lpls;
195 void ListBoxDrawItem (HWND hwnd, LPHEADLIST lphl, HDC hdc, LPLISTSTRUCT lpls,
196 RECT *rect, WORD itemAction, WORD itemState)
198 if (lphl->OwnerDrawn) {
199 DRAWITEMSTRUCT *dis = USER_HEAP_LIN_ADDR(lphl->hDrawItemStruct);
201 dis->CtlID = lpls->mis.CtlID;
202 dis->CtlType = lpls->mis.CtlType;
203 dis->itemID = lpls->mis.itemID;
204 dis->hDC = hdc;
205 dis->hwndItem = hwnd;
206 dis->itemData = lpls->mis.itemData;
207 dis->itemAction = itemAction;
208 dis->itemState = itemState;
209 dis->rcItem = *rect;
210 SendMessage(lphl->hParent, WM_DRAWITEM,
211 0, (LPARAM)USER_HEAP_SEG_ADDR(lphl->hDrawItemStruct));
212 } else {
213 if (itemAction == ODA_DRAWENTIRE || itemAction == ODA_SELECT) {
214 int OldBkMode;
215 DWORD dwOldTextColor = 0;
217 OldBkMode = SetBkMode(hdc, TRANSPARENT);
219 if (itemState != 0) {
220 dwOldTextColor = SetTextColor(hdc, 0x00FFFFFFL);
221 FillRect(hdc, rect, GetStockObject(BLACK_BRUSH));
224 if (lphl->dwStyle & LBS_USETABSTOPS) {
225 TabbedTextOut(hdc, rect->left + 5, rect->top + 2,
226 (char *)lpls->itemText, strlen((char *)lpls->itemText),
227 lphl->iNumStops, lphl->TabStops, 0);
228 } else {
229 TextOut(hdc, rect->left + 5, rect->top + 2,
230 (char *)lpls->itemText, strlen((char *)lpls->itemText));
233 if (itemState != 0) {
234 SetTextColor(hdc, dwOldTextColor);
237 SetBkMode(hdc, OldBkMode);
238 } else DrawFocusRect(hdc, rect);
241 return;
245 int ListBoxFindMouse(LPHEADLIST lphl, int X, int Y)
247 LPLISTSTRUCT lpls = lphl->lpFirst;
248 int i, j;
249 POINT point;
251 point.x = X; point.y = Y;
252 if (lphl->ItemsCount == 0) return LB_ERR;
254 for(i = 0; i < lphl->FirstVisible; i++) {
255 if (lpls == NULL) return LB_ERR;
256 lpls = lpls->lpNext;
258 for(j = 0; j < lphl->ItemsVisible; i++, j++) {
259 if (lpls == NULL) return LB_ERR;
260 if (PtInRect(&lpls->itemRect,point)) {
261 return i;
263 lpls = lpls->lpNext;
265 dprintf_listbox(stddeb,"ListBoxFindMouse: not found\n");
266 return LB_ERR;
270 void ListBoxAskMeasure(LPHEADLIST lphl, LPLISTSTRUCT lpls)
272 HANDLE hTemp = USER_HEAP_ALLOC( sizeof(MEASUREITEMSTRUCT) );
273 MEASUREITEMSTRUCT *lpmeasure = (MEASUREITEMSTRUCT *) USER_HEAP_LIN_ADDR(hTemp);
275 if (lpmeasure == NULL) {
276 fprintf(stderr,"ListBoxAskMeasure() out of memory !\n");
277 return;
280 *lpmeasure = lpls->mis;
281 lpmeasure->itemHeight = lphl->StdItemHeight;
282 SendMessage(lphl->hParent, WM_MEASUREITEM, 0, (LPARAM)USER_HEAP_SEG_ADDR(hTemp));
284 if (lphl->dwStyle & LBS_OWNERDRAWFIXED) {
285 lphl->StdItemHeight = lpmeasure->itemHeight;
286 lphl->needMeasure = FALSE;
289 USER_HEAP_FREE(hTemp);
293 LPLISTSTRUCT ListBoxCreateItem(LPHEADLIST lphl, int id)
295 LPLISTSTRUCT lplsnew = (LPLISTSTRUCT)malloc(sizeof(LISTSTRUCT));
297 if (lplsnew == NULL) return NULL;
299 lplsnew->itemState = 0;
300 lplsnew->mis.CtlType = lphl->DrawCtlType;
301 lplsnew->mis.CtlID = lphl->CtlID;
302 lplsnew->mis.itemID = id;
303 lplsnew->mis.itemHeight = lphl->StdItemHeight;
304 lplsnew->mis.itemWidth = 0; /* ignored */
305 lplsnew->mis.itemData = 0;
306 SetRect(&lplsnew->itemRect, 0, 0, 0, 0);
308 return lplsnew;
312 int ListBoxInsertString(LPHEADLIST lphl, UINT uIndex, LPSTR newstr)
314 LPLISTSTRUCT *lppls, lplsnew, lpls;
315 HANDLE hStr;
316 LPSTR str;
317 UINT Count;
319 dprintf_listbox(stddeb,"ListBoxInsertString(%d, %p);\n", uIndex, newstr);
321 if (uIndex == (UINT)-1)
322 uIndex = lphl->ItemsCount;
324 lppls = &lphl->lpFirst;
325 for(Count = 0; Count < uIndex; Count++) {
326 if (*lppls == NULL) return LB_ERR;
327 lppls = (LPLISTSTRUCT *) &(*lppls)->lpNext;
330 lplsnew = ListBoxCreateItem(lphl, Count);
332 if (lplsnew == NULL) {
333 printf("ListBoxInsertString() out of memory !\n");
334 return LB_ERRSPACE;
337 lplsnew->lpNext = *lppls;
338 *lppls = lplsnew;
339 lphl->ItemsCount++;
341 hStr = 0;
342 if (lphl->HasStrings) {
343 dprintf_listbox(stddeb," string: %s\n", newstr);
344 hStr = LIST_HEAP_ALLOC(lphl, LMEM_MOVEABLE, strlen(newstr) + 1);
345 str = (LPSTR)LIST_HEAP_ADDR(lphl, hStr);
346 if (str == NULL) return LB_ERRSPACE;
347 strcpy(str, newstr);
348 lplsnew->itemText = str;
349 /* I'm not so sure about the next one */
350 lplsnew->mis.itemData = 0;
351 } else {
352 lplsnew->itemText = NULL;
353 lplsnew->mis.itemData = (DWORD)newstr;
356 lplsnew->mis.itemID = uIndex;
357 lplsnew->hData = hStr;
359 /* adjust the itemID field of the following entries */
360 for(lpls = lplsnew->lpNext; lpls != NULL; lpls = lpls->lpNext) {
361 lpls->mis.itemID++;
364 if (lphl->needMeasure) {
365 ListBoxAskMeasure(lphl, lplsnew);
368 dprintf_listbox(stddeb,"ListBoxInsertString // count=%d\n", lphl->ItemsCount);
369 return uIndex;
373 int ListBoxAddString(LPHEADLIST lphl, LPSTR newstr)
375 UINT pos = (UINT) -1;
377 if (lphl->HasStrings && (lphl->dwStyle & LBS_SORT)) {
378 LPLISTSTRUCT lpls = lphl->lpFirst;
379 for (pos = 0; lpls != NULL; lpls = lpls->lpNext, pos++)
380 if (strcmp(lpls->itemText, newstr) >= 0)
381 break;
383 return ListBoxInsertString(lphl, pos, newstr);
387 int ListBoxGetText(LPHEADLIST lphl, UINT uIndex, LPSTR OutStr)
389 LPLISTSTRUCT lpls;
391 if (!OutStr) {
392 dprintf_listbox(stddeb, "ListBoxGetText // OutStr==NULL\n");
393 return 0;
396 lpls = ListBoxGetItem (lphl, uIndex);
397 if (lpls == NULL) return LB_ERR;
399 if (!lphl->HasStrings) {
400 *((long *)OutStr) = lpls->mis.itemData;
401 return 4;
404 strcpy(OutStr, lpls->itemText);
405 return strlen(OutStr);
409 DWORD ListBoxGetItemData(LPHEADLIST lphl, UINT uIndex)
411 LPLISTSTRUCT lpls;
413 lpls = ListBoxGetItem (lphl, uIndex);
414 if (lpls == NULL) return LB_ERR;
415 return lpls->mis.itemData;
419 int ListBoxSetItemData(LPHEADLIST lphl, UINT uIndex, DWORD ItemData)
421 LPLISTSTRUCT lpls = ListBoxGetItem(lphl, uIndex);
423 if (lpls == NULL) return LB_ERR;
424 lpls->mis.itemData = ItemData;
425 return 1;
429 int ListBoxDeleteString(LPHEADLIST lphl, UINT uIndex)
431 LPLISTSTRUCT lpls, lpls2;
432 UINT Count;
434 if (uIndex >= lphl->ItemsCount) return LB_ERR;
436 lpls = lphl->lpFirst;
437 if (lpls == NULL) return LB_ERR;
439 if (uIndex == 0)
440 lphl->lpFirst = lpls->lpNext;
441 else {
442 LPLISTSTRUCT lpls2 = NULL;
443 for(Count = 0; Count < uIndex; Count++) {
444 if (lpls->lpNext == NULL) return LB_ERR;
446 lpls2 = lpls;
447 lpls = (LPLISTSTRUCT)lpls->lpNext;
449 lpls2->lpNext = lpls->lpNext;
452 /* adjust the itemID field of the following entries */
453 for(lpls2 = lpls->lpNext; lpls2 != NULL; lpls2 = lpls2->lpNext) {
454 lpls2->mis.itemID--;
457 lphl->ItemsCount--;
459 if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
460 free(lpls);
462 return lphl->ItemsCount;
466 int ListBoxFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr)
468 LPLISTSTRUCT lpls;
469 UINT Count;
470 UINT First = nFirst + 1;
471 LPSTR lpMatchStr = (LPSTR)MatchStr;
473 if (First > lphl->ItemsCount) return LB_ERR;
475 if (lphl->HasStrings) lpMatchStr = PTR_SEG_TO_LIN(MatchStr);
477 lpls = ListBoxGetItem(lphl, First);
478 Count = 0;
479 while(lpls != NULL) {
480 if (lphl->HasStrings) {
481 if (strstr(lpls->itemText, lpMatchStr) == lpls->itemText) return Count;
482 } else if (lphl->dwStyle & LBS_SORT) {
483 /* XXX Do a compare item */
485 else
486 if (lpls->mis.itemData == (DWORD)lpMatchStr) return Count;
488 lpls = lpls->lpNext;
489 Count++;
492 /* Start over at top */
493 Count = 0;
494 lpls = lphl->lpFirst;
496 while (Count < First) {
497 if (lphl->HasStrings) {
498 if (strstr(lpls->itemText, lpMatchStr) == lpls->itemText) return Count;
499 } else if (lphl->dwStyle & LBS_SORT) {
500 /* XXX Do a compare item */
501 } else {
502 if (lpls->mis.itemData == (DWORD)lpMatchStr) return Count;
504 lpls = lpls->lpNext;
505 Count++;
508 return LB_ERR;
512 int ListBoxResetContent(LPHEADLIST lphl)
514 LPLISTSTRUCT lpls;
515 int i;
517 if (lphl->ItemsCount == 0) return 0;
519 dprintf_listbox(stddeb, "ListBoxResetContent // ItemCount = %d\n",
520 lphl->ItemsCount);
522 for(i = 0; i < lphl->ItemsCount; i++) {
523 lpls = lphl->lpFirst;
524 if (lpls == NULL) return LB_ERR;
526 lphl->lpFirst = lpls->lpNext;
527 if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
528 free(lpls);
530 ListBoxInitialize(lphl);
532 return TRUE;
536 int ListBoxSetCurSel(LPHEADLIST lphl, WORD wIndex)
538 LPLISTSTRUCT lpls;
540 if (lphl->dwStyle & LBS_MULTIPLESEL) return 0;
542 if (lphl->ItemFocused != -1) {
543 lpls = ListBoxGetItem(lphl, lphl->ItemFocused);
544 if (lpls == 0) return LB_ERR;
545 lpls->itemState = 0;
548 if (wIndex != (UINT)-1) {
549 lphl->ItemFocused = wIndex;
550 lpls = ListBoxGetItem(lphl, wIndex);
551 if (lpls == 0) return LB_ERR;
552 lpls->itemState = ODS_SELECTED | ODS_FOCUS;
554 return 0;
557 return LB_ERR;
561 int ListBoxSetSel(LPHEADLIST lphl, WORD wIndex, WORD state)
563 LPLISTSTRUCT lpls;
565 if (!(lphl->dwStyle & LBS_MULTIPLESEL)) return 0;
567 if (wIndex == (UINT)-1) {
568 for (lpls = lphl->lpFirst; lpls != NULL; lpls = lpls->lpNext) {
569 lpls->itemState = state;
571 return 0;
574 if (wIndex >= lphl->ItemsCount) return LB_ERR;
576 lpls = ListBoxGetItem(lphl, wIndex);
577 lpls->itemState = state;
579 return 0;
583 int ListBoxGetSel(LPHEADLIST lphl, WORD wIndex)
585 LPLISTSTRUCT lpls = ListBoxGetItem(lphl, wIndex);
587 if (lpls == NULL) return LB_ERR;
588 return lpls->itemState;
592 int ListBoxDirectory(LPHEADLIST lphl, UINT attrib, LPSTR filespec)
594 struct dosdirent *dp, *dp_old;
595 char temp[256];
596 int drive;
597 LPSTR tstr;
599 dprintf_listbox(stddeb,"ListBoxDirectory: %s, %4x\n",filespec,attrib);
601 if (strchr(filespec, '\\') || strchr(filespec, ':')) {
602 drive = DOS_GetDefaultDrive();
603 if (filespec[1] == ':') {
604 drive = toupper(filespec[0]) - 'A';
605 filespec += 2;
607 strcpy(temp,filespec);
608 tstr = strrchr(temp, '\\');
609 if (tstr != NULL) {
610 *(tstr+1) = 0;
611 filespec += tstr - temp + 1;
612 if (!DOS_ChangeDir( drive, temp )) return 0;
614 DOS_SetDefaultDrive( drive );
615 dprintf_listbox(stddeb,"Changing directory to %c:%s, filemask is %s\n",
616 drive+'A', temp, filespec);
619 if ((dp = (struct dosdirent *)DOS_opendir(filespec)) ==NULL) return 0;
620 dp_old = dp;
621 while ((dp = (struct dosdirent *)DOS_readdir(dp))) {
622 if (!dp->inuse) break;
623 dprintf_listbox(stddeb, "ListBoxDirectory %p '%s' !\n", dp->filename,
624 dp->filename);
625 if (dp->attribute & FA_DIREC) {
626 if (attrib & DDL_DIRECTORY && strcmp(dp->filename, ".") != 0) {
627 sprintf(temp, "[%s]", dp->filename);
628 if (ListBoxAddString(lphl, temp) == LB_ERR) break;
631 else {
632 if (attrib & DDL_EXCLUSIVE) {
633 if (attrib & (DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM)) {
634 if (ListBoxAddString(lphl, dp->filename) == LB_ERR) break;
636 } else {
637 if (ListBoxAddString(lphl, dp->filename) == LB_ERR) break;
641 DOS_closedir(dp_old);
643 if (attrib & DDL_DRIVES) {
644 int x;
645 for (x = 0; x != MAX_DOS_DRIVES ; x++) {
646 if (DOS_ValidDrive(x)) {
647 sprintf(temp, "[-%c-]", 'a'+x);
648 if (ListBoxInsertString(lphl, (UINT)-1, temp) == LB_ERR) break;
652 return 1;
656 int ListBoxGetItemRect(LPHEADLIST lphl, WORD wIndex, LPRECT lprect)
658 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wIndex);
660 if (lpls == NULL) return LB_ERR;
661 *lprect = lpls->itemRect;
662 return 0;
666 int ListBoxSetItemHeight(LPHEADLIST lphl, WORD wIndex, long height)
668 LPLISTSTRUCT lpls;
670 if (!(lphl->dwStyle & LBS_OWNERDRAWVARIABLE)) {
671 lphl->StdItemHeight = (short)height;
672 return 0;
675 lpls = ListBoxGetItem(lphl, wIndex);
676 if (lpls == NULL) return LB_ERR;
678 lpls->mis.itemHeight = height;
679 return 0;
683 int ListBoxFindNextMatch(LPHEADLIST lphl, WORD wChar)
685 LPLISTSTRUCT lpls;
686 UINT count,first;
688 if ((char)wChar < ' ') return LB_ERR;
689 if (!lphl->HasStrings) return LB_ERR;
691 lpls = lphl->lpFirst;
693 for (count = 0; lpls != NULL; lpls = lpls->lpNext, count++) {
694 if (tolower(*lpls->itemText) == tolower((char)wChar)) break;
696 if (lpls == NULL) return LB_ERR;
697 first = count;
698 for(; lpls != NULL; lpls = lpls->lpNext, count++) {
699 if (*lpls->itemText != (char)wChar)
700 break;
701 if (count > lphl->ItemFocused)
702 return count;
704 return first;
707 /***********************************************************************
708 * LBCreate
710 static LONG LBCreate(HWND hwnd, WORD wParam, LONG lParam)
712 LPHEADLIST lphl;
713 RECT rect;
715 CreateListBoxStruct(hwnd, ODT_LISTBOX, GetWindowLong(hwnd,GWL_STYLE), GetParent(hwnd));
716 lphl = ListBoxGetStorageHeader(hwnd);
717 dprintf_listbox(stddeb,"ListBox WM_CREATE %p !\n", lphl);
719 GetClientRect(hwnd,&rect);
720 lphl->ColumnsWidth = rect.right - rect.left;
722 SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
723 SetScrollRange(hwnd, SB_HORZ, 1, 1, TRUE);
725 return 0;
728 /***********************************************************************
729 * LBDestroy
731 static LONG LBDestroy(HWND hwnd, WORD wParam, LONG lParam)
733 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
735 ListBoxResetContent(lphl);
737 DestroyListBoxStruct(lphl);
738 dprintf_listbox(stddeb,"ListBox WM_DESTROY %p !\n", lphl);
739 return 0;
742 /***********************************************************************
743 * LBVScroll
745 static LONG LBVScroll(HWND hwnd, WORD wParam, LONG lParam)
747 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
748 int y;
750 dprintf_listbox(stddeb,"ListBox WM_VSCROLL w=%04X l=%08lX !\n",
751 wParam, lParam);
752 y = lphl->FirstVisible;
754 switch(wParam) {
755 case SB_LINEUP:
756 if (lphl->FirstVisible > 0)
757 lphl->FirstVisible--;
758 break;
760 case SB_LINEDOWN:
761 lphl->FirstVisible++;
762 break;
764 case SB_PAGEUP:
765 if (lphl->FirstVisible > lphl->ItemsVisible) {
766 lphl->FirstVisible -= lphl->ItemsVisible;
767 } else {
768 lphl->FirstVisible = 0;
770 break;
772 case SB_PAGEDOWN:
773 lphl->FirstVisible += lphl->ItemsVisible;
774 break;
776 case SB_THUMBTRACK:
777 lphl->FirstVisible = LOWORD(lParam);
778 break;
781 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
782 lphl->FirstVisible = ListMaxFirstVisible(lphl);
784 if (y != lphl->FirstVisible) {
785 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
786 InvalidateRect(hwnd, NULL, TRUE);
788 return 0;
791 /***********************************************************************
792 * LBHScroll
794 static LONG LBHScroll(HWND hwnd, WORD wParam, LONG lParam)
796 LPHEADLIST lphl;
797 int y;
799 dprintf_listbox(stddeb,"ListBox WM_HSCROLL w=%04X l=%08lX !\n",
800 wParam, lParam);
801 lphl = ListBoxGetStorageHeader(hwnd);
802 y = lphl->FirstVisible;
803 switch(wParam) {
804 case SB_LINEUP:
805 if (lphl->FirstVisible > lphl->ItemsPerColumn) {
806 lphl->FirstVisible -= lphl->ItemsPerColumn;
807 } else {
808 lphl->FirstVisible = 0;
810 break;
811 case SB_LINEDOWN:
812 lphl->FirstVisible += lphl->ItemsPerColumn;
813 break;
814 case SB_PAGEUP:
815 if (lphl->ItemsPerColumn != 0) {
816 int lbsub = lphl->ItemsVisible / lphl->ItemsPerColumn * lphl->ItemsPerColumn;
817 if (lphl->FirstVisible > lbsub) {
818 lphl->FirstVisible -= lbsub;
819 } else {
820 lphl->FirstVisible = 0;
823 break;
824 case SB_PAGEDOWN:
825 if (lphl->ItemsPerColumn != 0)
826 lphl->FirstVisible += lphl->ItemsVisible /
827 lphl->ItemsPerColumn * lphl->ItemsPerColumn;
828 break;
829 case SB_THUMBTRACK:
830 lphl->FirstVisible = lphl->ItemsPerColumn * LOWORD(lParam);
831 break;
833 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
834 lphl->FirstVisible = ListMaxFirstVisible(lphl);
836 if (lphl->ItemsPerColumn != 0) {
837 lphl->FirstVisible = lphl->FirstVisible /
838 lphl->ItemsPerColumn * lphl->ItemsPerColumn + 1;
839 if (y != lphl->FirstVisible) {
840 SetScrollPos(hwnd, SB_HORZ, lphl->FirstVisible /
841 lphl->ItemsPerColumn + 1, TRUE);
842 InvalidateRect(hwnd, NULL, TRUE);
845 return 0;
848 /***********************************************************************
849 * LBLButtonDown
851 static LONG LBLButtonDown(HWND hwnd, WORD wParam, LONG lParam)
853 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
854 WORD wRet;
855 int y;
856 RECT rectsel;
858 SetFocus(hwnd);
859 SetCapture(hwnd);
861 lphl->PrevFocused = lphl->ItemFocused;
863 y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
864 if (y == -1)
865 return 0;
867 if (lphl->dwStyle & LBS_MULTIPLESEL) {
868 lphl->ItemFocused = y;
869 wRet = ListBoxGetSel(lphl, y);
870 ListBoxSetSel(lphl, y, !wRet);
871 } else {
872 ListBoxSetCurSel(lphl, y);
874 if (lphl->dwStyle & LBS_MULTIPLESEL)
875 ListBoxSendNotification(lphl, hwnd, LBN_SELCHANGE);
877 ListBoxGetItemRect(lphl, y, &rectsel);
879 InvalidateRect(hwnd, NULL, TRUE);
881 return 0;
884 /***********************************************************************
885 * LBLButtonUp
887 static LONG LBLButtonUp(HWND hwnd, WORD wParam, LONG lParam)
889 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
891 if (GetCapture() == hwnd) ReleaseCapture();
893 if (lphl->PrevFocused != lphl->ItemFocused)
894 ListBoxSendNotification(lphl, hwnd, LBN_SELCHANGE);
896 return 0;
899 /***********************************************************************
900 * LBRButtonUp
902 static LONG LBRButtonUp(HWND hwnd, WORD wParam, LONG lParam)
904 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
906 #ifdef WINELIB32
907 SendMessage(lphl->hParent, WM_COMMAND,
908 MAKEWPARAM(GetWindowWord(hwnd,GWW_ID),LBN_DBLCLK),
909 (LPARAM)hwnd);
910 #else
911 SendMessage(lphl->hParent, WM_COMMAND, GetWindowWord(hwnd,GWW_ID),
912 MAKELONG(hwnd, LBN_DBLCLK));
913 #endif
915 return 0;
918 /***********************************************************************
919 * LBMouseMove
921 static LONG LBMouseMove(HWND hwnd, WORD wParam, LONG lParam)
923 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
924 int y;
925 WORD wRet;
926 RECT rect, rectsel; /* XXX Broken */
928 dprintf_listbox(stddeb,"LBMouseMove %d %d\n",SLOWORD(lParam),SHIWORD(lParam));
929 if ((wParam & MK_LBUTTON) != 0) {
930 y = SHIWORD(lParam);
931 if (y < 0) {
932 if (lphl->FirstVisible > 0) {
933 lphl->FirstVisible--;
934 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
935 InvalidateRect(hwnd, NULL, TRUE);
936 return 0;
939 GetClientRect(hwnd, &rect);
940 if (y >= rect.bottom) {
941 if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
942 lphl->FirstVisible++;
943 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
944 InvalidateRect(hwnd, NULL, TRUE);
945 return 0;
948 if ((y > 0) && (y < (rect.bottom - 4))) {
949 if ((y < rectsel.top) || (y > rectsel.bottom)) {
950 wRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
951 if (wRet == lphl->ItemFocused) {
952 return 0;
954 if (lphl->dwStyle & LBS_MULTIPLESEL) {
955 lphl->ItemFocused = wRet;
956 ListBoxSendNotification(lphl, hwnd, LBN_SELCHANGE);
957 } else {
958 ListBoxSetCurSel(lphl, wRet);
960 ListBoxGetItemRect(lphl, wRet, &rectsel);
961 InvalidateRect(hwnd, NULL, TRUE);
966 return 0;
969 /***********************************************************************
970 * LBKeyDown
972 static LONG LBKeyDown(HWND hwnd, WORD wParam, LONG lParam)
974 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
975 WORD newFocused = lphl->ItemFocused;
977 if (wParam == VK_SPACE) {
978 if (lphl->dwStyle & LBS_MULTIPLESEL) {
979 WORD wRet = ListBoxGetSel(lphl, lphl->ItemFocused);
980 ListBoxSetSel(lphl, lphl->ItemFocused, !wRet);
982 return 0;
984 switch(wParam) {
985 case VK_HOME:
986 newFocused = 0;
987 break;
988 case VK_END:
989 newFocused = lphl->ItemsCount - 1;
990 break;
991 case VK_LEFT:
992 if (lphl->dwStyle & LBS_MULTICOLUMN) {
993 if (newFocused >= lphl->ItemsPerColumn) {
994 newFocused -= lphl->ItemsPerColumn;
995 } else {
996 newFocused = 0;
999 break;
1000 case VK_UP:
1001 if (newFocused > 0) newFocused--;
1002 break;
1003 case VK_RIGHT:
1004 if (lphl->dwStyle & LBS_MULTICOLUMN) {
1005 newFocused += lphl->ItemsPerColumn;
1007 break;
1008 case VK_DOWN:
1009 newFocused++;
1010 break;
1011 case VK_PRIOR:
1012 if (newFocused > lphl->ItemsVisible) {
1013 newFocused -= lphl->ItemsVisible;
1014 } else {
1015 newFocused = 0;
1017 break;
1018 case VK_NEXT:
1019 newFocused += lphl->ItemsVisible;
1020 break;
1021 default:
1022 return 0;
1025 if (newFocused >= lphl->ItemsCount)
1026 newFocused = lphl->ItemsCount - 1;
1028 if (!(lphl->dwStyle & LBS_MULTIPLESEL)) {
1029 ListBoxSetCurSel(lphl, newFocused);
1030 ListBoxSendNotification(lphl, hwnd, LBN_SELCHANGE);
1033 lphl->ItemFocused = newFocused;
1034 ListBoxScrollToFocus(lphl);
1035 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1036 InvalidateRect(hwnd, NULL, TRUE);
1038 return 0;
1041 /***********************************************************************
1042 * LBChar
1044 static LONG LBChar(HWND hwnd, WORD wParam, LONG lParam)
1046 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1047 WORD newFocused;
1049 newFocused = ListBoxFindNextMatch(lphl, wParam);
1050 if (newFocused == (WORD)LB_ERR) return 0;
1052 if (newFocused >= lphl->ItemsCount)
1053 newFocused = lphl->ItemsCount - 1;
1054 if (!(lphl->dwStyle & LBS_MULTIPLESEL)) {
1055 ListBoxSetCurSel(lphl, newFocused);
1056 ListBoxSendNotification(lphl, hwnd, LBN_SELCHANGE);
1059 lphl->ItemFocused = newFocused;
1060 ListBoxScrollToFocus(lphl);
1061 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1062 InvalidateRect(hwnd, NULL, TRUE);
1064 return 0;
1067 /***********************************************************************
1068 * LBSetRedraw
1070 static LONG LBSetRedraw(HWND hwnd, WORD wParam, LONG lParam)
1072 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1074 dprintf_listbox(stddeb,"ListBox WM_SETREDRAW hWnd="NPFMT" w=%04X !\n",
1075 hwnd, wParam);
1076 lphl->bRedrawFlag = wParam;
1078 return 0;
1081 /***********************************************************************
1082 * LBSetFont
1084 static LONG LBSetFont(HWND hwnd, WPARAM wParam, LPARAM lParam)
1086 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1088 if (wParam == 0)
1089 lphl->hFont = GetStockObject(SYSTEM_FONT);
1090 else
1091 lphl->hFont = (HFONT) wParam;
1093 return 0;
1096 /***********************************************************************
1097 * LBPaint
1099 static LONG LBPaint(HWND hwnd, WORD wParam, LONG lParam)
1101 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1102 LPLISTSTRUCT lpls;
1103 PAINTSTRUCT ps;
1104 HBRUSH hBrush;
1105 HFONT hOldFont;
1106 HDC hdc;
1107 RECT rect;
1108 int i, top, height, maxwidth, ipc;
1110 top = 0;
1111 hdc = BeginPaint( hwnd, &ps );
1113 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) {
1114 EndPaint(hwnd, &ps);
1115 return 0;
1118 hOldFont = SelectObject(hdc, lphl->hFont);
1120 #ifdef WINELIB32
1121 hBrush = (HBRUSH) SendMessage(lphl->hParent, WM_CTLCOLORLISTBOX, (WPARAM)hdc,
1122 (LPARAM)hwnd);
1123 #else
1124 hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
1125 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
1126 #endif
1128 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
1130 GetClientRect(hwnd, &rect);
1131 FillRect(hdc, &rect, hBrush);
1133 maxwidth = rect.right;
1134 if (lphl->dwStyle & LBS_MULTICOLUMN) {
1135 rect.right = lphl->ColumnsWidth;
1137 lpls = lphl->lpFirst;
1139 lphl->ItemsVisible = 0;
1140 lphl->ItemsPerColumn = ipc = 0;
1142 for(i = 0; i < lphl->ItemsCount; i++) {
1143 if (lpls == NULL) break;
1145 if (i >= lphl->FirstVisible) {
1146 height = lpls->mis.itemHeight;
1148 if (top > rect.bottom) {
1149 if (lphl->dwStyle & LBS_MULTICOLUMN) {
1150 lphl->ItemsPerColumn = max(lphl->ItemsPerColumn, ipc);
1151 ipc = 0;
1152 top = 0;
1153 rect.left += lphl->ColumnsWidth;
1154 rect.right += lphl->ColumnsWidth;
1155 if (rect.left > maxwidth) break;
1156 } else {
1157 break;
1161 lpls->itemRect.top = top;
1162 lpls->itemRect.bottom = top + height;
1163 lpls->itemRect.left = rect.left;
1164 lpls->itemRect.right = rect.right;
1166 dprintf_listbox(stddeb,"drawing item: %d %d %d %d %d\n",rect.left,top,rect.right,top+height,lpls->itemState);
1167 if (lphl->OwnerDrawn) {
1168 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, 0);
1169 if (lpls->itemState)
1170 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_SELECT, ODS_SELECTED);
1171 } else {
1172 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
1173 lpls->itemState);
1175 if ((lphl->ItemFocused == i) && GetFocus() == hwnd)
1176 ListBoxDrawItem (hwnd,lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, ODS_FOCUS);
1178 top += height;
1179 lphl->ItemsVisible++;
1180 ipc++;
1183 lpls = lpls->lpNext;
1185 SelectObject(hdc,hOldFont);
1186 EndPaint( hwnd, &ps );
1187 return 0;
1190 /***********************************************************************
1191 * LBSetFocus
1193 static LONG LBSetFocus(HWND hwnd, WORD wParam, LONG lParam)
1195 dprintf_listbox(stddeb,"ListBox WM_SETFOCUS !\n");
1197 return 0;
1200 /***********************************************************************
1201 * LBKillFocus
1203 static LONG LBKillFocus(HWND hwnd, WORD wParam, LONG lParam)
1205 dprintf_listbox(stddeb,"ListBox WM_KILLFOCUS !\n");
1207 InvalidateRect(hwnd, NULL, TRUE);
1209 return 0;
1212 /***********************************************************************
1213 * LBResetContent
1215 static LONG LBResetContent(HWND hwnd, WORD wParam, LONG lParam)
1217 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1219 dprintf_listbox(stddeb,"ListBox LB_RESETCONTENT !\n");
1220 ListBoxResetContent(lphl);
1221 ListBoxUpdateWindow(hwnd, lphl, TRUE);
1222 return 0;
1225 /***********************************************************************
1226 * LBDir
1228 static LONG LBDir(HWND hwnd, WORD wParam, LONG lParam)
1230 WORD wRet;
1231 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1232 dprintf_listbox(stddeb,"ListBox LB_DIR !\n");
1234 wRet = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
1235 ListBoxUpdateWindow(hwnd, lphl, TRUE);
1236 return wRet;
1239 /***********************************************************************
1240 * LBAddString
1242 static LONG LBAddString(HWND hwnd, WORD wParam, LONG lParam)
1244 WORD wRet;
1245 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1247 if (lphl->HasStrings)
1248 wRet = ListBoxAddString(lphl, (LPSTR)PTR_SEG_TO_LIN(lParam));
1249 else
1250 wRet = ListBoxAddString(lphl, (LPSTR)lParam);
1252 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1253 return wRet;
1256 /***********************************************************************
1257 * LBGetText
1259 static LONG LBGetText(HWND hwnd, WORD wParam, LONG lParam)
1261 LONG wRet;
1262 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1264 dprintf_listbox(stddeb, "LB_GETTEXT wParam=%d\n",wParam);
1265 wRet = ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
1267 return wRet;
1270 /***********************************************************************
1271 * LBInsertString
1273 static LONG LBInsertString(HWND hwnd, WORD wParam, LONG lParam)
1275 WORD wRet;
1276 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1278 if (lphl->HasStrings)
1279 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
1280 else
1281 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)lParam);
1283 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1284 return wRet;
1287 /***********************************************************************
1288 * LBDeleteString
1290 static LONG LBDeleteString(HWND hwnd, WORD wParam, LONG lParam)
1292 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1293 LONG lRet = ListBoxDeleteString(lphl,wParam);
1295 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1296 return lRet;
1299 /***********************************************************************
1300 * LBFindString
1302 static LONG LBFindString(HWND hwnd, WORD wParam, LONG lParam)
1304 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1305 return ListBoxFindString(lphl, wParam, lParam);
1308 /***********************************************************************
1309 * LBGetCaretIndex
1311 static LONG LBGetCaretIndex(HWND hwnd, WORD wParam, LONG lParam)
1313 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1314 return lphl->ItemFocused;
1317 /***********************************************************************
1318 * LBGetCount
1320 static LONG LBGetCount(HWND hwnd, WORD wParam, LONG lParam)
1322 LPHEADLIST lphl;
1324 lphl = ListBoxGetStorageHeader(hwnd);
1325 return lphl->ItemsCount;
1328 /***********************************************************************
1329 * LBGetCurSel
1331 static LONG LBGetCurSel(HWND hwnd, WORD wParam, LONG lParam)
1333 LPHEADLIST lphl;
1335 lphl = ListBoxGetStorageHeader(hwnd);
1336 dprintf_listbox(stddeb,"ListBox LB_GETCURSEL %u !\n",
1337 lphl->ItemFocused);
1338 return lphl->ItemFocused;
1341 /***********************************************************************
1342 * LBGetHorizontalExtent
1344 static LONG LBGetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam)
1346 return 0;
1349 /***********************************************************************
1350 * LBGetItemHeight
1352 static LONG LBGetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
1354 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1355 LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
1357 if (lpls == NULL) return LB_ERR;
1358 return lpls->mis.itemHeight;
1361 /***********************************************************************
1362 * LBGetItemRect
1364 static LONG LBGetItemRect(HWND hwnd, WORD wParam, LONG lParam)
1366 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1367 return ListBoxGetItemRect(lphl, wParam, PTR_SEG_TO_LIN(lParam));
1370 /***********************************************************************
1371 * LBGetSel
1373 static LONG LBGetSel(HWND hwnd, WORD wParam, LONG lParam)
1375 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1376 return ListBoxGetSel(lphl, wParam);
1379 /***********************************************************************
1380 * LBGetSelCount
1382 static LONG LBGetSelCount(HWND hwnd, WORD wParam, LONG lParam)
1384 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1385 LPLISTSTRUCT lpls;
1386 int cnt = 0;
1388 if (!(lphl->dwStyle & LBS_MULTIPLESEL)) return LB_ERR;
1390 lpls = lphl->lpFirst;
1392 while (lpls != NULL) {
1393 if (lpls->itemState > 0) cnt++;
1395 lpls = lpls->lpNext;
1398 return cnt;
1401 /***********************************************************************
1402 * LBGetSelItems
1404 static LONG LBGetSelItems(HWND hwnd, WORD wParam, LONG lParam)
1406 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1407 LPLISTSTRUCT lpls;
1408 int cnt, idx;
1409 int *lpItems = PTR_SEG_TO_LIN(lParam);
1411 if (!(lphl->dwStyle & LBS_MULTIPLESEL)) return LB_ERR;
1413 if (wParam == 0) return 0;
1415 lpls = lphl->lpFirst;
1416 cnt = 0; idx = 0;
1418 while (lpls != NULL) {
1419 if (lpls->itemState > 0) lpItems[cnt++] = idx;
1421 if (cnt == wParam) break;
1422 idx++;
1423 lpls = lpls->lpNext;
1426 return cnt;
1429 /***********************************************************************
1430 * LBGetTextLen
1432 static LONG LBGetTextLen(HWND hwnd, WORD wParam, LONG lParam)
1434 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1435 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
1437 if (lpls == NULL || !lphl->HasStrings) return LB_ERR;
1438 return strlen(lpls->itemText);
1441 /***********************************************************************
1442 * LBGetDlgCode
1444 static LONG LBGetDlgCode(HWND hwnd, WORD wParam, LONG lParam)
1446 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1449 /***********************************************************************
1450 * LBGetTopIndex
1452 static LONG LBGetTopIndex(HWND hwnd, WORD wParam, LONG lParam)
1454 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1456 return lphl->FirstVisible;
1460 /***********************************************************************
1461 * LBSelectString
1463 static LONG LBSelectString(HWND hwnd, WORD wParam, LONG lParam)
1465 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1466 WORD wRet;
1468 wRet = ListBoxFindString(lphl, wParam, lParam);
1470 /* XXX add functionality here */
1472 return 0;
1475 /***********************************************************************
1476 * LBSelItemRange
1478 static LONG LBSelItemRange(HWND hwnd, WORD wParam, LONG lParam)
1480 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1481 LPLISTSTRUCT lpls;
1482 WORD cnt;
1483 WORD first = LOWORD(lParam);
1484 WORD last = HIWORD(lParam);
1485 BOOL select = wParam;
1487 if (!(lphl->dwStyle & LBS_MULTIPLESEL)) return LB_ERR;
1489 if (first >= lphl->ItemsCount ||
1490 last >= lphl->ItemsCount) return LB_ERR;
1492 lpls = lphl->lpFirst;
1493 cnt = 0;
1495 while (lpls != NULL) {
1496 if (cnt++ >= first)
1497 lpls->itemState = select ? ODS_SELECTED : 0;
1499 if (cnt > last)
1500 break;
1502 lpls = lpls->lpNext;
1505 return 0;
1508 /***********************************************************************
1509 * LBSetCaretIndex
1511 static LONG LBSetCaretIndex(HWND hwnd, WORD wParam, LONG lParam)
1513 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1515 if (!(lphl->dwStyle & LBS_MULTIPLESEL)) return 0;
1516 if (wParam >= lphl->ItemsCount) return LB_ERR;
1518 lphl->ItemFocused = wParam;
1519 ListBoxScrollToFocus (lphl);
1521 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1522 InvalidateRect(hwnd, NULL, TRUE);
1523 return 0;
1526 /***********************************************************************
1527 * LBSetColumnWidth
1529 static LONG LBSetColumnWidth(HWND hwnd, WORD wParam, LONG lParam)
1531 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1532 lphl->ColumnsWidth = wParam;
1533 InvalidateRect(hwnd,NULL,TRUE);
1534 return 0;
1537 /***********************************************************************
1538 * LBSetHorizontalExtent
1540 static LONG LBSetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam)
1542 return 0;
1545 /***********************************************************************
1546 * LBGetItemData
1548 static LONG LBGetItemData(HWND hwnd, WORD wParam, LONG lParam)
1550 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1551 dprintf_listbox(stddeb, "LB_GETITEMDATA wParam=%x\n", wParam);
1552 return ListBoxGetItemData(lphl, wParam);
1555 /***********************************************************************
1556 * LBSetItemData
1558 static LONG LBSetItemData(HWND hwnd, WORD wParam, LONG lParam)
1560 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1561 dprintf_listbox(stddeb, "LB_SETITEMDATA wParam=%x lParam=%lx\n", wParam, lParam);
1562 return ListBoxSetItemData(lphl, wParam, lParam);
1565 /***********************************************************************
1566 * LBSetTabStops
1568 static LONG LBSetTabStops(HWND hwnd, WORD wParam, LONG lParam)
1570 LPHEADLIST lphl;
1572 lphl = ListBoxGetStorageHeader(hwnd);
1574 if (lphl->TabStops != NULL) {
1575 lphl->iNumStops = 0;
1576 free (lphl->TabStops);
1579 lphl->TabStops = malloc (wParam * sizeof (short));
1580 if (lphl->TabStops) {
1581 lphl->iNumStops = wParam;
1582 memcpy (lphl->TabStops, PTR_SEG_TO_LIN(lParam), wParam * sizeof (short));
1583 return TRUE;
1586 return FALSE;
1589 /***********************************************************************
1590 * LBSetCurSel
1592 static LONG LBSetCurSel(HWND hwnd, WORD wParam, LONG lParam)
1594 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1595 WORD wRet;
1597 dprintf_listbox(stddeb,"ListBox LB_SETCURSEL wParam=%x !\n",
1598 wParam);
1600 wRet = ListBoxSetCurSel(lphl, wParam);
1602 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1603 InvalidateRect(hwnd, NULL, TRUE);
1605 return wRet;
1608 /***********************************************************************
1609 * LBSetSel
1611 static LONG LBSetSel(HWND hwnd, WORD wParam, LONG lParam)
1613 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1614 WORD wRet;
1616 dprintf_listbox(stddeb,"ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam, lParam);
1618 wRet = ListBoxSetSel(lphl, LOWORD(lParam), wParam);
1619 InvalidateRect(hwnd, NULL, TRUE);
1621 return wRet;
1624 /***********************************************************************
1625 * LBSetTopIndex
1627 static LONG LBSetTopIndex(HWND hwnd, WORD wParam, LONG lParam)
1629 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1631 dprintf_listbox(stddeb,"ListBox LB_SETTOPINDEX wParam=%x !\n",
1632 wParam);
1633 lphl->FirstVisible = wParam;
1634 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1636 InvalidateRect(hwnd, NULL, TRUE);
1638 return 0;
1641 /***********************************************************************
1642 * LBSetItemHeight
1644 static LONG LBSetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
1646 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1647 WORD wRet;
1649 dprintf_listbox(stddeb,"ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam, lParam);
1650 wRet = ListBoxSetItemHeight(lphl, wParam, lParam);
1651 InvalidateRect(hwnd,NULL,TRUE);
1652 return wRet;
1655 /***********************************************************************
1656 * ListBoxWndProc
1658 LRESULT ListBoxWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1660 switch (message) {
1661 case WM_CREATE: return LBCreate(hwnd, wParam, lParam);
1662 case WM_DESTROY: return LBDestroy(hwnd, wParam, lParam);
1663 case WM_GETDLGCODE: return LBGetDlgCode(hwnd, wParam, lParam);
1664 case WM_VSCROLL: return LBVScroll(hwnd, wParam, lParam);
1665 case WM_HSCROLL: return LBHScroll(hwnd, wParam, lParam);
1666 case WM_LBUTTONDOWN: return LBLButtonDown(hwnd, wParam, lParam);
1667 case WM_LBUTTONUP: return LBLButtonUp(hwnd, wParam, lParam);
1668 case WM_RBUTTONUP: return LBRButtonUp(hwnd, wParam, lParam);
1669 case WM_LBUTTONDBLCLK: return LBRButtonUp(hwnd, wParam, lParam);
1670 case WM_MOUSEMOVE: return LBMouseMove(hwnd, wParam, lParam);
1671 case WM_KEYDOWN: return LBKeyDown(hwnd, wParam, lParam);
1672 case WM_CHAR: return LBChar(hwnd, wParam, lParam);
1673 case WM_SETFONT: return LBSetFont(hwnd, wParam, lParam);
1674 case WM_SETREDRAW: return LBSetRedraw(hwnd, wParam, lParam);
1675 case WM_PAINT: return LBPaint(hwnd, wParam, lParam);
1676 case WM_SETFOCUS: return LBSetFocus(hwnd, wParam, lParam);
1677 case WM_KILLFOCUS: return LBKillFocus(hwnd, wParam, lParam);
1678 case LB_RESETCONTENT: return LBResetContent(hwnd, wParam, lParam);
1679 case LB_DIR: return LBDir(hwnd, wParam, lParam);
1680 case LB_ADDSTRING: return LBAddString(hwnd, wParam, lParam);
1681 case LB_INSERTSTRING: return LBInsertString(hwnd, wParam, lParam);
1682 case LB_DELETESTRING: return LBDeleteString(hwnd, wParam, lParam);
1683 case LB_FINDSTRING: return LBFindString(hwnd, wParam, lParam);
1684 case LB_GETCARETINDEX: return LBGetCaretIndex(hwnd, wParam, lParam);
1685 case LB_GETCOUNT: return LBGetCount(hwnd, wParam, lParam);
1686 case LB_GETCURSEL: return LBGetCurSel(hwnd, wParam, lParam);
1687 case LB_GETHORIZONTALEXTENT: return LBGetHorizontalExtent(hwnd, wParam, lParam);
1688 case LB_GETITEMDATA: return LBGetItemData(hwnd, wParam, lParam);
1689 case LB_GETITEMHEIGHT: return LBGetItemHeight(hwnd, wParam, lParam);
1690 case LB_GETITEMRECT: return LBGetItemRect(hwnd, wParam, lParam);
1691 case LB_GETSEL: return LBGetSel(hwnd, wParam, lParam);
1692 case LB_GETSELCOUNT: return LBGetSelCount(hwnd, wParam, lParam);
1693 case LB_GETSELITEMS: return LBGetSelItems(hwnd, wParam, lParam);
1694 case LB_GETTEXT: return LBGetText(hwnd, wParam, lParam);
1695 case LB_GETTEXTLEN: return LBGetTextLen(hwnd, wParam, lParam);
1696 case LB_GETTOPINDEX: return LBGetTopIndex(hwnd, wParam, lParam);
1697 case LB_SELECTSTRING: return LBSelectString(hwnd, wParam, lParam);
1698 case LB_SELITEMRANGE: return LBSelItemRange(hwnd, wParam, lParam);
1699 case LB_SETCARETINDEX: return LBSetCaretIndex(hwnd, wParam, lParam);
1700 case LB_SETCOLUMNWIDTH: return LBSetColumnWidth(hwnd, wParam, lParam);
1701 case LB_SETHORIZONTALEXTENT: return LBSetHorizontalExtent(hwnd, wParam, lParam);
1702 case LB_SETITEMDATA: return LBSetItemData(hwnd, wParam, lParam);
1703 case LB_SETTABSTOPS: return LBSetTabStops(hwnd, wParam, lParam);
1704 case LB_SETCURSEL: return LBSetCurSel(hwnd, wParam, lParam);
1705 case LB_SETSEL: return LBSetSel(hwnd, wParam, lParam);
1706 case LB_SETTOPINDEX: return LBSetTopIndex(hwnd, wParam, lParam);
1707 case LB_SETITEMHEIGHT: return LBSetItemHeight(hwnd, wParam, lParam);
1710 return DefWindowProc(hwnd, message, wParam, lParam);
1713 /************************************************************************
1714 * DlgDirSelect [USER.99]
1716 BOOL DlgDirSelect(HWND hDlg, LPSTR lpStr, int nIDLBox)
1718 HWND hwnd;
1719 LPHEADLIST lphl;
1720 char s[130];
1722 dprintf_listbox( stddeb, "DlgDirSelect("NPFMT", '%s', %d) \n", hDlg, lpStr,
1723 nIDLBox );
1725 hwnd = GetDlgItem(hDlg, nIDLBox);
1726 lphl = ListBoxGetStorageHeader(hwnd);
1727 if(lphl->ItemFocused == -1) {
1728 dprintf_listbox(stddeb, "Nothing selected!\n");
1729 return FALSE;
1731 ListBoxGetText(lphl, lphl->ItemFocused, s);
1732 dprintf_listbox(stddeb, "Selection is %s\n", s);
1733 if( s[0] == '[' ) {
1734 if( s[1] == '-' ) {
1735 strncpy( lpStr, s+2, strlen(s)-4 ); /* device name */
1736 lpStr[ strlen(s)-4 ] = 0;
1737 strcat( lpStr, ":" );
1739 else {
1740 strncpy( lpStr, s+1, strlen(s)-2 ); /* directory name */
1741 lpStr[ strlen(s)-2 ] = 0;
1742 strcat( lpStr, "\\" );
1744 dprintf_listbox( stddeb, "Returning %s\n", lpStr );
1745 return TRUE;
1746 } else {
1747 strcpy( lpStr, s ); /* file name */
1748 dprintf_listbox( stddeb, "Returning %s\n", lpStr );
1749 return FALSE;
1754 /************************************************************************
1755 * DlgDirList [USER.100]
1757 int DlgDirList(HWND hDlg, LPSTR lpPathSpec,
1758 int nIDLBox, int nIDStat, WORD wType)
1760 HWND hWnd;
1761 int ret;
1763 dprintf_listbox(stddeb,"DlgDirList("NPFMT", '%s', %d, %d, %04X) \n",
1764 hDlg, lpPathSpec, nIDLBox, nIDStat, wType);
1765 if (nIDLBox) {
1766 LPHEADLIST lphl;
1767 hWnd = GetDlgItem(hDlg, nIDLBox);
1768 lphl = ListBoxGetStorageHeader(hWnd);
1769 ListBoxResetContent(lphl);
1770 ret = ListBoxDirectory(lphl, wType, lpPathSpec);
1771 ListBoxUpdateWindow(hWnd, lphl, TRUE);
1772 } else {
1773 ret = 0;
1775 if (nIDStat) {
1776 int drive;
1777 HANDLE hTemp;
1778 char *temp;
1779 drive = DOS_GetDefaultDrive();
1780 hTemp = USER_HEAP_ALLOC( 256 );
1781 temp = (char *) USER_HEAP_LIN_ADDR( hTemp );
1782 strcpy( temp+3, DOS_GetCurrentDir(drive) );
1783 if( temp[3] == '\\' ) {
1784 temp[1] = 'A'+drive;
1785 temp[2] = ':';
1786 SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
1787 (LPARAM)(USER_HEAP_SEG_ADDR(hTemp) + 1) );
1788 } else {
1789 temp[0] = 'A'+drive;
1790 temp[1] = ':';
1791 temp[2] = '\\';
1792 SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
1793 (LPARAM)USER_HEAP_SEG_ADDR(hTemp) );
1795 USER_HEAP_FREE( hTemp );
1797 return ret;