4 * Copyright Martin Ayotte, 1993
5 * Constantine Sapuntzakis, 1995
12 * - check if multi-column listboxes work
13 * - implement more messages and styles
14 * - implement caret for LBS_EXTENDEDSEL
36 #define LIST_HEAP_ALLOC(lphl,f,size) ((int)HEAP_Alloc(&lphl->Heap,f,size) & 0xffff)
37 #define LIST_HEAP_FREE(lphl,handle) (HEAP_Free(&lphl->Heap,LIST_HEAP_ADDR(lphl,handle)))
38 #define LIST_HEAP_ADDR(lphl,handle) \
39 ((void *)((handle) ? ((handle) | ((int)lphl->Heap & 0xffff0000)) : 0))
41 /* FIXME: shouldn't each listbox have its own heap? */
43 #define LIST_HEAP_ALLOC(lphl,f,size) USER_HEAP_ALLOC(size)
44 #define LIST_HEAP_FREE(lphl,handle) USER_HEAP_FREE(handle)
45 #define LIST_HEAP_ADDR(lphl,handle) USER_HEAP_LIN_ADDR(handle)
46 #define LIST_HEAP_SEG_ADDR(lphl,handle) USER_HEAP_SEG_ADDR(handle)
48 /* Something like this maybe ? */
49 #define LIST_HEAP_ALLOC(lphl,f,size) \
50 LOCAL_Alloc( lphl->HeapSel, LMEM_FIXED, (size) )
52 #define LIST_HEAP_REALLOC(handle,size) \
53 LOCAL_ReAlloc( USER_HeapSel, (handle), (size), LMEM_FIXED )
55 #define LIST_HEAP_FREE(lphl,handle) \
56 LOCAL_Free( lphl->HeapSel, (handle) )
57 #define LIST_HEAP_ADDR(lphl,handle) \
58 ((handle) ? PTR_SEG_OFF_TO_LIN(lphl->HeapSel, (handle)) : NULL)
59 #define LIST_HEAP_SEG_ADDR(lphl,handle) \
60 ((handle) ? MAKELONG((handle), lphl->HeapSel) : 0)
64 #define LIST_HEAP_SIZE 0x10000
66 #define LBMM_EDGE 4 /* distance inside box which is same as moving mouse
67 outside box, to trigger scrolling of LB */
69 static void ListBoxInitialize(LPHEADLIST lphl)
73 lphl->ItemsVisible = 0;
74 lphl->FirstVisible = 0;
75 lphl->ColumnsVisible = 1;
76 lphl->ItemsPerColumn = 0;
77 lphl->ItemFocused = -1;
78 lphl->PrevFocused = -1;
81 void CreateListBoxStruct(HWND hwnd, WORD CtlType, LONG styles, HWND parent)
86 lphl = (LPHEADLIST)xmalloc(sizeof(HEADLIST));
87 SetWindowLong32A(hwnd, 0, (LONG)lphl);
88 ListBoxInitialize(lphl);
89 lphl->DrawCtlType = CtlType;
90 lphl->CtlID = GetWindowWord(hwnd,GWW_ID);
91 lphl->bRedrawFlag = TRUE;
93 lphl->TabStops = NULL;
94 lphl->hFont = GetStockObject(SYSTEM_FONT);
96 if (CtlType==ODT_COMBOBOX) /* use the "faked" style for COMBOLBOX */
97 /* LBS_SORT instead CBS_SORT e.g. */
98 lphl->dwStyle = MAKELONG(LOWORD(styles),HIWORD(GetWindowLong32A(hwnd,GWL_STYLE)));
100 lphl->dwStyle = GetWindowLong32A(hwnd,GWL_STYLE); /* use original style dword */
101 lphl->hParent = parent;
102 lphl->StdItemHeight = 15; /* FIXME: should get the font height */
103 lphl->OwnerDrawn = styles & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE);
104 lphl->HasStrings = (styles & LBS_HASSTRINGS) || !lphl->OwnerDrawn;
106 /* create dummy hdc to set text height */
107 if ((hdc = GetDC(0)))
110 GetTextMetrics16( hdc, &tm );
111 lphl->StdItemHeight = tm.tmHeight;
112 dprintf_listbox(stddeb,"CreateListBoxStruct: font height %d\n",
113 lphl->StdItemHeight);
117 if (lphl->OwnerDrawn)
121 lphl->needMeasure = TRUE;
122 dummyls.mis.CtlType = lphl->DrawCtlType;
123 dummyls.mis.CtlID = lphl->CtlID;
124 dummyls.mis.itemID = -1;
125 dummyls.mis.itemWidth = 0; /* ignored */
126 dummyls.mis.itemData = 0;
128 ListBoxAskMeasure(lphl,&dummyls);
131 /* WINELIBS list boxes do not operate on local heaps */
133 lphl->HeapSel = GlobalAlloc16(GMEM_FIXED,LIST_HEAP_SIZE);
134 LocalInit( lphl->HeapSel, 0, LIST_HEAP_SIZE-1);
140 void DestroyListBoxStruct(LPHEADLIST lphl)
142 /* XXX need to free lphl->Heap */
143 GlobalFree16(lphl->HeapSel);
147 static LPHEADLIST ListBoxGetStorageHeader(HWND hwnd)
149 return (LPHEADLIST)GetWindowLong32A(hwnd,0);
152 /* Send notification "code" as part of a WM_COMMAND-message if hwnd
153 has the LBS_NOTIFY style */
154 void ListBoxSendNotification(LPHEADLIST lphl, WORD code)
156 if (lphl->dwStyle & LBS_NOTIFY)
158 SendMessage32A(lphl->hParent, WM_COMMAND,
159 MAKEWPARAM(lphl->CtlID,code), (LPARAM)lphl->hSelf);
161 SendMessage16(lphl->hParent, WM_COMMAND,
162 lphl->CtlID, MAKELONG(lphl->hSelf, code));
167 /* get the maximum value of lphl->FirstVisible */
168 int ListMaxFirstVisible(LPHEADLIST lphl)
170 int m = lphl->ItemsCount-lphl->ItemsVisible;
171 return (m < 0) ? 0 : m;
175 void ListBoxUpdateWindow(HWND hwnd, LPHEADLIST lphl, BOOL repaint)
177 if (lphl->dwStyle & WS_VSCROLL)
178 SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
179 if ((lphl->dwStyle & WS_HSCROLL) && (lphl->ItemsPerColumn != 0))
180 SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible /
181 lphl->ItemsPerColumn + 1, TRUE);
183 if (repaint && lphl->bRedrawFlag) InvalidateRect32( hwnd, NULL, TRUE );
186 /* Returns: 0 if nothing needs to be changed */
187 /* 1 if FirstVisible changed */
189 int ListBoxScrollToFocus(LPHEADLIST lphl)
193 if (lphl->ItemsCount == 0) return 0;
194 if (lphl->ItemFocused == -1) return 0;
196 end = lphl->FirstVisible + lphl->ItemsVisible - 1;
198 if (lphl->ItemFocused < lphl->FirstVisible ) {
199 lphl->FirstVisible = lphl->ItemFocused;
202 if (lphl->ItemFocused > end) {
203 WORD maxFirstVisible = ListMaxFirstVisible(lphl);
205 lphl->FirstVisible = lphl->ItemFocused;
207 if (lphl->FirstVisible > maxFirstVisible) {
208 lphl->FirstVisible = maxFirstVisible;
217 LPLISTSTRUCT ListBoxGetItem(LPHEADLIST lphl, UINT uIndex)
222 if (uIndex >= lphl->ItemsCount) return NULL;
224 lpls = lphl->lpFirst;
225 while (Count++ < uIndex) lpls = lpls->lpNext;
230 void ListBoxDrawItem (HWND hwnd, LPHEADLIST lphl, HDC hdc, LPLISTSTRUCT lpls,
231 RECT16 *rect, WORD itemAction, WORD itemState)
233 if (lphl->OwnerDrawn)
235 DRAWITEMSTRUCT32 dis;
237 dis.CtlID = lpls->mis.CtlID;
238 dis.CtlType = lpls->mis.CtlType;
239 dis.itemID = lpls->mis.itemID;
242 dis.itemData = lpls->mis.itemData;
243 dis.itemAction = itemAction;
244 dis.itemState = itemState;
245 CONV_RECT16TO32( rect, &dis.rcItem );
246 SendMessage32A( lphl->hParent, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis );
249 if (itemAction == ODA_DRAWENTIRE || itemAction == ODA_SELECT) {
251 DWORD dwOldTextColor = 0;
253 OldBkMode = SetBkMode(hdc, TRANSPARENT);
255 if (itemState != 0) {
256 dwOldTextColor = SetTextColor(hdc, 0x00FFFFFFL);
257 FillRect16(hdc, rect, GetStockObject(BLACK_BRUSH));
260 if (lphl->dwStyle & LBS_USETABSTOPS) {
261 TabbedTextOut(hdc, rect->left + 5, rect->top + 2,
262 (char *)lpls->itemText, strlen((char *)lpls->itemText),
263 lphl->iNumStops, lphl->TabStops, 0);
265 TextOut16(hdc, rect->left + 5, rect->top + 2,
266 (char *)lpls->itemText, strlen((char *)lpls->itemText));
269 if (itemState != 0) {
270 SetTextColor(hdc, dwOldTextColor);
273 SetBkMode(hdc, OldBkMode);
275 else DrawFocusRect16(hdc, rect);
279 int ListBoxFindMouse(LPHEADLIST lphl, int X, int Y)
281 LPLISTSTRUCT lpls = lphl->lpFirst;
285 point.x = X; point.y = Y;
286 if (lphl->ItemsCount == 0) return LB_ERR;
288 for(i = 0; i < lphl->FirstVisible; i++) {
289 if (lpls == NULL) return LB_ERR;
292 for(j = 0; j < lphl->ItemsVisible; i++, j++) {
293 if (lpls == NULL) return LB_ERR;
294 if (PtInRect16(&lpls->itemRect,point)) {
299 dprintf_listbox(stddeb,"ListBoxFindMouse: not found\n");
304 void ListBoxAskMeasure(LPHEADLIST lphl, LPLISTSTRUCT lpls)
306 HANDLE hTemp = USER_HEAP_ALLOC( sizeof(MEASUREITEMSTRUCT16) );
307 MEASUREITEMSTRUCT16 *lpmeasure = (MEASUREITEMSTRUCT16 *) USER_HEAP_LIN_ADDR(hTemp);
309 if (lpmeasure == NULL) {
310 fprintf(stdnimp,"ListBoxAskMeasure() out of memory !\n");
314 *lpmeasure = lpls->mis;
315 lpmeasure->itemHeight = lphl->StdItemHeight;
316 SendMessage16(lphl->hParent, WM_MEASUREITEM, lphl->CtlID, (LPARAM)USER_HEAP_SEG_ADDR(hTemp));
318 if (lphl->dwStyle & LBS_OWNERDRAWFIXED) {
319 if (lpmeasure->itemHeight > lphl->StdItemHeight)
320 lphl->StdItemHeight = lpmeasure->itemHeight;
321 lpls->mis.itemHeight = lpmeasure->itemHeight;
324 USER_HEAP_FREE(hTemp);
327 /* -------------------- strings and item data ---------------------- */
329 LPLISTSTRUCT ListBoxCreateItem(LPHEADLIST lphl, int id)
331 LPLISTSTRUCT lplsnew = (LPLISTSTRUCT)malloc(sizeof(LISTSTRUCT));
333 if (lplsnew == NULL) return NULL;
335 lplsnew->itemState = 0;
336 lplsnew->mis.CtlType = lphl->DrawCtlType;
337 lplsnew->mis.CtlID = lphl->CtlID;
338 lplsnew->mis.itemID = id;
339 lplsnew->mis.itemHeight = lphl->StdItemHeight;
340 lplsnew->mis.itemWidth = 0; /* ignored */
341 lplsnew->mis.itemData = 0;
342 SetRectEmpty16( &lplsnew->itemRect );
349 int ListBoxInsertString(LPHEADLIST lphl, UINT uIndex, LPCSTR newstr)
351 LPLISTSTRUCT *lppls, lplsnew, lpls;
356 dprintf_listbox(stddeb,"ListBoxInsertString(%d, %p);\n", uIndex, newstr);
358 if (!newstr) return -1;
360 if (uIndex == (UINT)-1)
361 uIndex = lphl->ItemsCount;
363 lppls = &lphl->lpFirst;
364 for(Count = 0; Count < uIndex; Count++) {
365 if (*lppls == NULL) return LB_ERR;
366 lppls = (LPLISTSTRUCT *) &(*lppls)->lpNext;
369 lplsnew = ListBoxCreateItem(lphl, Count);
371 if (lplsnew == NULL) {
372 fprintf(stdnimp,"ListBoxInsertString() out of memory !\n");
376 lplsnew->lpNext = *lppls;
381 if (lphl->HasStrings) {
382 dprintf_listbox(stddeb," string: %s\n", newstr);
383 hStr = LIST_HEAP_ALLOC(lphl, LMEM_MOVEABLE, strlen(newstr) + 1);
384 str = (LPSTR)LIST_HEAP_ADDR(lphl, hStr);
385 if (str == NULL) return LB_ERRSPACE;
387 lplsnew->itemText = str;
388 /* I'm not so sure about the next one */
389 lplsnew->mis.itemData = 0;
391 lplsnew->itemText = NULL;
392 lplsnew->mis.itemData = (DWORD)newstr;
395 lplsnew->mis.itemID = uIndex;
396 lplsnew->hData = hStr;
398 /* adjust the itemID field of the following entries */
399 for(lpls = lplsnew->lpNext; lpls != NULL; lpls = lpls->lpNext) {
403 if (lphl->needMeasure) {
404 ListBoxAskMeasure(lphl, lplsnew);
407 dprintf_listbox(stddeb,"ListBoxInsertString // count=%d\n", lphl->ItemsCount);
412 int ListBoxAddString(LPHEADLIST lphl, LPCSTR newstr)
414 UINT pos = (UINT) -1;
416 if (lphl->HasStrings && (lphl->dwStyle & LBS_SORT)) {
417 LPLISTSTRUCT lpls = lphl->lpFirst;
418 for (pos = 0; lpls != NULL; lpls = lpls->lpNext, pos++)
419 if (strcmp(lpls->itemText, newstr) >= 0)
422 return ListBoxInsertString(lphl, pos, newstr);
426 int ListBoxGetText(LPHEADLIST lphl, UINT uIndex, LPSTR OutStr)
431 dprintf_listbox(stddeb, "ListBoxGetText // OutStr==NULL\n");
435 lpls = ListBoxGetItem (lphl, uIndex);
436 if (lpls == NULL) return LB_ERR;
438 if (!lphl->HasStrings) {
439 *((long *)OutStr) = lpls->mis.itemData;
443 strcpy(OutStr, lpls->itemText);
444 return strlen(OutStr);
448 DWORD ListBoxGetItemData(LPHEADLIST lphl, UINT uIndex)
452 lpls = ListBoxGetItem (lphl, uIndex);
453 if (lpls == NULL) return LB_ERR;
454 return lpls->mis.itemData;
458 int ListBoxSetItemData(LPHEADLIST lphl, UINT uIndex, DWORD ItemData)
460 LPLISTSTRUCT lpls = ListBoxGetItem(lphl, uIndex);
462 if (lpls == NULL) return LB_ERR;
463 lpls->mis.itemData = ItemData;
468 int ListBoxDeleteString(LPHEADLIST lphl, UINT uIndex)
470 LPLISTSTRUCT lpls, lpls2;
473 if (uIndex >= lphl->ItemsCount) return LB_ERR;
475 lpls = lphl->lpFirst;
476 if (lpls == NULL) return LB_ERR;
479 lphl->lpFirst = lpls->lpNext;
481 LPLISTSTRUCT lpls2 = NULL;
482 for(Count = 0; Count < uIndex; Count++) {
483 if (lpls->lpNext == NULL) return LB_ERR;
486 lpls = (LPLISTSTRUCT)lpls->lpNext;
488 lpls2->lpNext = lpls->lpNext;
491 /* adjust the itemID field of the following entries */
492 for(lpls2 = lpls->lpNext; lpls2 != NULL; lpls2 = lpls2->lpNext) {
498 if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
501 return lphl->ItemsCount;
505 int ListBoxFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr)
509 UINT First = nFirst + 1;
510 LPSTR lpMatchStr = (LPSTR)MatchStr;
512 if (First > lphl->ItemsCount) return LB_ERR;
514 if (lphl->HasStrings) lpMatchStr = PTR_SEG_TO_LIN(MatchStr);
516 lpls = ListBoxGetItem(lphl, First);
518 while(lpls != NULL) {
519 if (lphl->HasStrings) {
520 if (strstr(lpls->itemText, lpMatchStr) == lpls->itemText) return Count;
521 } else if (lphl->dwStyle & LBS_SORT) {
522 /* XXX Do a compare item */
525 if (lpls->mis.itemData == (DWORD)lpMatchStr) return Count;
531 /* Start over at top */
533 lpls = lphl->lpFirst;
535 while (Count < First) {
536 if (lphl->HasStrings) {
537 if (strstr(lpls->itemText, lpMatchStr) == lpls->itemText) return Count;
538 } else if (lphl->dwStyle & LBS_SORT) {
539 /* XXX Do a compare item */
541 if (lpls->mis.itemData == (DWORD)lpMatchStr) return Count;
551 int ListBoxResetContent(LPHEADLIST lphl)
556 if (lphl->ItemsCount == 0) return 0;
558 dprintf_listbox(stddeb, "ListBoxResetContent // ItemCount = %d\n",
561 for(i = 0; i < lphl->ItemsCount; i++) {
562 lpls = lphl->lpFirst;
563 if (lpls == NULL) return LB_ERR;
565 lphl->lpFirst = lpls->lpNext;
566 if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
569 ListBoxInitialize(lphl);
574 /* --------------------- selection ------------------------- */
576 int ListBoxSetCurSel(LPHEADLIST lphl, WORD wIndex)
580 /* use ListBoxSetSel instead */
581 if (lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ) return 0;
583 /* unselect previous item */
584 if (lphl->ItemFocused != -1) {
585 lphl->PrevFocused = lphl->ItemFocused;
586 lpls = ListBoxGetItem(lphl, lphl->ItemFocused);
587 if (lpls == 0) return LB_ERR;
591 if ((wIndex != (UINT)-1) && (wIndex < lphl->ItemsCount))
593 lphl->ItemFocused = wIndex;
594 lpls = ListBoxGetItem(lphl, wIndex);
595 if (lpls == 0) return LB_ERR;
596 lpls->itemState = ODS_SELECTED | ODS_FOCUS;
605 int ListBoxSetSel(LPHEADLIST lphl, WORD wIndex, WORD state)
610 if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
613 if (wIndex == (UINT)-1) {
614 for (lpls = lphl->lpFirst; lpls != NULL; lpls = lpls->lpNext) {
615 if( lpls->itemState & ODS_SELECTED) n++;
616 lpls->itemState = state? lpls->itemState | ODS_SELECTED
617 : lpls->itemState & ~ODS_SELECTED;
622 if (wIndex >= lphl->ItemsCount) return LB_ERR;
624 lpls = ListBoxGetItem(lphl, wIndex);
625 lpls->itemState = state? lpls->itemState | ODS_SELECTED
626 : lpls->itemState & ~ODS_SELECTED;
632 int ListBoxGetSel(LPHEADLIST lphl, WORD wIndex)
634 LPLISTSTRUCT lpls = ListBoxGetItem(lphl, wIndex);
636 if (lpls == NULL) return LB_ERR;
637 return lpls->itemState & ODS_SELECTED;
640 /* ------------------------- dir listing ------------------------ */
642 LONG ListBoxDirectory(LPHEADLIST lphl, UINT attrib, LPCSTR filespec)
644 char temp[16], mask[13];
651 dprintf_listbox(stddeb, "ListBoxDirectory: '%s' %04x\n", filespec, attrib);
652 if (!filespec) return LB_ERR;
653 if (!(ptr = DOSFS_GetUnixFileName( filespec, FALSE ))) return LB_ERR;
655 p = strrchr( path, '/' );
657 if (!(ptr = DOSFS_ToDosFCBFormat( p )))
664 dprintf_listbox(stddeb, "ListBoxDirectory: path=%s mask=%s\n", path, mask);
668 while ((count = DOSFS_FindNext( path, mask, 0, attrib, skip, &entry )) > 0)
671 if (entry.attr & FA_DIRECTORY)
673 if ((attrib & DDL_DIRECTORY) && strcmp(entry.name, ". "))
675 sprintf(temp, "[%s]", DOSFS_ToDosDTAFormat( entry.name ) );
677 if ((ret = ListBoxAddString(lphl, temp)) == LB_ERR) break;
680 else /* not a directory */
682 if (!(attrib & DDL_EXCLUSIVE) ||
683 ((attrib & (FA_RDONLY|FA_HIDDEN|FA_SYSTEM|FA_ARCHIVE)) ==
684 (entry.attr & (FA_RDONLY|FA_HIDDEN|FA_SYSTEM|FA_ARCHIVE))))
686 strcpy( temp, DOSFS_ToDosDTAFormat( entry.name ) );
688 if ((ret = ListBoxAddString(lphl, temp)) == LB_ERR) break;
692 if (attrib & DDL_DRIVES)
695 strcpy( temp, "[-a-]" );
696 for (x = 0; x < MAX_DOS_DRIVES; x++, temp[2]++)
698 if (DRIVE_IsValid(x))
699 if ((ret = ListBoxAddString(lphl, temp)) == LB_ERR) break;
706 /* ------------------------- dimensions ------------------------- */
708 int ListBoxGetItemRect(LPHEADLIST lphl, WORD wIndex, LPRECT16 lprect)
710 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wIndex);
712 if (lpls == NULL) return LB_ERR;
713 *lprect = lpls->itemRect;
718 int ListBoxSetItemHeight(LPHEADLIST lphl, WORD wIndex, long height)
722 if (!(lphl->dwStyle & LBS_OWNERDRAWVARIABLE)) {
723 lphl->StdItemHeight = (short)height;
727 lpls = ListBoxGetItem(lphl, wIndex);
728 if (lpls == NULL) return LB_ERR;
730 lpls->mis.itemHeight = height;
734 /* -------------------------- string search ------------------------ */
736 int ListBoxFindNextMatch(LPHEADLIST lphl, WORD wChar)
741 if ((char)wChar < ' ') return LB_ERR;
742 if (!lphl->HasStrings) return LB_ERR;
744 lpls = lphl->lpFirst;
746 for (count = 0; lpls != NULL; lpls = lpls->lpNext, count++) {
747 if (tolower(*lpls->itemText) == tolower((char)wChar)) break;
749 if (lpls == NULL) return LB_ERR;
751 for(; lpls != NULL; lpls = lpls->lpNext, count++) {
752 if (*lpls->itemText != (char)wChar)
754 if ((short) count > lphl->ItemFocused)
760 /***********************************************************************
763 static LONG LBCreate(HWND hwnd, WORD wParam, LONG lParam)
766 LONG dwStyle = GetWindowLong32A(hwnd,GWL_STYLE);
769 CreateListBoxStruct(hwnd, ODT_LISTBOX, dwStyle, GetParent(hwnd));
770 lphl = ListBoxGetStorageHeader(hwnd);
771 dprintf_listbox(stddeb,"ListBox created: lphl = %p dwStyle = %04x:%04x\n",
772 lphl, HIWORD(dwStyle), LOWORD(dwStyle));
774 GetClientRect16(hwnd,&rect);
775 lphl->ColumnsWidth = rect.right - rect.left;
777 if (dwStyle & WS_VSCROLL)
778 SetScrollRange(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
779 if (dwStyle & WS_HSCROLL)
780 SetScrollRange(hwnd, SB_HORZ, 1, 1, TRUE);
786 /***********************************************************************
789 static LONG LBDestroy(HWND hwnd, WORD wParam, LONG lParam)
791 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
793 ListBoxResetContent(lphl);
795 DestroyListBoxStruct(lphl);
796 dprintf_listbox(stddeb,"ListBox destroyed: lphl = %p\n",lphl);
800 /***********************************************************************
803 static LONG LBVScroll(HWND hwnd, WORD wParam, LONG lParam)
805 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
808 dprintf_listbox(stddeb,"ListBox WM_VSCROLL w=%04X l=%08lX !\n",
810 y = lphl->FirstVisible;
814 if (lphl->FirstVisible > 0)
815 lphl->FirstVisible--;
819 lphl->FirstVisible++;
823 if (lphl->FirstVisible > lphl->ItemsVisible) {
824 lphl->FirstVisible -= lphl->ItemsVisible;
826 lphl->FirstVisible = 0;
831 lphl->FirstVisible += lphl->ItemsVisible;
835 lphl->FirstVisible = LOWORD(lParam);
839 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
840 lphl->FirstVisible = ListMaxFirstVisible(lphl);
842 if (y != lphl->FirstVisible) {
843 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
844 InvalidateRect32( hwnd, NULL, TRUE );
849 /***********************************************************************
852 static LONG LBHScroll(HWND hwnd, WORD wParam, LONG lParam)
857 dprintf_listbox(stddeb,"ListBox WM_HSCROLL w=%04X l=%08lX !\n",
859 lphl = ListBoxGetStorageHeader(hwnd);
860 y = lphl->FirstVisible;
863 if (lphl->FirstVisible > lphl->ItemsPerColumn) {
864 lphl->FirstVisible -= lphl->ItemsPerColumn;
866 lphl->FirstVisible = 0;
870 lphl->FirstVisible += lphl->ItemsPerColumn;
873 if (lphl->ItemsPerColumn != 0) {
874 int lbsub = lphl->ItemsVisible / lphl->ItemsPerColumn * lphl->ItemsPerColumn;
875 if (lphl->FirstVisible > lbsub) {
876 lphl->FirstVisible -= lbsub;
878 lphl->FirstVisible = 0;
883 if (lphl->ItemsPerColumn != 0)
884 lphl->FirstVisible += lphl->ItemsVisible /
885 lphl->ItemsPerColumn * lphl->ItemsPerColumn;
888 lphl->FirstVisible = lphl->ItemsPerColumn * LOWORD(lParam);
891 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
892 lphl->FirstVisible = ListMaxFirstVisible(lphl);
894 if (lphl->ItemsPerColumn != 0) {
895 lphl->FirstVisible = lphl->FirstVisible /
896 lphl->ItemsPerColumn * lphl->ItemsPerColumn + 1;
897 if (y != lphl->FirstVisible) {
898 SetScrollPos(hwnd, SB_HORZ, lphl->FirstVisible /
899 lphl->ItemsPerColumn + 1, TRUE);
900 InvalidateRect32( hwnd, NULL, TRUE );
906 /***********************************************************************
909 static LONG LBLButtonDown(HWND hwnd, WORD wParam, LONG lParam)
911 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
919 lphl->PrevFocused = lphl->ItemFocused;
921 y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
923 if (y == -1) return 0;
925 if (lphl->dwStyle & LBS_NOTIFY && y!= LB_ERR )
926 if( SendMessage16(lphl->hParent, WM_LBTRACKPOINT, y, lParam) )
930 switch( lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) )
932 case LBS_MULTIPLESEL:
933 lphl->ItemFocused = y;
934 wRet = ListBoxGetSel(lphl, y);
935 ListBoxSetSel(lphl, y, !wRet);
937 case LBS_EXTENDEDSEL:
938 /* should handle extended mode here and in kbd handler
941 if ( lphl->PrevFocused != y && y!= LB_ERR)
943 LPLISTSTRUCT lpls = ListBoxGetItem( lphl, lphl->ItemFocused = y );
944 n = ListBoxSetSel(lphl,-1,FALSE);
946 lpls->itemState = ODS_FOCUS | ODS_SELECTED;
948 if( n > 1 && n != LB_ERR )
949 InvalidateRect32( hwnd,NULL,TRUE );
956 if( y!=lphl->ItemFocused )
957 ListBoxSetCurSel(lphl, y);
962 fprintf(stdnimp,"Listbox: LBS_MULTIPLESEL and LBS_EXTENDEDSEL are on!\n");
966 /* invalidate changed items */
967 if( lphl->dwStyle & LBS_MULTIPLESEL || y!=lphl->PrevFocused )
969 ListBoxGetItemRect(lphl, y, &rectsel);
970 InvalidateRect16( hwnd, &rectsel, TRUE );
972 if( lphl->PrevFocused!=-1 && y!=lphl->PrevFocused )
974 ListBoxGetItemRect(lphl, lphl->PrevFocused, &rectsel);
975 InvalidateRect16( hwnd, &rectsel, TRUE );
979 if (GetWindowLong32A(lphl->hSelf,GWL_EXSTYLE) & WS_EX_DRAGDETECT)
980 if( DragDetect(lphl->hSelf,MAKEPOINT16(lParam)) )
981 SendMessage16(lphl->hParent, WM_BEGINDRAG,0,0L);
986 /***********************************************************************
989 static LONG LBLButtonUp(HWND hwnd, WORD wParam, LONG lParam)
991 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
993 if (GetCapture() == hwnd) ReleaseCapture();
995 if (lphl->PrevFocused != lphl->ItemFocused)
996 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1001 /***********************************************************************
1004 static LONG LBRButtonUp(HWND hwnd, WORD wParam, LONG lParam)
1006 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1009 SendMessage32A(lphl->hParent, WM_COMMAND,
1010 MAKEWPARAM(GetWindowWord(hwnd,GWW_ID),LBN_DBLCLK),
1013 SendMessage16(lphl->hParent, WM_COMMAND, GetWindowWord(hwnd,GWW_ID),
1014 MAKELONG(hwnd, LBN_DBLCLK));
1020 /***********************************************************************
1023 static LONG LBMouseMove(HWND hwnd, WORD wParam, LONG lParam)
1025 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1026 int y,redraw_prev = 0;
1028 RECT16 rect, rectsel; /* XXX Broken */
1030 dprintf_listbox(stddeb,"LBMouseMove %d %d\n",SLOWORD(lParam),SHIWORD(lParam));
1031 if ((wParam & MK_LBUTTON) != 0) {
1032 y = SHIWORD(lParam);
1033 if (y < LBMM_EDGE) {
1034 if (lphl->FirstVisible > 0) {
1035 lphl->FirstVisible--;
1036 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1037 InvalidateRect32( hwnd, NULL, TRUE );
1041 GetClientRect16(hwnd, &rect);
1042 if (y >= (rect.bottom-LBMM_EDGE)) {
1043 if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
1044 lphl->FirstVisible++;
1045 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1046 InvalidateRect32( hwnd, NULL, TRUE );
1050 if ((y > 0) && (y < (rect.bottom - LBMM_EDGE))) {
1051 if ((y < rectsel.top) || (y > rectsel.bottom)) {
1052 iRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
1053 if (iRet == lphl->ItemFocused || iRet == -1) {
1056 if (lphl->dwStyle & LBS_MULTIPLESEL) {
1057 lphl->ItemFocused = iRet;
1058 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1059 } else if ( lphl->dwStyle & LBS_EXTENDEDSEL )
1061 /* Fixme: extended selection mode */
1062 ListBoxSetSel( lphl, lphl->ItemFocused, 0);
1063 lphl->PrevFocused = lphl->ItemFocused;
1064 lphl->ItemFocused = iRet;
1065 ListBoxSetSel( lphl, iRet, TRUE);
1070 ListBoxSetCurSel(lphl, (WORD)iRet);
1073 if( lphl->PrevFocused!=-1 && redraw_prev )
1075 ListBoxGetItemRect(lphl, lphl->PrevFocused, &rectsel);
1076 InvalidateRect16( hwnd, &rectsel, TRUE );
1078 ListBoxGetItemRect(lphl, iRet, &rectsel);
1079 InvalidateRect16( hwnd, &rectsel, TRUE );
1087 /***********************************************************************
1090 * Doesn't yet handle properly VK_SHIFT with LB_EXTENDEDSEL
1092 static LONG LBKeyDown(HWND hwnd, WORD wParam, LONG lParam)
1094 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1095 WORD newFocused = 0xFFFF;
1098 ListBoxGetItemRect(lphl,lphl->ItemFocused,&rect);
1109 if ( lphl->dwStyle & LBS_WANTKEYBOARDINPUT )
1111 newFocused = (WORD)(INT)SendMessage16(lphl->hParent,WM_VKEYTOITEM,
1112 wParam,MAKELPARAM(lphl->ItemFocused,hwnd));
1113 if ( newFocused == 0xFFFE ) return 0L;
1115 if ( newFocused == 0xFFFF )
1117 newFocused = lphl->ItemFocused;
1126 newFocused = lphl->ItemsCount - 1;
1129 if (lphl->dwStyle & LBS_MULTICOLUMN) {
1130 if (newFocused >= lphl->ItemsPerColumn) {
1131 newFocused -= lphl->ItemsPerColumn;
1138 if (newFocused > 0) newFocused--;
1141 if (lphl->dwStyle & LBS_MULTICOLUMN)
1142 newFocused += lphl->ItemsPerColumn;
1148 if (newFocused > lphl->ItemsVisible)
1149 newFocused -= lphl->ItemsVisible;
1150 else newFocused = 0;
1153 newFocused += lphl->ItemsVisible;
1158 /* end of nested switch */
1162 if (lphl->dwStyle & LBS_MULTIPLESEL)
1164 WORD wRet = ListBoxGetSel(lphl, lphl->ItemFocused);
1165 ListBoxSetSel(lphl, lphl->ItemFocused, !wRet);
1169 /* chars are handled in LBChar */
1174 /* at this point newFocused is set up */
1176 if (newFocused >= lphl->ItemsCount)
1177 newFocused = lphl->ItemsCount - 1;
1179 if (!(lphl->dwStyle & LBS_MULTIPLESEL))
1181 ListBoxSetCurSel(lphl, newFocused);
1182 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1185 lphl->ItemFocused = newFocused;
1187 if( ListBoxScrollToFocus(lphl) || (lphl->dwStyle &
1188 (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) )
1189 InvalidateRect32( hwnd, NULL, TRUE );
1192 InvalidateRect16( hwnd, &rect, TRUE );
1193 if( newFocused < 0x8000 )
1195 ListBoxGetItemRect(lphl, newFocused, &rect);
1196 InvalidateRect16( hwnd, &rect, TRUE );
1200 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1205 /***********************************************************************
1208 static LONG LBChar(HWND hwnd, WORD wParam, LONG lParam)
1210 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1211 WORD newFocused = 0xFFFF;
1213 if ( (lphl->dwStyle & LBS_WANTKEYBOARDINPUT) && !(lphl->HasStrings))
1215 newFocused = (WORD)(INT)SendMessage16(lphl->hParent,WM_CHARTOITEM,
1216 wParam,MAKELPARAM(lphl->ItemFocused,hwnd));
1217 if ( newFocused == 0xFFFE ) return 0L;
1220 if (newFocused == 0xFFFF )
1221 newFocused = ListBoxFindNextMatch(lphl, wParam);
1223 if (newFocused == (WORD)LB_ERR) return 0;
1225 if (newFocused >= lphl->ItemsCount)
1226 newFocused = lphl->ItemsCount - 1;
1228 if (!(lphl->dwStyle & LBS_MULTIPLESEL))
1230 ListBoxSetCurSel(lphl, newFocused);
1231 ListBoxSendNotification(lphl, LBN_SELCHANGE);
1234 lphl->ItemFocused = newFocused;
1235 ListBoxScrollToFocus(lphl);
1236 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1238 InvalidateRect32( hwnd, NULL, TRUE );
1243 /***********************************************************************
1246 static LONG LBSetRedraw(HWND hwnd, WORD wParam, LONG lParam)
1248 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1250 dprintf_listbox(stddeb,"ListBox WM_SETREDRAW hWnd=%04x w=%04x !\n",
1252 lphl->bRedrawFlag = wParam;
1257 /***********************************************************************
1260 static LONG LBSetFont(HWND hwnd, WPARAM wParam, LPARAM lParam)
1262 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1266 lphl->hFont = GetStockObject(SYSTEM_FONT);
1268 lphl->hFont = (HFONT) wParam;
1270 /* a new font means possible new text height */
1271 /* does this mean the height of each entry must be separately changed? */
1272 /* or are we guaranteed to get a LBSetFont before the first insert/add? */
1273 if ((hdc = GetDC(0)))
1276 GetTextMetrics16( hdc, &tm );
1277 lphl->StdItemHeight = tm.tmHeight;
1278 dprintf_listbox(stddeb,"LBSetFont: new font %d with height %d\n",
1279 lphl->hFont, lphl->StdItemHeight);
1280 ReleaseDC( 0, hdc );
1286 /***********************************************************************
1289 static LONG LBPaint(HWND hwnd, WORD wParam, LONG lParam)
1291 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1296 HDC16 hdc = BeginPaint16( hwnd, &ps );
1297 DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC);
1298 RECT16 rect, paintRect, scratchRect;
1299 int i, top, height, maxwidth, ipc;
1303 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) {
1304 EndPaint16(hwnd, &ps);
1308 GetRgnBox16(dc->w.hGCClipRgn,&paintRect);
1309 GetClientRect16(hwnd, &rect);
1310 IntersectRect16(&paintRect,&rect,&paintRect);
1312 hOldFont = SelectObject(hdc, lphl->hFont);
1315 hBrush = (HBRUSH) SendMessage16(lphl->hParent, WM_CTLCOLORLISTBOX, (WPARAM)hdc,
1318 hBrush = SendMessage16(lphl->hParent, WM_CTLCOLOR, hdc,
1319 MAKELONG(hwnd, CTLCOLOR_LISTBOX));
1322 if (hBrush == 0) hBrush = GetStockObject(WHITE_BRUSH);
1324 FillRect16(hdc, &rect, hBrush);
1326 maxwidth = rect.right;
1327 if (lphl->dwStyle & LBS_MULTICOLUMN) {
1328 rect.right = lphl->ColumnsWidth;
1330 lpls = lphl->lpFirst;
1332 lphl->ItemsVisible = 0;
1333 lphl->ItemsPerColumn = ipc = 0;
1335 for(i = 0; i < lphl->ItemsCount; i++) {
1336 if (lpls == NULL) break;
1338 if (i >= lphl->FirstVisible) {
1339 height = lpls->mis.itemHeight;
1341 if (top > (rect.bottom-height+1)) {
1342 if (lphl->dwStyle & LBS_MULTICOLUMN) {
1343 lphl->ItemsPerColumn = MAX(lphl->ItemsPerColumn, ipc);
1346 rect.left += lphl->ColumnsWidth;
1347 rect.right += lphl->ColumnsWidth;
1348 if (rect.left > maxwidth) break;
1354 lpls->itemRect.top = top;
1355 lpls->itemRect.bottom = top + height;
1356 lpls->itemRect.left = rect.left;
1357 lpls->itemRect.right = rect.right;
1359 if( IntersectRect16(&scratchRect,&paintRect,&lpls->itemRect) )
1361 dprintf_listbox(stddeb,"LBPaint: drawing item: %d %d %d %d %d\n",
1362 rect.left,top,rect.right,top+height,lpls->itemState);
1364 if (lphl->OwnerDrawn && (lphl->ItemFocused == i) && GetFocus() == hwnd)
1366 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS,
1367 lpls->itemState & ~ODS_FOCUS);
1368 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
1369 lpls->itemState & ~ODS_FOCUS);
1370 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, lpls->itemState);
1373 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
1378 lphl->ItemsVisible++;
1382 lpls = lpls->lpNext;
1384 ListBoxUpdateWindow(hwnd,lphl,FALSE);
1385 SelectObject(hdc,hOldFont);
1386 EndPaint16( hwnd, &ps );
1390 /***********************************************************************
1393 static LONG LBSetFocus(HWND hwnd, WORD wParam, LONG lParam)
1395 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1397 dprintf_listbox(stddeb,"ListBox WM_SETFOCUS for %04x\n",hwnd);
1398 if(!(lphl->dwStyle & LBS_MULTIPLESEL) )
1399 if( lphl->ItemsCount && lphl->ItemFocused != -1)
1401 HDC hDC = GetDC(hwnd);
1402 HFONT hOldFont = SelectObject(hDC, lphl->hFont);
1405 lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
1406 lpls->itemState |= ODS_FOCUS;
1408 ListBoxDrawItem(hwnd,lphl,hDC,lpls,&lpls->itemRect, ODA_FOCUS, lpls->itemState);
1409 SelectObject(hDC, hOldFont);
1410 ReleaseDC(hwnd,hDC);
1413 ListBoxSendNotification(lphl, LBN_SETFOCUS);
1418 /***********************************************************************
1421 static LONG LBKillFocus(HWND hwnd, WORD wParam, LONG lParam)
1423 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1425 dprintf_listbox(stddeb,"ListBox WM_KILLFOCUS for %04x\n",hwnd);
1426 if (!(lphl->dwStyle & LBS_MULTIPLESEL))
1428 if( lphl->ItemsCount )
1429 if( lphl->ItemFocused != -1 )
1431 HDC hDC = GetDC(hwnd);
1432 HFONT hOldFont = SelectObject(hDC, lphl->hFont);
1435 lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
1436 lpls->itemState &= ~ODS_FOCUS;
1438 ListBoxDrawItem(hwnd,lphl,hDC,lpls,&lpls->itemRect, ODA_FOCUS, lpls->itemState);
1439 SelectObject(hDC, hOldFont);
1440 ReleaseDC(hwnd,hDC);
1443 dprintf_listbox(stddeb,"LBKillFocus: no focused item!\n");
1446 InvalidateRect32( hwnd, NULL, TRUE );
1448 ListBoxSendNotification(lphl, LBN_KILLFOCUS);
1453 /***********************************************************************
1456 static LONG LBResetContent(HWND hwnd, WORD wParam, LONG lParam)
1458 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1460 dprintf_listbox(stddeb,"ListBox LB_RESETCONTENT !\n");
1461 ListBoxResetContent(lphl);
1462 ListBoxUpdateWindow(hwnd, lphl, TRUE);
1466 /***********************************************************************
1469 static LONG LBDir(HWND hwnd, WORD wParam, LONG lParam)
1472 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1473 dprintf_listbox(stddeb,"ListBox LB_DIR !\n");
1475 ret = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
1476 ListBoxUpdateWindow(hwnd, lphl, TRUE);
1480 /***********************************************************************
1483 static LONG LBAddString(HWND hwnd, WORD wParam, LONG lParam)
1486 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1488 if (lphl->HasStrings)
1489 wRet = ListBoxAddString(lphl, (LPCSTR)PTR_SEG_TO_LIN(lParam));
1491 wRet = ListBoxAddString(lphl, (LPCSTR)lParam);
1493 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1497 /***********************************************************************
1500 static LONG LBGetText(HWND hwnd, WORD wParam, LONG lParam)
1503 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1505 dprintf_listbox(stddeb, "LB_GETTEXT wParam=%d\n",wParam);
1506 wRet = ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
1511 /***********************************************************************
1514 static LONG LBInsertString(HWND hwnd, WORD wParam, LONG lParam)
1517 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1519 if (lphl->HasStrings)
1520 wRet = ListBoxInsertString(lphl, wParam, (LPCSTR)PTR_SEG_TO_LIN(lParam));
1522 wRet = ListBoxInsertString(lphl, wParam, (LPCSTR)lParam);
1524 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1528 /***********************************************************************
1531 static LONG LBDeleteString(HWND hwnd, WORD wParam, LONG lParam)
1533 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1534 LONG lRet = ListBoxDeleteString(lphl,wParam);
1536 ListBoxUpdateWindow(hwnd,lphl,TRUE);
1540 /***********************************************************************
1543 static LONG LBFindString(HWND hwnd, WORD wParam, LONG lParam)
1545 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1546 return ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
1549 /***********************************************************************
1552 static LONG LBGetCaretIndex(HWND hwnd, WORD wParam, LONG lParam)
1554 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1555 return lphl->ItemFocused;
1558 /***********************************************************************
1561 static LONG LBGetCount(HWND hwnd, WORD wParam, LONG lParam)
1565 lphl = ListBoxGetStorageHeader(hwnd);
1566 return lphl->ItemsCount;
1569 /***********************************************************************
1572 static LONG LBGetCurSel(HWND hwnd, WORD wParam, LONG lParam)
1576 lphl = ListBoxGetStorageHeader(hwnd);
1577 dprintf_listbox(stddeb,"ListBox LB_GETCURSEL %i !\n",
1579 return lphl->ItemFocused;
1582 /***********************************************************************
1583 * LBGetHorizontalExtent
1585 static LONG LBGetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam)
1590 /***********************************************************************
1593 static LONG LBGetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
1595 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1596 LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
1598 if (lpls == NULL) return LB_ERR;
1599 return lpls->mis.itemHeight;
1602 /***********************************************************************
1605 static LONG LBGetItemRect(HWND hwnd, WORD wParam, LONG lParam)
1607 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1608 return ListBoxGetItemRect(lphl, wParam, PTR_SEG_TO_LIN(lParam));
1611 /***********************************************************************
1614 static LONG LBGetSel(HWND hwnd, WORD wParam, LONG lParam)
1616 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1617 int iSel = ListBoxGetSel(lphl, wParam);
1619 dprintf_listbox(stdnimp,"LBGetSel: item %u - %i\n",wParam,iSel);
1621 return (iSel)? 1 : 0;
1624 /***********************************************************************
1627 static LONG LBGetSelCount(HWND hwnd, WORD wParam, LONG lParam)
1629 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1634 if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
1637 for( lpls = lphl->lpFirst;
1639 lpls = lpls->lpNext )
1642 if (lpls->itemState )
1649 /***********************************************************************
1652 static LONG LBGetSelItems(HWND hwnd, WORD wParam, LONG lParam)
1654 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1657 int *lpItems = PTR_SEG_TO_LIN(lParam);
1659 if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
1662 if (wParam == 0) return 0;
1664 lpls = lphl->lpFirst;
1667 while (lpls != NULL) {
1668 if (lpls->itemState > 0) lpItems[cnt++] = idx;
1670 if (cnt == wParam) break;
1672 lpls = lpls->lpNext;
1678 /***********************************************************************
1681 static LONG LBGetTextLen(HWND hwnd, WORD wParam, LONG lParam)
1683 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1684 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
1686 if (lpls == NULL || !lphl->HasStrings) return LB_ERR;
1687 return strlen(lpls->itemText);
1690 /***********************************************************************
1693 static LONG LBGetDlgCode(HWND hwnd, WORD wParam, LONG lParam)
1695 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1698 /***********************************************************************
1701 static LONG LBGetTopIndex(HWND hwnd, WORD wParam, LONG lParam)
1703 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1705 return lphl->FirstVisible;
1709 /***********************************************************************
1712 static LONG LBSelectString(HWND hwnd, WORD wParam, LONG lParam)
1714 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1717 iRet = ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
1721 if( lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) )
1722 ListBoxSetSel(lphl,iRet,TRUE);
1724 ListBoxSetCurSel(lphl,iRet);
1726 lphl->ItemFocused = iRet;
1727 InvalidateRect32( hwnd, 0, TRUE );
1732 /***********************************************************************
1735 static LONG LBSelItemRange(HWND hwnd, WORD wParam, LONG lParam)
1737 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1740 WORD first = LOWORD(lParam);
1741 WORD last = HIWORD(lParam);
1742 BOOL select = wParam;
1744 if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) ))
1747 if (first >= lphl->ItemsCount ||
1748 last >= lphl->ItemsCount) return LB_ERR;
1750 lpls = lphl->lpFirst;
1753 while (lpls != NULL) {
1755 lpls->itemState = select ? lpls->itemState | ODS_SELECTED : 0;
1760 lpls = lpls->lpNext;
1766 /***********************************************************************
1769 static LONG LBSetCaretIndex(HWND hwnd, WORD wParam, LONG lParam)
1771 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1774 if (!(lphl->dwStyle & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) )) return 0;
1776 dprintf_listbox(stddeb,"LBSetCaretIndex: hwnd %04x n=%i\n",hwnd,wParam);
1778 if (wParam >= lphl->ItemsCount) return LB_ERR;
1780 lphl->ItemFocused = wParam;
1781 i = ListBoxScrollToFocus (lphl);
1783 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1785 InvalidateRect32( hwnd, NULL, TRUE );
1790 /***********************************************************************
1793 static LONG LBSetColumnWidth(HWND hwnd, WORD wParam, LONG lParam)
1795 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1796 lphl->ColumnsWidth = wParam;
1797 InvalidateRect32( hwnd, NULL, TRUE );
1801 /***********************************************************************
1802 * LBSetHorizontalExtent
1804 static LONG LBSetHorizontalExtent(HWND hwnd, WORD wParam, LONG lParam)
1809 /***********************************************************************
1812 static LONG LBGetItemData(HWND hwnd, WORD wParam, LONG lParam)
1814 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1815 dprintf_listbox(stddeb, "LB_GETITEMDATA wParam=%x\n", wParam);
1816 return ListBoxGetItemData(lphl, wParam);
1819 /***********************************************************************
1822 static LONG LBSetItemData(HWND hwnd, WORD wParam, LONG lParam)
1824 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1825 dprintf_listbox(stddeb, "LB_SETITEMDATA wParam=%x lParam=%lx\n", wParam, lParam);
1826 return ListBoxSetItemData(lphl, wParam, lParam);
1829 /***********************************************************************
1832 static LONG LBSetTabStops(HWND hwnd, WORD wParam, LONG lParam)
1836 lphl = ListBoxGetStorageHeader(hwnd);
1838 if (lphl->TabStops != NULL) {
1839 lphl->iNumStops = 0;
1840 free (lphl->TabStops);
1843 lphl->TabStops = malloc (wParam * sizeof (short));
1844 if (lphl->TabStops) {
1845 lphl->iNumStops = wParam;
1846 memcpy (lphl->TabStops, PTR_SEG_TO_LIN(lParam), wParam * sizeof (short));
1853 /***********************************************************************
1856 static LONG LBSetCurSel(HWND hwnd, WORD wParam, LONG lParam)
1858 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1861 dprintf_listbox(stddeb,"ListBox LB_SETCURSEL wParam=%x !\n",
1864 wRet = ListBoxSetCurSel(lphl, wParam);
1866 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1867 InvalidateRect32( hwnd, NULL, TRUE );
1872 /***********************************************************************
1875 static LONG LBSetSel(HWND hwnd, WORD wParam, LONG lParam)
1877 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1881 dprintf_listbox(stddeb,"ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam, lParam);
1883 iRet = ListBoxSetSel(lphl, LOWORD(lParam), wParam);
1885 if( iRet > 1 ) InvalidateRect32( hwnd, NULL, TRUE );
1886 else if( iRet != LB_ERR )
1888 if( lphl->dwStyle & LBS_EXTENDEDSEL &&
1889 lphl->ItemFocused != LOWORD(lParam) )
1891 ListBoxGetItemRect(lphl, lphl->ItemFocused , &rect);
1892 InvalidateRect16( hwnd, &rect, TRUE );
1893 lphl->ItemFocused = LOWORD(lParam);
1895 ListBoxGetItemRect(lphl,LOWORD(lParam),&rect);
1896 InvalidateRect16( hwnd, &rect, TRUE );
1899 return (iRet == (WORD)LB_ERR)? LB_ERR: 0;
1902 /***********************************************************************
1905 static LONG LBSetTopIndex(HWND hwnd, WORD wParam, LONG lParam)
1907 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1909 dprintf_listbox(stddeb,"ListBox LB_SETTOPINDEX wParam=%x !\n",
1911 lphl->FirstVisible = wParam;
1912 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1914 InvalidateRect32( hwnd, NULL, TRUE );
1919 /***********************************************************************
1922 static LONG LBSetItemHeight(HWND hwnd, WORD wParam, LONG lParam)
1924 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
1927 dprintf_listbox(stddeb,"ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam, lParam);
1928 wRet = ListBoxSetItemHeight(lphl, wParam, lParam);
1929 InvalidateRect32( hwnd, NULL, TRUE );
1933 /***********************************************************************
1936 static LRESULT LBPassToParent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1938 WND* ptrWnd = WIN_FindWndPtr(hwnd);
1941 if( /* !(ptrWnd->dwExStyle & WS_EX_NOPARENTNOTIFY) && */
1943 return SendMessage16(ptrWnd->parent->hwndSelf,message,wParam,lParam);
1947 /***********************************************************************
1950 LRESULT ListBoxWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1953 case WM_CREATE: return LBCreate(hwnd, wParam, lParam);
1954 case WM_DESTROY: return LBDestroy(hwnd, wParam, lParam);
1955 case WM_GETDLGCODE: return LBGetDlgCode(hwnd, wParam, lParam);
1956 case WM_VSCROLL: return LBVScroll(hwnd, wParam, lParam);
1957 case WM_HSCROLL: return LBHScroll(hwnd, wParam, lParam);
1958 case WM_LBUTTONDOWN: return LBLButtonDown(hwnd, wParam, lParam);
1959 case WM_LBUTTONUP: return LBLButtonUp(hwnd, wParam, lParam);
1960 case WM_RBUTTONUP: return LBRButtonUp(hwnd, wParam, lParam);
1961 case WM_LBUTTONDBLCLK: return LBRButtonUp(hwnd, wParam, lParam);
1962 case WM_MOUSEMOVE: return LBMouseMove(hwnd, wParam, lParam);
1963 case WM_KEYDOWN: return LBKeyDown(hwnd, wParam, lParam);
1964 case WM_CHAR: return LBChar(hwnd, wParam, lParam);
1965 case WM_SETFONT: return LBSetFont(hwnd, wParam, lParam);
1966 case WM_SETREDRAW: return LBSetRedraw(hwnd, wParam, lParam);
1967 case WM_PAINT: return LBPaint(hwnd, wParam, lParam);
1968 case WM_SETFOCUS: return LBSetFocus(hwnd, wParam, lParam);
1969 case WM_KILLFOCUS: return LBKillFocus(hwnd, wParam, lParam);
1970 case LB_RESETCONTENT: return LBResetContent(hwnd, wParam, lParam);
1971 case LB_DIR: return LBDir(hwnd, wParam, lParam);
1972 case LB_ADDSTRING: return LBAddString(hwnd, wParam, lParam);
1973 case LB_INSERTSTRING: return LBInsertString(hwnd, wParam, lParam);
1974 case LB_DELETESTRING: return LBDeleteString(hwnd, wParam, lParam);
1975 case LB_FINDSTRING: return LBFindString(hwnd, wParam, lParam);
1976 case LB_GETCARETINDEX: return LBGetCaretIndex(hwnd, wParam, lParam);
1977 case LB_GETCOUNT: return LBGetCount(hwnd, wParam, lParam);
1978 case LB_GETCURSEL: return LBGetCurSel(hwnd, wParam, lParam);
1979 case LB_GETHORIZONTALEXTENT: return LBGetHorizontalExtent(hwnd, wParam, lParam);
1980 case LB_GETITEMDATA: return LBGetItemData(hwnd, wParam, lParam);
1981 case LB_GETITEMHEIGHT: return LBGetItemHeight(hwnd, wParam, lParam);
1982 case LB_GETITEMRECT: return LBGetItemRect(hwnd, wParam, lParam);
1983 case LB_GETSEL: return LBGetSel(hwnd, wParam, lParam);
1984 case LB_GETSELCOUNT: return LBGetSelCount(hwnd, wParam, lParam);
1985 case LB_GETSELITEMS: return LBGetSelItems(hwnd, wParam, lParam);
1986 case LB_GETTEXT: return LBGetText(hwnd, wParam, lParam);
1987 case LB_GETTEXTLEN: return LBGetTextLen(hwnd, wParam, lParam);
1988 case LB_GETTOPINDEX: return LBGetTopIndex(hwnd, wParam, lParam);
1989 case LB_SELECTSTRING: return LBSelectString(hwnd, wParam, lParam);
1990 case LB_SELITEMRANGE: return LBSelItemRange(hwnd, wParam, lParam);
1991 case LB_SETCARETINDEX: return LBSetCaretIndex(hwnd, wParam, lParam);
1992 case LB_SETCOLUMNWIDTH: return LBSetColumnWidth(hwnd, wParam, lParam);
1993 case LB_SETHORIZONTALEXTENT: return LBSetHorizontalExtent(hwnd, wParam, lParam);
1994 case LB_SETITEMDATA: return LBSetItemData(hwnd, wParam, lParam);
1995 case LB_SETTABSTOPS: return LBSetTabStops(hwnd, wParam, lParam);
1996 case LB_SETCURSEL: return LBSetCurSel(hwnd, wParam, lParam);
1997 case LB_SETSEL: return LBSetSel(hwnd, wParam, lParam);
1998 case LB_SETTOPINDEX: return LBSetTopIndex(hwnd, wParam, lParam);
1999 case LB_SETITEMHEIGHT: return LBSetItemHeight(hwnd, wParam, lParam);
2001 case WM_DROPFILES: return LBPassToParent(hwnd, message, wParam, lParam);
2003 /* these will have to be implemented for proper LBS_EXTENDEDSEL -
2005 * anchor item is an item that with caret (focused) item defines a
2006 * range of currently selected items when listbox is in the extended
2009 case LB_SETANCHORINDEX: return LB_SETANCHORINDEX; /* that's what Windows returns */
2010 case LB_GETANCHORINDEX: return 0;
2013 case WM_QUERYDROPOBJECT:
2017 LPDRAGINFO lpDragInfo = (LPDRAGINFO) PTR_SEG_TO_LIN((SEGPTR)lParam);
2018 LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
2020 lpDragInfo->l = ListBoxFindMouse(lphl,lpDragInfo->pt.x,
2023 return LBPassToParent(hwnd, message, wParam, lParam);
2027 return DefWindowProc16(hwnd, message, wParam, lParam);
2031 /**********************************************************************
2032 * DlgDirSelect (USER.99)
2034 BOOL DlgDirSelect( HWND hDlg, LPSTR lpStr, INT id )
2039 dprintf_listbox( stddeb, "DlgDirSelect: %04x '%s' %d\n", hDlg, lpStr, id );
2040 if ((i = SendDlgItemMessage16( hDlg, id, LB_GETCURSEL, 0, 0 )) == LB_ERR)
2042 if (!(buffer = SEGPTR_ALLOC( 20 * sizeof(char) ))) return FALSE;
2043 SendDlgItemMessage16(hDlg, id, LB_GETTEXT, i, (LPARAM)SEGPTR_GET(buffer) );
2044 if (buffer[0] == '[') /* drive or directory */
2046 if (buffer[1] == '-') /* drive */
2048 lpStr[0] = buffer[2];
2051 dprintf_listbox( stddeb, "Returning drive '%s'\n", lpStr );
2052 SEGPTR_FREE(buffer);
2055 strcpy( lpStr, buffer + 1 );
2056 lpStr[strlen(lpStr)-1] = '\\';
2057 dprintf_listbox( stddeb, "Returning directory '%s'\n", lpStr );
2058 SEGPTR_FREE(buffer);
2061 strcpy( lpStr, buffer );
2062 dprintf_listbox( stddeb, "Returning file '%s'\n", lpStr );
2063 SEGPTR_FREE(buffer);
2068 /**********************************************************************
2069 * DlgDirList (USER.100)
2071 INT DlgDirList( HWND hDlg, SEGPTR spec, INT idLBox, INT idStatic, UINT attrib )
2073 char *filespec = (char *)PTR_SEG_TO_LIN( spec );
2077 #define SENDMSG(msg,wparam,lparam) \
2078 ((attrib & DDL_POSTMSGS) ? PostMessage( hwnd, msg, wparam, lparam ) \
2079 : SendMessage16( hwnd, msg, wparam, lparam ))
2081 dprintf_listbox( stddeb, "DlgDirList: %04x '%s' %d %d %04x\n",
2082 hDlg, filespec ? filespec : "NULL",
2083 idLBox, idStatic, attrib );
2085 if (filespec && filespec[0] && (filespec[1] == ':'))
2087 drive = toupper( filespec[0] ) - 'A';
2089 if (!DRIVE_SetCurrentDrive( drive )) return FALSE;
2091 else drive = DRIVE_GetCurrentDrive();
2093 if (idLBox && ((hwnd = GetDlgItem( hDlg, idLBox )) != 0))
2097 if (!filespec || !filespec[0]) strcpy( mask, "*.*" );
2100 /* If the path exists and is a directory, chdir to it */
2101 if (DRIVE_Chdir( drive, filespec )) strcpy( mask, "*.*" );
2106 if ((p2 = strrchr( p, '\\' ))) p = p2 + 1;
2107 if ((p2 = strrchr( p, '/' ))) p = p2 + 1;
2108 lstrcpyn32A( mask, p, sizeof(mask) );
2112 if (!DRIVE_Chdir( drive, filespec )) return FALSE;
2117 strcpy( (char *)PTR_SEG_TO_LIN(spec), mask );
2119 dprintf_listbox(stddeb, "ListBoxDirectory: path=%c:\\%s mask=%s\n",
2120 'A' + drive, DRIVE_GetDosCwd(drive), mask);
2122 SENDMSG( LB_RESETCONTENT, 0, 0 );
2123 if ((attrib & DDL_DIRECTORY) && !(attrib & DDL_EXCLUSIVE))
2126 if (SENDMSG( LB_DIR, attrib & ~(DDL_DIRECTORY | DDL_DRIVES),
2127 (LPARAM)spec ) == LB_ERR) return FALSE;
2128 if (!(temp = SEGPTR_ALLOC( 4*sizeof(char) ))) return FALSE;
2129 strcpy( temp, "*.*" );
2130 /* FIXME: this won't work with PostMessage(), as temp will */
2131 /* have been freed by the time we do a DispatchMessage(). */
2132 if (SENDMSG( LB_DIR, (attrib & (DDL_DIRECTORY | DDL_DRIVES)) | DDL_EXCLUSIVE,
2133 (LPARAM)SEGPTR_GET(temp) ) == LB_ERR)
2142 if (SENDMSG( LB_DIR, attrib, (LPARAM)spec) == LB_ERR) return FALSE;
2146 if (idStatic && ((hwnd = GetDlgItem( hDlg, idStatic )) != 0))
2149 int drive = DRIVE_GetCurrentDrive();
2150 strcpy( temp, "A:\\" );
2152 lstrcpyn32A( temp + 3, DRIVE_GetDosCwd(drive), sizeof(temp)-3 );
2154 /* Can't use PostMessage() here, because the string is on the stack */
2155 SetDlgItemText32A( hDlg, idStatic, temp );