Release 951124
[wine/multimedia.git] / controls / listbox.c
bloba215ec380e36b970e8ea31152d9e3508f357597c
1 /*
2 * Listbox controls
3 *
4 * Copyright Martin Ayotte, 1993
5 * Constantine Sapuntzakis, 1995
6 * Alex Korobka, 1995
7 *
8 */
11 * FIXME:
12 * - check if multi-column listboxes work
13 * - implement more messages and styles (LB_EXTENDEDSEL for instance)
14 * - exterminate evil InvalidateRect(whole listbox) where possible!!!!
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include "windows.h"
22 #include "user.h"
23 #include "win.h"
24 #include "msdos.h"
25 #include "listbox.h"
26 #include "dos_fs.h"
27 #include "stddebug.h"
28 #include "debug.h"
29 #include "xmalloc.h"
31 #if 0
32 #define LIST_HEAP_ALLOC(lphl,f,size) ((int)HEAP_Alloc(&lphl->Heap,f,size) & 0xffff)
33 #define LIST_HEAP_FREE(lphl,handle) (HEAP_Free(&lphl->Heap,LIST_HEAP_ADDR(lphl,handle)))
34 #define LIST_HEAP_ADDR(lphl,handle) \
35 ((void *)((handle) ? ((handle) | ((int)lphl->Heap & 0xffff0000)) : 0))
36 #else
37 /* FIXME: shouldn't each listbox have its own heap? */
38 #if 0
39 #define LIST_HEAP_ALLOC(lphl,f,size) USER_HEAP_ALLOC(size)
40 #define LIST_HEAP_FREE(lphl,handle) USER_HEAP_FREE(handle)
41 #define LIST_HEAP_ADDR(lphl,handle) USER_HEAP_LIN_ADDR(handle)
42 #define LIST_HEAP_SEG_ADDR(lphl,handle) USER_HEAP_SEG_ADDR(handle)
43 #else
44 /* Something like this maybe ? */
45 #define LIST_HEAP_ALLOC(lphl,f,size) \
46 LOCAL_Alloc( lphl->HeapSel, LMEM_FIXED, (size) )
47 #if 0
48 #define LIST_HEAP_REALLOC(handle,size) \
49 LOCAL_ReAlloc( USER_HeapSel, (handle), (size), LMEM_FIXED )
50 #endif
51 #define LIST_HEAP_FREE(lphl,handle) \
52 LOCAL_Free( lphl->HeapSel, (handle) )
53 #define LIST_HEAP_ADDR(lphl,handle) \
54 ((handle) ? PTR_SEG_OFF_TO_LIN(lphl->HeapSel, (handle)) : NULL)
55 #define LIST_HEAP_SEG_ADDR(lphl,handle) \
56 ((handle) ? MAKELONG((handle), lphl->HeapSel) : 0)
57 #endif
58 #endif
60 #define LIST_HEAP_SIZE 0x10000
62 static void ListBoxInitialize(LPHEADLIST lphl)
64 lphl->lpFirst = NULL;
65 lphl->ItemsCount = 0;
66 lphl->ItemsVisible = 0;
67 lphl->FirstVisible = 0;
68 lphl->ColumnsVisible = 1;
69 lphl->ItemsPerColumn = 0;
70 lphl->ItemFocused = -1;
71 lphl->PrevFocused = -1;
74 void CreateListBoxStruct(HWND hwnd, WORD CtlType, LONG styles, HWND parent)
76 LPHEADLIST lphl;
78 lphl = (LPHEADLIST)xmalloc(sizeof(HEADLIST));
79 SetWindowLong(hwnd, 0, (LONG)lphl);
80 ListBoxInitialize(lphl);
81 lphl->DrawCtlType = CtlType;
82 lphl->CtlID = GetWindowWord(hwnd,GWW_ID);
83 lphl->bRedrawFlag = TRUE;
84 lphl->iNumStops = 0;
85 lphl->TabStops = NULL;
86 lphl->hFont = GetStockObject(SYSTEM_FONT);
87 lphl->hSelf = hwnd;
88 lphl->hParent = parent;
89 lphl->StdItemHeight = 15; /* FIXME: should get the font height */
90 lphl->OwnerDrawn = styles & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE);
91 lphl->HasStrings = (styles & LBS_HASSTRINGS) || !lphl->OwnerDrawn;
93 if (lphl->OwnerDrawn) {
94 LISTSTRUCT dummyls;
96 lphl->hDrawItemStruct = USER_HEAP_ALLOC(sizeof(DRAWITEMSTRUCT));
97 lphl->needMeasure = TRUE;
98 dummyls.mis.CtlType = lphl->DrawCtlType;
99 dummyls.mis.CtlID = lphl->CtlID;
100 dummyls.mis.itemID = -1;
101 dummyls.mis.itemWidth = 0; /* ignored */
102 dummyls.mis.itemData = 0;
104 ListBoxAskMeasure(lphl,&dummyls);
105 } else {
106 lphl->hDrawItemStruct = 0;
109 #if 0
110 HeapHandle = GlobalAlloc(GMEM_FIXED, LIST_HEAP_SIZE);
111 HeapBase = GlobalLock(HeapHandle);
112 HEAP_Init(&lphl->Heap, HeapBase, LIST_HEAP_SIZE);
113 #endif
114 lphl->HeapSel = GlobalAlloc(GMEM_FIXED,LIST_HEAP_SIZE);
115 LocalInit( lphl->HeapSel, 0, LIST_HEAP_SIZE-1);
118 void DestroyListBoxStruct(LPHEADLIST lphl)
120 if (lphl->hDrawItemStruct)
121 USER_HEAP_FREE(lphl->hDrawItemStruct);
123 /* XXX need to free lphl->Heap */
124 GlobalFree(lphl->HeapSel);
125 free(lphl);
128 static LPHEADLIST ListBoxGetStorageHeader(HWND hwnd)
130 return (LPHEADLIST)GetWindowLong(hwnd,0);
133 /* Send notification "code" as part of a WM_COMMAND-message if hwnd
134 has the LBS_NOTIFY style */
135 void ListBoxSendNotification(LPHEADLIST lphl, WORD code)
137 DWORD dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
139 if (dwStyle & LBS_NOTIFY)
140 #ifdef WINELIB32
141 SendMessage(lphl->hParent, WM_COMMAND,
142 MAKEWPARAM(lphl->CtlID,code), (LPARAM)lphl->hSelf);
143 #else
144 SendMessage(lphl->hParent, WM_COMMAND,
145 lphl->CtlID, MAKELONG(lphl->hSelf, code));
146 #endif
150 /* get the maximum value of lphl->FirstVisible */
151 int ListMaxFirstVisible(LPHEADLIST lphl)
153 int m = lphl->ItemsCount-lphl->ItemsVisible;
154 return (m < 0) ? 0 : m;
158 void ListBoxUpdateWindow(HWND hwnd, LPHEADLIST lphl, BOOL repaint)
160 SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
161 if (lphl->ItemsPerColumn != 0) {
162 SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible /
163 lphl->ItemsPerColumn + 1, TRUE);
165 if (repaint && lphl->bRedrawFlag) {
166 InvalidateRect(hwnd, NULL, TRUE);
170 /* Returns: 0 if nothing needs to be changed */
171 /* 1 if FirstVisible changed */
173 int ListBoxScrollToFocus(LPHEADLIST lphl)
175 short end;
177 if (lphl->ItemsCount == 0) return 0;
178 if (lphl->ItemFocused == -1) return 0;
180 end = lphl->FirstVisible + lphl->ItemsVisible - 1;
182 if (lphl->ItemFocused < lphl->FirstVisible ) {
183 lphl->FirstVisible = lphl->ItemFocused;
184 return 1;
185 } else {
186 if (lphl->ItemFocused > end) {
187 WORD maxFirstVisible = ListMaxFirstVisible(lphl);
189 lphl->FirstVisible = lphl->ItemFocused;
191 if (lphl->FirstVisible > maxFirstVisible) {
192 lphl->FirstVisible = maxFirstVisible;
194 return 1;
197 return 0;
201 LPLISTSTRUCT ListBoxGetItem(LPHEADLIST lphl, UINT uIndex)
203 LPLISTSTRUCT lpls;
204 UINT Count = 0;
206 if (uIndex >= lphl->ItemsCount) return NULL;
208 lpls = lphl->lpFirst;
209 while (Count++ < uIndex) lpls = lpls->lpNext;
210 return lpls;
214 void ListBoxDrawItem (HWND hwnd, LPHEADLIST lphl, HDC hdc, LPLISTSTRUCT lpls,
215 RECT *rect, WORD itemAction, WORD itemState)
217 LONG dwStyle = GetWindowLong(hwnd,GWL_STYLE);
219 if (lphl->OwnerDrawn) {
220 DRAWITEMSTRUCT *dis = USER_HEAP_LIN_ADDR(lphl->hDrawItemStruct);
222 dis->CtlID = lpls->mis.CtlID;
223 dis->CtlType = lpls->mis.CtlType;
224 dis->itemID = lpls->mis.itemID;
225 dis->hDC = hdc;
226 dis->hwndItem = hwnd;
227 dis->itemData = lpls->mis.itemData;
228 dis->itemAction = itemAction;
229 dis->itemState = itemState;
230 dis->rcItem = *rect;
231 SendMessage(lphl->hParent, WM_DRAWITEM,
232 0, (LPARAM)USER_HEAP_SEG_ADDR(lphl->hDrawItemStruct));
233 } else {
234 if (itemAction == ODA_DRAWENTIRE || itemAction == ODA_SELECT) {
235 int OldBkMode;
236 DWORD dwOldTextColor = 0;
238 OldBkMode = SetBkMode(hdc, TRANSPARENT);
240 if (itemState != 0) {
241 dwOldTextColor = SetTextColor(hdc, 0x00FFFFFFL);
242 FillRect(hdc, rect, GetStockObject(BLACK_BRUSH));
245 if (dwStyle & LBS_USETABSTOPS) {
246 TabbedTextOut(hdc, rect->left + 5, rect->top + 2,
247 (char *)lpls->itemText, strlen((char *)lpls->itemText),
248 lphl->iNumStops, lphl->TabStops, 0);
249 } else {
250 TextOut(hdc, rect->left + 5, rect->top + 2,
251 (char *)lpls->itemText, strlen((char *)lpls->itemText));
254 if (itemState != 0) {
255 SetTextColor(hdc, dwOldTextColor);
258 SetBkMode(hdc, OldBkMode);
259 } else DrawFocusRect(hdc, rect);
262 return;
266 int ListBoxFindMouse(LPHEADLIST lphl, int X, int Y)
268 LPLISTSTRUCT lpls = lphl->lpFirst;
269 int i, j;
270 POINT point;
272 point.x = X; point.y = Y;
273 if (lphl->ItemsCount == 0) return LB_ERR;
275 for(i = 0; i < lphl->FirstVisible; i++) {
276 if (lpls == NULL) return LB_ERR;
277 lpls = lpls->lpNext;
279 for(j = 0; j < lphl->ItemsVisible; i++, j++) {
280 if (lpls == NULL) return LB_ERR;
281 if (PtInRect(&lpls->itemRect,point)) {
282 return i;
284 lpls = lpls->lpNext;
286 dprintf_listbox(stddeb,"ListBoxFindMouse: not found\n");
287 return LB_ERR;
291 void ListBoxAskMeasure(LPHEADLIST lphl, LPLISTSTRUCT lpls)
293 HANDLE hTemp = USER_HEAP_ALLOC( sizeof(MEASUREITEMSTRUCT) );
294 MEASUREITEMSTRUCT *lpmeasure = (MEASUREITEMSTRUCT *) USER_HEAP_LIN_ADDR(hTemp);
296 if (lpmeasure == NULL) {
297 fprintf(stdnimp,"ListBoxAskMeasure() out of memory !\n");
298 return;
301 *lpmeasure = lpls->mis;
302 lpmeasure->itemHeight = lphl->StdItemHeight;
303 SendMessage(lphl->hParent, WM_MEASUREITEM, 0, (LPARAM)USER_HEAP_SEG_ADDR(hTemp));
305 if (GetWindowLong(lphl->hSelf,GWL_STYLE) & LBS_OWNERDRAWFIXED) {
306 lphl->StdItemHeight = lpmeasure->itemHeight;
307 lphl->needMeasure = FALSE;
310 USER_HEAP_FREE(hTemp);
313 /* -------------------- strings and item data ---------------------- */
315 LPLISTSTRUCT ListBoxCreateItem(LPHEADLIST lphl, int id)
317 LPLISTSTRUCT lplsnew = (LPLISTSTRUCT)malloc(sizeof(LISTSTRUCT));
319 if (lplsnew == NULL) return NULL;
321 lplsnew->itemState = 0;
322 lplsnew->mis.CtlType = lphl->DrawCtlType;
323 lplsnew->mis.CtlID = lphl->CtlID;
324 lplsnew->mis.itemID = id;
325 lplsnew->mis.itemHeight = lphl->StdItemHeight;
326 lplsnew->mis.itemWidth = 0; /* ignored */
327 lplsnew->mis.itemData = 0;
328 SetRect(&lplsnew->itemRect, 0, 0, 0, 0);
330 return lplsnew;
334 int ListBoxInsertString(LPHEADLIST lphl, UINT uIndex, LPSTR newstr)
336 LPLISTSTRUCT *lppls, lplsnew, lpls;
337 HANDLE hStr;
338 LPSTR str;
339 UINT Count;
341 dprintf_listbox(stddeb,"ListBoxInsertString(%d, %p);\n", uIndex, newstr);
343 if (!newstr) return -1;
345 if (uIndex == (UINT)-1)
346 uIndex = lphl->ItemsCount;
348 lppls = &lphl->lpFirst;
349 for(Count = 0; Count < uIndex; Count++) {
350 if (*lppls == NULL) return LB_ERR;
351 lppls = (LPLISTSTRUCT *) &(*lppls)->lpNext;
354 lplsnew = ListBoxCreateItem(lphl, Count);
356 if (lplsnew == NULL) {
357 fprintf(stdnimp,"ListBoxInsertString() out of memory !\n");
358 return LB_ERRSPACE;
361 lplsnew->lpNext = *lppls;
362 *lppls = lplsnew;
363 lphl->ItemsCount++;
365 hStr = 0;
366 if (lphl->HasStrings) {
367 dprintf_listbox(stddeb," string: %s\n", newstr);
368 hStr = LIST_HEAP_ALLOC(lphl, LMEM_MOVEABLE, strlen(newstr) + 1);
369 str = (LPSTR)LIST_HEAP_ADDR(lphl, hStr);
370 if (str == NULL) return LB_ERRSPACE;
371 strcpy(str, newstr);
372 lplsnew->itemText = str;
373 /* I'm not so sure about the next one */
374 lplsnew->mis.itemData = 0;
375 } else {
376 lplsnew->itemText = NULL;
377 lplsnew->mis.itemData = (DWORD)newstr;
380 lplsnew->mis.itemID = uIndex;
381 lplsnew->hData = hStr;
383 /* adjust the itemID field of the following entries */
384 for(lpls = lplsnew->lpNext; lpls != NULL; lpls = lpls->lpNext) {
385 lpls->mis.itemID++;
388 if (lphl->needMeasure) {
389 ListBoxAskMeasure(lphl, lplsnew);
392 dprintf_listbox(stddeb,"ListBoxInsertString // count=%d\n", lphl->ItemsCount);
393 return uIndex;
397 int ListBoxAddString(LPHEADLIST lphl, LPSTR newstr)
399 LONG dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
400 UINT pos = (UINT) -1;
402 if (lphl->HasStrings && (dwStyle & LBS_SORT)) {
403 LPLISTSTRUCT lpls = lphl->lpFirst;
404 for (pos = 0; lpls != NULL; lpls = lpls->lpNext, pos++)
405 if (strcmp(lpls->itemText, newstr) >= 0)
406 break;
408 return ListBoxInsertString(lphl, pos, newstr);
412 int ListBoxGetText(LPHEADLIST lphl, UINT uIndex, LPSTR OutStr)
414 LPLISTSTRUCT lpls;
416 if (!OutStr) {
417 dprintf_listbox(stddeb, "ListBoxGetText // OutStr==NULL\n");
418 return 0;
421 lpls = ListBoxGetItem (lphl, uIndex);
422 if (lpls == NULL) return LB_ERR;
424 if (!lphl->HasStrings) {
425 *((long *)OutStr) = lpls->mis.itemData;
426 return 4;
429 strcpy(OutStr, lpls->itemText);
430 return strlen(OutStr);
434 DWORD ListBoxGetItemData(LPHEADLIST lphl, UINT uIndex)
436 LPLISTSTRUCT lpls;
438 lpls = ListBoxGetItem (lphl, uIndex);
439 if (lpls == NULL) return LB_ERR;
440 return lpls->mis.itemData;
444 int ListBoxSetItemData(LPHEADLIST lphl, UINT uIndex, DWORD ItemData)
446 LPLISTSTRUCT lpls = ListBoxGetItem(lphl, uIndex);
448 if (lpls == NULL) return LB_ERR;
449 lpls->mis.itemData = ItemData;
450 return 1;
454 int ListBoxDeleteString(LPHEADLIST lphl, UINT uIndex)
456 LPLISTSTRUCT lpls, lpls2;
457 UINT Count;
459 if (uIndex >= lphl->ItemsCount) return LB_ERR;
461 lpls = lphl->lpFirst;
462 if (lpls == NULL) return LB_ERR;
464 if (uIndex == 0)
465 lphl->lpFirst = lpls->lpNext;
466 else {
467 LPLISTSTRUCT lpls2 = NULL;
468 for(Count = 0; Count < uIndex; Count++) {
469 if (lpls->lpNext == NULL) return LB_ERR;
471 lpls2 = lpls;
472 lpls = (LPLISTSTRUCT)lpls->lpNext;
474 lpls2->lpNext = lpls->lpNext;
477 /* adjust the itemID field of the following entries */
478 for(lpls2 = lpls->lpNext; lpls2 != NULL; lpls2 = lpls2->lpNext) {
479 lpls2->mis.itemID--;
482 lphl->ItemsCount--;
484 if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
485 free(lpls);
487 return lphl->ItemsCount;
491 int ListBoxFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr)
493 LPLISTSTRUCT lpls;
494 UINT Count;
495 UINT First = nFirst + 1;
496 LPSTR lpMatchStr = (LPSTR)MatchStr;
497 LONG dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
499 if (First > lphl->ItemsCount) return LB_ERR;
501 if (lphl->HasStrings) lpMatchStr = PTR_SEG_TO_LIN(MatchStr);
503 lpls = ListBoxGetItem(lphl, First);
504 Count = 0;
505 while(lpls != NULL) {
506 if (lphl->HasStrings) {
507 if (strstr(lpls->itemText, lpMatchStr) == lpls->itemText) return Count;
508 } else if (dwStyle & LBS_SORT) {
509 /* XXX Do a compare item */
511 else
512 if (lpls->mis.itemData == (DWORD)lpMatchStr) return Count;
514 lpls = lpls->lpNext;
515 Count++;
518 /* Start over at top */
519 Count = 0;
520 lpls = lphl->lpFirst;
522 while (Count < First) {
523 if (lphl->HasStrings) {
524 if (strstr(lpls->itemText, lpMatchStr) == lpls->itemText) return Count;
525 } else if (dwStyle & LBS_SORT) {
526 /* XXX Do a compare item */
527 } else {
528 if (lpls->mis.itemData == (DWORD)lpMatchStr) return Count;
530 lpls = lpls->lpNext;
531 Count++;
534 return LB_ERR;
538 int ListBoxResetContent(LPHEADLIST lphl)
540 LPLISTSTRUCT lpls;
541 int i;
543 if (lphl->ItemsCount == 0) return 0;
545 dprintf_listbox(stddeb, "ListBoxResetContent // ItemCount = %d\n",
546 lphl->ItemsCount);
548 for(i = 0; i < lphl->ItemsCount; i++) {
549 lpls = lphl->lpFirst;
550 if (lpls == NULL) return LB_ERR;
552 lphl->lpFirst = lpls->lpNext;
553 if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
554 free(lpls);
556 ListBoxInitialize(lphl);
558 return TRUE;
561 /* --------------------- selection ------------------------- */
563 int ListBoxSetCurSel(LPHEADLIST lphl, WORD wIndex)
565 LPLISTSTRUCT lpls;
566 DWORD dwStyle = GetWindowWord(lphl->hSelf,GWL_STYLE);
568 /* use ListBoxSetSel instead */
569 if (dwStyle & LBS_MULTIPLESEL ) return 0;
571 /* unselect all previously selected */
572 if (dwStyle & LBS_EXTENDEDSEL )
573 ListBoxSetSel(lphl,-1,0);
574 else
575 /* unselect previous item */
576 if (lphl->ItemFocused != -1) {
577 lpls = ListBoxGetItem(lphl, lphl->ItemFocused);
578 if (lpls == 0) return LB_ERR;
579 lpls->itemState = 0;
582 if (wIndex != (UINT)-1) {
583 lphl->ItemFocused = wIndex;
584 lpls = ListBoxGetItem(lphl, wIndex);
585 if (lpls == 0) return LB_ERR;
586 lpls->itemState = ODS_SELECTED | ODS_FOCUS;
588 return 0;
591 return LB_ERR;
595 int ListBoxSetSel(LPHEADLIST lphl, WORD wIndex, WORD state)
597 LPLISTSTRUCT lpls;
599 if (!(GetWindowLong(lphl->hSelf,GWL_STYLE) &
600 (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
601 return 0;
603 if (wIndex == (UINT)-1) {
604 for (lpls = lphl->lpFirst; lpls != NULL; lpls = lpls->lpNext) {
605 lpls->itemState = state;
607 return 0;
610 if (wIndex >= lphl->ItemsCount) return LB_ERR;
612 lpls = ListBoxGetItem(lphl, wIndex);
613 lpls->itemState = state;
615 return 0;
619 int ListBoxGetSel(LPHEADLIST lphl, WORD wIndex)
621 LPLISTSTRUCT lpls = ListBoxGetItem(lphl, wIndex);
623 if (lpls == NULL) return LB_ERR;
624 return lpls->itemState;
627 /* ------------------------- dir listing ------------------------ */
629 int ListBoxDirectory(LPHEADLIST lphl, UINT attrib, LPSTR filespec)
631 struct dosdirent *dp, *dp_old;
632 char temp[256];
633 int drive;
634 LPSTR tstr;
636 dprintf_listbox(stddeb,"ListBoxDirectory: %s, %4x\n",filespec,attrib);
638 if (strchr(filespec, '\\') || strchr(filespec, ':')) {
639 drive = DOS_GetDefaultDrive();
640 if (filespec[1] == ':') {
641 drive = toupper(filespec[0]) - 'A';
642 filespec += 2;
644 strcpy(temp,filespec);
645 tstr = strrchr(temp, '\\');
646 if (tstr != NULL) {
647 *(tstr+1) = 0;
648 filespec += tstr - temp + 1;
649 if (!DOS_ChangeDir( drive, temp )) return 0;
651 DOS_SetDefaultDrive( drive );
652 dprintf_listbox(stddeb,"Changing directory to %c:%s, filemask is %s\n",
653 drive+'A', temp, filespec);
656 if ((dp = (struct dosdirent *)DOS_opendir(filespec)) ==NULL) return 0;
657 dp_old = dp;
658 while ((dp = (struct dosdirent *)DOS_readdir(dp))) {
659 if (!dp->inuse) break;
660 dprintf_listbox(stddeb, "ListBoxDirectory %p '%s' !\n", dp->filename,
661 dp->filename);
662 if (dp->attribute & FA_DIREC) {
663 if (attrib & DDL_DIRECTORY && strcmp(dp->filename, ".") != 0) {
664 sprintf(temp, "[%s]", dp->filename);
665 if (ListBoxAddString(lphl, temp) == LB_ERR) break;
668 else {
669 if (attrib & DDL_EXCLUSIVE) {
670 if (attrib & (DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM)) {
671 if (ListBoxAddString(lphl, dp->filename) == LB_ERR) break;
673 } else {
674 if (ListBoxAddString(lphl, dp->filename) == LB_ERR) break;
678 DOS_closedir(dp_old);
680 if (attrib & DDL_DRIVES) {
681 int x;
682 for (x = 0; x != MAX_DOS_DRIVES ; x++) {
683 if (DOS_ValidDrive(x)) {
684 sprintf(temp, "[-%c-]", 'a'+x);
685 if (ListBoxInsertString(lphl, (UINT)-1, temp) == LB_ERR) break;
689 return 1;
692 /* ------------------------- dimensions ------------------------- */
694 int ListBoxGetItemRect(LPHEADLIST lphl, WORD wIndex, LPRECT lprect)
696 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wIndex);
698 if (lpls == NULL) return LB_ERR;
699 *lprect = lpls->itemRect;
700 return 0;
704 int ListBoxSetItemHeight(LPHEADLIST lphl, WORD wIndex, long height)
706 LPLISTSTRUCT lpls;
708 if (!(GetWindowLong(lphl->hSelf,GWL_STYLE) & LBS_OWNERDRAWVARIABLE)) {
709 lphl->StdItemHeight = (short)height;
710 return 0;
713 lpls = ListBoxGetItem(lphl, wIndex);
714 if (lpls == NULL) return LB_ERR;
716 lpls->mis.itemHeight = height;
717 return 0;
720 /* -------------------------- string search ------------------------ */
722 int ListBoxFindNextMatch(LPHEADLIST lphl, WORD wChar)
724 LPLISTSTRUCT lpls;
725 UINT count,first;
727 if ((char)wChar < ' ') return LB_ERR;
728 if (!lphl->HasStrings) return LB_ERR;
730 lpls = lphl->lpFirst;
732 for (count = 0; lpls != NULL; lpls = lpls->lpNext, count++) {
733 if (tolower(*lpls->itemText) == tolower((char)wChar)) break;
735 if (lpls == NULL) return LB_ERR;
736 first = count;
737 for(; lpls != NULL; lpls = lpls->lpNext, count++) {
738 if (*lpls->itemText != (char)wChar)
739 break;
740 if (count > lphl->ItemFocused)
741 return count;
743 return first;
746 /***********************************************************************
747 * LBCreate
749 static LONG LBCreate(HWND hwnd, WORD wParam, LONG lParam)
751 LPHEADLIST lphl;
752 LONG dwStyle = GetWindowLong(hwnd,GWL_STYLE);
753 RECT rect;
755 CreateListBoxStruct(hwnd, ODT_LISTBOX, dwStyle, GetParent(hwnd));
756 lphl = ListBoxGetStorageHeader(hwnd);
757 dprintf_listbox(stddeb,"ListBox created: lphl = %p dwStyle = "NPFMT":"NPFMT"\n",
758 lphl, HIWORD(dwStyle), LOWORD(dwStyle));
760 GetClientRect(hwnd,&rect);
761 lphl->ColumnsWidth = rect.right - rect.left;
763 SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
764 SetScrollRange(hwnd, SB_HORZ, 1, 1, TRUE);
766 return 0;
769 /***********************************************************************
770 * LBDestroy
772 static LONG LBDestroy(HWND hwnd, WORD wParam, LONG lParam)
774 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
776 ListBoxResetContent(lphl);
778 DestroyListBoxStruct(lphl);
779 dprintf_listbox(stddeb,"ListBox destroyed: lphl = %p\n",lphl);
780 return 0;
783 /***********************************************************************
784 * LBVScroll
786 static LONG LBVScroll(HWND hwnd, WORD wParam, LONG lParam)
788 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
789 int y;
791 dprintf_listbox(stddeb,"ListBox WM_VSCROLL w=%04X l=%08lX !\n",
792 wParam, lParam);
793 y = lphl->FirstVisible;
795 switch(wParam) {
796 case SB_LINEUP:
797 if (lphl->FirstVisible > 0)
798 lphl->FirstVisible--;
799 break;
801 case SB_LINEDOWN:
802 lphl->FirstVisible++;
803 break;
805 case SB_PAGEUP:
806 if (lphl->FirstVisible > lphl->ItemsVisible) {
807 lphl->FirstVisible -= lphl->ItemsVisible;
808 } else {
809 lphl->FirstVisible = 0;
811 break;
813 case SB_PAGEDOWN:
814 lphl->FirstVisible += lphl->ItemsVisible;
815 break;
817 case SB_THUMBTRACK:
818 lphl->FirstVisible = LOWORD(lParam);
819 break;
822 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
823 lphl->FirstVisible = ListMaxFirstVisible(lphl);
825 if (y != lphl->FirstVisible) {
826 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
827 InvalidateRect(hwnd, NULL, TRUE);
829 return 0;
832 /***********************************************************************
833 * LBHScroll
835 static LONG LBHScroll(HWND hwnd, WORD wParam, LONG lParam)
837 LPHEADLIST lphl;
838 int y;
840 dprintf_listbox(stddeb,"ListBox WM_HSCROLL w=%04X l=%08lX !\n",
841 wParam, lParam);
842 lphl = ListBoxGetStorageHeader(hwnd);
843 y = lphl->FirstVisible;
844 switch(wParam) {
845 case SB_LINEUP:
846 if (lphl->FirstVisible > lphl->ItemsPerColumn) {
847 lphl->FirstVisible -= lphl->ItemsPerColumn;
848 } else {
849 lphl->FirstVisible = 0;
851 break;
852 case SB_LINEDOWN:
853 lphl->FirstVisible += lphl->ItemsPerColumn;
854 break;
855 case SB_PAGEUP:
856 if (lphl->ItemsPerColumn != 0) {
857 int lbsub = lphl->ItemsVisible / lphl->ItemsPerColumn * lphl->ItemsPerColumn;
858 if (lphl->FirstVisible > lbsub) {
859 lphl->FirstVisible -= lbsub;
860 } else {
861 lphl->FirstVisible = 0;
864 break;
865 case SB_PAGEDOWN:
866 if (lphl->ItemsPerColumn != 0)
867 lphl->FirstVisible += lphl->ItemsVisible /
868 lphl->ItemsPerColumn * lphl->ItemsPerColumn;
869 break;
870 case SB_THUMBTRACK:
871 lphl->FirstVisible = lphl->ItemsPerColumn * LOWORD(lParam);
872 break;
874 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
875 lphl->FirstVisible = ListMaxFirstVisible(lphl);
877 if (lphl->ItemsPerColumn != 0) {
878 lphl->FirstVisible = lphl->FirstVisible /
879 lphl->ItemsPerColumn * lphl->ItemsPerColumn + 1;
880 if (y != lphl->FirstVisible) {
881 SetScrollPos(hwnd, SB_HORZ, lphl->FirstVisible /
882 lphl->ItemsPerColumn + 1, TRUE);
883 InvalidateRect(hwnd, NULL, TRUE);
886 return 0;
889 /***********************************************************************
890 * LBLButtonDown
892 static LONG LBLButtonDown(HWND hwnd, WORD wParam, LONG lParam)
894 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
895 WORD wRet;
896 int y;
897 RECT rectsel;
898 LONG dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
900 SetFocus(hwnd);
901 SetCapture(hwnd);
903 lphl->PrevFocused = lphl->ItemFocused;
905 y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
906 if (y == -1)
907 return 0;
909 if (dwStyle & LBS_MULTIPLESEL) {
910 lphl->ItemFocused = y;
911 wRet = ListBoxGetSel(lphl, y);
912 ListBoxSetSel(lphl, y, !wRet);
914 InvalidateRect(hwnd, NULL, TRUE);
915 } else {
916 ListBoxSetCurSel(lphl, y);
918 ListBoxGetItemRect(lphl, y, &rectsel);
919 InvalidateRect(hwnd, &rectsel, TRUE);
920 if(lphl->PrevFocused) {
921 ListBoxGetItemRect(lphl, lphl->PrevFocused, &rectsel);
922 InvalidateRect(hwnd, &rectsel, TRUE);
926 if (dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL))
927 ListBoxSendNotification(lphl, LBN_SELCHANGE);
929 if (dwStyle & LBS_NOTIFY)
930 SendMessage(lphl->hParent, WM_LBTRACKPOINT, y, lParam);
932 if (GetWindowLong(lphl->hSelf,GWL_EXSTYLE) & WS_EX_DRAGDETECT)
933 if( DragDetect(lphl->hSelf,MAKEPOINT(lParam)) )
934 SendMessage(lphl->hParent, WM_BEGINDRAG,0,0L);
936 return 0;
939 /***********************************************************************
940 * LBLButtonUp
942 static LONG LBLButtonUp(HWND hwnd, WORD wParam, LONG lParam)
944 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
946 if (GetCapture() == hwnd) ReleaseCapture();
948 if (lphl->PrevFocused != lphl->ItemFocused)
949 ListBoxSendNotification(lphl, LBN_SELCHANGE);
951 return 0;
954 /***********************************************************************
955 * LBRButtonUp
957 static LONG LBRButtonUp(HWND hwnd, WORD wParam, LONG lParam)
959 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
961 #ifdef WINELIB32
962 SendMessage(lphl->hParent, WM_COMMAND,
963 MAKEWPARAM(GetWindowWord(hwnd,GWW_ID),LBN_DBLCLK),
964 (LPARAM)hwnd);
965 #else
966 SendMessage(lphl->hParent, WM_COMMAND, GetWindowWord(hwnd,GWW_ID),
967 MAKELONG(hwnd, LBN_DBLCLK));
968 #endif
970 return 0;
973 /***********************************************************************
974 * LBMouseMove
976 static LONG LBMouseMove(HWND hwnd, WORD wParam, LONG lParam)
978 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
979 int y;
980 WORD wRet;
981 LONG dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
982 RECT rect, rectsel; /* XXX Broken */
984 dprintf_listbox(stddeb,"LBMouseMove %d %d\n",SLOWORD(lParam),SHIWORD(lParam));
985 if ((wParam & MK_LBUTTON) != 0) {
986 y = SHIWORD(lParam);
987 if (y < 0) {
988 if (lphl->FirstVisible > 0) {
989 lphl->FirstVisible--;
990 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
991 InvalidateRect(hwnd, NULL, TRUE);
992 return 0;
995 GetClientRect(hwnd, &rect);
996 if (y >= rect.bottom) {
997 if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
998 lphl->FirstVisible++;
999 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1000 InvalidateRect(hwnd, NULL, TRUE);
1001 return 0;
1004 if ((y > 0) && (y < (rect.bottom - 4))) {
1005 if ((y < rectsel.top) || (y > rectsel.bottom)) {
1006 wRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
1007 if (wRet == lphl->ItemFocused) {
1008 return 0;
1010 if (dwStyle & LBS_MULTIPLESEL) {
1011 lphl->ItemFocused = wRet;
1012 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1013 } else {
1014 ListBoxSetCurSel(lphl, wRet);
1015 if(dwStyle & LBS_EXTENDEDSEL)
1016 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1018 ListBoxGetItemRect(lphl, wRet, &rectsel);
1019 InvalidateRect(hwnd, &rectsel, TRUE);
1024 return 0;
1027 /***********************************************************************
1028 * LBKeyDown
1030 * Doesn't yet handle properly VK_SHIFT with LB_EXTENDEDSEL
1032 static LONG LBKeyDown(HWND hwnd, WORD wParam, LONG lParam)
1034 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1035 LONG dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
1036 WORD newFocused = 0xFFFF;
1037 RECT rect;
1039 ListBoxGetItemRect(lphl,lphl->ItemFocused,&rect);
1040 switch(wParam)
1042 /* ugly kludge that belongs in TranslateMessage */
1044 case VK_HOME:
1045 case VK_END:
1046 case VK_LEFT:
1047 case VK_RIGHT:
1048 case VK_UP:
1049 case VK_DOWN:
1050 case VK_PRIOR:
1051 case VK_NEXT:
1052 if ( dwStyle & LBS_WANTKEYBOARDINPUT )
1054 newFocused = (WORD)(INT)SendMessage(lphl->hParent,WM_VKEYTOITEM,
1055 wParam,MAKELPARAM(lphl->ItemFocused,hwnd));
1056 if ( newFocused == 0xFFFE ) return 0L;
1058 if ( newFocused == 0xFFFF )
1060 newFocused = lphl->ItemFocused;
1062 /* nested switch */
1063 switch(wParam)
1065 case VK_HOME:
1066 newFocused = 0;
1067 break;
1068 case VK_END:
1069 newFocused = lphl->ItemsCount - 1;
1070 break;
1071 case VK_LEFT:
1072 if (dwStyle & LBS_MULTICOLUMN) {
1073 if (newFocused >= lphl->ItemsPerColumn) {
1074 newFocused -= lphl->ItemsPerColumn;
1075 } else {
1076 newFocused = 0;
1079 break;
1080 case VK_UP:
1081 if (newFocused > 0) newFocused--;
1082 break;
1083 case VK_RIGHT:
1084 if (dwStyle & LBS_MULTICOLUMN)
1085 newFocused += lphl->ItemsPerColumn;
1086 break;
1087 case VK_DOWN:
1088 newFocused++;
1089 break;
1090 case VK_PRIOR:
1091 if (newFocused > lphl->ItemsVisible)
1092 newFocused -= lphl->ItemsVisible;
1093 else newFocused = 0;
1094 break;
1095 case VK_NEXT:
1096 newFocused += lphl->ItemsVisible;
1097 break;
1098 default:
1099 return 0;
1101 /* end of nested switch */
1103 break;
1104 case VK_SPACE:
1105 if (dwStyle & LBS_MULTIPLESEL)
1107 WORD wRet = ListBoxGetSel(lphl, lphl->ItemFocused);
1108 ListBoxSetSel(lphl, lphl->ItemFocused, !wRet);
1110 return 0;
1112 /* chars are handled in LBChar */
1113 default:
1114 return 0;
1117 /* at this point newFocused is set up */
1119 if (newFocused >= lphl->ItemsCount)
1120 newFocused = lphl->ItemsCount - 1;
1122 if (!(dwStyle & LBS_MULTIPLESEL))
1124 ListBoxSetCurSel(lphl, newFocused);
1125 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1128 lphl->ItemFocused = newFocused;
1130 if( ListBoxScrollToFocus(lphl) || (dwStyle &
1131 (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) )
1132 InvalidateRect(hwnd, NULL, TRUE);
1133 else
1135 InvalidateRect(hwnd, &rect, TRUE);
1136 if( newFocused < 0x8000 )
1138 ListBoxGetItemRect(lphl, newFocused, &rect);
1139 InvalidateRect(hwnd, &rect, TRUE);
1143 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1145 return 0;
1148 /***********************************************************************
1149 * LBChar
1151 static LONG LBChar(HWND hwnd, WORD wParam, LONG lParam)
1153 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1154 LONG dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
1155 WORD newFocused = 0xFFFF;
1157 if ( (dwStyle & LBS_WANTKEYBOARDINPUT) && !(lphl->HasStrings))
1159 newFocused = (WORD)(INT)SendMessage(lphl->hParent,WM_CHARTOITEM,
1160 wParam,MAKELPARAM(lphl->ItemFocused,hwnd));
1161 if ( newFocused == 0xFFFE ) return 0L;
1164 if (newFocused == 0xFFFF )
1165 newFocused = ListBoxFindNextMatch(lphl, wParam);
1167 if (newFocused == (WORD)LB_ERR) return 0;
1169 if (newFocused >= lphl->ItemsCount)
1170 newFocused = lphl->ItemsCount - 1;
1172 if (!(dwStyle & LBS_MULTIPLESEL))
1174 ListBoxSetCurSel(lphl, newFocused);
1175 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1178 lphl->ItemFocused = newFocused;
1179 ListBoxScrollToFocus(lphl);
1180 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1182 InvalidateRect(hwnd, NULL, TRUE);
1184 return 0;
1187 /***********************************************************************
1188 * LBSetRedraw
1190 static LONG LBSetRedraw(HWND hwnd, WORD wParam, LONG lParam)
1192 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1194 dprintf_listbox(stddeb,"ListBox WM_SETREDRAW hWnd="NPFMT" w=%04X !\n",
1195 hwnd, wParam);
1196 lphl->bRedrawFlag = wParam;
1198 return 0;
1201 /***********************************************************************
1202 * LBSetFont
1204 static LONG LBSetFont(HWND hwnd, WPARAM wParam, LPARAM lParam)
1206 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1208 if (wParam == 0)
1209 lphl->hFont = GetStockObject(SYSTEM_FONT);
1210 else
1211 lphl->hFont = (HFONT) wParam;
1213 return 0;
1216 /***********************************************************************
1217 * LBPaint
1219 static LONG LBPaint(HWND hwnd, WORD wParam, LONG lParam)
1221 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1222 LONG dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
1223 LPLISTSTRUCT lpls;
1224 PAINTSTRUCT ps;
1225 HBRUSH hBrush;
1226 HFONT hOldFont;
1227 HDC hdc;
1228 RECT rect;
1229 int i, top, height, maxwidth, ipc;
1231 top = 0;
1232 hdc = BeginPaint( hwnd, &ps );
1234 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) {
1235 EndPaint(hwnd, &ps);
1236 return 0;
1239 hOldFont = SelectObject(hdc, lphl->hFont);
1241 #ifdef WINELIB32
1242 hBrush = (HBRUSH) SendMessage(lphl->hParent, WM_CTLCOLORLISTBOX, (WPARAM)hdc,
1243 (LPARAM)hwnd);
1244 #else
1245 hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
1246 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
1247 #endif
1249 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
1251 GetClientRect(hwnd, &rect);
1252 FillRect(hdc, &rect, hBrush);
1254 maxwidth = rect.right;
1255 if (dwStyle & LBS_MULTICOLUMN) {
1256 rect.right = lphl->ColumnsWidth;
1258 lpls = lphl->lpFirst;
1260 lphl->ItemsVisible = 0;
1261 lphl->ItemsPerColumn = ipc = 0;
1263 for(i = 0; i < lphl->ItemsCount; i++) {
1264 if (lpls == NULL) break;
1266 if (i >= lphl->FirstVisible) {
1267 height = lpls->mis.itemHeight;
1269 if (top > rect.bottom) {
1270 if (dwStyle & LBS_MULTICOLUMN) {
1271 lphl->ItemsPerColumn = MAX(lphl->ItemsPerColumn, ipc);
1272 ipc = 0;
1273 top = 0;
1274 rect.left += lphl->ColumnsWidth;
1275 rect.right += lphl->ColumnsWidth;
1276 if (rect.left > maxwidth) break;
1277 } else {
1278 break;
1282 lpls->itemRect.top = top;
1283 lpls->itemRect.bottom = top + height;
1284 lpls->itemRect.left = rect.left;
1285 lpls->itemRect.right = rect.right;
1287 dprintf_listbox(stddeb,"drawing item: %ld %d %ld %d %d\n",(LONG)rect.left,top,(LONG)rect.right,top+height,lpls->itemState);
1288 if (lphl->OwnerDrawn) {
1289 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, 0);
1290 if (lpls->itemState)
1291 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_SELECT, ODS_SELECTED);
1292 } else {
1293 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
1294 lpls->itemState);
1296 if ((lphl->ItemFocused == i) && GetFocus() == hwnd)
1297 ListBoxDrawItem (hwnd,lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, ODS_FOCUS);
1299 top += height;
1300 lphl->ItemsVisible++;
1301 ipc++;
1304 lpls = lpls->lpNext;
1306 ListBoxUpdateWindow(hwnd,lphl,FALSE);
1307 SelectObject(hdc,hOldFont);
1308 EndPaint( hwnd, &ps );
1309 return 0;
1312 /***********************************************************************
1313 * LBSetFocus
1315 static LONG LBSetFocus(HWND hwnd, WORD wParam, LONG lParam)
1317 dprintf_listbox(stddeb,"ListBox WM_SETFOCUS !\n");
1319 return 0;
1322 /***********************************************************************
1323 * LBKillFocus
1325 static LONG LBKillFocus(HWND hwnd, WORD wParam, LONG lParam)
1327 dprintf_listbox(stddeb,"ListBox WM_KILLFOCUS !\n");
1329 InvalidateRect(hwnd, NULL, TRUE);
1331 return 0;
1334 /***********************************************************************
1335 * LBResetContent
1337 static LONG LBResetContent(HWND hwnd, WORD wParam, LONG lParam)
1339 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1341 dprintf_listbox(stddeb,"ListBox LB_RESETCONTENT !\n");
1342 ListBoxResetContent(lphl);
1343 ListBoxUpdateWindow(hwnd, lphl, TRUE);
1344 return 0;
1347 /***********************************************************************
1348 * LBDir
1350 static LONG LBDir(HWND hwnd, WORD wParam, LONG lParam)
1352 WORD wRet;
1353 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1354 dprintf_listbox(stddeb,"ListBox LB_DIR !\n");
1356 wRet = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
1357 ListBoxUpdateWindow(hwnd, lphl, TRUE);
1358 return wRet;
1361 /***********************************************************************
1362 * LBAddString
1364 static LONG LBAddString(HWND hwnd, WORD wParam, LONG lParam)
1366 WORD wRet;
1367 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1369 if (lphl->HasStrings)
1370 wRet = ListBoxAddString(lphl, (LPSTR)PTR_SEG_TO_LIN(lParam));
1371 else
1372 wRet = ListBoxAddString(lphl, (LPSTR)lParam);
1374 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1375 return wRet;
1378 /***********************************************************************
1379 * LBGetText
1381 static LONG LBGetText(HWND hwnd, WORD wParam, LONG lParam)
1383 LONG wRet;
1384 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1386 dprintf_listbox(stddeb, "LB_GETTEXT wParam=%d\n",wParam);
1387 wRet = ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
1389 return wRet;
1392 /***********************************************************************
1393 * LBInsertString
1395 static LONG LBInsertString(HWND hwnd, WORD wParam, LONG lParam)
1397 WORD wRet;
1398 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1400 if (lphl->HasStrings)
1401 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
1402 else
1403 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)lParam);
1405 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1406 return wRet;
1409 /***********************************************************************
1410 * LBDeleteString
1412 static LONG LBDeleteString(HWND hwnd, WORD wParam, LONG lParam)
1414 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1415 LONG lRet = ListBoxDeleteString(lphl,wParam);
1417 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1418 return lRet;
1421 /***********************************************************************
1422 * LBFindString
1424 static LONG LBFindString(HWND hwnd, WORD wParam, LONG lParam)
1426 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1427 return ListBoxFindString(lphl, wParam, lParam);
1430 /***********************************************************************
1431 * LBGetCaretIndex
1433 static LONG LBGetCaretIndex(HWND hwnd, WORD wParam, LONG lParam)
1435 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1436 return lphl->ItemFocused;
1439 /***********************************************************************
1440 * LBGetCount
1442 static LONG LBGetCount(HWND hwnd, WORD wParam, LONG lParam)
1444 LPHEADLIST lphl;
1446 lphl = ListBoxGetStorageHeader(hwnd);
1447 return lphl->ItemsCount;
1450 /***********************************************************************
1451 * LBGetCurSel
1453 static LONG LBGetCurSel(HWND hwnd, WORD wParam, LONG lParam)
1455 LPHEADLIST lphl;
1457 lphl = ListBoxGetStorageHeader(hwnd);
1458 dprintf_listbox(stddeb,"ListBox LB_GETCURSEL %u !\n",
1459 lphl->ItemFocused);
1460 return lphl->ItemFocused;
1463 /***********************************************************************
1464 * LBGetHorizontalExtent
1466 static LONG LBGetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam)
1468 return 0;
1471 /***********************************************************************
1472 * LBGetItemHeight
1474 static LONG LBGetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
1476 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1477 LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
1479 if (lpls == NULL) return LB_ERR;
1480 return lpls->mis.itemHeight;
1483 /***********************************************************************
1484 * LBGetItemRect
1486 static LONG LBGetItemRect(HWND hwnd, WORD wParam, LONG lParam)
1488 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1489 return ListBoxGetItemRect(lphl, wParam, PTR_SEG_TO_LIN(lParam));
1492 /***********************************************************************
1493 * LBGetSel
1495 static LONG LBGetSel(HWND hwnd, WORD wParam, LONG lParam)
1497 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1498 return (ListBoxGetSel(lphl, wParam) )? 1 : 0;
1501 /***********************************************************************
1502 * LBGetSelCount
1504 static LONG LBGetSelCount(HWND hwnd, WORD wParam, LONG lParam)
1506 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1507 LPLISTSTRUCT lpls;
1508 int cnt = 0;
1509 int items = 0;
1511 if (!(GetWindowLong(lphl->hSelf,GWL_STYLE) &
1512 (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
1513 return LB_ERR;
1515 for( lpls = lphl->lpFirst;
1516 lpls;
1517 lpls = lpls->lpNext )
1519 items++;
1520 if (lpls->itemState )
1521 cnt++;
1524 return cnt;
1527 /***********************************************************************
1528 * LBGetSelItems
1530 static LONG LBGetSelItems(HWND hwnd, WORD wParam, LONG lParam)
1532 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1533 LPLISTSTRUCT lpls;
1534 int cnt, idx;
1535 int *lpItems = PTR_SEG_TO_LIN(lParam);
1537 if (!(GetWindowLong(lphl->hSelf,GWL_STYLE) &
1538 (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
1539 return LB_ERR;
1541 if (wParam == 0) return 0;
1543 lpls = lphl->lpFirst;
1544 cnt = 0; idx = 0;
1546 while (lpls != NULL) {
1547 if (lpls->itemState > 0) lpItems[cnt++] = idx;
1549 if (cnt == wParam) break;
1550 idx++;
1551 lpls = lpls->lpNext;
1554 return cnt;
1557 /***********************************************************************
1558 * LBGetTextLen
1560 static LONG LBGetTextLen(HWND hwnd, WORD wParam, LONG lParam)
1562 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1563 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
1565 if (lpls == NULL || !lphl->HasStrings) return LB_ERR;
1566 return strlen(lpls->itemText);
1569 /***********************************************************************
1570 * LBGetDlgCode
1572 static LONG LBGetDlgCode(HWND hwnd, WORD wParam, LONG lParam)
1574 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1577 /***********************************************************************
1578 * LBGetTopIndex
1580 static LONG LBGetTopIndex(HWND hwnd, WORD wParam, LONG lParam)
1582 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1584 return lphl->FirstVisible;
1588 /***********************************************************************
1589 * LBSelectString
1591 static LONG LBSelectString(HWND hwnd, WORD wParam, LONG lParam)
1593 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1594 WORD wRet;
1596 wRet = ListBoxFindString(lphl, wParam, lParam);
1598 /* XXX add functionality here */
1600 return 0;
1603 /***********************************************************************
1604 * LBSelItemRange
1606 static LONG LBSelItemRange(HWND hwnd, WORD wParam, LONG lParam)
1608 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1609 LPLISTSTRUCT lpls;
1610 WORD cnt;
1611 WORD first = LOWORD(lParam);
1612 WORD last = HIWORD(lParam);
1613 BOOL select = wParam;
1615 if (!(GetWindowLong(lphl->hSelf,GWL_STYLE) &
1616 (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
1617 return LB_ERR;
1619 if (first >= lphl->ItemsCount ||
1620 last >= lphl->ItemsCount) return LB_ERR;
1622 lpls = lphl->lpFirst;
1623 cnt = 0;
1625 while (lpls != NULL) {
1626 if (cnt++ >= first)
1627 lpls->itemState = select ? ODS_SELECTED : 0;
1629 if (cnt > last)
1630 break;
1632 lpls = lpls->lpNext;
1635 return 0;
1638 /***********************************************************************
1639 * LBSetCaretIndex
1641 static LONG LBSetCaretIndex(HWND hwnd, WORD wParam, LONG lParam)
1643 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1645 if (!(GetWindowLong(lphl->hSelf,GWL_STYLE) & LBS_MULTIPLESEL)) return 0;
1646 if (wParam >= lphl->ItemsCount) return LB_ERR;
1648 lphl->ItemFocused = wParam;
1649 ListBoxScrollToFocus (lphl);
1651 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1652 InvalidateRect(hwnd, NULL, TRUE);
1653 return 0;
1656 /***********************************************************************
1657 * LBSetColumnWidth
1659 static LONG LBSetColumnWidth(HWND hwnd, WORD wParam, LONG lParam)
1661 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1662 lphl->ColumnsWidth = wParam;
1663 InvalidateRect(hwnd,NULL,TRUE);
1664 return 0;
1667 /***********************************************************************
1668 * LBSetHorizontalExtent
1670 static LONG LBSetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam)
1672 return 0;
1675 /***********************************************************************
1676 * LBGetItemData
1678 static LONG LBGetItemData(HWND hwnd, WORD wParam, LONG lParam)
1680 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1681 dprintf_listbox(stddeb, "LB_GETITEMDATA wParam=%x\n", wParam);
1682 return ListBoxGetItemData(lphl, wParam);
1685 /***********************************************************************
1686 * LBSetItemData
1688 static LONG LBSetItemData(HWND hwnd, WORD wParam, LONG lParam)
1690 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1691 dprintf_listbox(stddeb, "LB_SETITEMDATA wParam=%x lParam=%lx\n", wParam, lParam);
1692 return ListBoxSetItemData(lphl, wParam, lParam);
1695 /***********************************************************************
1696 * LBSetTabStops
1698 static LONG LBSetTabStops(HWND hwnd, WORD wParam, LONG lParam)
1700 LPHEADLIST lphl;
1702 lphl = ListBoxGetStorageHeader(hwnd);
1704 if (lphl->TabStops != NULL) {
1705 lphl->iNumStops = 0;
1706 free (lphl->TabStops);
1709 lphl->TabStops = malloc (wParam * sizeof (short));
1710 if (lphl->TabStops) {
1711 lphl->iNumStops = wParam;
1712 memcpy (lphl->TabStops, PTR_SEG_TO_LIN(lParam), wParam * sizeof (short));
1713 return TRUE;
1716 return FALSE;
1719 /***********************************************************************
1720 * LBSetCurSel
1722 static LONG LBSetCurSel(HWND hwnd, WORD wParam, LONG lParam)
1724 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1725 WORD wRet;
1727 dprintf_listbox(stddeb,"ListBox LB_SETCURSEL wParam=%x !\n",
1728 wParam);
1730 wRet = ListBoxSetCurSel(lphl, wParam);
1732 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1733 InvalidateRect(hwnd, NULL, TRUE);
1735 return wRet;
1738 /***********************************************************************
1739 * LBSetSel
1741 static LONG LBSetSel(HWND hwnd, WORD wParam, LONG lParam)
1743 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1744 WORD wRet;
1746 dprintf_listbox(stddeb,"ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam, lParam);
1748 wRet = ListBoxSetSel(lphl, LOWORD(lParam), wParam);
1749 InvalidateRect(hwnd, NULL, TRUE);
1751 return wRet;
1754 /***********************************************************************
1755 * LBSetTopIndex
1757 static LONG LBSetTopIndex(HWND hwnd, WORD wParam, LONG lParam)
1759 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1761 dprintf_listbox(stddeb,"ListBox LB_SETTOPINDEX wParam=%x !\n",
1762 wParam);
1763 lphl->FirstVisible = wParam;
1764 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1766 InvalidateRect(hwnd, NULL, TRUE);
1768 return 0;
1771 /***********************************************************************
1772 * LBSetItemHeight
1774 static LONG LBSetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
1776 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1777 WORD wRet;
1779 dprintf_listbox(stddeb,"ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam, lParam);
1780 wRet = ListBoxSetItemHeight(lphl, wParam, lParam);
1781 InvalidateRect(hwnd,NULL,TRUE);
1782 return wRet;
1785 /***********************************************************************
1786 * LBPassToParent
1788 static LRESULT LBPassToParent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1790 WND* ptrWnd = WIN_FindWndPtr(hwnd);
1792 if( ptrWnd )
1793 if( /* !(ptrWnd->dwExStyle & WS_EX_NOPARENTNOTIFY) && */
1794 ptrWnd->hwndParent )
1795 return SendMessage(ptrWnd->hwndParent,message,wParam,lParam);
1796 return 0;
1799 /***********************************************************************
1800 * ListBoxWndProc
1802 LRESULT ListBoxWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1804 switch (message) {
1805 case WM_CREATE: return LBCreate(hwnd, wParam, lParam);
1806 case WM_DESTROY: return LBDestroy(hwnd, wParam, lParam);
1807 case WM_GETDLGCODE: return LBGetDlgCode(hwnd, wParam, lParam);
1808 case WM_VSCROLL: return LBVScroll(hwnd, wParam, lParam);
1809 case WM_HSCROLL: return LBHScroll(hwnd, wParam, lParam);
1810 case WM_LBUTTONDOWN: return LBLButtonDown(hwnd, wParam, lParam);
1811 case WM_LBUTTONUP: return LBLButtonUp(hwnd, wParam, lParam);
1812 case WM_RBUTTONUP: return LBRButtonUp(hwnd, wParam, lParam);
1813 case WM_LBUTTONDBLCLK: return LBRButtonUp(hwnd, wParam, lParam);
1814 case WM_MOUSEMOVE: return LBMouseMove(hwnd, wParam, lParam);
1815 case WM_KEYDOWN: return LBKeyDown(hwnd, wParam, lParam);
1816 case WM_CHAR: return LBChar(hwnd, wParam, lParam);
1817 case WM_SETFONT: return LBSetFont(hwnd, wParam, lParam);
1818 case WM_SETREDRAW: return LBSetRedraw(hwnd, wParam, lParam);
1819 case WM_PAINT: return LBPaint(hwnd, wParam, lParam);
1820 case WM_SETFOCUS: return LBSetFocus(hwnd, wParam, lParam);
1821 case WM_KILLFOCUS: return LBKillFocus(hwnd, wParam, lParam);
1822 case LB_RESETCONTENT: return LBResetContent(hwnd, wParam, lParam);
1823 case LB_DIR: return LBDir(hwnd, wParam, lParam);
1824 case LB_ADDSTRING: return LBAddString(hwnd, wParam, lParam);
1825 case LB_INSERTSTRING: return LBInsertString(hwnd, wParam, lParam);
1826 case LB_DELETESTRING: return LBDeleteString(hwnd, wParam, lParam);
1827 case LB_FINDSTRING: return LBFindString(hwnd, wParam, lParam);
1828 case LB_GETCARETINDEX: return LBGetCaretIndex(hwnd, wParam, lParam);
1829 case LB_GETCOUNT: return LBGetCount(hwnd, wParam, lParam);
1830 case LB_GETCURSEL: return LBGetCurSel(hwnd, wParam, lParam);
1831 case LB_GETHORIZONTALEXTENT: return LBGetHorizontalExtent(hwnd, wParam, lParam);
1832 case LB_GETITEMDATA: return LBGetItemData(hwnd, wParam, lParam);
1833 case LB_GETITEMHEIGHT: return LBGetItemHeight(hwnd, wParam, lParam);
1834 case LB_GETITEMRECT: return LBGetItemRect(hwnd, wParam, lParam);
1835 case LB_GETSEL: return LBGetSel(hwnd, wParam, lParam);
1836 case LB_GETSELCOUNT: return LBGetSelCount(hwnd, wParam, lParam);
1837 case LB_GETSELITEMS: return LBGetSelItems(hwnd, wParam, lParam);
1838 case LB_GETTEXT: return LBGetText(hwnd, wParam, lParam);
1839 case LB_GETTEXTLEN: return LBGetTextLen(hwnd, wParam, lParam);
1840 case LB_GETTOPINDEX: return LBGetTopIndex(hwnd, wParam, lParam);
1841 case LB_SELECTSTRING: return LBSelectString(hwnd, wParam, lParam);
1842 case LB_SELITEMRANGE: return LBSelItemRange(hwnd, wParam, lParam);
1843 case LB_SETCARETINDEX: return LBSetCaretIndex(hwnd, wParam, lParam);
1844 case LB_SETCOLUMNWIDTH: return LBSetColumnWidth(hwnd, wParam, lParam);
1845 case LB_SETHORIZONTALEXTENT: return LBSetHorizontalExtent(hwnd, wParam, lParam);
1846 case LB_SETITEMDATA: return LBSetItemData(hwnd, wParam, lParam);
1847 case LB_SETTABSTOPS: return LBSetTabStops(hwnd, wParam, lParam);
1848 case LB_SETCURSEL: return LBSetCurSel(hwnd, wParam, lParam);
1849 case LB_SETSEL: return LBSetSel(hwnd, wParam, lParam);
1850 case LB_SETTOPINDEX: return LBSetTopIndex(hwnd, wParam, lParam);
1851 case LB_SETITEMHEIGHT: return LBSetItemHeight(hwnd, wParam, lParam);
1853 case WM_DROPFILES: return LBPassToParent(hwnd, message, wParam, lParam);
1855 case WM_DROPOBJECT:
1856 case WM_QUERYDROPOBJECT:
1857 case WM_DRAGSELECT:
1858 case WM_DRAGMOVE:
1860 LPDRAGINFO lpDragInfo = (LPDRAGINFO) PTR_SEG_TO_LIN((SEGPTR)lParam);
1861 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1863 /* more undocumented Microsoft crap - drag&drop depends on it - AK */
1865 lpDragInfo->l = ListBoxFindMouse(lphl,lpDragInfo->pt.x,
1866 lpDragInfo->pt.y);
1868 return LBPassToParent(hwnd, message, wParam, lParam);
1872 return DefWindowProc(hwnd, message, wParam, lParam);
1875 /************************************************************************
1876 * DlgDirSelect [USER.99]
1878 BOOL DlgDirSelect(HWND hDlg, LPSTR lpStr, int nIDLBox)
1880 HWND hwnd;
1881 LPHEADLIST lphl;
1882 char s[130];
1884 dprintf_listbox( stddeb, "DlgDirSelect("NPFMT", '%s', %d) \n", hDlg, lpStr,
1885 nIDLBox );
1887 hwnd = GetDlgItem(hDlg, nIDLBox);
1888 lphl = ListBoxGetStorageHeader(hwnd);
1889 if(lphl->ItemFocused == -1) {
1890 dprintf_listbox(stddeb, "Nothing selected!\n");
1891 return FALSE;
1893 ListBoxGetText(lphl, lphl->ItemFocused, s);
1894 dprintf_listbox(stddeb, "Selection is %s\n", s);
1895 if( s[0] == '[' ) {
1896 if( s[1] == '-' ) {
1897 strncpy( lpStr, s+2, strlen(s)-4 ); /* device name */
1898 lpStr[ strlen(s)-4 ] = 0;
1899 strcat( lpStr, ":" );
1901 else {
1902 strncpy( lpStr, s+1, strlen(s)-2 ); /* directory name */
1903 lpStr[ strlen(s)-2 ] = 0;
1904 strcat( lpStr, "\\" );
1906 dprintf_listbox( stddeb, "Returning %s\n", lpStr );
1907 return TRUE;
1908 } else {
1909 strcpy( lpStr, s ); /* file name */
1910 dprintf_listbox( stddeb, "Returning %s\n", lpStr );
1911 return FALSE;
1916 /************************************************************************
1917 * DlgDirList [USER.100]
1919 int DlgDirList(HWND hDlg, LPSTR lpPathSpec,
1920 int nIDLBox, int nIDStat, WORD wType)
1922 HWND hWnd;
1923 int ret;
1925 dprintf_listbox(stddeb,"DlgDirList("NPFMT", '%s', %d, %d, %04X) \n",
1926 hDlg, lpPathSpec, nIDLBox, nIDStat, wType);
1927 if (nIDLBox) {
1928 LPHEADLIST lphl;
1929 hWnd = GetDlgItem(hDlg, nIDLBox);
1930 lphl = ListBoxGetStorageHeader(hWnd);
1931 ListBoxResetContent(lphl);
1932 ret = ListBoxDirectory(lphl, wType, lpPathSpec);
1933 ListBoxUpdateWindow(hWnd, lphl, TRUE);
1934 } else {
1935 ret = 0;
1937 if (nIDStat) {
1938 int drive;
1939 HANDLE hTemp;
1940 char *temp;
1941 drive = DOS_GetDefaultDrive();
1942 hTemp = USER_HEAP_ALLOC( 256 );
1943 temp = (char *) USER_HEAP_LIN_ADDR( hTemp );
1944 strcpy( temp+3, DOS_GetCurrentDir(drive) );
1945 if( temp[3] == '\\' ) {
1946 temp[1] = 'A'+drive;
1947 temp[2] = ':';
1948 SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
1949 (LPARAM)(USER_HEAP_SEG_ADDR(hTemp) + 1) );
1950 } else {
1951 temp[0] = 'A'+drive;
1952 temp[1] = ':';
1953 temp[2] = '\\';
1954 SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
1955 (LPARAM)USER_HEAP_SEG_ADDR(hTemp) );
1957 USER_HEAP_FREE( hTemp );
1959 return ret;