Release 960928
[wine/multimedia.git] / controls / listbox.c
blob4abf763f4b2d5bdce591ad31eb23cb334bf985de
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 "stddebug.h"
33 #include "debug.h"
34 #include "xmalloc.h"
36 #define LIST_HEAP_ALLOC(lphl,f,size) \
37 LOCAL_Alloc( lphl->HeapSel, LMEM_FIXED, (size) )
38 #define LIST_HEAP_FREE(lphl,handle) \
39 LOCAL_Free( lphl->HeapSel, (handle) )
40 #define LIST_HEAP_ADDR(lphl,handle) \
41 ((handle) ? PTR_SEG_OFF_TO_LIN(lphl->HeapSel, (handle)) : NULL)
43 #define LIST_HEAP_SIZE 0x10000
45 #define LBMM_EDGE 4 /* distance inside box which is same as moving mouse
46 outside box, to trigger scrolling of LB */
48 #define MATCH_SUBSTR 2
49 #define MATCH_EXACT 1
50 #define MATCH_NEAREST 0
52 static void ListBoxInitialize(LPHEADLIST lphl)
54 lphl->lpFirst = NULL;
55 lphl->ItemsCount = 0;
56 lphl->ItemsVisible = 0;
57 lphl->FirstVisible = 0;
58 lphl->ColumnsVisible = 1;
59 lphl->ItemsPerColumn = 0;
60 lphl->ItemFocused = -1;
61 lphl->PrevFocused = -1;
64 void CreateListBoxStruct(HWND hwnd, WORD CtlType, LONG styles, HWND parent)
66 LPHEADLIST lphl;
67 HDC32 hdc;
69 lphl = (LPHEADLIST)xmalloc(sizeof(HEADLIST));
70 SetWindowLong32A(hwnd, 0, (LONG)lphl);
71 ListBoxInitialize(lphl);
72 lphl->DrawCtlType = CtlType;
73 lphl->CtlID = GetWindowWord(hwnd,GWW_ID);
74 lphl->bRedrawFlag = TRUE;
75 lphl->iNumStops = 0;
76 lphl->TabStops = NULL;
77 lphl->hFont = GetStockObject(SYSTEM_FONT);
78 lphl->hSelf = hwnd;
79 if (CtlType==ODT_COMBOBOX) /* use the "faked" style for COMBOLBOX */
80 /* LBS_SORT instead CBS_SORT e.g. */
81 lphl->dwStyle = MAKELONG(LOWORD(styles),HIWORD(GetWindowLong32A(hwnd,GWL_STYLE)));
82 else
83 lphl->dwStyle = GetWindowLong32A(hwnd,GWL_STYLE); /* use original style dword */
84 lphl->hParent = parent;
85 lphl->StdItemHeight = 15; /* FIXME: should get the font height */
86 lphl->OwnerDrawn = styles & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE);
87 lphl->HasStrings = (styles & LBS_HASSTRINGS) || !lphl->OwnerDrawn;
89 /* create dummy hdc to set text height */
90 if ((hdc = GetDC32(0)))
92 TEXTMETRIC16 tm;
93 GetTextMetrics16( hdc, &tm );
94 lphl->StdItemHeight = tm.tmHeight;
95 dprintf_listbox(stddeb,"CreateListBoxStruct: font height %d\n",
96 lphl->StdItemHeight);
97 ReleaseDC32( 0, hdc );
100 if (lphl->OwnerDrawn)
102 LISTSTRUCT dummyls;
104 lphl->needMeasure = TRUE;
105 dummyls.mis.CtlType = lphl->DrawCtlType;
106 dummyls.mis.CtlID = lphl->CtlID;
107 dummyls.mis.itemID = -1;
108 dummyls.mis.itemWidth = 0; /* ignored */
109 dummyls.mis.itemData = 0;
111 ListBoxAskMeasure(lphl,&dummyls);
114 lphl->HeapSel = GlobalAlloc16(GMEM_FIXED,LIST_HEAP_SIZE);
115 LocalInit( lphl->HeapSel, 0, LIST_HEAP_SIZE-1);
118 void DestroyListBoxStruct(LPHEADLIST lphl)
120 /* XXX need to free lphl->Heap */
121 GlobalFree16(lphl->HeapSel);
122 free(lphl);
125 static LPHEADLIST ListBoxGetStorageHeader(HWND hwnd)
127 return (LPHEADLIST)GetWindowLong32A(hwnd,0);
130 /* Send notification "code" as part of a WM_COMMAND-message if hwnd
131 has the LBS_NOTIFY style */
132 void ListBoxSendNotification(LPHEADLIST lphl, WORD code)
134 if (lphl->dwStyle & LBS_NOTIFY)
135 SendMessage32A( lphl->hParent, WM_COMMAND,
136 MAKEWPARAM( lphl->CtlID, code), (LPARAM)lphl->hSelf );
140 /* get the maximum value of lphl->FirstVisible */
141 int ListMaxFirstVisible(LPHEADLIST lphl)
143 int m = lphl->ItemsCount-lphl->ItemsVisible;
144 return (m < 0) ? 0 : m;
148 void ListBoxUpdateWindow(HWND hwnd, LPHEADLIST lphl, BOOL repaint)
150 if (lphl->dwStyle & WS_VSCROLL)
151 SetScrollRange32(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
152 if ((lphl->dwStyle & WS_HSCROLL) && (lphl->ItemsPerColumn != 0))
153 SetScrollRange32(hwnd, SB_HORZ, 1, lphl->ItemsVisible /
154 lphl->ItemsPerColumn + 1, TRUE);
156 if (repaint && lphl->bRedrawFlag) InvalidateRect32( hwnd, NULL, TRUE );
159 /* Returns: 0 if nothing needs to be changed */
160 /* 1 if FirstVisible changed */
162 int ListBoxScrollToFocus(LPHEADLIST lphl)
164 short end;
166 if (lphl->ItemsCount == 0) return 0;
167 if (lphl->ItemFocused == -1) return 0;
169 end = lphl->FirstVisible + lphl->ItemsVisible - 1;
171 if (lphl->ItemFocused < lphl->FirstVisible ) {
172 lphl->FirstVisible = lphl->ItemFocused;
173 return 1;
174 } else {
175 if (lphl->ItemFocused > end) {
176 WORD maxFirstVisible = ListMaxFirstVisible(lphl);
178 lphl->FirstVisible = lphl->ItemFocused;
180 if (lphl->FirstVisible > maxFirstVisible) {
181 lphl->FirstVisible = maxFirstVisible;
183 return 1;
186 return 0;
190 LPLISTSTRUCT ListBoxGetItem(LPHEADLIST lphl, UINT uIndex)
192 LPLISTSTRUCT lpls;
193 UINT Count = 0;
195 if (uIndex >= lphl->ItemsCount) return NULL;
197 lpls = lphl->lpFirst;
198 while (Count++ < uIndex) lpls = lpls->lpNext;
199 return lpls;
203 void ListBoxDrawItem (HWND hwnd, LPHEADLIST lphl, HDC hdc, LPLISTSTRUCT lpls,
204 RECT16 *rect, WORD itemAction, WORD itemState)
206 if (lphl->OwnerDrawn)
208 DRAWITEMSTRUCT32 dis;
210 dis.CtlID = lpls->mis.CtlID;
211 dis.CtlType = lpls->mis.CtlType;
212 dis.itemID = lpls->mis.itemID;
213 dis.hDC = hdc;
214 dis.hwndItem = hwnd;
215 dis.itemData = lpls->mis.itemData;
216 dis.itemAction = itemAction;
217 dis.itemState = itemState;
218 CONV_RECT16TO32( rect, &dis.rcItem );
219 SendMessage32A( lphl->hParent, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis );
220 return;
222 if (itemAction == ODA_DRAWENTIRE || itemAction == ODA_SELECT) {
223 int OldBkMode;
224 DWORD dwOldTextColor = 0;
226 OldBkMode = SetBkMode(hdc, TRANSPARENT);
228 if (itemState != 0) {
229 dwOldTextColor = SetTextColor(hdc, 0x00FFFFFFL);
230 FillRect16(hdc, rect, GetStockObject(BLACK_BRUSH));
233 if (lphl->dwStyle & LBS_USETABSTOPS) {
234 TabbedTextOut(hdc, rect->left + 5, rect->top + 2,
235 (char *)lpls->itemText, strlen((char *)lpls->itemText),
236 lphl->iNumStops, lphl->TabStops, 0);
237 } else {
238 TextOut16(hdc, rect->left + 5, rect->top + 2,
239 (char *)lpls->itemText, strlen((char *)lpls->itemText));
242 if (itemState != 0) {
243 SetTextColor(hdc, dwOldTextColor);
246 SetBkMode(hdc, OldBkMode);
248 else DrawFocusRect16(hdc, rect);
252 int ListBoxFindMouse(LPHEADLIST lphl, int X, int Y)
254 LPLISTSTRUCT lpls = lphl->lpFirst;
255 int i, j;
256 POINT16 point;
258 point.x = X; point.y = Y;
259 if (lphl->ItemsCount == 0) return LB_ERR;
261 for(i = 0; i < lphl->FirstVisible; i++) {
262 if (lpls == NULL) return LB_ERR;
263 lpls = lpls->lpNext;
265 for(j = 0; j < lphl->ItemsVisible; i++, j++) {
266 if (lpls == NULL) return LB_ERR;
267 if (PtInRect16(&lpls->itemRect,point)) {
268 return i;
270 lpls = lpls->lpNext;
272 dprintf_listbox(stddeb,"ListBoxFindMouse: not found\n");
273 return LB_ERR;
276 BOOL32 lbDeleteItemNotify(LPHEADLIST lphl, LPLISTSTRUCT lpls)
278 /* called only for owner drawn listboxes */
279 BOOL32 ret;
280 DELETEITEMSTRUCT16 *delItem = SEGPTR_NEW(DELETEITEMSTRUCT16);
281 if (!delItem) return FALSE;
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 ret = SendMessage16( lphl->hParent, WM_DELETEITEM, (WPARAM)lphl->CtlID,
290 (LPARAM)SEGPTR_GET(delItem) );
291 SEGPTR_FREE(delItem);
292 return ret;
295 void ListBoxAskMeasure(LPHEADLIST lphl, LPLISTSTRUCT lpls)
297 MEASUREITEMSTRUCT16 *lpmeasure = SEGPTR_NEW(MEASUREITEMSTRUCT16);
298 if (!lpmeasure) return;
299 *lpmeasure = lpls->mis;
300 lpmeasure->itemHeight = lphl->StdItemHeight;
301 SendMessage16( lphl->hParent, WM_MEASUREITEM, lphl->CtlID,
302 (LPARAM)SEGPTR_GET(lpmeasure) );
304 if (lphl->dwStyle & LBS_OWNERDRAWFIXED)
306 if (lpmeasure->itemHeight > lphl->StdItemHeight)
307 lphl->StdItemHeight = lpmeasure->itemHeight;
308 lpls->mis.itemHeight = lpmeasure->itemHeight;
310 SEGPTR_FREE(lpmeasure);
313 /* -------------------- strings and item data ---------------------- */
315 LPLISTSTRUCT ListBoxCreateItem(LPHEADLIST lphl, int id)
317 LPLISTSTRUCT lplsnew = (LPLISTSTRUCT)malloc(sizeof(LISTSTRUCT));
319 if (lplsnew == NULL) return NULL;
321 lplsnew->itemState = 0;
322 lplsnew->mis.CtlType = lphl->DrawCtlType;
323 lplsnew->mis.CtlID = lphl->CtlID;
324 lplsnew->mis.itemID = id;
325 lplsnew->mis.itemHeight = lphl->StdItemHeight;
326 lplsnew->mis.itemWidth = 0; /* ignored */
327 lplsnew->mis.itemData = 0;
328 SetRectEmpty16( &lplsnew->itemRect );
330 return lplsnew;
333 int ListBoxAskCompare(LPHEADLIST lphl, int startItem, SEGPTR matchData, BOOL exactMatch )
335 /* Do binary search for sorted listboxes. Linked list item storage sort of
336 * defeats the purpose ( forces to traverse item list all the time ) but M$ does it this way...
338 * MATCH_NEAREST (0) - return position for insertion - for all styles
339 * MATCH_EXACT (1) - search for an item, return index or LB_ERR
340 * MATCH_SUBSTR (2) - same as exact match but with strncmp for string comparision
343 COMPAREITEMSTRUCT16 *itemCmp;
344 LPLISTSTRUCT currentItem = NULL;
345 LPCSTR matchStr = (lphl->HasStrings)?(LPCSTR)PTR_SEG_TO_LIN(matchData):NULL;
346 int head, pos = -1, tail, loop = 1;
347 short b = 0, s_length = 0;
349 /* check if empty */
351 if( !lphl->ItemsCount )
352 return (exactMatch)? LB_ERR: 0;
354 /* set up variables */
356 if( exactMatch == MATCH_NEAREST )
357 startItem = 0;
358 else if( ++startItem )
360 loop = 2;
361 if( startItem >= lphl->ItemsCount ) startItem = lphl->ItemsCount - 1;
364 if( exactMatch == MATCH_SUBSTR && lphl->HasStrings )
366 s_length = strlen( matchStr );
367 if( !s_length ) return 0; /* head of the list - empty string */
370 head = startItem; tail = lphl->ItemsCount - 1;
372 dprintf_listbox(stddeb,"AskCompare: head = %i, tail = %i, data = %08x\n", head, tail, (unsigned)matchData );
374 if (!(itemCmp = SEGPTR_NEW(COMPAREITEMSTRUCT16))) return 0;
375 itemCmp->CtlType = lphl->DrawCtlType;
376 itemCmp->CtlID = lphl->CtlID;
377 itemCmp->hwndItem = lphl->hSelf;
379 /* search from startItem */
381 while ( loop-- )
383 while( head <= tail )
385 pos = (tail + head)/2;
386 currentItem = ListBoxGetItem( lphl, pos );
388 if( lphl->HasStrings )
390 b = ( s_length )? lstrncmpi32A( currentItem->itemText, matchStr, s_length)
391 : lstrcmpi32A( currentItem->itemText, matchStr);
393 else
395 itemCmp->itemID1 = pos;
396 itemCmp->itemData1 = currentItem->mis.itemData;
397 itemCmp->itemID2 = -1;
398 itemCmp->itemData2 = matchData;
400 b = SendMessage16( lphl->hParent, WM_COMPAREITEM, (WPARAM)lphl->CtlID,
401 (LPARAM)SEGPTR_GET(itemCmp) );
404 if( b == 0 )
406 SEGPTR_FREE(itemCmp);
407 return pos; /* found exact match */
409 else
410 if( b < 0 ) head = ++pos;
411 else
412 if( b > 0 ) tail = pos - 1;
415 /* reset to search from the first item */
416 head = 0; tail = startItem - 1;
419 dprintf_listbox(stddeb,"\t-> pos = %i\n", pos );
420 SEGPTR_FREE(itemCmp);
422 /* if we got here match is not exact */
424 if( pos < 0 ) pos = 0;
425 else if( pos > lphl->ItemsCount ) pos = lphl->ItemsCount;
427 return (exactMatch)? LB_ERR: pos;
430 int ListBoxInsertString(LPHEADLIST lphl, UINT uIndex, LPCSTR newstr)
432 LPLISTSTRUCT *lppls, lplsnew, lpls;
433 HANDLE hStr;
434 LPSTR str;
435 UINT Count;
437 dprintf_listbox(stddeb,"ListBoxInsertString(%d, %p);\n", uIndex, newstr);
439 if (!newstr) return -1;
441 if (uIndex == (UINT)-1)
442 uIndex = lphl->ItemsCount;
444 lppls = &lphl->lpFirst;
445 for(Count = 0; Count < uIndex; Count++) {
446 if (*lppls == NULL) return LB_ERR;
447 lppls = (LPLISTSTRUCT *) &(*lppls)->lpNext;
450 lplsnew = ListBoxCreateItem(lphl, Count);
452 if (lplsnew == NULL) {
453 fprintf(stdnimp,"ListBoxInsertString() out of memory !\n");
454 return LB_ERRSPACE;
457 lplsnew->lpNext = *lppls;
458 *lppls = lplsnew;
459 lphl->ItemsCount++;
461 hStr = 0;
462 if (lphl->HasStrings) {
463 dprintf_listbox(stddeb," string: %s\n", newstr);
464 hStr = LIST_HEAP_ALLOC(lphl, LMEM_MOVEABLE, strlen(newstr) + 1);
465 str = (LPSTR)LIST_HEAP_ADDR(lphl, hStr);
466 if (str == NULL) return LB_ERRSPACE;
467 strcpy(str, newstr);
468 lplsnew->itemText = str;
469 /* I'm not so sure about the next one */
470 lplsnew->mis.itemData = 0;
471 } else {
472 lplsnew->itemText = NULL;
473 lplsnew->mis.itemData = (DWORD)newstr;
476 lplsnew->mis.itemID = uIndex;
477 lplsnew->hData = hStr;
479 /* adjust the itemID field of the following entries */
480 for(lpls = lplsnew->lpNext; lpls != NULL; lpls = lpls->lpNext) {
481 lpls->mis.itemID++;
484 if (lphl->needMeasure) {
485 ListBoxAskMeasure(lphl, lplsnew);
488 dprintf_listbox(stddeb,"ListBoxInsertString // count=%d\n", lphl->ItemsCount);
489 return uIndex;
493 int ListBoxAddString(LPHEADLIST lphl, SEGPTR itemData)
495 UINT pos = (UINT) -1;
496 LPCSTR newstr = (lphl->HasStrings)?(LPCSTR)PTR_SEG_TO_LIN(itemData):(LPCSTR)itemData;
498 if ( lphl->dwStyle & LBS_SORT )
499 pos = ListBoxAskCompare( lphl, -1, itemData, MATCH_NEAREST );
501 return ListBoxInsertString(lphl, pos, newstr);
505 int ListBoxGetText(LPHEADLIST lphl, UINT uIndex, LPSTR OutStr)
507 LPLISTSTRUCT lpls;
509 if (!OutStr) {
510 dprintf_listbox(stddeb, "ListBoxGetText // OutStr==NULL\n");
511 return 0;
513 *OutStr = '\0';
514 lpls = ListBoxGetItem (lphl, uIndex);
515 if (lpls == NULL) return LB_ERR;
517 if (!lphl->HasStrings) {
518 *((long *)OutStr) = lpls->mis.itemData;
519 return 4;
522 strcpy(OutStr, lpls->itemText);
523 return strlen(OutStr);
527 DWORD ListBoxGetItemData(LPHEADLIST lphl, UINT uIndex)
529 LPLISTSTRUCT lpls;
531 lpls = ListBoxGetItem (lphl, uIndex);
532 if (lpls == NULL) return LB_ERR;
533 return lpls->mis.itemData;
537 int ListBoxSetItemData(LPHEADLIST lphl, UINT uIndex, DWORD ItemData)
539 LPLISTSTRUCT lpls = ListBoxGetItem(lphl, uIndex);
541 if (lpls == NULL) return LB_ERR;
542 lpls->mis.itemData = ItemData;
543 return 1;
547 int ListBoxDeleteString(LPHEADLIST lphl, UINT uIndex)
549 LPLISTSTRUCT lpls, lpls2;
550 UINT Count;
552 if (uIndex >= lphl->ItemsCount) return LB_ERR;
554 lpls = lphl->lpFirst;
555 if (lpls == NULL) return LB_ERR;
557 if (uIndex == 0)
559 if( lphl->OwnerDrawn )
560 lbDeleteItemNotify( lphl, lpls);
561 lphl->lpFirst = lpls->lpNext;
563 else
565 LPLISTSTRUCT lpls2 = NULL;
566 for(Count = 0; Count < uIndex; Count++) {
567 if (lpls->lpNext == NULL) return LB_ERR;
569 lpls2 = lpls;
570 lpls = (LPLISTSTRUCT)lpls->lpNext;
572 if( lphl->OwnerDrawn )
573 lbDeleteItemNotify( lphl, lpls);
574 lpls2->lpNext = lpls->lpNext;
577 /* adjust the itemID field of the following entries */
578 for(lpls2 = lpls->lpNext; lpls2 != NULL; lpls2 = lpls2->lpNext) {
579 lpls2->mis.itemID--;
582 lphl->ItemsCount--;
584 if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
585 free(lpls);
587 return lphl->ItemsCount;
590 int lbFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr, BOOL match)
592 /* match is either MATCH_SUBSTR or MATCH_EXACT */
594 LPLISTSTRUCT lpls;
595 UINT Count;
596 UINT First = nFirst + 1;
597 int s_length = 0;
598 LPSTR lpMatchStr = (LPSTR)MatchStr;
600 if (First > lphl->ItemsCount) return LB_ERR;
602 if (lphl->dwStyle & LBS_SORT )
603 return ListBoxAskCompare( lphl, nFirst, MatchStr, match );
605 if (lphl->HasStrings )
607 lpMatchStr = PTR_SEG_TO_LIN(MatchStr);
609 if( match == MATCH_SUBSTR )
611 s_length = strlen(lpMatchStr);
612 if( !s_length ) return (lphl->ItemsCount)?0:LB_ERR;
616 lpls = ListBoxGetItem(lphl, First);
617 Count = 0;
618 while(lpls != NULL)
620 if (lphl->HasStrings)
622 if ( ( s_length )? !lstrncmpi32A(lpls->itemText, lpMatchStr, s_length)
623 : !lstrcmpi32A(lpls->itemText, lpMatchStr) ) return Count;
625 else
626 if ( lpls->mis.itemData == (DWORD)lpMatchStr ) return Count;
628 lpls = lpls->lpNext;
629 Count++;
632 /* Start over at top */
633 Count = 0;
634 lpls = lphl->lpFirst;
636 while (Count < First)
638 if (lphl->HasStrings)
640 if ( ( s_length )? !lstrncmpi32A(lpls->itemText, lpMatchStr, s_length)
641 : !lstrcmpi32A(lpls->itemText, lpMatchStr) ) return Count;
643 else
644 if ( lpls->mis.itemData == (DWORD)lpMatchStr ) return Count;
646 lpls = lpls->lpNext;
647 Count++;
650 return LB_ERR;
653 int ListBoxFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr)
655 return lbFindString(lphl, nFirst, MatchStr, MATCH_SUBSTR );
658 int ListBoxFindStringExact(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr)
660 return lbFindString(lphl, nFirst, MatchStr, MATCH_EXACT );
663 int ListBoxResetContent(LPHEADLIST lphl)
665 LPLISTSTRUCT lpls;
666 int i;
668 if (lphl->ItemsCount == 0) return 0;
670 dprintf_listbox(stddeb, "ListBoxResetContent // ItemCount = %d\n",
671 lphl->ItemsCount);
673 for(i = 0; i < lphl->ItemsCount; i++) {
674 lpls = lphl->lpFirst;
675 if (lpls == NULL) return LB_ERR;
677 if (lphl->OwnerDrawn) lbDeleteItemNotify(lphl, lpls);
679 lphl->lpFirst = lpls->lpNext;
680 if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
681 free(lpls);
683 ListBoxInitialize(lphl);
685 return TRUE;
688 /* --------------------- selection ------------------------- */
690 int ListBoxSetCurSel(LPHEADLIST lphl, WORD wIndex)
692 LPLISTSTRUCT lpls;
694 /* use ListBoxSetSel instead */
695 if (lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ) return 0;
697 /* unselect previous item */
698 if (lphl->ItemFocused != -1) {
699 lphl->PrevFocused = lphl->ItemFocused;
700 lpls = ListBoxGetItem(lphl, lphl->ItemFocused);
701 if (lpls == 0) return LB_ERR;
702 lpls->itemState = 0;
705 if ((wIndex != (UINT)-1) && (wIndex < lphl->ItemsCount))
707 lphl->ItemFocused = wIndex;
708 lpls = ListBoxGetItem(lphl, wIndex);
709 if (lpls == 0) return LB_ERR;
710 lpls->itemState = ODS_SELECTED | ODS_FOCUS;
712 return 0;
715 return LB_ERR;
719 int ListBoxSetSel(LPHEADLIST lphl, WORD wIndex, WORD state)
721 LPLISTSTRUCT lpls;
722 int n = 0;
724 if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
725 return LB_ERR;
727 if (wIndex == (UINT)-1) {
728 for (lpls = lphl->lpFirst; lpls != NULL; lpls = lpls->lpNext) {
729 if( lpls->itemState & ODS_SELECTED) n++;
730 lpls->itemState = state? lpls->itemState | ODS_SELECTED
731 : lpls->itemState & ~ODS_SELECTED;
733 return n;
736 if (wIndex >= lphl->ItemsCount) return LB_ERR;
738 lpls = ListBoxGetItem(lphl, wIndex);
739 lpls->itemState = state? lpls->itemState | ODS_SELECTED
740 : lpls->itemState & ~ODS_SELECTED;
742 return 0;
746 int ListBoxGetSel(LPHEADLIST lphl, WORD wIndex)
748 LPLISTSTRUCT lpls = ListBoxGetItem(lphl, wIndex);
750 if (lpls == NULL) return LB_ERR;
751 return lpls->itemState & ODS_SELECTED;
754 /* ------------------------- dir listing ------------------------ */
756 LONG ListBoxDirectory(LPHEADLIST lphl, UINT attrib, LPCSTR filespec)
758 char mask[13];
759 char* temp = NULL;
760 const char* ptr;
761 int skip, count;
762 LONG ret;
763 DOS_DIRENT entry;
764 char *path, *p;
766 dprintf_listbox(stddeb, "ListBoxDirectory: '%s' %04x\n", filespec, attrib);
767 if (!filespec) return LB_ERR;
768 if (!(ptr = DOSFS_GetUnixFileName( filespec, FALSE ))) return LB_ERR;
769 path = xstrdup(ptr);
770 p = strrchr( path, '/' );
771 *p++ = '\0';
772 if (!(ptr = DOSFS_ToDosFCBFormat( p )) ||
773 !(temp = SEGPTR_ALLOC( sizeof(char) * 16 )) )
775 free( path );
776 return LB_ERR;
779 strcpy( mask, ptr );
781 dprintf_listbox(stddeb, "ListBoxDirectory: path=%s mask=%s\n", path, mask);
783 skip = ret = 0;
784 attrib &= ~FA_LABEL;
785 while ((count = DOSFS_FindNext( path, mask, 0, attrib, skip, &entry )) > 0)
787 skip += count;
788 if (entry.attr & FA_DIRECTORY)
790 if ((attrib & DDL_DIRECTORY) && strcmp(entry.name, ". "))
792 sprintf(temp, "[%s]", DOSFS_ToDosDTAFormat( entry.name ) );
793 AnsiLower( temp );
794 if ((ret = ListBoxAddString(lphl, SEGPTR_GET(temp))) == LB_ERR) break;
797 else /* not a directory */
799 if (!(attrib & DDL_EXCLUSIVE) ||
800 ((attrib & (FA_RDONLY|FA_HIDDEN|FA_SYSTEM|FA_ARCHIVE)) ==
801 (entry.attr & (FA_RDONLY|FA_HIDDEN|FA_SYSTEM|FA_ARCHIVE))))
803 strcpy( temp, DOSFS_ToDosDTAFormat( entry.name ) );
804 AnsiLower( temp );
805 if ((ret = ListBoxAddString(lphl, SEGPTR_GET(temp))) == LB_ERR) break;
809 dprintf_listbox(stddeb,"\tn - %i, file '%s'\n", count, temp);
811 if (attrib & DDL_DRIVES)
813 int x;
814 DWORD oldstyle = lphl->dwStyle;
816 lphl->dwStyle &= ~LBS_SORT;
817 strcpy( temp, "[-a-]" );
818 for (x = 0; x < MAX_DOS_DRIVES; x++, temp[2]++)
820 if (DRIVE_IsValid(x))
821 if ((ret = ListBoxAddString(lphl, SEGPTR_GET(temp))) == LB_ERR) break;
823 lphl->dwStyle = oldstyle;
826 free( path );
827 SEGPTR_FREE( temp );
829 return ret;
832 /* ------------------------- dimensions ------------------------- */
834 int ListBoxGetItemRect(LPHEADLIST lphl, WORD wIndex, LPRECT16 lprect)
836 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wIndex);
838 dprintf_listbox(stddeb,"ListBox LB_GETITEMRECT %i %p", wIndex,lpls);
839 if (lpls == NULL)
841 if (lphl->dwStyle & LBS_OWNERDRAWVARIABLE)
842 return LB_ERR;
843 else
845 GetClientRect16(lphl->hSelf,lprect);
846 lprect->bottom=lphl->StdItemHeight;
847 if (lprect->right<0) lprect->right=0;
850 else
851 *lprect = lpls->itemRect;
852 dprintf_listbox(stddeb," = %d,%d %d,%d\n", lprect->left,lprect->top,
853 lprect->right,lprect->bottom);
854 return 0;
858 int ListBoxSetItemHeight(LPHEADLIST lphl, WORD wIndex, long height)
860 LPLISTSTRUCT lpls;
862 if (!(lphl->dwStyle & LBS_OWNERDRAWVARIABLE)) {
863 lphl->StdItemHeight = (short)height;
864 return 0;
867 lpls = ListBoxGetItem(lphl, wIndex);
868 if (lpls == NULL) return LB_ERR;
870 lpls->mis.itemHeight = height;
871 return 0;
874 /* -------------------------- string search ------------------------ */
876 int ListBoxFindNextMatch(LPHEADLIST lphl, WORD wChar)
878 LPLISTSTRUCT lpls;
879 UINT count,first;
881 if ((char)wChar < ' ') return LB_ERR;
882 if (!lphl->HasStrings) return LB_ERR;
884 lpls = lphl->lpFirst;
886 for (count = 0; lpls != NULL; lpls = lpls->lpNext, count++) {
887 if (tolower(*lpls->itemText) == tolower((char)wChar)) break;
889 if (lpls == NULL) return LB_ERR;
890 first = count;
891 for(; lpls != NULL; lpls = lpls->lpNext, count++) {
892 if (*lpls->itemText != (char)wChar)
893 break;
894 if ((short) count > lphl->ItemFocused)
895 return count;
897 return first;
900 /***********************************************************************
901 * LBCreate
903 static LONG LBCreate(HWND hwnd, WORD wParam, LONG lParam)
905 LPHEADLIST lphl;
906 LONG dwStyle = GetWindowLong32A(hwnd,GWL_STYLE);
907 RECT16 rect;
909 CreateListBoxStruct(hwnd, ODT_LISTBOX, dwStyle, GetParent16(hwnd));
910 lphl = ListBoxGetStorageHeader(hwnd);
911 dprintf_listbox(stddeb,"ListBox created: lphl = %p dwStyle = %04x:%04x\n",
912 lphl, HIWORD(dwStyle), LOWORD(dwStyle));
914 GetClientRect16(hwnd,&rect);
915 lphl->ColumnsWidth = rect.right - rect.left;
917 if (dwStyle & WS_VSCROLL)
918 SetScrollRange32(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
919 if (dwStyle & WS_HSCROLL)
920 SetScrollRange32(hwnd, SB_HORZ, 1, 1, TRUE);
922 return 0;
926 /***********************************************************************
927 * LBDestroy
929 static LONG LBDestroy(HWND hwnd, WORD wParam, LONG lParam)
931 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
933 ListBoxResetContent(lphl);
935 DestroyListBoxStruct(lphl);
936 dprintf_listbox(stddeb,"ListBox destroyed: lphl = %p\n",lphl);
937 return 0;
941 /***********************************************************************
942 * LBNCCalcSize
944 static LONG LBNCCalcSize(HWND hwnd, WORD wParam, LONG lParam)
946 LONG ret = DefWindowProc16(hwnd, WM_NCCALCSIZE, wParam, lParam);
948 return (GetWindowLong32A(hwnd,GWL_STYLE) & LBS_MULTICOLUMN)? WVR_VREDRAW : ret;
952 /***********************************************************************
953 * LBVScroll
955 static LONG LBVScroll(HWND hwnd, WORD wParam, LONG lParam)
957 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
958 int y;
960 dprintf_listbox(stddeb,"ListBox WM_VSCROLL w=%04X l=%08lX !\n",
961 wParam, lParam);
962 y = lphl->FirstVisible;
964 switch(wParam) {
965 case SB_LINEUP:
966 if (lphl->FirstVisible > 0)
967 lphl->FirstVisible--;
968 break;
970 case SB_LINEDOWN:
971 lphl->FirstVisible++;
972 break;
974 case SB_PAGEUP:
975 if (lphl->FirstVisible > lphl->ItemsVisible) {
976 lphl->FirstVisible -= lphl->ItemsVisible;
977 } else {
978 lphl->FirstVisible = 0;
980 break;
982 case SB_PAGEDOWN:
983 lphl->FirstVisible += lphl->ItemsVisible;
984 break;
986 case SB_THUMBTRACK:
987 lphl->FirstVisible = LOWORD(lParam);
988 break;
991 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
992 lphl->FirstVisible = ListMaxFirstVisible(lphl);
994 if (y != lphl->FirstVisible) {
995 SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
996 InvalidateRect32( hwnd, NULL, TRUE );
998 return 0;
1001 /***********************************************************************
1002 * LBHScroll
1004 static LONG LBHScroll(HWND hwnd, WORD wParam, LONG lParam)
1006 LPHEADLIST lphl;
1007 int y;
1009 dprintf_listbox(stddeb,"ListBox WM_HSCROLL w=%04X l=%08lX !\n",
1010 wParam, lParam);
1011 lphl = ListBoxGetStorageHeader(hwnd);
1012 y = lphl->FirstVisible;
1013 switch(wParam) {
1014 case SB_LINEUP:
1015 if (lphl->FirstVisible > lphl->ItemsPerColumn) {
1016 lphl->FirstVisible -= lphl->ItemsPerColumn;
1017 } else {
1018 lphl->FirstVisible = 0;
1020 break;
1021 case SB_LINEDOWN:
1022 lphl->FirstVisible += lphl->ItemsPerColumn;
1023 break;
1024 case SB_PAGEUP:
1025 if (lphl->ItemsPerColumn != 0) {
1026 int lbsub = lphl->ItemsVisible / lphl->ItemsPerColumn * lphl->ItemsPerColumn;
1027 if (lphl->FirstVisible > lbsub) {
1028 lphl->FirstVisible -= lbsub;
1029 } else {
1030 lphl->FirstVisible = 0;
1033 break;
1034 case SB_PAGEDOWN:
1035 if (lphl->ItemsPerColumn != 0)
1036 lphl->FirstVisible += lphl->ItemsVisible /
1037 lphl->ItemsPerColumn * lphl->ItemsPerColumn;
1038 break;
1039 case SB_THUMBTRACK:
1040 lphl->FirstVisible = lphl->ItemsPerColumn * LOWORD(lParam);
1041 break;
1043 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
1044 lphl->FirstVisible = ListMaxFirstVisible(lphl);
1046 if (lphl->ItemsPerColumn != 0) {
1047 lphl->FirstVisible = lphl->FirstVisible /
1048 lphl->ItemsPerColumn * lphl->ItemsPerColumn + 1;
1049 if (y != lphl->FirstVisible) {
1050 SetScrollPos32(hwnd, SB_HORZ, lphl->FirstVisible /
1051 lphl->ItemsPerColumn + 1, TRUE);
1052 InvalidateRect32( hwnd, NULL, TRUE );
1055 return 0;
1058 /***********************************************************************
1059 * LBLButtonDown
1061 static LONG LBLButtonDown(HWND hwnd, WORD wParam, LONG lParam)
1063 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1064 WORD wRet;
1065 int y,n;
1066 RECT16 rectsel;
1068 SetFocus32(hwnd);
1069 SetCapture32(hwnd);
1071 lphl->PrevFocused = lphl->ItemFocused;
1073 y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
1075 if (y == -1) return 0;
1077 if (lphl->dwStyle & LBS_NOTIFY && y!= LB_ERR )
1078 if( SendMessage16(lphl->hParent, WM_LBTRACKPOINT, y, lParam) )
1079 return 0;
1082 switch( lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) )
1084 case LBS_MULTIPLESEL:
1085 lphl->ItemFocused = y;
1086 wRet = ListBoxGetSel(lphl, y);
1087 ListBoxSetSel(lphl, y, !wRet);
1088 break;
1089 case LBS_EXTENDEDSEL:
1090 /* should handle extended mode here and in kbd handler
1093 if ( lphl->PrevFocused != y && y!= LB_ERR)
1095 LPLISTSTRUCT lpls = ListBoxGetItem( lphl, lphl->ItemFocused = y );
1096 n = ListBoxSetSel(lphl,-1,FALSE);
1098 lpls->itemState = ODS_FOCUS | ODS_SELECTED;
1100 if( n > 1 && n != LB_ERR )
1101 InvalidateRect32( hwnd,NULL,TRUE );
1103 else
1104 return 0;
1106 break;
1107 case 0:
1108 if( y!=lphl->ItemFocused )
1109 ListBoxSetCurSel(lphl, y);
1110 else
1111 return 0;
1112 break;
1113 default:
1114 fprintf(stdnimp,"Listbox: LBS_MULTIPLESEL and LBS_EXTENDEDSEL are on!\n");
1115 return 0;
1118 /* invalidate changed items */
1119 if( lphl->dwStyle & LBS_MULTIPLESEL || y!=lphl->PrevFocused )
1121 ListBoxGetItemRect(lphl, y, &rectsel);
1122 InvalidateRect16( hwnd, &rectsel, TRUE );
1124 if( lphl->PrevFocused!=-1 && y!=lphl->PrevFocused )
1126 ListBoxGetItemRect(lphl, lphl->PrevFocused, &rectsel);
1127 InvalidateRect16( hwnd, &rectsel, TRUE );
1130 if (GetWindowLong32A(lphl->hSelf,GWL_EXSTYLE) & WS_EX_DRAGDETECT)
1131 if( DragDetect(lphl->hSelf,MAKEPOINT16(lParam)) )
1132 SendMessage16(lphl->hParent, WM_BEGINDRAG,0,0L);
1133 return 0;
1136 /***********************************************************************
1137 * LBLButtonUp
1139 static LONG LBLButtonUp(HWND hwnd, WORD wParam, LONG lParam)
1141 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1143 if (GetCapture32() == hwnd) ReleaseCapture();
1145 if (lphl->PrevFocused != lphl->ItemFocused)
1146 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1148 return 0;
1151 /***********************************************************************
1152 * LBRButtonUp
1154 static LONG LBRButtonUp(HWND hwnd, WORD wParam, LONG lParam)
1156 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1158 SendMessage16(lphl->hParent, WM_COMMAND, GetWindowWord(hwnd,GWW_ID),
1159 MAKELONG(hwnd, LBN_DBLCLK));
1160 return 0;
1163 /***********************************************************************
1164 * LBMouseMove
1166 static LONG LBMouseMove(HWND hwnd, WORD wParam, LONG lParam)
1168 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1169 int y,redraw_prev = 0;
1170 int iRet;
1171 RECT16 rect, rectsel; /* XXX Broken */
1173 dprintf_listbox(stddeb,"LBMouseMove %d %d\n",SLOWORD(lParam),SHIWORD(lParam));
1174 if ((wParam & MK_LBUTTON) != 0) {
1175 y = SHIWORD(lParam);
1176 if (y < LBMM_EDGE) {
1177 if (lphl->FirstVisible > 0) {
1178 lphl->FirstVisible--;
1179 SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1180 InvalidateRect32( hwnd, NULL, TRUE );
1181 return 0;
1184 GetClientRect16(hwnd, &rect);
1185 if (y >= (rect.bottom-LBMM_EDGE)) {
1186 if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
1187 lphl->FirstVisible++;
1188 SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1189 InvalidateRect32( hwnd, NULL, TRUE );
1190 return 0;
1193 if ((y > 0) && (y < (rect.bottom - LBMM_EDGE))) {
1194 if ((y < rectsel.top) || (y > rectsel.bottom)) {
1195 iRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
1196 if (iRet == lphl->ItemFocused || iRet == -1) {
1197 return 0;
1199 if (lphl->dwStyle & LBS_MULTIPLESEL) {
1200 lphl->ItemFocused = iRet;
1201 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1202 } else if ( lphl->dwStyle & LBS_EXTENDEDSEL )
1204 /* Fixme: extended selection mode */
1205 ListBoxSetSel( lphl, lphl->ItemFocused, 0);
1206 lphl->PrevFocused = lphl->ItemFocused;
1207 lphl->ItemFocused = iRet;
1208 ListBoxSetSel( lphl, iRet, TRUE);
1209 redraw_prev = 1;
1211 else
1213 ListBoxSetCurSel(lphl, (WORD)iRet);
1214 redraw_prev = 1;
1216 if( lphl->PrevFocused!=-1 && redraw_prev )
1218 ListBoxGetItemRect(lphl, lphl->PrevFocused, &rectsel);
1219 InvalidateRect16( hwnd, &rectsel, TRUE );
1221 ListBoxGetItemRect(lphl, iRet, &rectsel);
1222 InvalidateRect16( hwnd, &rectsel, TRUE );
1227 return 0;
1230 /***********************************************************************
1231 * LBKeyDown
1233 * Doesn't yet handle properly VK_SHIFT with LB_EXTENDEDSEL
1235 static LONG LBKeyDown(HWND hwnd, WORD wParam, LONG lParam)
1237 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1238 WORD newFocused = 0xFFFF;
1239 RECT16 rect;
1241 ListBoxGetItemRect(lphl,lphl->ItemFocused,&rect);
1242 switch(wParam)
1244 case VK_HOME:
1245 case VK_END:
1246 case VK_LEFT:
1247 case VK_RIGHT:
1248 case VK_UP:
1249 case VK_DOWN:
1250 case VK_PRIOR:
1251 case VK_NEXT:
1252 if ( lphl->dwStyle & LBS_WANTKEYBOARDINPUT )
1254 newFocused = (WORD)(INT)SendMessage16(lphl->hParent,WM_VKEYTOITEM,
1255 wParam,MAKELPARAM(lphl->ItemFocused,hwnd));
1256 if ( newFocused == 0xFFFE ) return 0L;
1258 if ( newFocused == 0xFFFF )
1260 newFocused = lphl->ItemFocused;
1262 /* nested switch */
1263 switch(wParam)
1265 case VK_HOME:
1266 newFocused = 0;
1267 break;
1268 case VK_END:
1269 newFocused = lphl->ItemsCount - 1;
1270 break;
1271 case VK_LEFT:
1272 if (lphl->dwStyle & LBS_MULTICOLUMN) {
1273 if (newFocused >= lphl->ItemsPerColumn) {
1274 newFocused -= lphl->ItemsPerColumn;
1275 } else {
1276 newFocused = 0;
1279 break;
1280 case VK_UP:
1281 if (newFocused > 0) newFocused--;
1282 break;
1283 case VK_RIGHT:
1284 if (lphl->dwStyle & LBS_MULTICOLUMN)
1285 newFocused += lphl->ItemsPerColumn;
1286 break;
1287 case VK_DOWN:
1288 newFocused++;
1289 break;
1290 case VK_PRIOR:
1291 if (newFocused > lphl->ItemsVisible)
1292 newFocused -= lphl->ItemsVisible;
1293 else newFocused = 0;
1294 break;
1295 case VK_NEXT:
1296 newFocused += lphl->ItemsVisible;
1297 break;
1298 default:
1299 return 0;
1301 /* end of nested switch */
1303 break;
1304 case VK_SPACE:
1305 if (lphl->dwStyle & LBS_MULTIPLESEL)
1307 WORD wRet = ListBoxGetSel(lphl, lphl->ItemFocused);
1308 ListBoxSetSel(lphl, lphl->ItemFocused, !wRet);
1310 return 0;
1312 /* chars are handled in LBChar */
1313 default:
1314 return 0;
1317 /* at this point newFocused is set up */
1319 if (newFocused >= lphl->ItemsCount)
1320 newFocused = lphl->ItemsCount - 1;
1322 if (!(lphl->dwStyle & LBS_MULTIPLESEL))
1324 ListBoxSetCurSel(lphl, newFocused);
1325 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1328 lphl->ItemFocused = newFocused;
1330 if( ListBoxScrollToFocus(lphl) || (lphl->dwStyle &
1331 (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) )
1332 InvalidateRect32( hwnd, NULL, TRUE );
1333 else
1335 InvalidateRect16( hwnd, &rect, TRUE );
1336 if( newFocused < 0x8000 )
1338 ListBoxGetItemRect(lphl, newFocused, &rect);
1339 InvalidateRect16( hwnd, &rect, TRUE );
1343 SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1345 return 0;
1348 /***********************************************************************
1349 * LBChar
1351 static LONG LBChar(HWND hwnd, WORD wParam, LONG lParam)
1353 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1354 WORD newFocused = 0xFFFF;
1356 if ( (lphl->dwStyle & LBS_WANTKEYBOARDINPUT) && !(lphl->HasStrings))
1358 newFocused = (WORD)(INT)SendMessage16(lphl->hParent,WM_CHARTOITEM,
1359 wParam,MAKELPARAM(lphl->ItemFocused,hwnd));
1360 if ( newFocused == 0xFFFE ) return 0L;
1363 if (newFocused == 0xFFFF )
1364 newFocused = ListBoxFindNextMatch(lphl, wParam);
1366 if (newFocused == (WORD)LB_ERR) return 0;
1368 if (newFocused >= lphl->ItemsCount)
1369 newFocused = lphl->ItemsCount - 1;
1371 if (!(lphl->dwStyle & LBS_MULTIPLESEL))
1373 ListBoxSetCurSel(lphl, newFocused);
1374 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1377 lphl->ItemFocused = newFocused;
1378 ListBoxScrollToFocus(lphl);
1379 SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1381 InvalidateRect32( hwnd, NULL, TRUE );
1383 return 0;
1386 /***********************************************************************
1387 * LBSetRedraw
1389 static LONG LBSetRedraw(HWND hwnd, WORD wParam, LONG lParam)
1391 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1393 dprintf_listbox(stddeb,"ListBox WM_SETREDRAW hWnd=%04x w=%04x !\n",
1394 hwnd, wParam);
1395 lphl->bRedrawFlag = wParam;
1397 return 0;
1400 /***********************************************************************
1401 * LBSetFont
1403 static LONG LBSetFont(HWND hwnd, WPARAM wParam, LPARAM lParam)
1405 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1406 HDC32 hdc;
1408 if (wParam == 0)
1409 lphl->hFont = GetStockObject(SYSTEM_FONT);
1410 else
1411 lphl->hFont = (HFONT) wParam;
1413 /* a new font means possible new text height */
1414 /* does this mean the height of each entry must be separately changed? */
1415 /* or are we guaranteed to get a LBSetFont before the first insert/add? */
1416 if ((hdc = GetDC32(0)))
1418 TEXTMETRIC16 tm;
1419 GetTextMetrics16( hdc, &tm );
1420 lphl->StdItemHeight = tm.tmHeight;
1421 dprintf_listbox(stddeb,"LBSetFont: new font %d with height %d\n",
1422 lphl->hFont, lphl->StdItemHeight);
1423 ReleaseDC32( 0, hdc );
1426 return 0;
1429 /***********************************************************************
1430 * LBPaint
1432 static LONG LBPaint(HWND hwnd, WORD wParam, LONG lParam)
1434 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1435 LPLISTSTRUCT lpls;
1436 PAINTSTRUCT16 ps;
1437 HBRUSH hBrush;
1438 HFONT hOldFont;
1439 HDC16 hdc = BeginPaint16( hwnd, &ps );
1440 DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC);
1441 RECT16 rect, paintRect, scratchRect;
1442 int i, top, height, maxwidth, ipc;
1444 top = 0;
1446 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) {
1447 EndPaint16(hwnd, &ps);
1448 return 0;
1451 GetRgnBox16(dc->w.hGCClipRgn,&paintRect);
1452 GetClientRect16(hwnd, &rect);
1453 IntersectRect16(&paintRect,&rect,&paintRect);
1455 hOldFont = SelectObject(hdc, lphl->hFont);
1457 hBrush = (HBRUSH)SendMessage32A( lphl->hParent, WM_CTLCOLORLISTBOX,
1458 (WPARAM)hdc, (LPARAM)hwnd);
1459 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
1461 FillRect16(hdc, &rect, hBrush);
1463 maxwidth = rect.right;
1464 if (lphl->dwStyle & LBS_MULTICOLUMN) {
1465 rect.right = lphl->ColumnsWidth;
1467 lpls = lphl->lpFirst;
1469 lphl->ItemsVisible = 0;
1470 lphl->ItemsPerColumn = ipc = 0;
1472 for(i = 0; i < lphl->ItemsCount; i++) {
1473 if (lpls == NULL) break;
1475 if (i >= lphl->FirstVisible) {
1476 height = lpls->mis.itemHeight;
1478 if (top > (rect.bottom-height+1)) {
1479 if (lphl->dwStyle & LBS_MULTICOLUMN) {
1480 lphl->ItemsPerColumn = MAX(lphl->ItemsPerColumn, ipc);
1481 ipc = 0;
1482 top = 0;
1483 rect.left += lphl->ColumnsWidth;
1484 rect.right += lphl->ColumnsWidth;
1485 if (rect.left > maxwidth) break;
1486 } else {
1487 break;
1491 lpls->itemRect.top = top;
1492 lpls->itemRect.bottom = top + height;
1493 lpls->itemRect.left = rect.left;
1494 lpls->itemRect.right = rect.right;
1496 if( IntersectRect16(&scratchRect,&paintRect,&lpls->itemRect) )
1498 dprintf_listbox(stddeb,"LBPaint: drawing item: %d %d %d %d %d\n",
1499 rect.left,top,rect.right,top+height,lpls->itemState);
1501 if (lphl->OwnerDrawn && (lphl->ItemFocused == i) && GetFocus32() == hwnd)
1503 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS,
1504 lpls->itemState & ~ODS_FOCUS);
1505 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
1506 lpls->itemState & ~ODS_FOCUS);
1507 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, lpls->itemState);
1509 else
1510 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
1511 lpls->itemState);
1514 top += height;
1515 lphl->ItemsVisible++;
1516 ipc++;
1519 lpls = lpls->lpNext;
1521 ListBoxUpdateWindow(hwnd,lphl,FALSE);
1522 SelectObject(hdc,hOldFont);
1523 EndPaint16( hwnd, &ps );
1524 return 0;
1527 /***********************************************************************
1528 * LBSetFocus
1530 static LONG LBSetFocus(HWND hwnd, WORD wParam, LONG lParam)
1532 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1534 dprintf_listbox(stddeb,"ListBox WM_SETFOCUS for %04x\n",hwnd);
1535 if(!(lphl->dwStyle & LBS_MULTIPLESEL) )
1536 if( lphl->ItemsCount && lphl->ItemFocused != -1)
1538 HDC32 hDC = GetDC32(hwnd);
1539 HFONT hOldFont = SelectObject(hDC, lphl->hFont);
1540 LPLISTSTRUCT lpls;
1542 lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
1543 lpls->itemState |= ODS_FOCUS;
1545 ListBoxDrawItem(hwnd,lphl,hDC,lpls,&lpls->itemRect, ODA_FOCUS, lpls->itemState);
1546 SelectObject(hDC, hOldFont);
1547 ReleaseDC32(hwnd,hDC);
1550 ListBoxSendNotification(lphl, LBN_SETFOCUS);
1552 return 0;
1555 /***********************************************************************
1556 * LBKillFocus
1558 static LONG LBKillFocus(HWND hwnd, WORD wParam, LONG lParam)
1560 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1562 dprintf_listbox(stddeb,"ListBox WM_KILLFOCUS for %04x\n",hwnd);
1563 if (!(lphl->dwStyle & LBS_MULTIPLESEL))
1565 if( lphl->ItemsCount )
1566 if( lphl->ItemFocused != -1 )
1568 HDC32 hDC = GetDC32(hwnd);
1569 HFONT hOldFont = SelectObject(hDC, lphl->hFont);
1570 LPLISTSTRUCT lpls;
1572 lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
1573 lpls->itemState &= ~ODS_FOCUS;
1575 ListBoxDrawItem(hwnd,lphl,hDC,lpls,&lpls->itemRect, ODA_FOCUS, lpls->itemState);
1576 SelectObject(hDC, hOldFont);
1577 ReleaseDC32(hwnd,hDC);
1579 else
1580 dprintf_listbox(stddeb,"LBKillFocus: no focused item!\n");
1582 else
1583 InvalidateRect32( hwnd, NULL, TRUE );
1585 ListBoxSendNotification(lphl, LBN_KILLFOCUS);
1587 return 0;
1590 /***********************************************************************
1591 * LBResetContent
1593 static LONG LBResetContent(HWND hwnd, WORD wParam, LONG lParam)
1595 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1597 dprintf_listbox(stddeb,"ListBox LB_RESETCONTENT !\n");
1598 ListBoxResetContent(lphl);
1599 ListBoxUpdateWindow(hwnd, lphl, TRUE);
1600 return 0;
1603 /***********************************************************************
1604 * LBDir
1606 static LONG LBDir(HWND hwnd, WORD wParam, LONG lParam)
1608 LONG ret;
1609 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1610 dprintf_listbox(stddeb,"ListBox LB_DIR !\n");
1612 ret = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
1613 ListBoxUpdateWindow(hwnd, lphl, TRUE);
1614 return ret;
1617 /***********************************************************************
1618 * LBAddString
1620 static LONG LBAddString(HWND hwnd, WORD wParam, LONG lParam)
1622 WORD wRet;
1623 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1625 wRet = ListBoxAddString(lphl, (SEGPTR)lParam);
1627 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1628 return wRet;
1631 /***********************************************************************
1632 * LBGetText
1634 static LONG LBGetText(HWND hwnd, WORD wParam, LONG lParam)
1636 LONG wRet;
1637 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1639 dprintf_listbox(stddeb, "LB_GETTEXT wParam=%d\n",wParam);
1640 wRet = ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
1642 return wRet;
1645 /***********************************************************************
1646 * LBInsertString
1648 static LONG LBInsertString(HWND hwnd, WORD wParam, LONG lParam)
1650 WORD wRet;
1651 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1653 if (lphl->HasStrings)
1654 wRet = ListBoxInsertString(lphl, wParam, (LPCSTR)PTR_SEG_TO_LIN(lParam));
1655 else
1656 wRet = ListBoxInsertString(lphl, wParam, (LPCSTR)lParam);
1658 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1659 return wRet;
1662 /***********************************************************************
1663 * LBDeleteString
1665 static LONG LBDeleteString(HWND hwnd, WORD wParam, LONG lParam)
1667 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1668 LONG lRet = ListBoxDeleteString(lphl,wParam);
1670 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1671 return lRet;
1674 /***********************************************************************
1675 * LBFindString
1677 static LONG LBFindString(HWND hwnd, WORD wParam, LONG lParam)
1679 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1680 return lbFindString(lphl, wParam, (SEGPTR)lParam, MATCH_SUBSTR);
1683 /***********************************************************************
1684 * LBFindStringExact
1686 static LONG LBFindStringExact(HWND hwnd, WORD wParam, LONG lParam)
1688 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1689 return lbFindString(lphl, wParam, (SEGPTR)lParam, MATCH_EXACT);
1692 /***********************************************************************
1693 * LBGetCaretIndex
1695 static LONG LBGetCaretIndex(HWND hwnd, WORD wParam, LONG lParam)
1697 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1698 return lphl->ItemFocused;
1701 /***********************************************************************
1702 * LBGetCount
1704 static LONG LBGetCount(HWND hwnd, WORD wParam, LONG lParam)
1706 LPHEADLIST lphl;
1708 lphl = ListBoxGetStorageHeader(hwnd);
1709 return lphl->ItemsCount;
1712 /***********************************************************************
1713 * LBGetCurSel
1715 static LONG LBGetCurSel(HWND hwnd, WORD wParam, LONG lParam)
1717 LPHEADLIST lphl;
1719 lphl = ListBoxGetStorageHeader(hwnd);
1720 dprintf_listbox(stddeb,"ListBox LB_GETCURSEL %i !\n",
1721 lphl->ItemFocused);
1722 return lphl->ItemFocused;
1725 /***********************************************************************
1726 * LBGetHorizontalExtent
1728 static LONG LBGetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam)
1730 return 0;
1733 /***********************************************************************
1734 * LBGetItemHeight
1736 static LONG LBGetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
1738 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1739 LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
1741 if (lpls == NULL) return LB_ERR;
1742 return lpls->mis.itemHeight;
1745 /***********************************************************************
1746 * LBGetItemRect
1748 static LONG LBGetItemRect(HWND hwnd, WORD wParam, LONG lParam)
1750 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1751 return ListBoxGetItemRect(lphl, wParam, PTR_SEG_TO_LIN(lParam));
1754 /***********************************************************************
1755 * LBGetSel
1757 static LONG LBGetSel(HWND hwnd, WORD wParam, LONG lParam)
1759 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1760 int iSel = ListBoxGetSel(lphl, wParam);
1762 dprintf_listbox(stdnimp,"LBGetSel: item %u - %i\n",wParam,iSel);
1764 return (iSel)? 1 : 0;
1767 /***********************************************************************
1768 * LBGetSelCount
1770 static LONG LBGetSelCount(HWND hwnd, WORD wParam, LONG lParam)
1772 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1773 LPLISTSTRUCT lpls;
1774 int cnt = 0;
1775 int items = 0;
1777 if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
1778 return LB_ERR;
1780 for( lpls = lphl->lpFirst;
1781 lpls;
1782 lpls = lpls->lpNext )
1784 items++;
1785 if (lpls->itemState )
1786 cnt++;
1789 return cnt;
1792 /***********************************************************************
1793 * LBGetSelItems
1795 static LONG LBGetSelItems(HWND hwnd, WORD wParam, LONG lParam)
1797 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1798 LPLISTSTRUCT lpls;
1799 int cnt, idx;
1800 int *lpItems = PTR_SEG_TO_LIN(lParam);
1802 if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
1803 return LB_ERR;
1805 if (wParam == 0) return 0;
1807 lpls = lphl->lpFirst;
1808 cnt = 0; idx = 0;
1810 while (lpls != NULL) {
1811 if (lpls->itemState > 0) lpItems[cnt++] = idx;
1813 if (cnt == wParam) break;
1814 idx++;
1815 lpls = lpls->lpNext;
1818 return cnt;
1821 /***********************************************************************
1822 * LBGetTextLen
1824 static LONG LBGetTextLen(HWND hwnd, WORD wParam, LONG lParam)
1826 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1827 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
1829 if (lpls == NULL || !lphl->HasStrings) return LB_ERR;
1830 return strlen(lpls->itemText);
1833 /***********************************************************************
1834 * LBGetDlgCode
1836 static LONG LBGetDlgCode(HWND hwnd, WORD wParam, LONG lParam)
1838 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1841 /***********************************************************************
1842 * LBGetTopIndex
1844 static LONG LBGetTopIndex(HWND hwnd, WORD wParam, LONG lParam)
1846 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1848 return lphl->FirstVisible;
1852 /***********************************************************************
1853 * LBSelectString
1855 static LONG LBSelectString(HWND hwnd, WORD wParam, LONG lParam)
1857 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1858 INT iRet;
1860 iRet = lbFindString(lphl, wParam, (SEGPTR)lParam, MATCH_SUBSTR);
1862 if( iRet != LB_ERR)
1864 if( lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) )
1865 ListBoxSetSel(lphl,iRet,TRUE);
1866 else
1867 ListBoxSetCurSel(lphl,iRet);
1869 lphl->ItemFocused = iRet;
1870 InvalidateRect32( hwnd, 0, TRUE );
1872 return iRet;
1875 /***********************************************************************
1876 * LBSelItemRange
1878 static LONG LBSelItemRange(HWND hwnd, WORD wParam, LONG lParam)
1880 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1881 LPLISTSTRUCT lpls;
1882 WORD cnt;
1883 WORD first = LOWORD(lParam);
1884 WORD last = HIWORD(lParam);
1885 BOOL select = wParam;
1887 if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
1888 return LB_ERR;
1890 if (first >= lphl->ItemsCount ||
1891 last >= lphl->ItemsCount) return LB_ERR;
1893 lpls = lphl->lpFirst;
1894 cnt = 0;
1896 while (lpls != NULL) {
1897 if (cnt++ >= first)
1898 lpls->itemState = select ? lpls->itemState | ODS_SELECTED : 0;
1900 if (cnt > last)
1901 break;
1903 lpls = lpls->lpNext;
1906 return 0;
1909 /***********************************************************************
1910 * LBSetCaretIndex
1912 static LONG LBSetCaretIndex(HWND hwnd, WORD wParam, LONG lParam)
1914 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1915 int i;
1917 if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) )) return 0;
1919 dprintf_listbox(stddeb,"LBSetCaretIndex: hwnd %04x n=%i\n",hwnd,wParam);
1921 if (wParam >= lphl->ItemsCount) return LB_ERR;
1923 lphl->ItemFocused = wParam;
1924 i = ListBoxScrollToFocus (lphl);
1926 SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1927 if(i)
1928 InvalidateRect32( hwnd, NULL, TRUE );
1930 return 1;
1933 /***********************************************************************
1934 * LBSetColumnWidth
1936 static LONG LBSetColumnWidth(HWND hwnd, WORD wParam, LONG lParam)
1938 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1939 lphl->ColumnsWidth = wParam;
1940 InvalidateRect32( hwnd, NULL, TRUE );
1941 return 0;
1944 /***********************************************************************
1945 * LBSetHorizontalExtent
1947 static LONG LBSetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam)
1949 return 0;
1952 /***********************************************************************
1953 * LBGetItemData
1955 static LONG LBGetItemData(HWND hwnd, WORD wParam, LONG lParam)
1957 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1958 dprintf_listbox(stddeb, "LB_GETITEMDATA wParam=%x\n", wParam);
1959 return ListBoxGetItemData(lphl, wParam);
1962 /***********************************************************************
1963 * LBSetItemData
1965 static LONG LBSetItemData(HWND hwnd, WORD wParam, LONG lParam)
1967 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1968 dprintf_listbox(stddeb, "LB_SETITEMDATA wParam=%x lParam=%lx\n", wParam, lParam);
1969 return ListBoxSetItemData(lphl, wParam, lParam);
1972 /***********************************************************************
1973 * LBSetTabStops
1975 static LONG LBSetTabStops(HWND hwnd, WORD wParam, LONG lParam)
1977 LPHEADLIST lphl;
1979 lphl = ListBoxGetStorageHeader(hwnd);
1981 if (lphl->TabStops != NULL) {
1982 lphl->iNumStops = 0;
1983 free (lphl->TabStops);
1986 lphl->TabStops = malloc (wParam * sizeof (short));
1987 if (lphl->TabStops) {
1988 lphl->iNumStops = wParam;
1989 memcpy (lphl->TabStops, PTR_SEG_TO_LIN(lParam), wParam * sizeof (short));
1990 return TRUE;
1993 return FALSE;
1996 /***********************************************************************
1997 * LBSetCurSel
1999 static LONG LBSetCurSel(HWND hwnd, WORD wParam, LONG lParam)
2001 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
2002 WORD wRet;
2004 dprintf_listbox(stddeb,"ListBox LB_SETCURSEL wParam=%x !\n",
2005 wParam);
2007 wRet = ListBoxSetCurSel(lphl, wParam);
2009 SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
2010 InvalidateRect32( hwnd, NULL, TRUE );
2012 return wRet;
2015 /***********************************************************************
2016 * LBSetSel
2018 static LONG LBSetSel(HWND hwnd, WORD wParam, LONG lParam)
2020 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
2021 RECT16 rect;
2022 int iRet;
2024 dprintf_listbox(stddeb,"ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam, lParam);
2026 iRet = ListBoxSetSel(lphl, LOWORD(lParam), wParam);
2028 if( iRet > 1 ) InvalidateRect32( hwnd, NULL, TRUE );
2029 else if( iRet != LB_ERR )
2031 if( lphl->dwStyle & LBS_EXTENDEDSEL &&
2032 lphl->ItemFocused != LOWORD(lParam) )
2034 ListBoxGetItemRect(lphl, lphl->ItemFocused , &rect);
2035 InvalidateRect16( hwnd, &rect, TRUE );
2036 lphl->ItemFocused = LOWORD(lParam);
2038 ListBoxGetItemRect(lphl,LOWORD(lParam),&rect);
2039 InvalidateRect16( hwnd, &rect, TRUE );
2042 return (iRet == (WORD)LB_ERR)? LB_ERR: 0;
2045 /***********************************************************************
2046 * LBSetTopIndex
2048 static LONG LBSetTopIndex(HWND hwnd, WORD wParam, LONG lParam)
2050 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
2052 dprintf_listbox(stddeb,"ListBox LB_SETTOPINDEX wParam=%x !\n",
2053 wParam);
2054 lphl->FirstVisible = wParam;
2055 SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
2057 InvalidateRect32( hwnd, NULL, TRUE );
2059 return 0;
2062 /***********************************************************************
2063 * LBSetItemHeight
2065 static LONG LBSetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
2067 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
2068 WORD wRet;
2070 dprintf_listbox(stddeb,"ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam, lParam);
2071 wRet = ListBoxSetItemHeight(lphl, wParam, lParam);
2072 InvalidateRect32( hwnd, NULL, TRUE );
2073 return wRet;
2076 /***********************************************************************
2077 * LBPassToParent
2079 static LRESULT LBPassToParent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2081 WND* ptrWnd = WIN_FindWndPtr(hwnd);
2083 if( ptrWnd )
2084 if( /* !(ptrWnd->dwExStyle & WS_EX_NOPARENTNOTIFY) && */
2085 ptrWnd->parent )
2086 return SendMessage16(ptrWnd->parent->hwndSelf,message,wParam,lParam);
2087 return 0;
2090 /***********************************************************************
2091 * ListBoxWndProc
2093 LRESULT ListBoxWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2095 switch (message) {
2096 case WM_CREATE: return LBCreate(hwnd, wParam, lParam);
2097 case WM_DESTROY: return LBDestroy(hwnd, wParam, lParam);
2098 case WM_GETDLGCODE: return LBGetDlgCode(hwnd, wParam, lParam);
2099 case WM_VSCROLL: return LBVScroll(hwnd, wParam, lParam);
2100 case WM_HSCROLL: return LBHScroll(hwnd, wParam, lParam);
2101 case WM_LBUTTONDOWN: return LBLButtonDown(hwnd, wParam, lParam);
2102 case WM_LBUTTONUP: return LBLButtonUp(hwnd, wParam, lParam);
2103 case WM_RBUTTONUP: return LBRButtonUp(hwnd, wParam, lParam);
2104 case WM_LBUTTONDBLCLK: return LBRButtonUp(hwnd, wParam, lParam);
2105 case WM_MOUSEMOVE: return LBMouseMove(hwnd, wParam, lParam);
2106 case WM_KEYDOWN: return LBKeyDown(hwnd, wParam, lParam);
2107 case WM_CHAR: return LBChar(hwnd, wParam, lParam);
2108 case WM_SETFONT: return LBSetFont(hwnd, wParam, lParam);
2109 case WM_SETREDRAW: return LBSetRedraw(hwnd, wParam, lParam);
2110 case WM_PAINT: return LBPaint(hwnd, wParam, lParam);
2111 case WM_SETFOCUS: return LBSetFocus(hwnd, wParam, lParam);
2112 case WM_KILLFOCUS: return LBKillFocus(hwnd, wParam, lParam);
2113 case WM_NCCALCSIZE: return LBNCCalcSize(hwnd, wParam, lParam);
2114 case LB_RESETCONTENT16: return LBResetContent(hwnd, wParam, lParam);
2115 case LB_DIR16: return LBDir(hwnd, wParam, lParam);
2116 case LB_ADDSTRING16: return LBAddString(hwnd, wParam, lParam);
2117 case LB_INSERTSTRING16: return LBInsertString(hwnd, wParam, lParam);
2118 case LB_DELETESTRING16: return LBDeleteString(hwnd, wParam, lParam);
2119 case LB_FINDSTRING16: return LBFindString(hwnd, wParam, lParam);
2120 case LB_FINDSTRINGEXACT16: return LBFindStringExact(hwnd, wParam, lParam);
2121 case LB_GETCARETINDEX16: return LBGetCaretIndex(hwnd, wParam, lParam);
2122 case LB_GETCOUNT16: return LBGetCount(hwnd, wParam, lParam);
2123 case LB_GETCURSEL16: return LBGetCurSel(hwnd, wParam, lParam);
2124 case LB_GETHORIZONTALEXTENT16: return LBGetHorizontalExtent(hwnd, wParam, lParam);
2125 case LB_GETITEMDATA16: return LBGetItemData(hwnd, wParam, lParam);
2126 case LB_GETITEMHEIGHT16: return LBGetItemHeight(hwnd, wParam, lParam);
2127 case LB_GETITEMRECT16: return LBGetItemRect(hwnd, wParam, lParam);
2128 case LB_GETSEL16: return LBGetSel(hwnd, wParam, lParam);
2129 case LB_GETSELCOUNT16: return LBGetSelCount(hwnd, wParam, lParam);
2130 case LB_GETSELITEMS16: return LBGetSelItems(hwnd, wParam, lParam);
2131 case LB_GETTEXT16: return LBGetText(hwnd, wParam, lParam);
2132 case LB_GETTEXTLEN16: return LBGetTextLen(hwnd, wParam, lParam);
2133 case LB_GETTOPINDEX16: return LBGetTopIndex(hwnd, wParam, lParam);
2134 case LB_SELECTSTRING16: return LBSelectString(hwnd, wParam, lParam);
2135 case LB_SELITEMRANGE16: return LBSelItemRange(hwnd, wParam, lParam);
2136 case LB_SETCARETINDEX16: return LBSetCaretIndex(hwnd, wParam, lParam);
2137 case LB_SETCOLUMNWIDTH16: return LBSetColumnWidth(hwnd, wParam, lParam);
2138 case LB_SETHORIZONTALEXTENT16: return LBSetHorizontalExtent(hwnd, wParam, lParam);
2139 case LB_SETITEMDATA16: return LBSetItemData(hwnd, wParam, lParam);
2140 case LB_SETTABSTOPS16: return LBSetTabStops(hwnd, wParam, lParam);
2141 case LB_SETCURSEL16: return LBSetCurSel(hwnd, wParam, lParam);
2142 case LB_SETSEL16: return LBSetSel(hwnd, wParam, lParam);
2143 case LB_SETTOPINDEX16: return LBSetTopIndex(hwnd, wParam, lParam);
2144 case LB_SETITEMHEIGHT16: return LBSetItemHeight(hwnd, wParam, lParam);
2146 case WM_DROPFILES: return LBPassToParent(hwnd, message, wParam, lParam);
2148 /* these will have to be implemented for proper LBS_EXTENDEDSEL -
2150 * anchor item is an item that with caret (focused) item defines a
2151 * range of currently selected items when listbox is in the extended
2152 * selection mode.
2154 case LB_SETANCHORINDEX16: return LB_SETANCHORINDEX16; /* that's what Windows returns */
2155 case LB_GETANCHORINDEX16: return 0;
2157 case WM_DROPOBJECT:
2158 case WM_QUERYDROPOBJECT:
2159 case WM_DRAGSELECT:
2160 case WM_DRAGMOVE:
2162 LPDRAGINFO lpDragInfo = (LPDRAGINFO) PTR_SEG_TO_LIN((SEGPTR)lParam);
2163 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
2165 lpDragInfo->l = ListBoxFindMouse(lphl,lpDragInfo->pt.x,
2166 lpDragInfo->pt.y);
2168 return LBPassToParent(hwnd, message, wParam, lParam);
2172 return DefWindowProc16(hwnd, message, wParam, lParam);
2176 /**********************************************************************
2177 * DlgDirSelect (USER.99)
2179 BOOL DlgDirSelect( HWND hDlg, LPSTR lpStr, INT id )
2181 char *buffer;
2182 INT i;
2184 dprintf_listbox( stddeb, "DlgDirSelect: %04x '%s' %d\n", hDlg, lpStr, id );
2185 if ((i = SendDlgItemMessage16( hDlg, id, LB_GETCURSEL16, 0, 0 )) == LB_ERR)
2186 return FALSE;
2187 if (!(buffer = SEGPTR_ALLOC( 20 * sizeof(char) ))) return FALSE;
2188 SendDlgItemMessage16(hDlg, id, LB_GETTEXT16, i, (LPARAM)SEGPTR_GET(buffer) );
2189 if (buffer[0] == '[') /* drive or directory */
2191 if (buffer[1] == '-') /* drive */
2193 lpStr[0] = buffer[2];
2194 lpStr[1] = ':';
2195 lpStr[2] = '\0';
2196 dprintf_listbox( stddeb, "Returning drive '%s'\n", lpStr );
2197 SEGPTR_FREE(buffer);
2198 return TRUE;
2200 strcpy( lpStr, buffer + 1 );
2201 lpStr[strlen(lpStr)-1] = '\\';
2202 dprintf_listbox( stddeb, "Returning directory '%s'\n", lpStr );
2203 SEGPTR_FREE(buffer);
2204 return TRUE;
2206 strcpy( lpStr, buffer );
2207 dprintf_listbox( stddeb, "Returning file '%s'\n", lpStr );
2208 SEGPTR_FREE(buffer);
2209 return FALSE;
2213 /**********************************************************************
2214 * DlgDirList (USER.100)
2216 INT DlgDirList( HWND hDlg, SEGPTR spec, INT idLBox, INT idStatic, UINT attrib )
2218 char *filespec = (char *)PTR_SEG_TO_LIN( spec );
2219 int drive;
2220 HWND hwnd;
2222 #define SENDMSG(msg,wparam,lparam) \
2223 ((attrib & DDL_POSTMSGS) ? PostMessage( hwnd, msg, wparam, lparam ) \
2224 : SendMessage16( hwnd, msg, wparam, lparam ))
2226 dprintf_listbox( stddeb, "DlgDirList: %04x '%s' %d %d %04x\n",
2227 hDlg, filespec ? filespec : "NULL",
2228 idLBox, idStatic, attrib );
2230 if (filespec && filespec[0] && (filespec[1] == ':'))
2232 drive = toupper( filespec[0] ) - 'A';
2233 filespec += 2;
2234 if (!DRIVE_SetCurrentDrive( drive )) return FALSE;
2236 else drive = DRIVE_GetCurrentDrive();
2238 if (idLBox && ((hwnd = GetDlgItem( hDlg, idLBox )) != 0))
2240 char mask[20];
2242 if (!filespec || !filespec[0]) strcpy( mask, "*.*" );
2243 else
2245 /* If the path exists and is a directory, chdir to it */
2246 if (DRIVE_Chdir( drive, filespec )) strcpy( mask, "*.*" );
2247 else
2249 char *p, *p2;
2250 p = filespec;
2251 if ((p2 = strrchr( p, '\\' ))) p = p2 + 1;
2252 if ((p2 = strrchr( p, '/' ))) p = p2 + 1;
2253 lstrcpyn32A( mask, p, sizeof(mask) );
2254 if (p != filespec)
2256 p[-1] = '\0';
2257 if (!DRIVE_Chdir( drive, filespec )) return FALSE;
2262 strcpy( (char *)PTR_SEG_TO_LIN(spec), mask );
2264 dprintf_listbox(stddeb, "ListBoxDirectory: path=%c:\\%s mask=%s\n",
2265 'A' + drive, DRIVE_GetDosCwd(drive), mask);
2267 SENDMSG( LB_RESETCONTENT16, 0, 0 );
2268 if ((attrib & DDL_DIRECTORY) && !(attrib & DDL_EXCLUSIVE))
2270 char *temp;
2271 if (SENDMSG( LB_DIR16, attrib & ~(DDL_DIRECTORY | DDL_DRIVES),
2272 (LPARAM)spec ) == LB_ERR) return FALSE;
2273 if (!(temp = SEGPTR_ALLOC( 4*sizeof(char) ))) return FALSE;
2274 strcpy( temp, "*.*" );
2275 /* FIXME: this won't work with PostMessage(), as temp will */
2276 /* have been freed by the time we do a DispatchMessage(). */
2277 if (SENDMSG( LB_DIR16, (attrib & (DDL_DIRECTORY | DDL_DRIVES)) | DDL_EXCLUSIVE,
2278 (LPARAM)SEGPTR_GET(temp) ) == LB_ERR)
2280 SEGPTR_FREE(temp);
2281 return FALSE;
2283 SEGPTR_FREE(temp);
2285 else
2287 if (SENDMSG( LB_DIR16, attrib, (LPARAM)spec) == LB_ERR) return FALSE;
2291 if (idStatic && ((hwnd = GetDlgItem( hDlg, idStatic )) != 0))
2293 char temp[512];
2294 int drive = DRIVE_GetCurrentDrive();
2295 strcpy( temp, "A:\\" );
2296 temp[0] += drive;
2297 lstrcpyn32A( temp + 3, DRIVE_GetDosCwd(drive), sizeof(temp)-3 );
2298 AnsiLower( temp );
2299 /* Can't use PostMessage() here, because the string is on the stack */
2300 SetDlgItemText32A( hDlg, idStatic, temp );
2302 return TRUE;
2303 #undef SENDMSG