Release 960728
[wine/multimedia.git] / controls / listbox.c
blob1cbb28c91c1a64fd056c6446cb55c54d925b1e57
1 /*
2 * Listbox controls
3 *
4 * Copyright Martin Ayotte, 1993
5 * Constantine Sapuntzakis, 1995
6 * Alex Korobka, 1995, 1996
7 *
8 */
11 * FIXME:
12 * - proper scrolling for multicolumn style
13 * - anchor and caret for LBS_EXTENDEDSEL
14 * - proper selection with keyboard
15 * - how to handle (LBS_EXTENDEDSEL | LBS_MULTIPLESEL) style
16 * - support for LBS_NOINTEGRALHEIGHT and LBS_OWNERDRAWVARIABLE styles
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include "windows.h"
24 #include "win.h"
25 #include "gdi.h"
26 #include "msdos.h"
27 #include "listbox.h"
28 #include "dos_fs.h"
29 #include "drive.h"
30 #include "file.h"
31 #include "heap.h"
32 #include "stackframe.h"
33 #include "stddebug.h"
34 #include "debug.h"
35 #include "xmalloc.h"
37 #define LIST_HEAP_ALLOC(lphl,f,size) \
38 LOCAL_Alloc( lphl->HeapSel, LMEM_FIXED, (size) )
39 #define LIST_HEAP_FREE(lphl,handle) \
40 LOCAL_Free( lphl->HeapSel, (handle) )
41 #define LIST_HEAP_ADDR(lphl,handle) \
42 ((handle) ? PTR_SEG_OFF_TO_LIN(lphl->HeapSel, (handle)) : NULL)
44 #define LIST_HEAP_SIZE 0x10000
46 #define LBMM_EDGE 4 /* distance inside box which is same as moving mouse
47 outside box, to trigger scrolling of LB */
49 #define MATCH_SUBSTR 2
50 #define MATCH_EXACT 1
51 #define MATCH_NEAREST 0
53 static void ListBoxInitialize(LPHEADLIST lphl)
55 lphl->lpFirst = NULL;
56 lphl->ItemsCount = 0;
57 lphl->ItemsVisible = 0;
58 lphl->FirstVisible = 0;
59 lphl->ColumnsVisible = 1;
60 lphl->ItemsPerColumn = 0;
61 lphl->ItemFocused = -1;
62 lphl->PrevFocused = -1;
65 void CreateListBoxStruct(HWND hwnd, WORD CtlType, LONG styles, HWND parent)
67 LPHEADLIST lphl;
68 HDC hdc;
70 lphl = (LPHEADLIST)xmalloc(sizeof(HEADLIST));
71 SetWindowLong32A(hwnd, 0, (LONG)lphl);
72 ListBoxInitialize(lphl);
73 lphl->DrawCtlType = CtlType;
74 lphl->CtlID = GetWindowWord(hwnd,GWW_ID);
75 lphl->bRedrawFlag = TRUE;
76 lphl->iNumStops = 0;
77 lphl->TabStops = NULL;
78 lphl->hFont = GetStockObject(SYSTEM_FONT);
79 lphl->hSelf = hwnd;
80 if (CtlType==ODT_COMBOBOX) /* use the "faked" style for COMBOLBOX */
81 /* LBS_SORT instead CBS_SORT e.g. */
82 lphl->dwStyle = MAKELONG(LOWORD(styles),HIWORD(GetWindowLong32A(hwnd,GWL_STYLE)));
83 else
84 lphl->dwStyle = GetWindowLong32A(hwnd,GWL_STYLE); /* use original style dword */
85 lphl->hParent = parent;
86 lphl->StdItemHeight = 15; /* FIXME: should get the font height */
87 lphl->OwnerDrawn = styles & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE);
88 lphl->HasStrings = (styles & LBS_HASSTRINGS) || !lphl->OwnerDrawn;
90 /* create dummy hdc to set text height */
91 if ((hdc = GetDC(0)))
93 TEXTMETRIC16 tm;
94 GetTextMetrics16( hdc, &tm );
95 lphl->StdItemHeight = tm.tmHeight;
96 dprintf_listbox(stddeb,"CreateListBoxStruct: font height %d\n",
97 lphl->StdItemHeight);
98 ReleaseDC( 0, hdc );
101 if (lphl->OwnerDrawn)
103 LISTSTRUCT dummyls;
105 lphl->needMeasure = TRUE;
106 dummyls.mis.CtlType = lphl->DrawCtlType;
107 dummyls.mis.CtlID = lphl->CtlID;
108 dummyls.mis.itemID = -1;
109 dummyls.mis.itemWidth = 0; /* ignored */
110 dummyls.mis.itemData = 0;
112 ListBoxAskMeasure(lphl,&dummyls);
115 lphl->HeapSel = GlobalAlloc16(GMEM_FIXED,LIST_HEAP_SIZE);
116 LocalInit( lphl->HeapSel, 0, LIST_HEAP_SIZE-1);
119 void DestroyListBoxStruct(LPHEADLIST lphl)
121 /* XXX need to free lphl->Heap */
122 GlobalFree16(lphl->HeapSel);
123 free(lphl);
126 static LPHEADLIST ListBoxGetStorageHeader(HWND hwnd)
128 return (LPHEADLIST)GetWindowLong32A(hwnd,0);
131 /* Send notification "code" as part of a WM_COMMAND-message if hwnd
132 has the LBS_NOTIFY style */
133 void ListBoxSendNotification(LPHEADLIST lphl, WORD code)
135 if (lphl->dwStyle & LBS_NOTIFY)
136 SendMessage32A( lphl->hParent, WM_COMMAND,
137 MAKEWPARAM( lphl->CtlID, code), (LPARAM)lphl->hSelf );
141 /* get the maximum value of lphl->FirstVisible */
142 int ListMaxFirstVisible(LPHEADLIST lphl)
144 int m = lphl->ItemsCount-lphl->ItemsVisible;
145 return (m < 0) ? 0 : m;
149 void ListBoxUpdateWindow(HWND hwnd, LPHEADLIST lphl, BOOL repaint)
151 if (lphl->dwStyle & WS_VSCROLL)
152 SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
153 if ((lphl->dwStyle & WS_HSCROLL) && (lphl->ItemsPerColumn != 0))
154 SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible /
155 lphl->ItemsPerColumn + 1, TRUE);
157 if (repaint && lphl->bRedrawFlag) InvalidateRect32( hwnd, NULL, TRUE );
160 /* Returns: 0 if nothing needs to be changed */
161 /* 1 if FirstVisible changed */
163 int ListBoxScrollToFocus(LPHEADLIST lphl)
165 short end;
167 if (lphl->ItemsCount == 0) return 0;
168 if (lphl->ItemFocused == -1) return 0;
170 end = lphl->FirstVisible + lphl->ItemsVisible - 1;
172 if (lphl->ItemFocused < lphl->FirstVisible ) {
173 lphl->FirstVisible = lphl->ItemFocused;
174 return 1;
175 } else {
176 if (lphl->ItemFocused > end) {
177 WORD maxFirstVisible = ListMaxFirstVisible(lphl);
179 lphl->FirstVisible = lphl->ItemFocused;
181 if (lphl->FirstVisible > maxFirstVisible) {
182 lphl->FirstVisible = maxFirstVisible;
184 return 1;
187 return 0;
191 LPLISTSTRUCT ListBoxGetItem(LPHEADLIST lphl, UINT uIndex)
193 LPLISTSTRUCT lpls;
194 UINT Count = 0;
196 if (uIndex >= lphl->ItemsCount) return NULL;
198 lpls = lphl->lpFirst;
199 while (Count++ < uIndex) lpls = lpls->lpNext;
200 return lpls;
204 void ListBoxDrawItem (HWND hwnd, LPHEADLIST lphl, HDC hdc, LPLISTSTRUCT lpls,
205 RECT16 *rect, WORD itemAction, WORD itemState)
207 if (lphl->OwnerDrawn)
209 DRAWITEMSTRUCT32 dis;
211 dis.CtlID = lpls->mis.CtlID;
212 dis.CtlType = lpls->mis.CtlType;
213 dis.itemID = lpls->mis.itemID;
214 dis.hDC = hdc;
215 dis.hwndItem = hwnd;
216 dis.itemData = lpls->mis.itemData;
217 dis.itemAction = itemAction;
218 dis.itemState = itemState;
219 CONV_RECT16TO32( rect, &dis.rcItem );
220 SendMessage32A( lphl->hParent, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis );
221 return;
223 if (itemAction == ODA_DRAWENTIRE || itemAction == ODA_SELECT) {
224 int OldBkMode;
225 DWORD dwOldTextColor = 0;
227 OldBkMode = SetBkMode(hdc, TRANSPARENT);
229 if (itemState != 0) {
230 dwOldTextColor = SetTextColor(hdc, 0x00FFFFFFL);
231 FillRect16(hdc, rect, GetStockObject(BLACK_BRUSH));
234 if (lphl->dwStyle & LBS_USETABSTOPS) {
235 TabbedTextOut(hdc, rect->left + 5, rect->top + 2,
236 (char *)lpls->itemText, strlen((char *)lpls->itemText),
237 lphl->iNumStops, lphl->TabStops, 0);
238 } else {
239 TextOut16(hdc, rect->left + 5, rect->top + 2,
240 (char *)lpls->itemText, strlen((char *)lpls->itemText));
243 if (itemState != 0) {
244 SetTextColor(hdc, dwOldTextColor);
247 SetBkMode(hdc, OldBkMode);
249 else DrawFocusRect16(hdc, rect);
253 int ListBoxFindMouse(LPHEADLIST lphl, int X, int Y)
255 LPLISTSTRUCT lpls = lphl->lpFirst;
256 int i, j;
257 POINT16 point;
259 point.x = X; point.y = Y;
260 if (lphl->ItemsCount == 0) return LB_ERR;
262 for(i = 0; i < lphl->FirstVisible; i++) {
263 if (lpls == NULL) return LB_ERR;
264 lpls = lpls->lpNext;
266 for(j = 0; j < lphl->ItemsVisible; i++, j++) {
267 if (lpls == NULL) return LB_ERR;
268 if (PtInRect16(&lpls->itemRect,point)) {
269 return i;
271 lpls = lpls->lpNext;
273 dprintf_listbox(stddeb,"ListBoxFindMouse: not found\n");
274 return LB_ERR;
277 BOOL lbDeleteItemNotify(LPHEADLIST lphl, LPLISTSTRUCT lpls)
279 /* called only for owner drawn listboxes */
281 DELETEITEMSTRUCT16 delItem;
283 delItem.CtlType = lphl->DrawCtlType;
284 delItem.CtlID = lphl->CtlID;
285 delItem.itemID = lpls->mis.itemID;
286 delItem.hwndItem= lphl->hSelf;
287 delItem.itemData= lpls->mis.itemData;
289 return (BOOL) SendMessage16(lphl->hParent, WM_DELETEITEM, (WPARAM)lphl->CtlID,
290 (LPARAM)MAKE_SEGPTR(&delItem));
293 void ListBoxAskMeasure(LPHEADLIST lphl, LPLISTSTRUCT lpls)
295 MEASUREITEMSTRUCT16 *lpmeasure = SEGPTR_NEW(MEASUREITEMSTRUCT16);
296 if (!lpmeasure) return;
297 *lpmeasure = lpls->mis;
298 lpmeasure->itemHeight = lphl->StdItemHeight;
299 SendMessage16( lphl->hParent, WM_MEASUREITEM, lphl->CtlID,
300 (LPARAM)SEGPTR_GET(lpmeasure) );
302 if (lphl->dwStyle & LBS_OWNERDRAWFIXED)
304 if (lpmeasure->itemHeight > lphl->StdItemHeight)
305 lphl->StdItemHeight = lpmeasure->itemHeight;
306 lpls->mis.itemHeight = lpmeasure->itemHeight;
308 SEGPTR_FREE(lpmeasure);
311 /* -------------------- strings and item data ---------------------- */
313 LPLISTSTRUCT ListBoxCreateItem(LPHEADLIST lphl, int id)
315 LPLISTSTRUCT lplsnew = (LPLISTSTRUCT)malloc(sizeof(LISTSTRUCT));
317 if (lplsnew == NULL) return NULL;
319 lplsnew->itemState = 0;
320 lplsnew->mis.CtlType = lphl->DrawCtlType;
321 lplsnew->mis.CtlID = lphl->CtlID;
322 lplsnew->mis.itemID = id;
323 lplsnew->mis.itemHeight = lphl->StdItemHeight;
324 lplsnew->mis.itemWidth = 0; /* ignored */
325 lplsnew->mis.itemData = 0;
326 SetRectEmpty16( &lplsnew->itemRect );
328 return lplsnew;
331 int ListBoxAskCompare(LPHEADLIST lphl, int startItem, SEGPTR matchData, BOOL exactMatch )
333 /* Do binary search for sorted listboxes. Linked list item storage sort of
334 * defeats the purpose ( forces to traverse item list all the time ) but M$ does it this way...
336 * MATCH_NEAREST (0) - return position for insertion - for all styles
337 * MATCH_EXACT (1) - search for an item, return index or LB_ERR
338 * MATCH_SUBSTR (2) - same as exact match but with strncmp for string comparision
341 COMPAREITEMSTRUCT16 itemCmp;
342 LPLISTSTRUCT currentItem = NULL;
343 LPCSTR matchStr = (lphl->HasStrings)?(LPCSTR)PTR_SEG_TO_LIN(matchData):NULL;
344 int head, pos = -1, tail, loop = 1;
345 short b = 0, s_length = 0;
347 /* check if empty */
349 if( !lphl->ItemsCount )
350 return (exactMatch)? LB_ERR: 0;
352 /* set up variables */
354 if( exactMatch == MATCH_NEAREST )
355 startItem = 0;
356 else if( ++startItem )
358 loop = 2;
359 if( startItem >= lphl->ItemsCount ) startItem = lphl->ItemsCount - 1;
362 if( exactMatch == MATCH_SUBSTR && lphl->HasStrings )
364 s_length = strlen( matchStr );
365 if( !s_length ) return 0; /* head of the list - empty string */
368 head = startItem; tail = lphl->ItemsCount - 1;
370 dprintf_listbox(stddeb,"AskCompare: head = %i, tail = %i, data = %08x\n", head, tail, (unsigned)matchData );
372 itemCmp.CtlType = lphl->DrawCtlType;
373 itemCmp.CtlID = lphl->CtlID;
374 itemCmp.hwndItem = lphl->hSelf;
376 /* search from startItem */
378 while ( loop-- )
380 while( head <= tail )
382 pos = (tail + head)/2;
383 currentItem = ListBoxGetItem( lphl, pos );
385 if( lphl->HasStrings )
387 b = ( s_length )? strncasecmp( currentItem->itemText, matchStr, s_length)
388 : strcasecmp( currentItem->itemText, matchStr);
390 else
392 itemCmp.itemID1 = pos;
393 itemCmp.itemData1 = currentItem->mis.itemData;
394 itemCmp.itemID2 = -1;
395 itemCmp.itemData2 = matchData;
397 b = SendMessage16( lphl->hParent, WM_COMPAREITEM, (WPARAM)lphl->CtlID,
398 (LPARAM)MAKE_SEGPTR(&itemCmp) );
401 if( b == 0 )
402 return pos; /* found exact match */
403 else
404 if( b < 0 ) head = ++pos;
405 else
406 if( b > 0 ) tail = pos - 1;
409 /* reset to search from the first item */
410 head = 0; tail = startItem - 1;
413 dprintf_listbox(stddeb,"\t-> pos = %i\n", pos );
415 /* if we got here match is not exact */
417 if( pos < 0 ) pos = 0;
418 else if( pos > lphl->ItemsCount ) pos = lphl->ItemsCount;
420 return (exactMatch)? LB_ERR: pos;
423 int ListBoxInsertString(LPHEADLIST lphl, UINT uIndex, LPCSTR newstr)
425 LPLISTSTRUCT *lppls, lplsnew, lpls;
426 HANDLE hStr;
427 LPSTR str;
428 UINT Count;
430 dprintf_listbox(stddeb,"ListBoxInsertString(%d, %p);\n", uIndex, newstr);
432 if (!newstr) return -1;
434 if (uIndex == (UINT)-1)
435 uIndex = lphl->ItemsCount;
437 lppls = &lphl->lpFirst;
438 for(Count = 0; Count < uIndex; Count++) {
439 if (*lppls == NULL) return LB_ERR;
440 lppls = (LPLISTSTRUCT *) &(*lppls)->lpNext;
443 lplsnew = ListBoxCreateItem(lphl, Count);
445 if (lplsnew == NULL) {
446 fprintf(stdnimp,"ListBoxInsertString() out of memory !\n");
447 return LB_ERRSPACE;
450 lplsnew->lpNext = *lppls;
451 *lppls = lplsnew;
452 lphl->ItemsCount++;
454 hStr = 0;
455 if (lphl->HasStrings) {
456 dprintf_listbox(stddeb," string: %s\n", newstr);
457 hStr = LIST_HEAP_ALLOC(lphl, LMEM_MOVEABLE, strlen(newstr) + 1);
458 str = (LPSTR)LIST_HEAP_ADDR(lphl, hStr);
459 if (str == NULL) return LB_ERRSPACE;
460 strcpy(str, newstr);
461 lplsnew->itemText = str;
462 /* I'm not so sure about the next one */
463 lplsnew->mis.itemData = 0;
464 } else {
465 lplsnew->itemText = NULL;
466 lplsnew->mis.itemData = (DWORD)newstr;
469 lplsnew->mis.itemID = uIndex;
470 lplsnew->hData = hStr;
472 /* adjust the itemID field of the following entries */
473 for(lpls = lplsnew->lpNext; lpls != NULL; lpls = lpls->lpNext) {
474 lpls->mis.itemID++;
477 if (lphl->needMeasure) {
478 ListBoxAskMeasure(lphl, lplsnew);
481 dprintf_listbox(stddeb,"ListBoxInsertString // count=%d\n", lphl->ItemsCount);
482 return uIndex;
486 int ListBoxAddString(LPHEADLIST lphl, SEGPTR itemData)
488 UINT pos = (UINT) -1;
489 LPCSTR newstr = (lphl->HasStrings)?(LPCSTR)PTR_SEG_TO_LIN(itemData):(LPCSTR)itemData;
491 if ( lphl->dwStyle & LBS_SORT )
492 pos = ListBoxAskCompare( lphl, -1, itemData, MATCH_NEAREST );
494 return ListBoxInsertString(lphl, pos, newstr);
498 int ListBoxGetText(LPHEADLIST lphl, UINT uIndex, LPSTR OutStr)
500 LPLISTSTRUCT lpls;
502 if (!OutStr) {
503 dprintf_listbox(stddeb, "ListBoxGetText // OutStr==NULL\n");
504 return 0;
506 *OutStr = '\0';
507 lpls = ListBoxGetItem (lphl, uIndex);
508 if (lpls == NULL) return LB_ERR;
510 if (!lphl->HasStrings) {
511 *((long *)OutStr) = lpls->mis.itemData;
512 return 4;
515 strcpy(OutStr, lpls->itemText);
516 return strlen(OutStr);
520 DWORD ListBoxGetItemData(LPHEADLIST lphl, UINT uIndex)
522 LPLISTSTRUCT lpls;
524 lpls = ListBoxGetItem (lphl, uIndex);
525 if (lpls == NULL) return LB_ERR;
526 return lpls->mis.itemData;
530 int ListBoxSetItemData(LPHEADLIST lphl, UINT uIndex, DWORD ItemData)
532 LPLISTSTRUCT lpls = ListBoxGetItem(lphl, uIndex);
534 if (lpls == NULL) return LB_ERR;
535 lpls->mis.itemData = ItemData;
536 return 1;
540 int ListBoxDeleteString(LPHEADLIST lphl, UINT uIndex)
542 LPLISTSTRUCT lpls, lpls2;
543 UINT Count;
545 if (uIndex >= lphl->ItemsCount) return LB_ERR;
547 lpls = lphl->lpFirst;
548 if (lpls == NULL) return LB_ERR;
550 if (uIndex == 0)
552 if( lphl->OwnerDrawn )
553 lbDeleteItemNotify( lphl, lpls);
554 lphl->lpFirst = lpls->lpNext;
556 else
558 LPLISTSTRUCT lpls2 = NULL;
559 for(Count = 0; Count < uIndex; Count++) {
560 if (lpls->lpNext == NULL) return LB_ERR;
562 lpls2 = lpls;
563 lpls = (LPLISTSTRUCT)lpls->lpNext;
565 if( lphl->OwnerDrawn )
566 lbDeleteItemNotify( lphl, lpls);
567 lpls2->lpNext = lpls->lpNext;
570 /* adjust the itemID field of the following entries */
571 for(lpls2 = lpls->lpNext; lpls2 != NULL; lpls2 = lpls2->lpNext) {
572 lpls2->mis.itemID--;
575 lphl->ItemsCount--;
577 if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
578 free(lpls);
580 return lphl->ItemsCount;
583 int lbFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr, BOOL match)
585 /* match is either MATCH_SUBSTR or MATCH_EXACT */
587 LPLISTSTRUCT lpls;
588 UINT Count;
589 UINT First = nFirst + 1;
590 int s_length = 0;
591 LPSTR lpMatchStr = (LPSTR)MatchStr;
593 if (First > lphl->ItemsCount) return LB_ERR;
595 if (lphl->dwStyle & LBS_SORT )
596 return ListBoxAskCompare( lphl, nFirst, MatchStr, match );
598 if (lphl->HasStrings )
600 lpMatchStr = PTR_SEG_TO_LIN(MatchStr);
602 if( match == MATCH_SUBSTR )
604 s_length = strlen(lpMatchStr);
605 if( !s_length ) return (lphl->ItemsCount)?0:LB_ERR;
609 lpls = ListBoxGetItem(lphl, First);
610 Count = 0;
611 while(lpls != NULL)
613 if (lphl->HasStrings)
615 if ( ( s_length )? !strncasecmp(lpls->itemText, lpMatchStr, s_length)
616 : !strcasecmp(lpls->itemText, lpMatchStr) ) return Count;
618 else
619 if ( lpls->mis.itemData == (DWORD)lpMatchStr ) return Count;
621 lpls = lpls->lpNext;
622 Count++;
625 /* Start over at top */
626 Count = 0;
627 lpls = lphl->lpFirst;
629 while (Count < First)
631 if (lphl->HasStrings)
633 if ( ( s_length )? !strncasecmp(lpls->itemText, lpMatchStr, s_length)
634 : !strcasecmp(lpls->itemText, lpMatchStr) ) return Count;
636 else
637 if ( lpls->mis.itemData == (DWORD)lpMatchStr ) return Count;
639 lpls = lpls->lpNext;
640 Count++;
643 return LB_ERR;
646 int ListBoxFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr)
648 return lbFindString(lphl, nFirst, MatchStr, MATCH_SUBSTR );
651 int ListBoxFindStringExact(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr)
653 return lbFindString(lphl, nFirst, MatchStr, MATCH_EXACT );
656 int ListBoxResetContent(LPHEADLIST lphl)
658 LPLISTSTRUCT lpls;
659 int i;
661 if (lphl->ItemsCount == 0) return 0;
663 dprintf_listbox(stddeb, "ListBoxResetContent // ItemCount = %d\n",
664 lphl->ItemsCount);
666 for(i = 0; i < lphl->ItemsCount; i++) {
667 lpls = lphl->lpFirst;
668 if (lpls == NULL) return LB_ERR;
670 if (lphl->OwnerDrawn) lbDeleteItemNotify(lphl, lpls);
672 lphl->lpFirst = lpls->lpNext;
673 if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
674 free(lpls);
676 ListBoxInitialize(lphl);
678 return TRUE;
681 /* --------------------- selection ------------------------- */
683 int ListBoxSetCurSel(LPHEADLIST lphl, WORD wIndex)
685 LPLISTSTRUCT lpls;
687 /* use ListBoxSetSel instead */
688 if (lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ) return 0;
690 /* unselect previous item */
691 if (lphl->ItemFocused != -1) {
692 lphl->PrevFocused = lphl->ItemFocused;
693 lpls = ListBoxGetItem(lphl, lphl->ItemFocused);
694 if (lpls == 0) return LB_ERR;
695 lpls->itemState = 0;
698 if ((wIndex != (UINT)-1) && (wIndex < lphl->ItemsCount))
700 lphl->ItemFocused = wIndex;
701 lpls = ListBoxGetItem(lphl, wIndex);
702 if (lpls == 0) return LB_ERR;
703 lpls->itemState = ODS_SELECTED | ODS_FOCUS;
705 return 0;
708 return LB_ERR;
712 int ListBoxSetSel(LPHEADLIST lphl, WORD wIndex, WORD state)
714 LPLISTSTRUCT lpls;
715 int n = 0;
717 if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
718 return LB_ERR;
720 if (wIndex == (UINT)-1) {
721 for (lpls = lphl->lpFirst; lpls != NULL; lpls = lpls->lpNext) {
722 if( lpls->itemState & ODS_SELECTED) n++;
723 lpls->itemState = state? lpls->itemState | ODS_SELECTED
724 : lpls->itemState & ~ODS_SELECTED;
726 return n;
729 if (wIndex >= lphl->ItemsCount) return LB_ERR;
731 lpls = ListBoxGetItem(lphl, wIndex);
732 lpls->itemState = state? lpls->itemState | ODS_SELECTED
733 : lpls->itemState & ~ODS_SELECTED;
735 return 0;
739 int ListBoxGetSel(LPHEADLIST lphl, WORD wIndex)
741 LPLISTSTRUCT lpls = ListBoxGetItem(lphl, wIndex);
743 if (lpls == NULL) return LB_ERR;
744 return lpls->itemState & ODS_SELECTED;
747 /* ------------------------- dir listing ------------------------ */
749 LONG ListBoxDirectory(LPHEADLIST lphl, UINT attrib, LPCSTR filespec)
751 char mask[13];
752 char* temp = NULL;
753 const char* ptr;
754 int skip, count;
755 LONG ret;
756 DOS_DIRENT entry;
757 char *path, *p;
759 dprintf_listbox(stddeb, "ListBoxDirectory: '%s' %04x\n", filespec, attrib);
760 if (!filespec) return LB_ERR;
761 if (!(ptr = DOSFS_GetUnixFileName( filespec, FALSE ))) return LB_ERR;
762 path = xstrdup(ptr);
763 p = strrchr( path, '/' );
764 *p++ = '\0';
765 if (!(ptr = DOSFS_ToDosFCBFormat( p )) ||
766 !(temp = SEGPTR_ALLOC( sizeof(char) * 16 )) )
768 free( path );
769 return LB_ERR;
772 strcpy( mask, ptr );
774 dprintf_listbox(stddeb, "ListBoxDirectory: path=%s mask=%s\n", path, mask);
776 skip = ret = 0;
777 attrib &= ~FA_LABEL;
778 while ((count = DOSFS_FindNext( path, mask, 0, attrib, skip, &entry )) > 0)
780 skip += count;
781 if (entry.attr & FA_DIRECTORY)
783 if ((attrib & DDL_DIRECTORY) && strcmp(entry.name, ". "))
785 sprintf(temp, "[%s]", DOSFS_ToDosDTAFormat( entry.name ) );
786 AnsiLower( temp );
787 if ((ret = ListBoxAddString(lphl, SEGPTR_GET(temp))) == LB_ERR) break;
790 else /* not a directory */
792 if (!(attrib & DDL_EXCLUSIVE) ||
793 ((attrib & (FA_RDONLY|FA_HIDDEN|FA_SYSTEM|FA_ARCHIVE)) ==
794 (entry.attr & (FA_RDONLY|FA_HIDDEN|FA_SYSTEM|FA_ARCHIVE))))
796 strcpy( temp, DOSFS_ToDosDTAFormat( entry.name ) );
797 AnsiLower( temp );
798 if ((ret = ListBoxAddString(lphl, SEGPTR_GET(temp))) == LB_ERR) break;
802 dprintf_listbox(stddeb,"\tn - %i, file '%s'\n", count, temp);
804 if (attrib & DDL_DRIVES)
806 int x;
807 strcpy( temp, "[-a-]" );
808 for (x = 0; x < MAX_DOS_DRIVES; x++, temp[2]++)
810 if (DRIVE_IsValid(x))
811 if ((ret = ListBoxAddString(lphl, SEGPTR_GET(temp))) == LB_ERR) break;
815 free( path );
816 SEGPTR_FREE( temp );
818 return ret;
821 /* ------------------------- dimensions ------------------------- */
823 int ListBoxGetItemRect(LPHEADLIST lphl, WORD wIndex, LPRECT16 lprect)
825 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wIndex);
827 if (lpls == NULL) return LB_ERR;
828 *lprect = lpls->itemRect;
829 return 0;
833 int ListBoxSetItemHeight(LPHEADLIST lphl, WORD wIndex, long height)
835 LPLISTSTRUCT lpls;
837 if (!(lphl->dwStyle & LBS_OWNERDRAWVARIABLE)) {
838 lphl->StdItemHeight = (short)height;
839 return 0;
842 lpls = ListBoxGetItem(lphl, wIndex);
843 if (lpls == NULL) return LB_ERR;
845 lpls->mis.itemHeight = height;
846 return 0;
849 /* -------------------------- string search ------------------------ */
851 int ListBoxFindNextMatch(LPHEADLIST lphl, WORD wChar)
853 LPLISTSTRUCT lpls;
854 UINT count,first;
856 if ((char)wChar < ' ') return LB_ERR;
857 if (!lphl->HasStrings) return LB_ERR;
859 lpls = lphl->lpFirst;
861 for (count = 0; lpls != NULL; lpls = lpls->lpNext, count++) {
862 if (tolower(*lpls->itemText) == tolower((char)wChar)) break;
864 if (lpls == NULL) return LB_ERR;
865 first = count;
866 for(; lpls != NULL; lpls = lpls->lpNext, count++) {
867 if (*lpls->itemText != (char)wChar)
868 break;
869 if ((short) count > lphl->ItemFocused)
870 return count;
872 return first;
875 /***********************************************************************
876 * LBCreate
878 static LONG LBCreate(HWND hwnd, WORD wParam, LONG lParam)
880 LPHEADLIST lphl;
881 LONG dwStyle = GetWindowLong32A(hwnd,GWL_STYLE);
882 RECT16 rect;
884 CreateListBoxStruct(hwnd, ODT_LISTBOX, dwStyle, GetParent(hwnd));
885 lphl = ListBoxGetStorageHeader(hwnd);
886 dprintf_listbox(stddeb,"ListBox created: lphl = %p dwStyle = %04x:%04x\n",
887 lphl, HIWORD(dwStyle), LOWORD(dwStyle));
889 GetClientRect16(hwnd,&rect);
890 lphl->ColumnsWidth = rect.right - rect.left;
892 if (dwStyle & WS_VSCROLL)
893 SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
894 if (dwStyle & WS_HSCROLL)
895 SetScrollRange(hwnd, SB_HORZ, 1, 1, TRUE);
897 return 0;
901 /***********************************************************************
902 * LBDestroy
904 static LONG LBDestroy(HWND hwnd, WORD wParam, LONG lParam)
906 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
908 ListBoxResetContent(lphl);
910 DestroyListBoxStruct(lphl);
911 dprintf_listbox(stddeb,"ListBox destroyed: lphl = %p\n",lphl);
912 return 0;
915 /***********************************************************************
916 * LBVScroll
918 static LONG LBVScroll(HWND hwnd, WORD wParam, LONG lParam)
920 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
921 int y;
923 dprintf_listbox(stddeb,"ListBox WM_VSCROLL w=%04X l=%08lX !\n",
924 wParam, lParam);
925 y = lphl->FirstVisible;
927 switch(wParam) {
928 case SB_LINEUP:
929 if (lphl->FirstVisible > 0)
930 lphl->FirstVisible--;
931 break;
933 case SB_LINEDOWN:
934 lphl->FirstVisible++;
935 break;
937 case SB_PAGEUP:
938 if (lphl->FirstVisible > lphl->ItemsVisible) {
939 lphl->FirstVisible -= lphl->ItemsVisible;
940 } else {
941 lphl->FirstVisible = 0;
943 break;
945 case SB_PAGEDOWN:
946 lphl->FirstVisible += lphl->ItemsVisible;
947 break;
949 case SB_THUMBTRACK:
950 lphl->FirstVisible = LOWORD(lParam);
951 break;
954 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
955 lphl->FirstVisible = ListMaxFirstVisible(lphl);
957 if (y != lphl->FirstVisible) {
958 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
959 InvalidateRect32( hwnd, NULL, TRUE );
961 return 0;
964 /***********************************************************************
965 * LBHScroll
967 static LONG LBHScroll(HWND hwnd, WORD wParam, LONG lParam)
969 LPHEADLIST lphl;
970 int y;
972 dprintf_listbox(stddeb,"ListBox WM_HSCROLL w=%04X l=%08lX !\n",
973 wParam, lParam);
974 lphl = ListBoxGetStorageHeader(hwnd);
975 y = lphl->FirstVisible;
976 switch(wParam) {
977 case SB_LINEUP:
978 if (lphl->FirstVisible > lphl->ItemsPerColumn) {
979 lphl->FirstVisible -= lphl->ItemsPerColumn;
980 } else {
981 lphl->FirstVisible = 0;
983 break;
984 case SB_LINEDOWN:
985 lphl->FirstVisible += lphl->ItemsPerColumn;
986 break;
987 case SB_PAGEUP:
988 if (lphl->ItemsPerColumn != 0) {
989 int lbsub = lphl->ItemsVisible / lphl->ItemsPerColumn * lphl->ItemsPerColumn;
990 if (lphl->FirstVisible > lbsub) {
991 lphl->FirstVisible -= lbsub;
992 } else {
993 lphl->FirstVisible = 0;
996 break;
997 case SB_PAGEDOWN:
998 if (lphl->ItemsPerColumn != 0)
999 lphl->FirstVisible += lphl->ItemsVisible /
1000 lphl->ItemsPerColumn * lphl->ItemsPerColumn;
1001 break;
1002 case SB_THUMBTRACK:
1003 lphl->FirstVisible = lphl->ItemsPerColumn * LOWORD(lParam);
1004 break;
1006 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
1007 lphl->FirstVisible = ListMaxFirstVisible(lphl);
1009 if (lphl->ItemsPerColumn != 0) {
1010 lphl->FirstVisible = lphl->FirstVisible /
1011 lphl->ItemsPerColumn * lphl->ItemsPerColumn + 1;
1012 if (y != lphl->FirstVisible) {
1013 SetScrollPos(hwnd, SB_HORZ, lphl->FirstVisible /
1014 lphl->ItemsPerColumn + 1, TRUE);
1015 InvalidateRect32( hwnd, NULL, TRUE );
1018 return 0;
1021 /***********************************************************************
1022 * LBLButtonDown
1024 static LONG LBLButtonDown(HWND hwnd, WORD wParam, LONG lParam)
1026 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1027 WORD wRet;
1028 int y,n;
1029 RECT16 rectsel;
1031 SetFocus(hwnd);
1032 SetCapture(hwnd);
1034 lphl->PrevFocused = lphl->ItemFocused;
1036 y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
1038 if (y == -1) return 0;
1040 if (lphl->dwStyle & LBS_NOTIFY && y!= LB_ERR )
1041 if( SendMessage16(lphl->hParent, WM_LBTRACKPOINT, y, lParam) )
1042 return 0;
1045 switch( lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) )
1047 case LBS_MULTIPLESEL:
1048 lphl->ItemFocused = y;
1049 wRet = ListBoxGetSel(lphl, y);
1050 ListBoxSetSel(lphl, y, !wRet);
1051 break;
1052 case LBS_EXTENDEDSEL:
1053 /* should handle extended mode here and in kbd handler
1056 if ( lphl->PrevFocused != y && y!= LB_ERR)
1058 LPLISTSTRUCT lpls = ListBoxGetItem( lphl, lphl->ItemFocused = y );
1059 n = ListBoxSetSel(lphl,-1,FALSE);
1061 lpls->itemState = ODS_FOCUS | ODS_SELECTED;
1063 if( n > 1 && n != LB_ERR )
1064 InvalidateRect32( hwnd,NULL,TRUE );
1066 else
1067 return 0;
1069 break;
1070 case 0:
1071 if( y!=lphl->ItemFocused )
1072 ListBoxSetCurSel(lphl, y);
1073 else
1074 return 0;
1075 break;
1076 default:
1077 fprintf(stdnimp,"Listbox: LBS_MULTIPLESEL and LBS_EXTENDEDSEL are on!\n");
1078 return 0;
1081 /* invalidate changed items */
1082 if( lphl->dwStyle & LBS_MULTIPLESEL || y!=lphl->PrevFocused )
1084 ListBoxGetItemRect(lphl, y, &rectsel);
1085 InvalidateRect16( hwnd, &rectsel, TRUE );
1087 if( lphl->PrevFocused!=-1 && y!=lphl->PrevFocused )
1089 ListBoxGetItemRect(lphl, lphl->PrevFocused, &rectsel);
1090 InvalidateRect16( hwnd, &rectsel, TRUE );
1093 if (GetWindowLong32A(lphl->hSelf,GWL_EXSTYLE) & WS_EX_DRAGDETECT)
1094 if( DragDetect(lphl->hSelf,MAKEPOINT16(lParam)) )
1095 SendMessage16(lphl->hParent, WM_BEGINDRAG,0,0L);
1096 return 0;
1099 /***********************************************************************
1100 * LBLButtonUp
1102 static LONG LBLButtonUp(HWND hwnd, WORD wParam, LONG lParam)
1104 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1106 if (GetCapture() == hwnd) ReleaseCapture();
1108 if (lphl->PrevFocused != lphl->ItemFocused)
1109 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1111 return 0;
1114 /***********************************************************************
1115 * LBRButtonUp
1117 static LONG LBRButtonUp(HWND hwnd, WORD wParam, LONG lParam)
1119 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1121 SendMessage16(lphl->hParent, WM_COMMAND, GetWindowWord(hwnd,GWW_ID),
1122 MAKELONG(hwnd, LBN_DBLCLK));
1123 return 0;
1126 /***********************************************************************
1127 * LBMouseMove
1129 static LONG LBMouseMove(HWND hwnd, WORD wParam, LONG lParam)
1131 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1132 int y,redraw_prev = 0;
1133 int iRet;
1134 RECT16 rect, rectsel; /* XXX Broken */
1136 dprintf_listbox(stddeb,"LBMouseMove %d %d\n",SLOWORD(lParam),SHIWORD(lParam));
1137 if ((wParam & MK_LBUTTON) != 0) {
1138 y = SHIWORD(lParam);
1139 if (y < LBMM_EDGE) {
1140 if (lphl->FirstVisible > 0) {
1141 lphl->FirstVisible--;
1142 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1143 InvalidateRect32( hwnd, NULL, TRUE );
1144 return 0;
1147 GetClientRect16(hwnd, &rect);
1148 if (y >= (rect.bottom-LBMM_EDGE)) {
1149 if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
1150 lphl->FirstVisible++;
1151 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1152 InvalidateRect32( hwnd, NULL, TRUE );
1153 return 0;
1156 if ((y > 0) && (y < (rect.bottom - LBMM_EDGE))) {
1157 if ((y < rectsel.top) || (y > rectsel.bottom)) {
1158 iRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
1159 if (iRet == lphl->ItemFocused || iRet == -1) {
1160 return 0;
1162 if (lphl->dwStyle & LBS_MULTIPLESEL) {
1163 lphl->ItemFocused = iRet;
1164 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1165 } else if ( lphl->dwStyle & LBS_EXTENDEDSEL )
1167 /* Fixme: extended selection mode */
1168 ListBoxSetSel( lphl, lphl->ItemFocused, 0);
1169 lphl->PrevFocused = lphl->ItemFocused;
1170 lphl->ItemFocused = iRet;
1171 ListBoxSetSel( lphl, iRet, TRUE);
1172 redraw_prev = 1;
1174 else
1176 ListBoxSetCurSel(lphl, (WORD)iRet);
1177 redraw_prev = 1;
1179 if( lphl->PrevFocused!=-1 && redraw_prev )
1181 ListBoxGetItemRect(lphl, lphl->PrevFocused, &rectsel);
1182 InvalidateRect16( hwnd, &rectsel, TRUE );
1184 ListBoxGetItemRect(lphl, iRet, &rectsel);
1185 InvalidateRect16( hwnd, &rectsel, TRUE );
1190 return 0;
1193 /***********************************************************************
1194 * LBKeyDown
1196 * Doesn't yet handle properly VK_SHIFT with LB_EXTENDEDSEL
1198 static LONG LBKeyDown(HWND hwnd, WORD wParam, LONG lParam)
1200 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1201 WORD newFocused = 0xFFFF;
1202 RECT16 rect;
1204 ListBoxGetItemRect(lphl,lphl->ItemFocused,&rect);
1205 switch(wParam)
1207 case VK_HOME:
1208 case VK_END:
1209 case VK_LEFT:
1210 case VK_RIGHT:
1211 case VK_UP:
1212 case VK_DOWN:
1213 case VK_PRIOR:
1214 case VK_NEXT:
1215 if ( lphl->dwStyle & LBS_WANTKEYBOARDINPUT )
1217 newFocused = (WORD)(INT)SendMessage16(lphl->hParent,WM_VKEYTOITEM,
1218 wParam,MAKELPARAM(lphl->ItemFocused,hwnd));
1219 if ( newFocused == 0xFFFE ) return 0L;
1221 if ( newFocused == 0xFFFF )
1223 newFocused = lphl->ItemFocused;
1225 /* nested switch */
1226 switch(wParam)
1228 case VK_HOME:
1229 newFocused = 0;
1230 break;
1231 case VK_END:
1232 newFocused = lphl->ItemsCount - 1;
1233 break;
1234 case VK_LEFT:
1235 if (lphl->dwStyle & LBS_MULTICOLUMN) {
1236 if (newFocused >= lphl->ItemsPerColumn) {
1237 newFocused -= lphl->ItemsPerColumn;
1238 } else {
1239 newFocused = 0;
1242 break;
1243 case VK_UP:
1244 if (newFocused > 0) newFocused--;
1245 break;
1246 case VK_RIGHT:
1247 if (lphl->dwStyle & LBS_MULTICOLUMN)
1248 newFocused += lphl->ItemsPerColumn;
1249 break;
1250 case VK_DOWN:
1251 newFocused++;
1252 break;
1253 case VK_PRIOR:
1254 if (newFocused > lphl->ItemsVisible)
1255 newFocused -= lphl->ItemsVisible;
1256 else newFocused = 0;
1257 break;
1258 case VK_NEXT:
1259 newFocused += lphl->ItemsVisible;
1260 break;
1261 default:
1262 return 0;
1264 /* end of nested switch */
1266 break;
1267 case VK_SPACE:
1268 if (lphl->dwStyle & LBS_MULTIPLESEL)
1270 WORD wRet = ListBoxGetSel(lphl, lphl->ItemFocused);
1271 ListBoxSetSel(lphl, lphl->ItemFocused, !wRet);
1273 return 0;
1275 /* chars are handled in LBChar */
1276 default:
1277 return 0;
1280 /* at this point newFocused is set up */
1282 if (newFocused >= lphl->ItemsCount)
1283 newFocused = lphl->ItemsCount - 1;
1285 if (!(lphl->dwStyle & LBS_MULTIPLESEL))
1287 ListBoxSetCurSel(lphl, newFocused);
1288 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1291 lphl->ItemFocused = newFocused;
1293 if( ListBoxScrollToFocus(lphl) || (lphl->dwStyle &
1294 (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) )
1295 InvalidateRect32( hwnd, NULL, TRUE );
1296 else
1298 InvalidateRect16( hwnd, &rect, TRUE );
1299 if( newFocused < 0x8000 )
1301 ListBoxGetItemRect(lphl, newFocused, &rect);
1302 InvalidateRect16( hwnd, &rect, TRUE );
1306 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1308 return 0;
1311 /***********************************************************************
1312 * LBChar
1314 static LONG LBChar(HWND hwnd, WORD wParam, LONG lParam)
1316 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1317 WORD newFocused = 0xFFFF;
1319 if ( (lphl->dwStyle & LBS_WANTKEYBOARDINPUT) && !(lphl->HasStrings))
1321 newFocused = (WORD)(INT)SendMessage16(lphl->hParent,WM_CHARTOITEM,
1322 wParam,MAKELPARAM(lphl->ItemFocused,hwnd));
1323 if ( newFocused == 0xFFFE ) return 0L;
1326 if (newFocused == 0xFFFF )
1327 newFocused = ListBoxFindNextMatch(lphl, wParam);
1329 if (newFocused == (WORD)LB_ERR) return 0;
1331 if (newFocused >= lphl->ItemsCount)
1332 newFocused = lphl->ItemsCount - 1;
1334 if (!(lphl->dwStyle & LBS_MULTIPLESEL))
1336 ListBoxSetCurSel(lphl, newFocused);
1337 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1340 lphl->ItemFocused = newFocused;
1341 ListBoxScrollToFocus(lphl);
1342 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1344 InvalidateRect32( hwnd, NULL, TRUE );
1346 return 0;
1349 /***********************************************************************
1350 * LBSetRedraw
1352 static LONG LBSetRedraw(HWND hwnd, WORD wParam, LONG lParam)
1354 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1356 dprintf_listbox(stddeb,"ListBox WM_SETREDRAW hWnd=%04x w=%04x !\n",
1357 hwnd, wParam);
1358 lphl->bRedrawFlag = wParam;
1360 return 0;
1363 /***********************************************************************
1364 * LBSetFont
1366 static LONG LBSetFont(HWND hwnd, WPARAM wParam, LPARAM lParam)
1368 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1369 HDC hdc;
1371 if (wParam == 0)
1372 lphl->hFont = GetStockObject(SYSTEM_FONT);
1373 else
1374 lphl->hFont = (HFONT) wParam;
1376 /* a new font means possible new text height */
1377 /* does this mean the height of each entry must be separately changed? */
1378 /* or are we guaranteed to get a LBSetFont before the first insert/add? */
1379 if ((hdc = GetDC(0)))
1381 TEXTMETRIC16 tm;
1382 GetTextMetrics16( hdc, &tm );
1383 lphl->StdItemHeight = tm.tmHeight;
1384 dprintf_listbox(stddeb,"LBSetFont: new font %d with height %d\n",
1385 lphl->hFont, lphl->StdItemHeight);
1386 ReleaseDC( 0, hdc );
1389 return 0;
1392 /***********************************************************************
1393 * LBPaint
1395 static LONG LBPaint(HWND hwnd, WORD wParam, LONG lParam)
1397 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1398 LPLISTSTRUCT lpls;
1399 PAINTSTRUCT16 ps;
1400 HBRUSH hBrush;
1401 HFONT hOldFont;
1402 HDC16 hdc = BeginPaint16( hwnd, &ps );
1403 DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC);
1404 RECT16 rect, paintRect, scratchRect;
1405 int i, top, height, maxwidth, ipc;
1407 top = 0;
1409 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) {
1410 EndPaint16(hwnd, &ps);
1411 return 0;
1414 GetRgnBox16(dc->w.hGCClipRgn,&paintRect);
1415 GetClientRect16(hwnd, &rect);
1416 IntersectRect16(&paintRect,&rect,&paintRect);
1418 hOldFont = SelectObject(hdc, lphl->hFont);
1420 hBrush = (HBRUSH)SendMessage32A( lphl->hParent, WM_CTLCOLORLISTBOX,
1421 (WPARAM)hdc, (LPARAM)hwnd);
1422 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
1424 FillRect16(hdc, &rect, hBrush);
1426 maxwidth = rect.right;
1427 if (lphl->dwStyle & LBS_MULTICOLUMN) {
1428 rect.right = lphl->ColumnsWidth;
1430 lpls = lphl->lpFirst;
1432 lphl->ItemsVisible = 0;
1433 lphl->ItemsPerColumn = ipc = 0;
1435 for(i = 0; i < lphl->ItemsCount; i++) {
1436 if (lpls == NULL) break;
1438 if (i >= lphl->FirstVisible) {
1439 height = lpls->mis.itemHeight;
1441 if (top > (rect.bottom-height+1)) {
1442 if (lphl->dwStyle & LBS_MULTICOLUMN) {
1443 lphl->ItemsPerColumn = MAX(lphl->ItemsPerColumn, ipc);
1444 ipc = 0;
1445 top = 0;
1446 rect.left += lphl->ColumnsWidth;
1447 rect.right += lphl->ColumnsWidth;
1448 if (rect.left > maxwidth) break;
1449 } else {
1450 break;
1454 lpls->itemRect.top = top;
1455 lpls->itemRect.bottom = top + height;
1456 lpls->itemRect.left = rect.left;
1457 lpls->itemRect.right = rect.right;
1459 if( IntersectRect16(&scratchRect,&paintRect,&lpls->itemRect) )
1461 dprintf_listbox(stddeb,"LBPaint: drawing item: %d %d %d %d %d\n",
1462 rect.left,top,rect.right,top+height,lpls->itemState);
1464 if (lphl->OwnerDrawn && (lphl->ItemFocused == i) && GetFocus() == hwnd)
1466 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS,
1467 lpls->itemState & ~ODS_FOCUS);
1468 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
1469 lpls->itemState & ~ODS_FOCUS);
1470 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, lpls->itemState);
1472 else
1473 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
1474 lpls->itemState);
1477 top += height;
1478 lphl->ItemsVisible++;
1479 ipc++;
1482 lpls = lpls->lpNext;
1484 ListBoxUpdateWindow(hwnd,lphl,FALSE);
1485 SelectObject(hdc,hOldFont);
1486 EndPaint16( hwnd, &ps );
1487 return 0;
1490 /***********************************************************************
1491 * LBSetFocus
1493 static LONG LBSetFocus(HWND hwnd, WORD wParam, LONG lParam)
1495 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1497 dprintf_listbox(stddeb,"ListBox WM_SETFOCUS for %04x\n",hwnd);
1498 if(!(lphl->dwStyle & LBS_MULTIPLESEL) )
1499 if( lphl->ItemsCount && lphl->ItemFocused != -1)
1501 HDC hDC = GetDC(hwnd);
1502 HFONT hOldFont = SelectObject(hDC, lphl->hFont);
1503 LPLISTSTRUCT lpls;
1505 lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
1506 lpls->itemState |= ODS_FOCUS;
1508 ListBoxDrawItem(hwnd,lphl,hDC,lpls,&lpls->itemRect, ODA_FOCUS, lpls->itemState);
1509 SelectObject(hDC, hOldFont);
1510 ReleaseDC(hwnd,hDC);
1513 ListBoxSendNotification(lphl, LBN_SETFOCUS);
1515 return 0;
1518 /***********************************************************************
1519 * LBKillFocus
1521 static LONG LBKillFocus(HWND hwnd, WORD wParam, LONG lParam)
1523 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1525 dprintf_listbox(stddeb,"ListBox WM_KILLFOCUS for %04x\n",hwnd);
1526 if (!(lphl->dwStyle & LBS_MULTIPLESEL))
1528 if( lphl->ItemsCount )
1529 if( lphl->ItemFocused != -1 )
1531 HDC hDC = GetDC(hwnd);
1532 HFONT hOldFont = SelectObject(hDC, lphl->hFont);
1533 LPLISTSTRUCT lpls;
1535 lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
1536 lpls->itemState &= ~ODS_FOCUS;
1538 ListBoxDrawItem(hwnd,lphl,hDC,lpls,&lpls->itemRect, ODA_FOCUS, lpls->itemState);
1539 SelectObject(hDC, hOldFont);
1540 ReleaseDC(hwnd,hDC);
1542 else
1543 dprintf_listbox(stddeb,"LBKillFocus: no focused item!\n");
1545 else
1546 InvalidateRect32( hwnd, NULL, TRUE );
1548 ListBoxSendNotification(lphl, LBN_KILLFOCUS);
1550 return 0;
1553 /***********************************************************************
1554 * LBResetContent
1556 static LONG LBResetContent(HWND hwnd, WORD wParam, LONG lParam)
1558 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1560 dprintf_listbox(stddeb,"ListBox LB_RESETCONTENT !\n");
1561 ListBoxResetContent(lphl);
1562 ListBoxUpdateWindow(hwnd, lphl, TRUE);
1563 return 0;
1566 /***********************************************************************
1567 * LBDir
1569 static LONG LBDir(HWND hwnd, WORD wParam, LONG lParam)
1571 LONG ret;
1572 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1573 dprintf_listbox(stddeb,"ListBox LB_DIR !\n");
1575 ret = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
1576 ListBoxUpdateWindow(hwnd, lphl, TRUE);
1577 return ret;
1580 /***********************************************************************
1581 * LBAddString
1583 static LONG LBAddString(HWND hwnd, WORD wParam, LONG lParam)
1585 WORD wRet;
1586 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1588 wRet = ListBoxAddString(lphl, (SEGPTR)lParam);
1590 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1591 return wRet;
1594 /***********************************************************************
1595 * LBGetText
1597 static LONG LBGetText(HWND hwnd, WORD wParam, LONG lParam)
1599 LONG wRet;
1600 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1602 dprintf_listbox(stddeb, "LB_GETTEXT wParam=%d\n",wParam);
1603 wRet = ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
1605 return wRet;
1608 /***********************************************************************
1609 * LBInsertString
1611 static LONG LBInsertString(HWND hwnd, WORD wParam, LONG lParam)
1613 WORD wRet;
1614 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1616 if (lphl->HasStrings)
1617 wRet = ListBoxInsertString(lphl, wParam, (LPCSTR)PTR_SEG_TO_LIN(lParam));
1618 else
1619 wRet = ListBoxInsertString(lphl, wParam, (LPCSTR)lParam);
1621 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1622 return wRet;
1625 /***********************************************************************
1626 * LBDeleteString
1628 static LONG LBDeleteString(HWND hwnd, WORD wParam, LONG lParam)
1630 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1631 LONG lRet = ListBoxDeleteString(lphl,wParam);
1633 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1634 return lRet;
1637 /***********************************************************************
1638 * LBFindString
1640 static LONG LBFindString(HWND hwnd, WORD wParam, LONG lParam)
1642 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1643 return lbFindString(lphl, wParam, (SEGPTR)lParam, MATCH_SUBSTR);
1646 /***********************************************************************
1647 * LBFindStringExact
1649 static LONG LBFindStringExact(HWND hwnd, WORD wParam, LONG lParam)
1651 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1652 return lbFindString(lphl, wParam, (SEGPTR)lParam, MATCH_EXACT);
1655 /***********************************************************************
1656 * LBGetCaretIndex
1658 static LONG LBGetCaretIndex(HWND hwnd, WORD wParam, LONG lParam)
1660 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1661 return lphl->ItemFocused;
1664 /***********************************************************************
1665 * LBGetCount
1667 static LONG LBGetCount(HWND hwnd, WORD wParam, LONG lParam)
1669 LPHEADLIST lphl;
1671 lphl = ListBoxGetStorageHeader(hwnd);
1672 return lphl->ItemsCount;
1675 /***********************************************************************
1676 * LBGetCurSel
1678 static LONG LBGetCurSel(HWND hwnd, WORD wParam, LONG lParam)
1680 LPHEADLIST lphl;
1682 lphl = ListBoxGetStorageHeader(hwnd);
1683 dprintf_listbox(stddeb,"ListBox LB_GETCURSEL %i !\n",
1684 lphl->ItemFocused);
1685 return lphl->ItemFocused;
1688 /***********************************************************************
1689 * LBGetHorizontalExtent
1691 static LONG LBGetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam)
1693 return 0;
1696 /***********************************************************************
1697 * LBGetItemHeight
1699 static LONG LBGetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
1701 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1702 LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
1704 if (lpls == NULL) return LB_ERR;
1705 return lpls->mis.itemHeight;
1708 /***********************************************************************
1709 * LBGetItemRect
1711 static LONG LBGetItemRect(HWND hwnd, WORD wParam, LONG lParam)
1713 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1714 return ListBoxGetItemRect(lphl, wParam, PTR_SEG_TO_LIN(lParam));
1717 /***********************************************************************
1718 * LBGetSel
1720 static LONG LBGetSel(HWND hwnd, WORD wParam, LONG lParam)
1722 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1723 int iSel = ListBoxGetSel(lphl, wParam);
1725 dprintf_listbox(stdnimp,"LBGetSel: item %u - %i\n",wParam,iSel);
1727 return (iSel)? 1 : 0;
1730 /***********************************************************************
1731 * LBGetSelCount
1733 static LONG LBGetSelCount(HWND hwnd, WORD wParam, LONG lParam)
1735 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1736 LPLISTSTRUCT lpls;
1737 int cnt = 0;
1738 int items = 0;
1740 if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
1741 return LB_ERR;
1743 for( lpls = lphl->lpFirst;
1744 lpls;
1745 lpls = lpls->lpNext )
1747 items++;
1748 if (lpls->itemState )
1749 cnt++;
1752 return cnt;
1755 /***********************************************************************
1756 * LBGetSelItems
1758 static LONG LBGetSelItems(HWND hwnd, WORD wParam, LONG lParam)
1760 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1761 LPLISTSTRUCT lpls;
1762 int cnt, idx;
1763 int *lpItems = PTR_SEG_TO_LIN(lParam);
1765 if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
1766 return LB_ERR;
1768 if (wParam == 0) return 0;
1770 lpls = lphl->lpFirst;
1771 cnt = 0; idx = 0;
1773 while (lpls != NULL) {
1774 if (lpls->itemState > 0) lpItems[cnt++] = idx;
1776 if (cnt == wParam) break;
1777 idx++;
1778 lpls = lpls->lpNext;
1781 return cnt;
1784 /***********************************************************************
1785 * LBGetTextLen
1787 static LONG LBGetTextLen(HWND hwnd, WORD wParam, LONG lParam)
1789 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1790 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
1792 if (lpls == NULL || !lphl->HasStrings) return LB_ERR;
1793 return strlen(lpls->itemText);
1796 /***********************************************************************
1797 * LBGetDlgCode
1799 static LONG LBGetDlgCode(HWND hwnd, WORD wParam, LONG lParam)
1801 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1804 /***********************************************************************
1805 * LBGetTopIndex
1807 static LONG LBGetTopIndex(HWND hwnd, WORD wParam, LONG lParam)
1809 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1811 return lphl->FirstVisible;
1815 /***********************************************************************
1816 * LBSelectString
1818 static LONG LBSelectString(HWND hwnd, WORD wParam, LONG lParam)
1820 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1821 INT iRet;
1823 iRet = lbFindString(lphl, wParam, (SEGPTR)lParam, MATCH_SUBSTR);
1825 if( iRet != LB_ERR)
1827 if( lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) )
1828 ListBoxSetSel(lphl,iRet,TRUE);
1829 else
1830 ListBoxSetCurSel(lphl,iRet);
1832 lphl->ItemFocused = iRet;
1833 InvalidateRect32( hwnd, 0, TRUE );
1835 return iRet;
1838 /***********************************************************************
1839 * LBSelItemRange
1841 static LONG LBSelItemRange(HWND hwnd, WORD wParam, LONG lParam)
1843 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1844 LPLISTSTRUCT lpls;
1845 WORD cnt;
1846 WORD first = LOWORD(lParam);
1847 WORD last = HIWORD(lParam);
1848 BOOL select = wParam;
1850 if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
1851 return LB_ERR;
1853 if (first >= lphl->ItemsCount ||
1854 last >= lphl->ItemsCount) return LB_ERR;
1856 lpls = lphl->lpFirst;
1857 cnt = 0;
1859 while (lpls != NULL) {
1860 if (cnt++ >= first)
1861 lpls->itemState = select ? lpls->itemState | ODS_SELECTED : 0;
1863 if (cnt > last)
1864 break;
1866 lpls = lpls->lpNext;
1869 return 0;
1872 /***********************************************************************
1873 * LBSetCaretIndex
1875 static LONG LBSetCaretIndex(HWND hwnd, WORD wParam, LONG lParam)
1877 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1878 int i;
1880 if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) )) return 0;
1882 dprintf_listbox(stddeb,"LBSetCaretIndex: hwnd %04x n=%i\n",hwnd,wParam);
1884 if (wParam >= lphl->ItemsCount) return LB_ERR;
1886 lphl->ItemFocused = wParam;
1887 i = ListBoxScrollToFocus (lphl);
1889 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1890 if(i)
1891 InvalidateRect32( hwnd, NULL, TRUE );
1893 return 1;
1896 /***********************************************************************
1897 * LBSetColumnWidth
1899 static LONG LBSetColumnWidth(HWND hwnd, WORD wParam, LONG lParam)
1901 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1902 lphl->ColumnsWidth = wParam;
1903 InvalidateRect32( hwnd, NULL, TRUE );
1904 return 0;
1907 /***********************************************************************
1908 * LBSetHorizontalExtent
1910 static LONG LBSetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam)
1912 return 0;
1915 /***********************************************************************
1916 * LBGetItemData
1918 static LONG LBGetItemData(HWND hwnd, WORD wParam, LONG lParam)
1920 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1921 dprintf_listbox(stddeb, "LB_GETITEMDATA wParam=%x\n", wParam);
1922 return ListBoxGetItemData(lphl, wParam);
1925 /***********************************************************************
1926 * LBSetItemData
1928 static LONG LBSetItemData(HWND hwnd, WORD wParam, LONG lParam)
1930 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1931 dprintf_listbox(stddeb, "LB_SETITEMDATA wParam=%x lParam=%lx\n", wParam, lParam);
1932 return ListBoxSetItemData(lphl, wParam, lParam);
1935 /***********************************************************************
1936 * LBSetTabStops
1938 static LONG LBSetTabStops(HWND hwnd, WORD wParam, LONG lParam)
1940 LPHEADLIST lphl;
1942 lphl = ListBoxGetStorageHeader(hwnd);
1944 if (lphl->TabStops != NULL) {
1945 lphl->iNumStops = 0;
1946 free (lphl->TabStops);
1949 lphl->TabStops = malloc (wParam * sizeof (short));
1950 if (lphl->TabStops) {
1951 lphl->iNumStops = wParam;
1952 memcpy (lphl->TabStops, PTR_SEG_TO_LIN(lParam), wParam * sizeof (short));
1953 return TRUE;
1956 return FALSE;
1959 /***********************************************************************
1960 * LBSetCurSel
1962 static LONG LBSetCurSel(HWND hwnd, WORD wParam, LONG lParam)
1964 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1965 WORD wRet;
1967 dprintf_listbox(stddeb,"ListBox LB_SETCURSEL wParam=%x !\n",
1968 wParam);
1970 wRet = ListBoxSetCurSel(lphl, wParam);
1972 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1973 InvalidateRect32( hwnd, NULL, TRUE );
1975 return wRet;
1978 /***********************************************************************
1979 * LBSetSel
1981 static LONG LBSetSel(HWND hwnd, WORD wParam, LONG lParam)
1983 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1984 RECT16 rect;
1985 int iRet;
1987 dprintf_listbox(stddeb,"ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam, lParam);
1989 iRet = ListBoxSetSel(lphl, LOWORD(lParam), wParam);
1991 if( iRet > 1 ) InvalidateRect32( hwnd, NULL, TRUE );
1992 else if( iRet != LB_ERR )
1994 if( lphl->dwStyle & LBS_EXTENDEDSEL &&
1995 lphl->ItemFocused != LOWORD(lParam) )
1997 ListBoxGetItemRect(lphl, lphl->ItemFocused , &rect);
1998 InvalidateRect16( hwnd, &rect, TRUE );
1999 lphl->ItemFocused = LOWORD(lParam);
2001 ListBoxGetItemRect(lphl,LOWORD(lParam),&rect);
2002 InvalidateRect16( hwnd, &rect, TRUE );
2005 return (iRet == (WORD)LB_ERR)? LB_ERR: 0;
2008 /***********************************************************************
2009 * LBSetTopIndex
2011 static LONG LBSetTopIndex(HWND hwnd, WORD wParam, LONG lParam)
2013 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
2015 dprintf_listbox(stddeb,"ListBox LB_SETTOPINDEX wParam=%x !\n",
2016 wParam);
2017 lphl->FirstVisible = wParam;
2018 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
2020 InvalidateRect32( hwnd, NULL, TRUE );
2022 return 0;
2025 /***********************************************************************
2026 * LBSetItemHeight
2028 static LONG LBSetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
2030 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
2031 WORD wRet;
2033 dprintf_listbox(stddeb,"ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam, lParam);
2034 wRet = ListBoxSetItemHeight(lphl, wParam, lParam);
2035 InvalidateRect32( hwnd, NULL, TRUE );
2036 return wRet;
2039 /***********************************************************************
2040 * LBPassToParent
2042 static LRESULT LBPassToParent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2044 WND* ptrWnd = WIN_FindWndPtr(hwnd);
2046 if( ptrWnd )
2047 if( /* !(ptrWnd->dwExStyle & WS_EX_NOPARENTNOTIFY) && */
2048 ptrWnd->parent )
2049 return SendMessage16(ptrWnd->parent->hwndSelf,message,wParam,lParam);
2050 return 0;
2053 /***********************************************************************
2054 * ListBoxWndProc
2056 LRESULT ListBoxWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2058 switch (message) {
2059 case WM_CREATE: return LBCreate(hwnd, wParam, lParam);
2060 case WM_DESTROY: return LBDestroy(hwnd, wParam, lParam);
2061 case WM_GETDLGCODE: return LBGetDlgCode(hwnd, wParam, lParam);
2062 case WM_VSCROLL: return LBVScroll(hwnd, wParam, lParam);
2063 case WM_HSCROLL: return LBHScroll(hwnd, wParam, lParam);
2064 case WM_LBUTTONDOWN: return LBLButtonDown(hwnd, wParam, lParam);
2065 case WM_LBUTTONUP: return LBLButtonUp(hwnd, wParam, lParam);
2066 case WM_RBUTTONUP: return LBRButtonUp(hwnd, wParam, lParam);
2067 case WM_LBUTTONDBLCLK: return LBRButtonUp(hwnd, wParam, lParam);
2068 case WM_MOUSEMOVE: return LBMouseMove(hwnd, wParam, lParam);
2069 case WM_KEYDOWN: return LBKeyDown(hwnd, wParam, lParam);
2070 case WM_CHAR: return LBChar(hwnd, wParam, lParam);
2071 case WM_SETFONT: return LBSetFont(hwnd, wParam, lParam);
2072 case WM_SETREDRAW: return LBSetRedraw(hwnd, wParam, lParam);
2073 case WM_PAINT: return LBPaint(hwnd, wParam, lParam);
2074 case WM_SETFOCUS: return LBSetFocus(hwnd, wParam, lParam);
2075 case WM_KILLFOCUS: return LBKillFocus(hwnd, wParam, lParam);
2076 case LB_RESETCONTENT: return LBResetContent(hwnd, wParam, lParam);
2077 case LB_DIR: return LBDir(hwnd, wParam, lParam);
2078 case LB_ADDSTRING: return LBAddString(hwnd, wParam, lParam);
2079 case LB_INSERTSTRING: return LBInsertString(hwnd, wParam, lParam);
2080 case LB_DELETESTRING: return LBDeleteString(hwnd, wParam, lParam);
2081 case LB_FINDSTRING: return LBFindString(hwnd, wParam, lParam);
2082 case LB_FINDSTRINGEXACT: return LBFindStringExact(hwnd, wParam, lParam);
2083 case LB_GETCARETINDEX: return LBGetCaretIndex(hwnd, wParam, lParam);
2084 case LB_GETCOUNT: return LBGetCount(hwnd, wParam, lParam);
2085 case LB_GETCURSEL: return LBGetCurSel(hwnd, wParam, lParam);
2086 case LB_GETHORIZONTALEXTENT: return LBGetHorizontalExtent(hwnd, wParam, lParam);
2087 case LB_GETITEMDATA: return LBGetItemData(hwnd, wParam, lParam);
2088 case LB_GETITEMHEIGHT: return LBGetItemHeight(hwnd, wParam, lParam);
2089 case LB_GETITEMRECT: return LBGetItemRect(hwnd, wParam, lParam);
2090 case LB_GETSEL: return LBGetSel(hwnd, wParam, lParam);
2091 case LB_GETSELCOUNT: return LBGetSelCount(hwnd, wParam, lParam);
2092 case LB_GETSELITEMS: return LBGetSelItems(hwnd, wParam, lParam);
2093 case LB_GETTEXT: return LBGetText(hwnd, wParam, lParam);
2094 case LB_GETTEXTLEN: return LBGetTextLen(hwnd, wParam, lParam);
2095 case LB_GETTOPINDEX: return LBGetTopIndex(hwnd, wParam, lParam);
2096 case LB_SELECTSTRING: return LBSelectString(hwnd, wParam, lParam);
2097 case LB_SELITEMRANGE: return LBSelItemRange(hwnd, wParam, lParam);
2098 case LB_SETCARETINDEX: return LBSetCaretIndex(hwnd, wParam, lParam);
2099 case LB_SETCOLUMNWIDTH: return LBSetColumnWidth(hwnd, wParam, lParam);
2100 case LB_SETHORIZONTALEXTENT: return LBSetHorizontalExtent(hwnd, wParam, lParam);
2101 case LB_SETITEMDATA: return LBSetItemData(hwnd, wParam, lParam);
2102 case LB_SETTABSTOPS: return LBSetTabStops(hwnd, wParam, lParam);
2103 case LB_SETCURSEL: return LBSetCurSel(hwnd, wParam, lParam);
2104 case LB_SETSEL: return LBSetSel(hwnd, wParam, lParam);
2105 case LB_SETTOPINDEX: return LBSetTopIndex(hwnd, wParam, lParam);
2106 case LB_SETITEMHEIGHT: return LBSetItemHeight(hwnd, wParam, lParam);
2108 case WM_DROPFILES: return LBPassToParent(hwnd, message, wParam, lParam);
2110 /* these will have to be implemented for proper LBS_EXTENDEDSEL -
2112 * anchor item is an item that with caret (focused) item defines a
2113 * range of currently selected items when listbox is in the extended
2114 * selection mode.
2116 case LB_SETANCHORINDEX: return LB_SETANCHORINDEX; /* that's what Windows returns */
2117 case LB_GETANCHORINDEX: return 0;
2119 case WM_DROPOBJECT:
2120 case WM_QUERYDROPOBJECT:
2121 case WM_DRAGSELECT:
2122 case WM_DRAGMOVE:
2124 LPDRAGINFO lpDragInfo = (LPDRAGINFO) PTR_SEG_TO_LIN((SEGPTR)lParam);
2125 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
2127 lpDragInfo->l = ListBoxFindMouse(lphl,lpDragInfo->pt.x,
2128 lpDragInfo->pt.y);
2130 return LBPassToParent(hwnd, message, wParam, lParam);
2134 return DefWindowProc16(hwnd, message, wParam, lParam);
2138 /**********************************************************************
2139 * DlgDirSelect (USER.99)
2141 BOOL DlgDirSelect( HWND hDlg, LPSTR lpStr, INT id )
2143 char *buffer;
2144 INT i;
2146 dprintf_listbox( stddeb, "DlgDirSelect: %04x '%s' %d\n", hDlg, lpStr, id );
2147 if ((i = SendDlgItemMessage16( hDlg, id, LB_GETCURSEL, 0, 0 )) == LB_ERR)
2148 return FALSE;
2149 if (!(buffer = SEGPTR_ALLOC( 20 * sizeof(char) ))) return FALSE;
2150 SendDlgItemMessage16(hDlg, id, LB_GETTEXT, i, (LPARAM)SEGPTR_GET(buffer) );
2151 if (buffer[0] == '[') /* drive or directory */
2153 if (buffer[1] == '-') /* drive */
2155 lpStr[0] = buffer[2];
2156 lpStr[1] = ':';
2157 lpStr[2] = '\0';
2158 dprintf_listbox( stddeb, "Returning drive '%s'\n", lpStr );
2159 SEGPTR_FREE(buffer);
2160 return TRUE;
2162 strcpy( lpStr, buffer + 1 );
2163 lpStr[strlen(lpStr)-1] = '\\';
2164 dprintf_listbox( stddeb, "Returning directory '%s'\n", lpStr );
2165 SEGPTR_FREE(buffer);
2166 return TRUE;
2168 strcpy( lpStr, buffer );
2169 dprintf_listbox( stddeb, "Returning file '%s'\n", lpStr );
2170 SEGPTR_FREE(buffer);
2171 return FALSE;
2175 /**********************************************************************
2176 * DlgDirList (USER.100)
2178 INT DlgDirList( HWND hDlg, SEGPTR spec, INT idLBox, INT idStatic, UINT attrib )
2180 char *filespec = (char *)PTR_SEG_TO_LIN( spec );
2181 int drive;
2182 HWND hwnd;
2184 #define SENDMSG(msg,wparam,lparam) \
2185 ((attrib & DDL_POSTMSGS) ? PostMessage( hwnd, msg, wparam, lparam ) \
2186 : SendMessage16( hwnd, msg, wparam, lparam ))
2188 dprintf_listbox( stddeb, "DlgDirList: %04x '%s' %d %d %04x\n",
2189 hDlg, filespec ? filespec : "NULL",
2190 idLBox, idStatic, attrib );
2192 if (filespec && filespec[0] && (filespec[1] == ':'))
2194 drive = toupper( filespec[0] ) - 'A';
2195 filespec += 2;
2196 if (!DRIVE_SetCurrentDrive( drive )) return FALSE;
2198 else drive = DRIVE_GetCurrentDrive();
2200 if (idLBox && ((hwnd = GetDlgItem( hDlg, idLBox )) != 0))
2202 char mask[20];
2204 if (!filespec || !filespec[0]) strcpy( mask, "*.*" );
2205 else
2207 /* If the path exists and is a directory, chdir to it */
2208 if (DRIVE_Chdir( drive, filespec )) strcpy( mask, "*.*" );
2209 else
2211 char *p, *p2;
2212 p = filespec;
2213 if ((p2 = strrchr( p, '\\' ))) p = p2 + 1;
2214 if ((p2 = strrchr( p, '/' ))) p = p2 + 1;
2215 lstrcpyn32A( mask, p, sizeof(mask) );
2216 if (p != filespec)
2218 p[-1] = '\0';
2219 if (!DRIVE_Chdir( drive, filespec )) return FALSE;
2224 strcpy( (char *)PTR_SEG_TO_LIN(spec), mask );
2226 dprintf_listbox(stddeb, "ListBoxDirectory: path=%c:\\%s mask=%s\n",
2227 'A' + drive, DRIVE_GetDosCwd(drive), mask);
2229 SENDMSG( LB_RESETCONTENT, 0, 0 );
2230 if ((attrib & DDL_DIRECTORY) && !(attrib & DDL_EXCLUSIVE))
2232 char *temp;
2233 if (SENDMSG( LB_DIR, attrib & ~(DDL_DIRECTORY | DDL_DRIVES),
2234 (LPARAM)spec ) == LB_ERR) return FALSE;
2235 if (!(temp = SEGPTR_ALLOC( 4*sizeof(char) ))) return FALSE;
2236 strcpy( temp, "*.*" );
2237 /* FIXME: this won't work with PostMessage(), as temp will */
2238 /* have been freed by the time we do a DispatchMessage(). */
2239 if (SENDMSG( LB_DIR, (attrib & (DDL_DIRECTORY | DDL_DRIVES)) | DDL_EXCLUSIVE,
2240 (LPARAM)SEGPTR_GET(temp) ) == LB_ERR)
2242 SEGPTR_FREE(temp);
2243 return FALSE;
2245 SEGPTR_FREE(temp);
2247 else
2249 if (SENDMSG( LB_DIR, attrib, (LPARAM)spec) == LB_ERR) return FALSE;
2253 if (idStatic && ((hwnd = GetDlgItem( hDlg, idStatic )) != 0))
2255 char temp[512];
2256 int drive = DRIVE_GetCurrentDrive();
2257 strcpy( temp, "A:\\" );
2258 temp[0] += drive;
2259 lstrcpyn32A( temp + 3, DRIVE_GetDosCwd(drive), sizeof(temp)-3 );
2260 AnsiLower( temp );
2261 /* Can't use PostMessage() here, because the string is on the stack */
2262 SetDlgItemText32A( hDlg, idStatic, temp );
2264 return TRUE;
2265 #undef SENDMSG