Release 951226
[wine/gsoc-2012-control.git] / controls / listbox.c
blobd1b0df792077868477e904250116edc9fbd4730d
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 /* WINELIBS list boxes do not operate on local heaps */
115 #ifndef WINELIB
116 lphl->HeapSel = GlobalAlloc(GMEM_FIXED,LIST_HEAP_SIZE);
117 LocalInit( lphl->HeapSel, 0, LIST_HEAP_SIZE-1);
118 #else
119 lphl->HeapSel = 0;
120 #endif
123 void DestroyListBoxStruct(LPHEADLIST lphl)
125 if (lphl->hDrawItemStruct)
126 USER_HEAP_FREE(lphl->hDrawItemStruct);
128 /* XXX need to free lphl->Heap */
129 GlobalFree(lphl->HeapSel);
130 free(lphl);
133 static LPHEADLIST ListBoxGetStorageHeader(HWND hwnd)
135 return (LPHEADLIST)GetWindowLong(hwnd,0);
138 /* Send notification "code" as part of a WM_COMMAND-message if hwnd
139 has the LBS_NOTIFY style */
140 void ListBoxSendNotification(LPHEADLIST lphl, WORD code)
142 DWORD dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
144 if (dwStyle & LBS_NOTIFY)
145 #ifdef WINELIB32
146 SendMessage(lphl->hParent, WM_COMMAND,
147 MAKEWPARAM(lphl->CtlID,code), (LPARAM)lphl->hSelf);
148 #else
149 SendMessage(lphl->hParent, WM_COMMAND,
150 lphl->CtlID, MAKELONG(lphl->hSelf, code));
151 #endif
155 /* get the maximum value of lphl->FirstVisible */
156 int ListMaxFirstVisible(LPHEADLIST lphl)
158 int m = lphl->ItemsCount-lphl->ItemsVisible;
159 return (m < 0) ? 0 : m;
163 void ListBoxUpdateWindow(HWND hwnd, LPHEADLIST lphl, BOOL repaint)
165 SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
166 if (lphl->ItemsPerColumn != 0) {
167 SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible /
168 lphl->ItemsPerColumn + 1, TRUE);
170 if (repaint && lphl->bRedrawFlag) {
171 InvalidateRect(hwnd, NULL, TRUE);
175 /* Returns: 0 if nothing needs to be changed */
176 /* 1 if FirstVisible changed */
178 int ListBoxScrollToFocus(LPHEADLIST lphl)
180 short end;
182 if (lphl->ItemsCount == 0) return 0;
183 if (lphl->ItemFocused == -1) return 0;
185 end = lphl->FirstVisible + lphl->ItemsVisible - 1;
187 if (lphl->ItemFocused < lphl->FirstVisible ) {
188 lphl->FirstVisible = lphl->ItemFocused;
189 return 1;
190 } else {
191 if (lphl->ItemFocused > end) {
192 WORD maxFirstVisible = ListMaxFirstVisible(lphl);
194 lphl->FirstVisible = lphl->ItemFocused;
196 if (lphl->FirstVisible > maxFirstVisible) {
197 lphl->FirstVisible = maxFirstVisible;
199 return 1;
202 return 0;
206 LPLISTSTRUCT ListBoxGetItem(LPHEADLIST lphl, UINT uIndex)
208 LPLISTSTRUCT lpls;
209 UINT Count = 0;
211 if (uIndex >= lphl->ItemsCount) return NULL;
213 lpls = lphl->lpFirst;
214 while (Count++ < uIndex) lpls = lpls->lpNext;
215 return lpls;
219 void ListBoxDrawItem (HWND hwnd, LPHEADLIST lphl, HDC hdc, LPLISTSTRUCT lpls,
220 RECT *rect, WORD itemAction, WORD itemState)
222 LONG dwStyle = GetWindowLong(hwnd,GWL_STYLE);
224 if (lphl->OwnerDrawn) {
225 DRAWITEMSTRUCT *dis = USER_HEAP_LIN_ADDR(lphl->hDrawItemStruct);
227 dis->CtlID = lpls->mis.CtlID;
228 dis->CtlType = lpls->mis.CtlType;
229 dis->itemID = lpls->mis.itemID;
230 dis->hDC = hdc;
231 dis->hwndItem = hwnd;
232 dis->itemData = lpls->mis.itemData;
233 dis->itemAction = itemAction;
234 dis->itemState = itemState;
235 dis->rcItem = *rect;
236 SendMessage(lphl->hParent, WM_DRAWITEM,
237 0, (LPARAM)USER_HEAP_SEG_ADDR(lphl->hDrawItemStruct));
238 } else {
239 if (itemAction == ODA_DRAWENTIRE || itemAction == ODA_SELECT) {
240 int OldBkMode;
241 DWORD dwOldTextColor = 0;
243 OldBkMode = SetBkMode(hdc, TRANSPARENT);
245 if (itemState != 0) {
246 dwOldTextColor = SetTextColor(hdc, 0x00FFFFFFL);
247 FillRect(hdc, rect, GetStockObject(BLACK_BRUSH));
250 if (dwStyle & LBS_USETABSTOPS) {
251 TabbedTextOut(hdc, rect->left + 5, rect->top + 2,
252 (char *)lpls->itemText, strlen((char *)lpls->itemText),
253 lphl->iNumStops, lphl->TabStops, 0);
254 } else {
255 TextOut(hdc, rect->left + 5, rect->top + 2,
256 (char *)lpls->itemText, strlen((char *)lpls->itemText));
259 if (itemState != 0) {
260 SetTextColor(hdc, dwOldTextColor);
263 SetBkMode(hdc, OldBkMode);
264 } else DrawFocusRect(hdc, rect);
267 return;
271 int ListBoxFindMouse(LPHEADLIST lphl, int X, int Y)
273 LPLISTSTRUCT lpls = lphl->lpFirst;
274 int i, j;
275 POINT point;
277 point.x = X; point.y = Y;
278 if (lphl->ItemsCount == 0) return LB_ERR;
280 for(i = 0; i < lphl->FirstVisible; i++) {
281 if (lpls == NULL) return LB_ERR;
282 lpls = lpls->lpNext;
284 for(j = 0; j < lphl->ItemsVisible; i++, j++) {
285 if (lpls == NULL) return LB_ERR;
286 if (PtInRect(&lpls->itemRect,point)) {
287 return i;
289 lpls = lpls->lpNext;
291 dprintf_listbox(stddeb,"ListBoxFindMouse: not found\n");
292 return LB_ERR;
296 void ListBoxAskMeasure(LPHEADLIST lphl, LPLISTSTRUCT lpls)
298 HANDLE hTemp = USER_HEAP_ALLOC( sizeof(MEASUREITEMSTRUCT) );
299 MEASUREITEMSTRUCT *lpmeasure = (MEASUREITEMSTRUCT *) USER_HEAP_LIN_ADDR(hTemp);
301 if (lpmeasure == NULL) {
302 fprintf(stdnimp,"ListBoxAskMeasure() out of memory !\n");
303 return;
306 *lpmeasure = lpls->mis;
307 lpmeasure->itemHeight = lphl->StdItemHeight;
308 SendMessage(lphl->hParent, WM_MEASUREITEM, 0, (LPARAM)USER_HEAP_SEG_ADDR(hTemp));
310 if (GetWindowLong(lphl->hSelf,GWL_STYLE) & LBS_OWNERDRAWFIXED) {
311 lphl->StdItemHeight = lpmeasure->itemHeight;
312 lphl->needMeasure = FALSE;
315 USER_HEAP_FREE(hTemp);
318 /* -------------------- strings and item data ---------------------- */
320 LPLISTSTRUCT ListBoxCreateItem(LPHEADLIST lphl, int id)
322 LPLISTSTRUCT lplsnew = (LPLISTSTRUCT)malloc(sizeof(LISTSTRUCT));
324 if (lplsnew == NULL) return NULL;
326 lplsnew->itemState = 0;
327 lplsnew->mis.CtlType = lphl->DrawCtlType;
328 lplsnew->mis.CtlID = lphl->CtlID;
329 lplsnew->mis.itemID = id;
330 lplsnew->mis.itemHeight = lphl->StdItemHeight;
331 lplsnew->mis.itemWidth = 0; /* ignored */
332 lplsnew->mis.itemData = 0;
333 SetRect(&lplsnew->itemRect, 0, 0, 0, 0);
335 return lplsnew;
339 int ListBoxInsertString(LPHEADLIST lphl, UINT uIndex, LPSTR newstr)
341 LPLISTSTRUCT *lppls, lplsnew, lpls;
342 HANDLE hStr;
343 LPSTR str;
344 UINT Count;
346 dprintf_listbox(stddeb,"ListBoxInsertString(%d, %p);\n", uIndex, newstr);
348 if (!newstr) return -1;
350 if (uIndex == (UINT)-1)
351 uIndex = lphl->ItemsCount;
353 lppls = &lphl->lpFirst;
354 for(Count = 0; Count < uIndex; Count++) {
355 if (*lppls == NULL) return LB_ERR;
356 lppls = (LPLISTSTRUCT *) &(*lppls)->lpNext;
359 lplsnew = ListBoxCreateItem(lphl, Count);
361 if (lplsnew == NULL) {
362 fprintf(stdnimp,"ListBoxInsertString() out of memory !\n");
363 return LB_ERRSPACE;
366 lplsnew->lpNext = *lppls;
367 *lppls = lplsnew;
368 lphl->ItemsCount++;
370 hStr = 0;
371 if (lphl->HasStrings) {
372 dprintf_listbox(stddeb," string: %s\n", newstr);
373 hStr = LIST_HEAP_ALLOC(lphl, LMEM_MOVEABLE, strlen(newstr) + 1);
374 str = (LPSTR)LIST_HEAP_ADDR(lphl, hStr);
375 if (str == NULL) return LB_ERRSPACE;
376 strcpy(str, newstr);
377 lplsnew->itemText = str;
378 /* I'm not so sure about the next one */
379 lplsnew->mis.itemData = 0;
380 } else {
381 lplsnew->itemText = NULL;
382 lplsnew->mis.itemData = (DWORD)newstr;
385 lplsnew->mis.itemID = uIndex;
386 lplsnew->hData = hStr;
388 /* adjust the itemID field of the following entries */
389 for(lpls = lplsnew->lpNext; lpls != NULL; lpls = lpls->lpNext) {
390 lpls->mis.itemID++;
393 if (lphl->needMeasure) {
394 ListBoxAskMeasure(lphl, lplsnew);
397 dprintf_listbox(stddeb,"ListBoxInsertString // count=%d\n", lphl->ItemsCount);
398 return uIndex;
402 int ListBoxAddString(LPHEADLIST lphl, LPSTR newstr)
404 LONG dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
405 UINT pos = (UINT) -1;
407 if (lphl->HasStrings && (dwStyle & LBS_SORT)) {
408 LPLISTSTRUCT lpls = lphl->lpFirst;
409 for (pos = 0; lpls != NULL; lpls = lpls->lpNext, pos++)
410 if (strcmp(lpls->itemText, newstr) >= 0)
411 break;
413 return ListBoxInsertString(lphl, pos, newstr);
417 int ListBoxGetText(LPHEADLIST lphl, UINT uIndex, LPSTR OutStr)
419 LPLISTSTRUCT lpls;
421 if (!OutStr) {
422 dprintf_listbox(stddeb, "ListBoxGetText // OutStr==NULL\n");
423 return 0;
426 lpls = ListBoxGetItem (lphl, uIndex);
427 if (lpls == NULL) return LB_ERR;
429 if (!lphl->HasStrings) {
430 *((long *)OutStr) = lpls->mis.itemData;
431 return 4;
434 strcpy(OutStr, lpls->itemText);
435 return strlen(OutStr);
439 DWORD ListBoxGetItemData(LPHEADLIST lphl, UINT uIndex)
441 LPLISTSTRUCT lpls;
443 lpls = ListBoxGetItem (lphl, uIndex);
444 if (lpls == NULL) return LB_ERR;
445 return lpls->mis.itemData;
449 int ListBoxSetItemData(LPHEADLIST lphl, UINT uIndex, DWORD ItemData)
451 LPLISTSTRUCT lpls = ListBoxGetItem(lphl, uIndex);
453 if (lpls == NULL) return LB_ERR;
454 lpls->mis.itemData = ItemData;
455 return 1;
459 int ListBoxDeleteString(LPHEADLIST lphl, UINT uIndex)
461 LPLISTSTRUCT lpls, lpls2;
462 UINT Count;
464 if (uIndex >= lphl->ItemsCount) return LB_ERR;
466 lpls = lphl->lpFirst;
467 if (lpls == NULL) return LB_ERR;
469 if (uIndex == 0)
470 lphl->lpFirst = lpls->lpNext;
471 else {
472 LPLISTSTRUCT lpls2 = NULL;
473 for(Count = 0; Count < uIndex; Count++) {
474 if (lpls->lpNext == NULL) return LB_ERR;
476 lpls2 = lpls;
477 lpls = (LPLISTSTRUCT)lpls->lpNext;
479 lpls2->lpNext = lpls->lpNext;
482 /* adjust the itemID field of the following entries */
483 for(lpls2 = lpls->lpNext; lpls2 != NULL; lpls2 = lpls2->lpNext) {
484 lpls2->mis.itemID--;
487 lphl->ItemsCount--;
489 if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
490 free(lpls);
492 return lphl->ItemsCount;
496 int ListBoxFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr)
498 LPLISTSTRUCT lpls;
499 UINT Count;
500 UINT First = nFirst + 1;
501 LPSTR lpMatchStr = (LPSTR)MatchStr;
502 LONG dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
504 if (First > lphl->ItemsCount) return LB_ERR;
506 if (lphl->HasStrings) lpMatchStr = PTR_SEG_TO_LIN(MatchStr);
508 lpls = ListBoxGetItem(lphl, First);
509 Count = 0;
510 while(lpls != NULL) {
511 if (lphl->HasStrings) {
512 if (strstr(lpls->itemText, lpMatchStr) == lpls->itemText) return Count;
513 } else if (dwStyle & LBS_SORT) {
514 /* XXX Do a compare item */
516 else
517 if (lpls->mis.itemData == (DWORD)lpMatchStr) return Count;
519 lpls = lpls->lpNext;
520 Count++;
523 /* Start over at top */
524 Count = 0;
525 lpls = lphl->lpFirst;
527 while (Count < First) {
528 if (lphl->HasStrings) {
529 if (strstr(lpls->itemText, lpMatchStr) == lpls->itemText) return Count;
530 } else if (dwStyle & LBS_SORT) {
531 /* XXX Do a compare item */
532 } else {
533 if (lpls->mis.itemData == (DWORD)lpMatchStr) return Count;
535 lpls = lpls->lpNext;
536 Count++;
539 return LB_ERR;
543 int ListBoxResetContent(LPHEADLIST lphl)
545 LPLISTSTRUCT lpls;
546 int i;
548 if (lphl->ItemsCount == 0) return 0;
550 dprintf_listbox(stddeb, "ListBoxResetContent // ItemCount = %d\n",
551 lphl->ItemsCount);
553 for(i = 0; i < lphl->ItemsCount; i++) {
554 lpls = lphl->lpFirst;
555 if (lpls == NULL) return LB_ERR;
557 lphl->lpFirst = lpls->lpNext;
558 if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
559 free(lpls);
561 ListBoxInitialize(lphl);
563 return TRUE;
566 /* --------------------- selection ------------------------- */
568 int ListBoxSetCurSel(LPHEADLIST lphl, WORD wIndex)
570 LPLISTSTRUCT lpls;
571 DWORD dwStyle = GetWindowWord(lphl->hSelf,GWL_STYLE);
573 /* use ListBoxSetSel instead */
574 if (dwStyle & LBS_MULTIPLESEL ) return 0;
576 /* unselect all previously selected */
577 if (dwStyle & LBS_EXTENDEDSEL )
578 ListBoxSetSel(lphl,-1,0);
579 else
580 /* unselect previous item */
581 if (lphl->ItemFocused != -1) {
582 lpls = ListBoxGetItem(lphl, lphl->ItemFocused);
583 if (lpls == 0) return LB_ERR;
584 lpls->itemState = 0;
587 if (wIndex != (UINT)-1) {
588 lphl->ItemFocused = wIndex;
589 lpls = ListBoxGetItem(lphl, wIndex);
590 if (lpls == 0) return LB_ERR;
591 lpls->itemState = ODS_SELECTED | ODS_FOCUS;
593 return 0;
596 return LB_ERR;
600 int ListBoxSetSel(LPHEADLIST lphl, WORD wIndex, WORD state)
602 LPLISTSTRUCT lpls;
604 if (!(GetWindowLong(lphl->hSelf,GWL_STYLE) &
605 (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
606 return 0;
608 if (wIndex == (UINT)-1) {
609 for (lpls = lphl->lpFirst; lpls != NULL; lpls = lpls->lpNext) {
610 lpls->itemState = state;
612 return 0;
615 if (wIndex >= lphl->ItemsCount) return LB_ERR;
617 lpls = ListBoxGetItem(lphl, wIndex);
618 lpls->itemState = state;
620 return 0;
624 int ListBoxGetSel(LPHEADLIST lphl, WORD wIndex)
626 LPLISTSTRUCT lpls = ListBoxGetItem(lphl, wIndex);
628 if (lpls == NULL) return LB_ERR;
629 return lpls->itemState;
632 /* ------------------------- dir listing ------------------------ */
634 int ListBoxDirectory(LPHEADLIST lphl, UINT attrib, LPSTR filespec)
636 struct dosdirent *dp, *dp_old;
637 char temp[256];
638 int drive;
639 LPSTR tstr;
641 dprintf_listbox(stddeb,"ListBoxDirectory: %s, %4x\n",filespec,attrib);
643 if (strchr(filespec, '\\') || strchr(filespec, ':')) {
644 drive = DOS_GetDefaultDrive();
645 if (filespec[1] == ':') {
646 drive = toupper(filespec[0]) - 'A';
647 filespec += 2;
649 strcpy(temp,filespec);
650 tstr = strrchr(temp, '\\');
651 if (tstr != NULL) {
652 *(tstr+1) = 0;
653 filespec += tstr - temp + 1;
654 if (!DOS_ChangeDir( drive, temp )) return 0;
656 DOS_SetDefaultDrive( drive );
657 dprintf_listbox(stddeb,"Changing directory to %c:%s, filemask is %s\n",
658 drive+'A', temp, filespec);
661 if ((dp = (struct dosdirent *)DOS_opendir(filespec)) ==NULL) return 0;
662 dp_old = dp;
663 while ((dp = (struct dosdirent *)DOS_readdir(dp))) {
664 if (!dp->inuse) break;
665 dprintf_listbox(stddeb, "ListBoxDirectory %p '%s' !\n", dp->filename,
666 dp->filename);
667 if (dp->attribute & FA_DIREC) {
668 if (attrib & DDL_DIRECTORY && strcmp(dp->filename, ".") != 0) {
669 sprintf(temp, "[%s]", dp->filename);
670 if (ListBoxAddString(lphl, temp) == LB_ERR) break;
673 else {
674 if (attrib & DDL_EXCLUSIVE) {
675 if (attrib & (DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM)) {
676 if (ListBoxAddString(lphl, dp->filename) == LB_ERR) break;
678 } else {
679 if (ListBoxAddString(lphl, dp->filename) == LB_ERR) break;
683 DOS_closedir(dp_old);
685 if (attrib & DDL_DRIVES) {
686 int x;
687 for (x = 0; x != MAX_DOS_DRIVES ; x++) {
688 if (DOS_ValidDrive(x)) {
689 sprintf(temp, "[-%c-]", 'a'+x);
690 if (ListBoxInsertString(lphl, (UINT)-1, temp) == LB_ERR) break;
694 return 1;
697 /* ------------------------- dimensions ------------------------- */
699 int ListBoxGetItemRect(LPHEADLIST lphl, WORD wIndex, LPRECT lprect)
701 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wIndex);
703 if (lpls == NULL) return LB_ERR;
704 *lprect = lpls->itemRect;
705 return 0;
709 int ListBoxSetItemHeight(LPHEADLIST lphl, WORD wIndex, long height)
711 LPLISTSTRUCT lpls;
713 if (!(GetWindowLong(lphl->hSelf,GWL_STYLE) & LBS_OWNERDRAWVARIABLE)) {
714 lphl->StdItemHeight = (short)height;
715 return 0;
718 lpls = ListBoxGetItem(lphl, wIndex);
719 if (lpls == NULL) return LB_ERR;
721 lpls->mis.itemHeight = height;
722 return 0;
725 /* -------------------------- string search ------------------------ */
727 int ListBoxFindNextMatch(LPHEADLIST lphl, WORD wChar)
729 LPLISTSTRUCT lpls;
730 UINT count,first;
732 if ((char)wChar < ' ') return LB_ERR;
733 if (!lphl->HasStrings) return LB_ERR;
735 lpls = lphl->lpFirst;
737 for (count = 0; lpls != NULL; lpls = lpls->lpNext, count++) {
738 if (tolower(*lpls->itemText) == tolower((char)wChar)) break;
740 if (lpls == NULL) return LB_ERR;
741 first = count;
742 for(; lpls != NULL; lpls = lpls->lpNext, count++) {
743 if (*lpls->itemText != (char)wChar)
744 break;
745 if (count > lphl->ItemFocused)
746 return count;
748 return first;
751 /***********************************************************************
752 * LBCreate
754 static LONG LBCreate(HWND hwnd, WORD wParam, LONG lParam)
756 LPHEADLIST lphl;
757 LONG dwStyle = GetWindowLong(hwnd,GWL_STYLE);
758 RECT rect;
760 CreateListBoxStruct(hwnd, ODT_LISTBOX, dwStyle, GetParent(hwnd));
761 lphl = ListBoxGetStorageHeader(hwnd);
762 dprintf_listbox(stddeb,"ListBox created: lphl = %p dwStyle = %04x:%04x\n",
763 lphl, HIWORD(dwStyle), LOWORD(dwStyle));
765 GetClientRect(hwnd,&rect);
766 lphl->ColumnsWidth = rect.right - rect.left;
768 SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
769 SetScrollRange(hwnd, SB_HORZ, 1, 1, TRUE);
771 return 0;
774 /***********************************************************************
775 * LBDestroy
777 static LONG LBDestroy(HWND hwnd, WORD wParam, LONG lParam)
779 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
781 ListBoxResetContent(lphl);
783 DestroyListBoxStruct(lphl);
784 dprintf_listbox(stddeb,"ListBox destroyed: lphl = %p\n",lphl);
785 return 0;
788 /***********************************************************************
789 * LBVScroll
791 static LONG LBVScroll(HWND hwnd, WORD wParam, LONG lParam)
793 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
794 int y;
796 dprintf_listbox(stddeb,"ListBox WM_VSCROLL w=%04X l=%08lX !\n",
797 wParam, lParam);
798 y = lphl->FirstVisible;
800 switch(wParam) {
801 case SB_LINEUP:
802 if (lphl->FirstVisible > 0)
803 lphl->FirstVisible--;
804 break;
806 case SB_LINEDOWN:
807 lphl->FirstVisible++;
808 break;
810 case SB_PAGEUP:
811 if (lphl->FirstVisible > lphl->ItemsVisible) {
812 lphl->FirstVisible -= lphl->ItemsVisible;
813 } else {
814 lphl->FirstVisible = 0;
816 break;
818 case SB_PAGEDOWN:
819 lphl->FirstVisible += lphl->ItemsVisible;
820 break;
822 case SB_THUMBTRACK:
823 lphl->FirstVisible = LOWORD(lParam);
824 break;
827 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
828 lphl->FirstVisible = ListMaxFirstVisible(lphl);
830 if (y != lphl->FirstVisible) {
831 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
832 InvalidateRect(hwnd, NULL, TRUE);
834 return 0;
837 /***********************************************************************
838 * LBHScroll
840 static LONG LBHScroll(HWND hwnd, WORD wParam, LONG lParam)
842 LPHEADLIST lphl;
843 int y;
845 dprintf_listbox(stddeb,"ListBox WM_HSCROLL w=%04X l=%08lX !\n",
846 wParam, lParam);
847 lphl = ListBoxGetStorageHeader(hwnd);
848 y = lphl->FirstVisible;
849 switch(wParam) {
850 case SB_LINEUP:
851 if (lphl->FirstVisible > lphl->ItemsPerColumn) {
852 lphl->FirstVisible -= lphl->ItemsPerColumn;
853 } else {
854 lphl->FirstVisible = 0;
856 break;
857 case SB_LINEDOWN:
858 lphl->FirstVisible += lphl->ItemsPerColumn;
859 break;
860 case SB_PAGEUP:
861 if (lphl->ItemsPerColumn != 0) {
862 int lbsub = lphl->ItemsVisible / lphl->ItemsPerColumn * lphl->ItemsPerColumn;
863 if (lphl->FirstVisible > lbsub) {
864 lphl->FirstVisible -= lbsub;
865 } else {
866 lphl->FirstVisible = 0;
869 break;
870 case SB_PAGEDOWN:
871 if (lphl->ItemsPerColumn != 0)
872 lphl->FirstVisible += lphl->ItemsVisible /
873 lphl->ItemsPerColumn * lphl->ItemsPerColumn;
874 break;
875 case SB_THUMBTRACK:
876 lphl->FirstVisible = lphl->ItemsPerColumn * LOWORD(lParam);
877 break;
879 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
880 lphl->FirstVisible = ListMaxFirstVisible(lphl);
882 if (lphl->ItemsPerColumn != 0) {
883 lphl->FirstVisible = lphl->FirstVisible /
884 lphl->ItemsPerColumn * lphl->ItemsPerColumn + 1;
885 if (y != lphl->FirstVisible) {
886 SetScrollPos(hwnd, SB_HORZ, lphl->FirstVisible /
887 lphl->ItemsPerColumn + 1, TRUE);
888 InvalidateRect(hwnd, NULL, TRUE);
891 return 0;
894 /***********************************************************************
895 * LBLButtonDown
897 static LONG LBLButtonDown(HWND hwnd, WORD wParam, LONG lParam)
899 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
900 WORD wRet;
901 int y;
902 RECT rectsel;
903 LONG dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
904 POINT tmpPOINT;
905 tmpPOINT.x = LOWORD(lParam); tmpPOINT.y = HIWORD(lParam);
907 SetFocus(hwnd);
908 SetCapture(hwnd);
910 lphl->PrevFocused = lphl->ItemFocused;
912 y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
913 if (y == -1)
914 return 0;
916 if (dwStyle & LBS_MULTIPLESEL) {
917 lphl->ItemFocused = y;
918 wRet = ListBoxGetSel(lphl, y);
919 ListBoxSetSel(lphl, y, !wRet);
921 InvalidateRect(hwnd, NULL, TRUE);
922 } else {
923 ListBoxSetCurSel(lphl, y);
925 ListBoxGetItemRect(lphl, y, &rectsel);
926 InvalidateRect(hwnd, &rectsel, TRUE);
927 if(lphl->PrevFocused) {
928 ListBoxGetItemRect(lphl, lphl->PrevFocused, &rectsel);
929 InvalidateRect(hwnd, &rectsel, TRUE);
933 if (dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL))
934 ListBoxSendNotification(lphl, LBN_SELCHANGE);
936 if (dwStyle & LBS_NOTIFY)
937 SendMessage(lphl->hParent, WM_LBTRACKPOINT, y, lParam);
938 #ifndef WINELIB
939 if (GetWindowLong(lphl->hSelf,GWL_EXSTYLE) & WS_EX_DRAGDETECT)
940 if( DragDetect(lphl->hSelf,tmpPOINT) )
941 SendMessage(lphl->hParent, WM_BEGINDRAG,0,0L);
942 #endif
943 return 0;
946 /***********************************************************************
947 * LBLButtonUp
949 static LONG LBLButtonUp(HWND hwnd, WORD wParam, LONG lParam)
951 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
953 if (GetCapture() == hwnd) ReleaseCapture();
955 if (lphl->PrevFocused != lphl->ItemFocused)
956 ListBoxSendNotification(lphl, LBN_SELCHANGE);
958 return 0;
961 /***********************************************************************
962 * LBRButtonUp
964 static LONG LBRButtonUp(HWND hwnd, WORD wParam, LONG lParam)
966 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
968 #ifdef WINELIB32
969 SendMessage(lphl->hParent, WM_COMMAND,
970 MAKEWPARAM(GetWindowWord(hwnd,GWW_ID),LBN_DBLCLK),
971 (LPARAM)hwnd);
972 #else
973 SendMessage(lphl->hParent, WM_COMMAND, GetWindowWord(hwnd,GWW_ID),
974 MAKELONG(hwnd, LBN_DBLCLK));
975 #endif
977 return 0;
980 /***********************************************************************
981 * LBMouseMove
983 static LONG LBMouseMove(HWND hwnd, WORD wParam, LONG lParam)
985 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
986 int y;
987 WORD wRet;
988 LONG dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
989 RECT rect, rectsel; /* XXX Broken */
991 dprintf_listbox(stddeb,"LBMouseMove %d %d\n",SLOWORD(lParam),SHIWORD(lParam));
992 if ((wParam & MK_LBUTTON) != 0) {
993 y = SHIWORD(lParam);
994 if (y < 0) {
995 if (lphl->FirstVisible > 0) {
996 lphl->FirstVisible--;
997 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
998 InvalidateRect(hwnd, NULL, TRUE);
999 return 0;
1002 GetClientRect(hwnd, &rect);
1003 if (y >= rect.bottom) {
1004 if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
1005 lphl->FirstVisible++;
1006 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1007 InvalidateRect(hwnd, NULL, TRUE);
1008 return 0;
1011 if ((y > 0) && (y < (rect.bottom - 4))) {
1012 if ((y < rectsel.top) || (y > rectsel.bottom)) {
1013 wRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
1014 if (wRet == lphl->ItemFocused) {
1015 return 0;
1017 if (dwStyle & LBS_MULTIPLESEL) {
1018 lphl->ItemFocused = wRet;
1019 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1020 } else {
1021 ListBoxSetCurSel(lphl, wRet);
1022 if(dwStyle & LBS_EXTENDEDSEL)
1023 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1025 ListBoxGetItemRect(lphl, wRet, &rectsel);
1026 InvalidateRect(hwnd, &rectsel, TRUE);
1031 return 0;
1034 /***********************************************************************
1035 * LBKeyDown
1037 * Doesn't yet handle properly VK_SHIFT with LB_EXTENDEDSEL
1039 static LONG LBKeyDown(HWND hwnd, WORD wParam, LONG lParam)
1041 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1042 LONG dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
1043 WORD newFocused = 0xFFFF;
1044 RECT rect;
1046 ListBoxGetItemRect(lphl,lphl->ItemFocused,&rect);
1047 switch(wParam)
1049 /* ugly kludge that belongs in TranslateMessage */
1051 case VK_HOME:
1052 case VK_END:
1053 case VK_LEFT:
1054 case VK_RIGHT:
1055 case VK_UP:
1056 case VK_DOWN:
1057 case VK_PRIOR:
1058 case VK_NEXT:
1059 if ( dwStyle & LBS_WANTKEYBOARDINPUT )
1061 newFocused = (WORD)(INT)SendMessage(lphl->hParent,WM_VKEYTOITEM,
1062 wParam,MAKELPARAM(lphl->ItemFocused,hwnd));
1063 if ( newFocused == 0xFFFE ) return 0L;
1065 if ( newFocused == 0xFFFF )
1067 newFocused = lphl->ItemFocused;
1069 /* nested switch */
1070 switch(wParam)
1072 case VK_HOME:
1073 newFocused = 0;
1074 break;
1075 case VK_END:
1076 newFocused = lphl->ItemsCount - 1;
1077 break;
1078 case VK_LEFT:
1079 if (dwStyle & LBS_MULTICOLUMN) {
1080 if (newFocused >= lphl->ItemsPerColumn) {
1081 newFocused -= lphl->ItemsPerColumn;
1082 } else {
1083 newFocused = 0;
1086 break;
1087 case VK_UP:
1088 if (newFocused > 0) newFocused--;
1089 break;
1090 case VK_RIGHT:
1091 if (dwStyle & LBS_MULTICOLUMN)
1092 newFocused += lphl->ItemsPerColumn;
1093 break;
1094 case VK_DOWN:
1095 newFocused++;
1096 break;
1097 case VK_PRIOR:
1098 if (newFocused > lphl->ItemsVisible)
1099 newFocused -= lphl->ItemsVisible;
1100 else newFocused = 0;
1101 break;
1102 case VK_NEXT:
1103 newFocused += lphl->ItemsVisible;
1104 break;
1105 default:
1106 return 0;
1108 /* end of nested switch */
1110 break;
1111 case VK_SPACE:
1112 if (dwStyle & LBS_MULTIPLESEL)
1114 WORD wRet = ListBoxGetSel(lphl, lphl->ItemFocused);
1115 ListBoxSetSel(lphl, lphl->ItemFocused, !wRet);
1117 return 0;
1119 /* chars are handled in LBChar */
1120 default:
1121 return 0;
1124 /* at this point newFocused is set up */
1126 if (newFocused >= lphl->ItemsCount)
1127 newFocused = lphl->ItemsCount - 1;
1129 if (!(dwStyle & LBS_MULTIPLESEL))
1131 ListBoxSetCurSel(lphl, newFocused);
1132 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1135 lphl->ItemFocused = newFocused;
1137 if( ListBoxScrollToFocus(lphl) || (dwStyle &
1138 (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) )
1139 InvalidateRect(hwnd, NULL, TRUE);
1140 else
1142 InvalidateRect(hwnd, &rect, TRUE);
1143 if( newFocused < 0x8000 )
1145 ListBoxGetItemRect(lphl, newFocused, &rect);
1146 InvalidateRect(hwnd, &rect, TRUE);
1150 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1152 return 0;
1155 /***********************************************************************
1156 * LBChar
1158 static LONG LBChar(HWND hwnd, WORD wParam, LONG lParam)
1160 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1161 LONG dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
1162 WORD newFocused = 0xFFFF;
1164 if ( (dwStyle & LBS_WANTKEYBOARDINPUT) && !(lphl->HasStrings))
1166 newFocused = (WORD)(INT)SendMessage(lphl->hParent,WM_CHARTOITEM,
1167 wParam,MAKELPARAM(lphl->ItemFocused,hwnd));
1168 if ( newFocused == 0xFFFE ) return 0L;
1171 if (newFocused == 0xFFFF )
1172 newFocused = ListBoxFindNextMatch(lphl, wParam);
1174 if (newFocused == (WORD)LB_ERR) return 0;
1176 if (newFocused >= lphl->ItemsCount)
1177 newFocused = lphl->ItemsCount - 1;
1179 if (!(dwStyle & LBS_MULTIPLESEL))
1181 ListBoxSetCurSel(lphl, newFocused);
1182 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1185 lphl->ItemFocused = newFocused;
1186 ListBoxScrollToFocus(lphl);
1187 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1189 InvalidateRect(hwnd, NULL, TRUE);
1191 return 0;
1194 /***********************************************************************
1195 * LBSetRedraw
1197 static LONG LBSetRedraw(HWND hwnd, WORD wParam, LONG lParam)
1199 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1201 dprintf_listbox(stddeb,"ListBox WM_SETREDRAW hWnd="NPFMT" w=%04X !\n",
1202 hwnd, wParam);
1203 lphl->bRedrawFlag = wParam;
1205 return 0;
1208 /***********************************************************************
1209 * LBSetFont
1211 static LONG LBSetFont(HWND hwnd, WPARAM wParam, LPARAM lParam)
1213 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1215 if (wParam == 0)
1216 lphl->hFont = GetStockObject(SYSTEM_FONT);
1217 else
1218 lphl->hFont = (HFONT) wParam;
1220 return 0;
1223 /***********************************************************************
1224 * LBPaint
1226 static LONG LBPaint(HWND hwnd, WORD wParam, LONG lParam)
1228 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1229 LONG dwStyle = GetWindowLong(lphl->hSelf,GWL_STYLE);
1230 LPLISTSTRUCT lpls;
1231 PAINTSTRUCT ps;
1232 HBRUSH hBrush;
1233 HFONT hOldFont;
1234 HDC hdc;
1235 RECT rect;
1236 int i, top, height, maxwidth, ipc;
1238 top = 0;
1239 hdc = BeginPaint( hwnd, &ps );
1241 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) {
1242 EndPaint(hwnd, &ps);
1243 return 0;
1246 hOldFont = SelectObject(hdc, lphl->hFont);
1248 #ifdef WINELIB32
1249 hBrush = (HBRUSH) SendMessage(lphl->hParent, WM_CTLCOLORLISTBOX, (WPARAM)hdc,
1250 (LPARAM)hwnd);
1251 #else
1252 hBrush = SendMessage(lphl->hParent, WM_CTLCOLOR, hdc,
1253 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
1254 #endif
1256 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
1258 GetClientRect(hwnd, &rect);
1259 FillRect(hdc, &rect, hBrush);
1261 maxwidth = rect.right;
1262 if (dwStyle & LBS_MULTICOLUMN) {
1263 rect.right = lphl->ColumnsWidth;
1265 lpls = lphl->lpFirst;
1267 lphl->ItemsVisible = 0;
1268 lphl->ItemsPerColumn = ipc = 0;
1270 for(i = 0; i < lphl->ItemsCount; i++) {
1271 if (lpls == NULL) break;
1273 if (i >= lphl->FirstVisible) {
1274 height = lpls->mis.itemHeight;
1276 if (top > rect.bottom) {
1277 if (dwStyle & LBS_MULTICOLUMN) {
1278 lphl->ItemsPerColumn = MAX(lphl->ItemsPerColumn, ipc);
1279 ipc = 0;
1280 top = 0;
1281 rect.left += lphl->ColumnsWidth;
1282 rect.right += lphl->ColumnsWidth;
1283 if (rect.left > maxwidth) break;
1284 } else {
1285 break;
1289 lpls->itemRect.top = top;
1290 lpls->itemRect.bottom = top + height;
1291 lpls->itemRect.left = rect.left;
1292 lpls->itemRect.right = rect.right;
1294 dprintf_listbox(stddeb,"drawing item: %ld %d %ld %d %d\n",(LONG)rect.left,top,(LONG)rect.right,top+height,lpls->itemState);
1295 if (lphl->OwnerDrawn) {
1296 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, 0);
1297 if (lpls->itemState)
1298 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_SELECT, ODS_SELECTED);
1299 } else {
1300 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
1301 lpls->itemState);
1303 if ((lphl->ItemFocused == i) && GetFocus() == hwnd)
1304 ListBoxDrawItem (hwnd,lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, ODS_FOCUS);
1306 top += height;
1307 lphl->ItemsVisible++;
1308 ipc++;
1311 lpls = lpls->lpNext;
1313 ListBoxUpdateWindow(hwnd,lphl,FALSE);
1314 SelectObject(hdc,hOldFont);
1315 EndPaint( hwnd, &ps );
1316 return 0;
1319 /***********************************************************************
1320 * LBSetFocus
1322 static LONG LBSetFocus(HWND hwnd, WORD wParam, LONG lParam)
1324 dprintf_listbox(stddeb,"ListBox WM_SETFOCUS !\n");
1326 return 0;
1329 /***********************************************************************
1330 * LBKillFocus
1332 static LONG LBKillFocus(HWND hwnd, WORD wParam, LONG lParam)
1334 dprintf_listbox(stddeb,"ListBox WM_KILLFOCUS !\n");
1336 InvalidateRect(hwnd, NULL, TRUE);
1338 return 0;
1341 /***********************************************************************
1342 * LBResetContent
1344 static LONG LBResetContent(HWND hwnd, WORD wParam, LONG lParam)
1346 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1348 dprintf_listbox(stddeb,"ListBox LB_RESETCONTENT !\n");
1349 ListBoxResetContent(lphl);
1350 ListBoxUpdateWindow(hwnd, lphl, TRUE);
1351 return 0;
1354 /***********************************************************************
1355 * LBDir
1357 static LONG LBDir(HWND hwnd, WORD wParam, LONG lParam)
1359 WORD wRet;
1360 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1361 dprintf_listbox(stddeb,"ListBox LB_DIR !\n");
1363 wRet = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
1364 ListBoxUpdateWindow(hwnd, lphl, TRUE);
1365 return wRet;
1368 /***********************************************************************
1369 * LBAddString
1371 static LONG LBAddString(HWND hwnd, WORD wParam, LONG lParam)
1373 WORD wRet;
1374 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1376 if (lphl->HasStrings)
1377 wRet = ListBoxAddString(lphl, (LPSTR)PTR_SEG_TO_LIN(lParam));
1378 else
1379 wRet = ListBoxAddString(lphl, (LPSTR)lParam);
1381 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1382 return wRet;
1385 /***********************************************************************
1386 * LBGetText
1388 static LONG LBGetText(HWND hwnd, WORD wParam, LONG lParam)
1390 LONG wRet;
1391 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1393 dprintf_listbox(stddeb, "LB_GETTEXT wParam=%d\n",wParam);
1394 wRet = ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
1396 return wRet;
1399 /***********************************************************************
1400 * LBInsertString
1402 static LONG LBInsertString(HWND hwnd, WORD wParam, LONG lParam)
1404 WORD wRet;
1405 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1407 if (lphl->HasStrings)
1408 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
1409 else
1410 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)lParam);
1412 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1413 return wRet;
1416 /***********************************************************************
1417 * LBDeleteString
1419 static LONG LBDeleteString(HWND hwnd, WORD wParam, LONG lParam)
1421 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1422 LONG lRet = ListBoxDeleteString(lphl,wParam);
1424 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1425 return lRet;
1428 /***********************************************************************
1429 * LBFindString
1431 static LONG LBFindString(HWND hwnd, WORD wParam, LONG lParam)
1433 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1434 return ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
1437 /***********************************************************************
1438 * LBGetCaretIndex
1440 static LONG LBGetCaretIndex(HWND hwnd, WORD wParam, LONG lParam)
1442 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1443 return lphl->ItemFocused;
1446 /***********************************************************************
1447 * LBGetCount
1449 static LONG LBGetCount(HWND hwnd, WORD wParam, LONG lParam)
1451 LPHEADLIST lphl;
1453 lphl = ListBoxGetStorageHeader(hwnd);
1454 return lphl->ItemsCount;
1457 /***********************************************************************
1458 * LBGetCurSel
1460 static LONG LBGetCurSel(HWND hwnd, WORD wParam, LONG lParam)
1462 LPHEADLIST lphl;
1464 lphl = ListBoxGetStorageHeader(hwnd);
1465 dprintf_listbox(stddeb,"ListBox LB_GETCURSEL %u !\n",
1466 lphl->ItemFocused);
1467 return lphl->ItemFocused;
1470 /***********************************************************************
1471 * LBGetHorizontalExtent
1473 static LONG LBGetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam)
1475 return 0;
1478 /***********************************************************************
1479 * LBGetItemHeight
1481 static LONG LBGetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
1483 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1484 LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
1486 if (lpls == NULL) return LB_ERR;
1487 return lpls->mis.itemHeight;
1490 /***********************************************************************
1491 * LBGetItemRect
1493 static LONG LBGetItemRect(HWND hwnd, WORD wParam, LONG lParam)
1495 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1496 return ListBoxGetItemRect(lphl, wParam, PTR_SEG_TO_LIN(lParam));
1499 /***********************************************************************
1500 * LBGetSel
1502 static LONG LBGetSel(HWND hwnd, WORD wParam, LONG lParam)
1504 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1505 return (ListBoxGetSel(lphl, wParam) )? 1 : 0;
1508 /***********************************************************************
1509 * LBGetSelCount
1511 static LONG LBGetSelCount(HWND hwnd, WORD wParam, LONG lParam)
1513 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1514 LPLISTSTRUCT lpls;
1515 int cnt = 0;
1516 int items = 0;
1518 if (!(GetWindowLong(lphl->hSelf,GWL_STYLE) &
1519 (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
1520 return LB_ERR;
1522 for( lpls = lphl->lpFirst;
1523 lpls;
1524 lpls = lpls->lpNext )
1526 items++;
1527 if (lpls->itemState )
1528 cnt++;
1531 return cnt;
1534 /***********************************************************************
1535 * LBGetSelItems
1537 static LONG LBGetSelItems(HWND hwnd, WORD wParam, LONG lParam)
1539 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1540 LPLISTSTRUCT lpls;
1541 int cnt, idx;
1542 int *lpItems = PTR_SEG_TO_LIN(lParam);
1544 if (!(GetWindowLong(lphl->hSelf,GWL_STYLE) &
1545 (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
1546 return LB_ERR;
1548 if (wParam == 0) return 0;
1550 lpls = lphl->lpFirst;
1551 cnt = 0; idx = 0;
1553 while (lpls != NULL) {
1554 if (lpls->itemState > 0) lpItems[cnt++] = idx;
1556 if (cnt == wParam) break;
1557 idx++;
1558 lpls = lpls->lpNext;
1561 return cnt;
1564 /***********************************************************************
1565 * LBGetTextLen
1567 static LONG LBGetTextLen(HWND hwnd, WORD wParam, LONG lParam)
1569 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1570 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
1572 if (lpls == NULL || !lphl->HasStrings) return LB_ERR;
1573 return strlen(lpls->itemText);
1576 /***********************************************************************
1577 * LBGetDlgCode
1579 static LONG LBGetDlgCode(HWND hwnd, WORD wParam, LONG lParam)
1581 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1584 /***********************************************************************
1585 * LBGetTopIndex
1587 static LONG LBGetTopIndex(HWND hwnd, WORD wParam, LONG lParam)
1589 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1591 return lphl->FirstVisible;
1595 /***********************************************************************
1596 * LBSelectString
1598 static LONG LBSelectString(HWND hwnd, WORD wParam, LONG lParam)
1600 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1601 WORD wRet;
1603 wRet = ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
1605 /* XXX add functionality here */
1607 return 0;
1610 /***********************************************************************
1611 * LBSelItemRange
1613 static LONG LBSelItemRange(HWND hwnd, WORD wParam, LONG lParam)
1615 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1616 LPLISTSTRUCT lpls;
1617 WORD cnt;
1618 WORD first = LOWORD(lParam);
1619 WORD last = HIWORD(lParam);
1620 BOOL select = wParam;
1622 if (!(GetWindowLong(lphl->hSelf,GWL_STYLE) &
1623 (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
1624 return LB_ERR;
1626 if (first >= lphl->ItemsCount ||
1627 last >= lphl->ItemsCount) return LB_ERR;
1629 lpls = lphl->lpFirst;
1630 cnt = 0;
1632 while (lpls != NULL) {
1633 if (cnt++ >= first)
1634 lpls->itemState = select ? ODS_SELECTED : 0;
1636 if (cnt > last)
1637 break;
1639 lpls = lpls->lpNext;
1642 return 0;
1645 /***********************************************************************
1646 * LBSetCaretIndex
1648 static LONG LBSetCaretIndex(HWND hwnd, WORD wParam, LONG lParam)
1650 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1652 if (!(GetWindowLong(lphl->hSelf,GWL_STYLE) & LBS_MULTIPLESEL)) return 0;
1653 if (wParam >= lphl->ItemsCount) return LB_ERR;
1655 lphl->ItemFocused = wParam;
1656 ListBoxScrollToFocus (lphl);
1658 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1659 InvalidateRect(hwnd, NULL, TRUE);
1660 return 0;
1663 /***********************************************************************
1664 * LBSetColumnWidth
1666 static LONG LBSetColumnWidth(HWND hwnd, WORD wParam, LONG lParam)
1668 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1669 lphl->ColumnsWidth = wParam;
1670 InvalidateRect(hwnd,NULL,TRUE);
1671 return 0;
1674 /***********************************************************************
1675 * LBSetHorizontalExtent
1677 static LONG LBSetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam)
1679 return 0;
1682 /***********************************************************************
1683 * LBGetItemData
1685 static LONG LBGetItemData(HWND hwnd, WORD wParam, LONG lParam)
1687 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1688 dprintf_listbox(stddeb, "LB_GETITEMDATA wParam=%x\n", wParam);
1689 return ListBoxGetItemData(lphl, wParam);
1692 /***********************************************************************
1693 * LBSetItemData
1695 static LONG LBSetItemData(HWND hwnd, WORD wParam, LONG lParam)
1697 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1698 dprintf_listbox(stddeb, "LB_SETITEMDATA wParam=%x lParam=%lx\n", wParam, lParam);
1699 return ListBoxSetItemData(lphl, wParam, lParam);
1702 /***********************************************************************
1703 * LBSetTabStops
1705 static LONG LBSetTabStops(HWND hwnd, WORD wParam, LONG lParam)
1707 LPHEADLIST lphl;
1709 lphl = ListBoxGetStorageHeader(hwnd);
1711 if (lphl->TabStops != NULL) {
1712 lphl->iNumStops = 0;
1713 free (lphl->TabStops);
1716 lphl->TabStops = malloc (wParam * sizeof (short));
1717 if (lphl->TabStops) {
1718 lphl->iNumStops = wParam;
1719 memcpy (lphl->TabStops, PTR_SEG_TO_LIN(lParam), wParam * sizeof (short));
1720 return TRUE;
1723 return FALSE;
1726 /***********************************************************************
1727 * LBSetCurSel
1729 static LONG LBSetCurSel(HWND hwnd, WORD wParam, LONG lParam)
1731 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1732 WORD wRet;
1734 dprintf_listbox(stddeb,"ListBox LB_SETCURSEL wParam=%x !\n",
1735 wParam);
1737 wRet = ListBoxSetCurSel(lphl, wParam);
1739 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1740 InvalidateRect(hwnd, NULL, TRUE);
1742 return wRet;
1745 /***********************************************************************
1746 * LBSetSel
1748 static LONG LBSetSel(HWND hwnd, WORD wParam, LONG lParam)
1750 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1751 WORD wRet;
1753 dprintf_listbox(stddeb,"ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam, lParam);
1755 wRet = ListBoxSetSel(lphl, LOWORD(lParam), wParam);
1756 InvalidateRect(hwnd, NULL, TRUE);
1758 return wRet;
1761 /***********************************************************************
1762 * LBSetTopIndex
1764 static LONG LBSetTopIndex(HWND hwnd, WORD wParam, LONG lParam)
1766 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1768 dprintf_listbox(stddeb,"ListBox LB_SETTOPINDEX wParam=%x !\n",
1769 wParam);
1770 lphl->FirstVisible = wParam;
1771 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1773 InvalidateRect(hwnd, NULL, TRUE);
1775 return 0;
1778 /***********************************************************************
1779 * LBSetItemHeight
1781 static LONG LBSetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
1783 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1784 WORD wRet;
1786 dprintf_listbox(stddeb,"ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam, lParam);
1787 wRet = ListBoxSetItemHeight(lphl, wParam, lParam);
1788 InvalidateRect(hwnd,NULL,TRUE);
1789 return wRet;
1792 /***********************************************************************
1793 * LBPassToParent
1795 static LRESULT LBPassToParent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1797 WND* ptrWnd = WIN_FindWndPtr(hwnd);
1799 if( ptrWnd )
1800 if( /* !(ptrWnd->dwExStyle & WS_EX_NOPARENTNOTIFY) && */
1801 ptrWnd->hwndParent )
1802 return SendMessage(ptrWnd->hwndParent,message,wParam,lParam);
1803 return 0;
1806 /***********************************************************************
1807 * ListBoxWndProc
1809 LRESULT ListBoxWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1811 switch (message) {
1812 case WM_CREATE: return LBCreate(hwnd, wParam, lParam);
1813 case WM_DESTROY: return LBDestroy(hwnd, wParam, lParam);
1814 case WM_GETDLGCODE: return LBGetDlgCode(hwnd, wParam, lParam);
1815 case WM_VSCROLL: return LBVScroll(hwnd, wParam, lParam);
1816 case WM_HSCROLL: return LBHScroll(hwnd, wParam, lParam);
1817 case WM_LBUTTONDOWN: return LBLButtonDown(hwnd, wParam, lParam);
1818 case WM_LBUTTONUP: return LBLButtonUp(hwnd, wParam, lParam);
1819 case WM_RBUTTONUP: return LBRButtonUp(hwnd, wParam, lParam);
1820 case WM_LBUTTONDBLCLK: return LBRButtonUp(hwnd, wParam, lParam);
1821 case WM_MOUSEMOVE: return LBMouseMove(hwnd, wParam, lParam);
1822 case WM_KEYDOWN: return LBKeyDown(hwnd, wParam, lParam);
1823 case WM_CHAR: return LBChar(hwnd, wParam, lParam);
1824 case WM_SETFONT: return LBSetFont(hwnd, wParam, lParam);
1825 case WM_SETREDRAW: return LBSetRedraw(hwnd, wParam, lParam);
1826 case WM_PAINT: return LBPaint(hwnd, wParam, lParam);
1827 case WM_SETFOCUS: return LBSetFocus(hwnd, wParam, lParam);
1828 case WM_KILLFOCUS: return LBKillFocus(hwnd, wParam, lParam);
1829 case LB_RESETCONTENT: return LBResetContent(hwnd, wParam, lParam);
1830 case LB_DIR: return LBDir(hwnd, wParam, lParam);
1831 case LB_ADDSTRING: return LBAddString(hwnd, wParam, lParam);
1832 case LB_INSERTSTRING: return LBInsertString(hwnd, wParam, lParam);
1833 case LB_DELETESTRING: return LBDeleteString(hwnd, wParam, lParam);
1834 case LB_FINDSTRING: return LBFindString(hwnd, wParam, lParam);
1835 case LB_GETCARETINDEX: return LBGetCaretIndex(hwnd, wParam, lParam);
1836 case LB_GETCOUNT: return LBGetCount(hwnd, wParam, lParam);
1837 case LB_GETCURSEL: return LBGetCurSel(hwnd, wParam, lParam);
1838 case LB_GETHORIZONTALEXTENT: return LBGetHorizontalExtent(hwnd, wParam, lParam);
1839 case LB_GETITEMDATA: return LBGetItemData(hwnd, wParam, lParam);
1840 case LB_GETITEMHEIGHT: return LBGetItemHeight(hwnd, wParam, lParam);
1841 case LB_GETITEMRECT: return LBGetItemRect(hwnd, wParam, lParam);
1842 case LB_GETSEL: return LBGetSel(hwnd, wParam, lParam);
1843 case LB_GETSELCOUNT: return LBGetSelCount(hwnd, wParam, lParam);
1844 case LB_GETSELITEMS: return LBGetSelItems(hwnd, wParam, lParam);
1845 case LB_GETTEXT: return LBGetText(hwnd, wParam, lParam);
1846 case LB_GETTEXTLEN: return LBGetTextLen(hwnd, wParam, lParam);
1847 case LB_GETTOPINDEX: return LBGetTopIndex(hwnd, wParam, lParam);
1848 case LB_SELECTSTRING: return LBSelectString(hwnd, wParam, lParam);
1849 case LB_SELITEMRANGE: return LBSelItemRange(hwnd, wParam, lParam);
1850 case LB_SETCARETINDEX: return LBSetCaretIndex(hwnd, wParam, lParam);
1851 case LB_SETCOLUMNWIDTH: return LBSetColumnWidth(hwnd, wParam, lParam);
1852 case LB_SETHORIZONTALEXTENT: return LBSetHorizontalExtent(hwnd, wParam, lParam);
1853 case LB_SETITEMDATA: return LBSetItemData(hwnd, wParam, lParam);
1854 case LB_SETTABSTOPS: return LBSetTabStops(hwnd, wParam, lParam);
1855 case LB_SETCURSEL: return LBSetCurSel(hwnd, wParam, lParam);
1856 case LB_SETSEL: return LBSetSel(hwnd, wParam, lParam);
1857 case LB_SETTOPINDEX: return LBSetTopIndex(hwnd, wParam, lParam);
1858 case LB_SETITEMHEIGHT: return LBSetItemHeight(hwnd, wParam, lParam);
1860 case WM_DROPFILES: return LBPassToParent(hwnd, message, wParam, lParam);
1862 case WM_DROPOBJECT:
1863 case WM_QUERYDROPOBJECT:
1864 case WM_DRAGSELECT:
1865 case WM_DRAGMOVE:
1867 LPDRAGINFO lpDragInfo = (LPDRAGINFO) PTR_SEG_TO_LIN((SEGPTR)lParam);
1868 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1870 /* more undocumented Microsoft crap - drag&drop depends on it - AK */
1872 lpDragInfo->l = ListBoxFindMouse(lphl,lpDragInfo->pt.x,
1873 lpDragInfo->pt.y);
1875 return LBPassToParent(hwnd, message, wParam, lParam);
1879 return DefWindowProc(hwnd, message, wParam, lParam);
1882 /************************************************************************
1883 * DlgDirSelect [USER.99]
1885 BOOL DlgDirSelect(HWND hDlg, LPSTR lpStr, int nIDLBox)
1887 HWND hwnd;
1888 LPHEADLIST lphl;
1889 char s[130];
1891 dprintf_listbox( stddeb, "DlgDirSelect("NPFMT", '%s', %d) \n", hDlg, lpStr,
1892 nIDLBox );
1894 hwnd = GetDlgItem(hDlg, nIDLBox);
1895 lphl = ListBoxGetStorageHeader(hwnd);
1896 if(lphl->ItemFocused == -1) {
1897 dprintf_listbox(stddeb, "Nothing selected!\n");
1898 return FALSE;
1900 ListBoxGetText(lphl, lphl->ItemFocused, s);
1901 dprintf_listbox(stddeb, "Selection is %s\n", s);
1902 if( s[0] == '[' ) {
1903 if( s[1] == '-' ) {
1904 strncpy( lpStr, s+2, strlen(s)-4 ); /* device name */
1905 lpStr[ strlen(s)-4 ] = 0;
1906 strcat( lpStr, ":" );
1908 else {
1909 strncpy( lpStr, s+1, strlen(s)-2 ); /* directory name */
1910 lpStr[ strlen(s)-2 ] = 0;
1911 strcat( lpStr, "\\" );
1913 dprintf_listbox( stddeb, "Returning %s\n", lpStr );
1914 return TRUE;
1915 } else {
1916 strcpy( lpStr, s ); /* file name */
1917 dprintf_listbox( stddeb, "Returning %s\n", lpStr );
1918 return FALSE;
1923 /************************************************************************
1924 * DlgDirList [USER.100]
1926 int DlgDirList(HWND hDlg, LPSTR lpPathSpec,
1927 int nIDLBox, int nIDStat, WORD wType)
1929 HWND hWnd;
1930 int ret;
1932 dprintf_listbox(stddeb,"DlgDirList("NPFMT", '%s', %d, %d, %04X) \n",
1933 hDlg, lpPathSpec, nIDLBox, nIDStat, wType);
1934 if (nIDLBox) {
1935 LPHEADLIST lphl;
1936 hWnd = GetDlgItem(hDlg, nIDLBox);
1937 lphl = ListBoxGetStorageHeader(hWnd);
1938 ListBoxResetContent(lphl);
1939 ret = ListBoxDirectory(lphl, wType, lpPathSpec);
1940 ListBoxUpdateWindow(hWnd, lphl, TRUE);
1941 } else {
1942 ret = 0;
1944 if (nIDStat) {
1945 int drive;
1946 HANDLE hTemp;
1947 char *temp;
1948 drive = DOS_GetDefaultDrive();
1949 hTemp = USER_HEAP_ALLOC( 256 );
1950 temp = (char *) USER_HEAP_LIN_ADDR( hTemp );
1951 strcpy( temp+3, DOS_GetCurrentDir(drive) );
1952 if( temp[3] == '\\' ) {
1953 temp[1] = 'A'+drive;
1954 temp[2] = ':';
1955 SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
1956 (LPARAM)(USER_HEAP_SEG_ADDR(hTemp) + 1) );
1957 } else {
1958 temp[0] = 'A'+drive;
1959 temp[1] = ':';
1960 temp[2] = '\\';
1961 SendDlgItemMessage( hDlg, nIDStat, WM_SETTEXT, 0,
1962 (LPARAM)USER_HEAP_SEG_ADDR(hTemp) );
1964 USER_HEAP_FREE( hTemp );
1966 return ret;