4 * Copyright Martin Ayotte, 1993
5 * Constantine Sapuntzakis, 1995
12 * - check if multi-column listboxes work
13 * - implement more messages and styles (LB_EXTENDEDSEL for instance)
14 * - exterminate evil InvalidateRect(whole listbox) where possible!!!!
32 #define LIST_HEAP_ALLOC(lphl,f,size) ((int)HEAP_Alloc(&lphl->Heap,f,size) & 0xffff)
33 #define LIST_HEAP_FREE(lphl,handle) (HEAP_Free(&lphl->Heap,LIST_HEAP_ADDR(lphl,handle)))
34 #define LIST_HEAP_ADDR(lphl,handle) \
35 ((void *)((handle) ? ((handle) | ((int)lphl->Heap & 0xffff0000)) : 0))
37 /* FIXME: shouldn't each listbox have its own heap? */
39 #define LIST_HEAP_ALLOC(lphl,f,size) USER_HEAP_ALLOC(size)
40 #define LIST_HEAP_FREE(lphl,handle) USER_HEAP_FREE(handle)
41 #define LIST_HEAP_ADDR(lphl,handle) USER_HEAP_LIN_ADDR(handle)
42 #define LIST_HEAP_SEG_ADDR(lphl,handle) USER_HEAP_SEG_ADDR(handle)
44 /* Something like this maybe ? */
45 #define LIST_HEAP_ALLOC(lphl,f,size) \
46 LOCAL_Alloc( lphl->HeapSel, LMEM_FIXED, (size) )
48 #define LIST_HEAP_REALLOC(handle,size) \
49 LOCAL_ReAlloc( USER_HeapSel, (handle), (size), LMEM_FIXED )
51 #define LIST_HEAP_FREE(lphl,handle) \
52 LOCAL_Free( lphl->HeapSel, (handle) )
53 #define LIST_HEAP_ADDR(lphl,handle) \
54 ((handle) ? PTR_SEG_OFF_TO_LIN(lphl->HeapSel, (handle)) : NULL)
55 #define LIST_HEAP_SEG_ADDR(lphl,handle) \
56 ((handle) ? MAKELONG((handle), lphl->HeapSel) : 0)
60 #define LIST_HEAP_SIZE 0x10000
62 static void ListBoxInitialize(LPHEADLIST lphl
)
66 lphl
->ItemsVisible
= 0;
67 lphl
->FirstVisible
= 0;
68 lphl
->ColumnsVisible
= 1;
69 lphl
->ItemsPerColumn
= 0;
70 lphl
->ItemFocused
= -1;
71 lphl
->PrevFocused
= -1;
74 void CreateListBoxStruct(HWND hwnd
, WORD CtlType
, LONG styles
, HWND parent
)
78 lphl
= (LPHEADLIST
)xmalloc(sizeof(HEADLIST
));
79 SetWindowLong(hwnd
, 0, (LONG
)lphl
);
80 ListBoxInitialize(lphl
);
81 lphl
->DrawCtlType
= CtlType
;
82 lphl
->CtlID
= GetWindowWord(hwnd
,GWW_ID
);
83 lphl
->bRedrawFlag
= TRUE
;
85 lphl
->TabStops
= NULL
;
86 lphl
->hFont
= GetStockObject(SYSTEM_FONT
);
88 lphl
->hParent
= parent
;
89 lphl
->StdItemHeight
= 15; /* FIXME: should get the font height */
90 lphl
->OwnerDrawn
= styles
& (LBS_OWNERDRAWFIXED
| LBS_OWNERDRAWVARIABLE
);
91 lphl
->HasStrings
= (styles
& LBS_HASSTRINGS
) || !lphl
->OwnerDrawn
;
93 if (lphl
->OwnerDrawn
) {
96 lphl
->hDrawItemStruct
= USER_HEAP_ALLOC(sizeof(DRAWITEMSTRUCT
));
97 lphl
->needMeasure
= TRUE
;
98 dummyls
.mis
.CtlType
= lphl
->DrawCtlType
;
99 dummyls
.mis
.CtlID
= lphl
->CtlID
;
100 dummyls
.mis
.itemID
= -1;
101 dummyls
.mis
.itemWidth
= 0; /* ignored */
102 dummyls
.mis
.itemData
= 0;
104 ListBoxAskMeasure(lphl
,&dummyls
);
106 lphl
->hDrawItemStruct
= 0;
110 HeapHandle
= GlobalAlloc(GMEM_FIXED
, LIST_HEAP_SIZE
);
111 HeapBase
= GlobalLock(HeapHandle
);
112 HEAP_Init(&lphl
->Heap
, HeapBase
, LIST_HEAP_SIZE
);
114 /* WINELIBS list boxes do not operate on local heaps */
116 lphl
->HeapSel
= GlobalAlloc(GMEM_FIXED
,LIST_HEAP_SIZE
);
117 LocalInit( lphl
->HeapSel
, 0, LIST_HEAP_SIZE
-1);
123 void DestroyListBoxStruct(LPHEADLIST lphl
)
125 if (lphl
->hDrawItemStruct
)
126 USER_HEAP_FREE(lphl
->hDrawItemStruct
);
128 /* XXX need to free lphl->Heap */
129 GlobalFree(lphl
->HeapSel
);
133 static LPHEADLIST
ListBoxGetStorageHeader(HWND hwnd
)
135 return (LPHEADLIST
)GetWindowLong(hwnd
,0);
138 /* Send notification "code" as part of a WM_COMMAND-message if hwnd
139 has the LBS_NOTIFY style */
140 void ListBoxSendNotification(LPHEADLIST lphl
, WORD code
)
142 DWORD dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
144 if (dwStyle
& LBS_NOTIFY
)
146 SendMessage(lphl
->hParent
, WM_COMMAND
,
147 MAKEWPARAM(lphl
->CtlID
,code
), (LPARAM
)lphl
->hSelf
);
149 SendMessage(lphl
->hParent
, WM_COMMAND
,
150 lphl
->CtlID
, MAKELONG(lphl
->hSelf
, code
));
155 /* get the maximum value of lphl->FirstVisible */
156 int ListMaxFirstVisible(LPHEADLIST lphl
)
158 int m
= lphl
->ItemsCount
-lphl
->ItemsVisible
;
159 return (m
< 0) ? 0 : m
;
163 void ListBoxUpdateWindow(HWND hwnd
, LPHEADLIST lphl
, BOOL repaint
)
165 SetScrollRange(hwnd
, SB_VERT
, 0, ListMaxFirstVisible(lphl
), TRUE
);
166 if (lphl
->ItemsPerColumn
!= 0) {
167 SetScrollRange(hwnd
, SB_HORZ
, 1, lphl
->ItemsVisible
/
168 lphl
->ItemsPerColumn
+ 1, TRUE
);
170 if (repaint
&& lphl
->bRedrawFlag
) {
171 InvalidateRect(hwnd
, NULL
, TRUE
);
175 /* Returns: 0 if nothing needs to be changed */
176 /* 1 if FirstVisible changed */
178 int ListBoxScrollToFocus(LPHEADLIST lphl
)
182 if (lphl
->ItemsCount
== 0) return 0;
183 if (lphl
->ItemFocused
== -1) return 0;
185 end
= lphl
->FirstVisible
+ lphl
->ItemsVisible
- 1;
187 if (lphl
->ItemFocused
< lphl
->FirstVisible
) {
188 lphl
->FirstVisible
= lphl
->ItemFocused
;
191 if (lphl
->ItemFocused
> end
) {
192 WORD maxFirstVisible
= ListMaxFirstVisible(lphl
);
194 lphl
->FirstVisible
= lphl
->ItemFocused
;
196 if (lphl
->FirstVisible
> maxFirstVisible
) {
197 lphl
->FirstVisible
= maxFirstVisible
;
206 LPLISTSTRUCT
ListBoxGetItem(LPHEADLIST lphl
, UINT uIndex
)
211 if (uIndex
>= lphl
->ItemsCount
) return NULL
;
213 lpls
= lphl
->lpFirst
;
214 while (Count
++ < uIndex
) lpls
= lpls
->lpNext
;
219 void ListBoxDrawItem (HWND hwnd
, LPHEADLIST lphl
, HDC hdc
, LPLISTSTRUCT lpls
,
220 RECT
*rect
, WORD itemAction
, WORD itemState
)
222 LONG dwStyle
= GetWindowLong(hwnd
,GWL_STYLE
);
224 if (lphl
->OwnerDrawn
) {
225 DRAWITEMSTRUCT
*dis
= USER_HEAP_LIN_ADDR(lphl
->hDrawItemStruct
);
227 dis
->CtlID
= lpls
->mis
.CtlID
;
228 dis
->CtlType
= lpls
->mis
.CtlType
;
229 dis
->itemID
= lpls
->mis
.itemID
;
231 dis
->hwndItem
= hwnd
;
232 dis
->itemData
= lpls
->mis
.itemData
;
233 dis
->itemAction
= itemAction
;
234 dis
->itemState
= itemState
;
236 SendMessage(lphl
->hParent
, WM_DRAWITEM
,
237 0, (LPARAM
)USER_HEAP_SEG_ADDR(lphl
->hDrawItemStruct
));
239 if (itemAction
== ODA_DRAWENTIRE
|| itemAction
== ODA_SELECT
) {
241 DWORD dwOldTextColor
= 0;
243 OldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
245 if (itemState
!= 0) {
246 dwOldTextColor
= SetTextColor(hdc
, 0x00FFFFFFL
);
247 FillRect(hdc
, rect
, GetStockObject(BLACK_BRUSH
));
250 if (dwStyle
& LBS_USETABSTOPS
) {
251 TabbedTextOut(hdc
, rect
->left
+ 5, rect
->top
+ 2,
252 (char *)lpls
->itemText
, strlen((char *)lpls
->itemText
),
253 lphl
->iNumStops
, lphl
->TabStops
, 0);
255 TextOut(hdc
, rect
->left
+ 5, rect
->top
+ 2,
256 (char *)lpls
->itemText
, strlen((char *)lpls
->itemText
));
259 if (itemState
!= 0) {
260 SetTextColor(hdc
, dwOldTextColor
);
263 SetBkMode(hdc
, OldBkMode
);
264 } else DrawFocusRect(hdc
, rect
);
271 int ListBoxFindMouse(LPHEADLIST lphl
, int X
, int Y
)
273 LPLISTSTRUCT lpls
= lphl
->lpFirst
;
277 point
.x
= X
; point
.y
= Y
;
278 if (lphl
->ItemsCount
== 0) return LB_ERR
;
280 for(i
= 0; i
< lphl
->FirstVisible
; i
++) {
281 if (lpls
== NULL
) return LB_ERR
;
284 for(j
= 0; j
< lphl
->ItemsVisible
; i
++, j
++) {
285 if (lpls
== NULL
) return LB_ERR
;
286 if (PtInRect(&lpls
->itemRect
,point
)) {
291 dprintf_listbox(stddeb
,"ListBoxFindMouse: not found\n");
296 void ListBoxAskMeasure(LPHEADLIST lphl
, LPLISTSTRUCT lpls
)
298 HANDLE hTemp
= USER_HEAP_ALLOC( sizeof(MEASUREITEMSTRUCT
) );
299 MEASUREITEMSTRUCT
*lpmeasure
= (MEASUREITEMSTRUCT
*) USER_HEAP_LIN_ADDR(hTemp
);
301 if (lpmeasure
== NULL
) {
302 fprintf(stdnimp
,"ListBoxAskMeasure() out of memory !\n");
306 *lpmeasure
= lpls
->mis
;
307 lpmeasure
->itemHeight
= lphl
->StdItemHeight
;
308 SendMessage(lphl
->hParent
, WM_MEASUREITEM
, 0, (LPARAM
)USER_HEAP_SEG_ADDR(hTemp
));
310 if (GetWindowLong(lphl
->hSelf
,GWL_STYLE
) & LBS_OWNERDRAWFIXED
) {
311 lphl
->StdItemHeight
= lpmeasure
->itemHeight
;
312 lphl
->needMeasure
= FALSE
;
315 USER_HEAP_FREE(hTemp
);
318 /* -------------------- strings and item data ---------------------- */
320 LPLISTSTRUCT
ListBoxCreateItem(LPHEADLIST lphl
, int id
)
322 LPLISTSTRUCT lplsnew
= (LPLISTSTRUCT
)malloc(sizeof(LISTSTRUCT
));
324 if (lplsnew
== NULL
) return NULL
;
326 lplsnew
->itemState
= 0;
327 lplsnew
->mis
.CtlType
= lphl
->DrawCtlType
;
328 lplsnew
->mis
.CtlID
= lphl
->CtlID
;
329 lplsnew
->mis
.itemID
= id
;
330 lplsnew
->mis
.itemHeight
= lphl
->StdItemHeight
;
331 lplsnew
->mis
.itemWidth
= 0; /* ignored */
332 lplsnew
->mis
.itemData
= 0;
333 SetRect(&lplsnew
->itemRect
, 0, 0, 0, 0);
339 int ListBoxInsertString(LPHEADLIST lphl
, UINT uIndex
, LPSTR newstr
)
341 LPLISTSTRUCT
*lppls
, lplsnew
, lpls
;
346 dprintf_listbox(stddeb
,"ListBoxInsertString(%d, %p);\n", uIndex
, newstr
);
348 if (!newstr
) return -1;
350 if (uIndex
== (UINT
)-1)
351 uIndex
= lphl
->ItemsCount
;
353 lppls
= &lphl
->lpFirst
;
354 for(Count
= 0; Count
< uIndex
; Count
++) {
355 if (*lppls
== NULL
) return LB_ERR
;
356 lppls
= (LPLISTSTRUCT
*) &(*lppls
)->lpNext
;
359 lplsnew
= ListBoxCreateItem(lphl
, Count
);
361 if (lplsnew
== NULL
) {
362 fprintf(stdnimp
,"ListBoxInsertString() out of memory !\n");
366 lplsnew
->lpNext
= *lppls
;
371 if (lphl
->HasStrings
) {
372 dprintf_listbox(stddeb
," string: %s\n", newstr
);
373 hStr
= LIST_HEAP_ALLOC(lphl
, LMEM_MOVEABLE
, strlen(newstr
) + 1);
374 str
= (LPSTR
)LIST_HEAP_ADDR(lphl
, hStr
);
375 if (str
== NULL
) return LB_ERRSPACE
;
377 lplsnew
->itemText
= str
;
378 /* I'm not so sure about the next one */
379 lplsnew
->mis
.itemData
= 0;
381 lplsnew
->itemText
= NULL
;
382 lplsnew
->mis
.itemData
= (DWORD
)newstr
;
385 lplsnew
->mis
.itemID
= uIndex
;
386 lplsnew
->hData
= hStr
;
388 /* adjust the itemID field of the following entries */
389 for(lpls
= lplsnew
->lpNext
; lpls
!= NULL
; lpls
= lpls
->lpNext
) {
393 if (lphl
->needMeasure
) {
394 ListBoxAskMeasure(lphl
, lplsnew
);
397 dprintf_listbox(stddeb
,"ListBoxInsertString // count=%d\n", lphl
->ItemsCount
);
402 int ListBoxAddString(LPHEADLIST lphl
, LPSTR newstr
)
404 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
405 UINT pos
= (UINT
) -1;
407 if (lphl
->HasStrings
&& (dwStyle
& LBS_SORT
)) {
408 LPLISTSTRUCT lpls
= lphl
->lpFirst
;
409 for (pos
= 0; lpls
!= NULL
; lpls
= lpls
->lpNext
, pos
++)
410 if (strcmp(lpls
->itemText
, newstr
) >= 0)
413 return ListBoxInsertString(lphl
, pos
, newstr
);
417 int ListBoxGetText(LPHEADLIST lphl
, UINT uIndex
, LPSTR OutStr
)
422 dprintf_listbox(stddeb
, "ListBoxGetText // OutStr==NULL\n");
426 lpls
= ListBoxGetItem (lphl
, uIndex
);
427 if (lpls
== NULL
) return LB_ERR
;
429 if (!lphl
->HasStrings
) {
430 *((long *)OutStr
) = lpls
->mis
.itemData
;
434 strcpy(OutStr
, lpls
->itemText
);
435 return strlen(OutStr
);
439 DWORD
ListBoxGetItemData(LPHEADLIST lphl
, UINT uIndex
)
443 lpls
= ListBoxGetItem (lphl
, uIndex
);
444 if (lpls
== NULL
) return LB_ERR
;
445 return lpls
->mis
.itemData
;
449 int ListBoxSetItemData(LPHEADLIST lphl
, UINT uIndex
, DWORD ItemData
)
451 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
, uIndex
);
453 if (lpls
== NULL
) return LB_ERR
;
454 lpls
->mis
.itemData
= ItemData
;
459 int ListBoxDeleteString(LPHEADLIST lphl
, UINT uIndex
)
461 LPLISTSTRUCT lpls
, lpls2
;
464 if (uIndex
>= lphl
->ItemsCount
) return LB_ERR
;
466 lpls
= lphl
->lpFirst
;
467 if (lpls
== NULL
) return LB_ERR
;
470 lphl
->lpFirst
= lpls
->lpNext
;
472 LPLISTSTRUCT lpls2
= NULL
;
473 for(Count
= 0; Count
< uIndex
; Count
++) {
474 if (lpls
->lpNext
== NULL
) return LB_ERR
;
477 lpls
= (LPLISTSTRUCT
)lpls
->lpNext
;
479 lpls2
->lpNext
= lpls
->lpNext
;
482 /* adjust the itemID field of the following entries */
483 for(lpls2
= lpls
->lpNext
; lpls2
!= NULL
; lpls2
= lpls2
->lpNext
) {
489 if (lpls
->hData
!= 0) LIST_HEAP_FREE(lphl
, lpls
->hData
);
492 return lphl
->ItemsCount
;
496 int ListBoxFindString(LPHEADLIST lphl
, UINT nFirst
, SEGPTR MatchStr
)
500 UINT First
= nFirst
+ 1;
501 LPSTR lpMatchStr
= (LPSTR
)MatchStr
;
502 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
504 if (First
> lphl
->ItemsCount
) return LB_ERR
;
506 if (lphl
->HasStrings
) lpMatchStr
= PTR_SEG_TO_LIN(MatchStr
);
508 lpls
= ListBoxGetItem(lphl
, First
);
510 while(lpls
!= NULL
) {
511 if (lphl
->HasStrings
) {
512 if (strstr(lpls
->itemText
, lpMatchStr
) == lpls
->itemText
) return Count
;
513 } else if (dwStyle
& LBS_SORT
) {
514 /* XXX Do a compare item */
517 if (lpls
->mis
.itemData
== (DWORD
)lpMatchStr
) return Count
;
523 /* Start over at top */
525 lpls
= lphl
->lpFirst
;
527 while (Count
< First
) {
528 if (lphl
->HasStrings
) {
529 if (strstr(lpls
->itemText
, lpMatchStr
) == lpls
->itemText
) return Count
;
530 } else if (dwStyle
& LBS_SORT
) {
531 /* XXX Do a compare item */
533 if (lpls
->mis
.itemData
== (DWORD
)lpMatchStr
) return Count
;
543 int ListBoxResetContent(LPHEADLIST lphl
)
548 if (lphl
->ItemsCount
== 0) return 0;
550 dprintf_listbox(stddeb
, "ListBoxResetContent // ItemCount = %d\n",
553 for(i
= 0; i
< lphl
->ItemsCount
; i
++) {
554 lpls
= lphl
->lpFirst
;
555 if (lpls
== NULL
) return LB_ERR
;
557 lphl
->lpFirst
= lpls
->lpNext
;
558 if (lpls
->hData
!= 0) LIST_HEAP_FREE(lphl
, lpls
->hData
);
561 ListBoxInitialize(lphl
);
566 /* --------------------- selection ------------------------- */
568 int ListBoxSetCurSel(LPHEADLIST lphl
, WORD wIndex
)
571 DWORD dwStyle
= GetWindowWord(lphl
->hSelf
,GWL_STYLE
);
573 /* use ListBoxSetSel instead */
574 if (dwStyle
& LBS_MULTIPLESEL
) return 0;
576 /* unselect all previously selected */
577 if (dwStyle
& LBS_EXTENDEDSEL
)
578 ListBoxSetSel(lphl
,-1,0);
580 /* unselect previous item */
581 if (lphl
->ItemFocused
!= -1) {
582 lpls
= ListBoxGetItem(lphl
, lphl
->ItemFocused
);
583 if (lpls
== 0) return LB_ERR
;
587 if (wIndex
!= (UINT
)-1) {
588 lphl
->ItemFocused
= wIndex
;
589 lpls
= ListBoxGetItem(lphl
, wIndex
);
590 if (lpls
== 0) return LB_ERR
;
591 lpls
->itemState
= ODS_SELECTED
| ODS_FOCUS
;
600 int ListBoxSetSel(LPHEADLIST lphl
, WORD wIndex
, WORD state
)
604 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) &
605 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
608 if (wIndex
== (UINT
)-1) {
609 for (lpls
= lphl
->lpFirst
; lpls
!= NULL
; lpls
= lpls
->lpNext
) {
610 lpls
->itemState
= state
;
615 if (wIndex
>= lphl
->ItemsCount
) return LB_ERR
;
617 lpls
= ListBoxGetItem(lphl
, wIndex
);
618 lpls
->itemState
= state
;
624 int ListBoxGetSel(LPHEADLIST lphl
, WORD wIndex
)
626 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
, wIndex
);
628 if (lpls
== NULL
) return LB_ERR
;
629 return lpls
->itemState
;
632 /* ------------------------- dir listing ------------------------ */
634 int ListBoxDirectory(LPHEADLIST lphl
, UINT attrib
, LPSTR filespec
)
636 struct dosdirent
*dp
, *dp_old
;
641 dprintf_listbox(stddeb
,"ListBoxDirectory: %s, %4x\n",filespec
,attrib
);
643 if (strchr(filespec
, '\\') || strchr(filespec
, ':')) {
644 drive
= DOS_GetDefaultDrive();
645 if (filespec
[1] == ':') {
646 drive
= toupper(filespec
[0]) - 'A';
649 strcpy(temp
,filespec
);
650 tstr
= strrchr(temp
, '\\');
653 filespec
+= tstr
- temp
+ 1;
654 if (!DOS_ChangeDir( drive
, temp
)) return 0;
656 DOS_SetDefaultDrive( drive
);
657 dprintf_listbox(stddeb
,"Changing directory to %c:%s, filemask is %s\n",
658 drive
+'A', temp
, filespec
);
661 if ((dp
= (struct dosdirent
*)DOS_opendir(filespec
)) ==NULL
) return 0;
663 while ((dp
= (struct dosdirent
*)DOS_readdir(dp
))) {
664 if (!dp
->inuse
) break;
665 dprintf_listbox(stddeb
, "ListBoxDirectory %p '%s' !\n", dp
->filename
,
667 if (dp
->attribute
& FA_DIREC
) {
668 if (attrib
& DDL_DIRECTORY
&& strcmp(dp
->filename
, ".") != 0) {
669 sprintf(temp
, "[%s]", dp
->filename
);
670 if (ListBoxAddString(lphl
, temp
) == LB_ERR
) break;
674 if (attrib
& DDL_EXCLUSIVE
) {
675 if (attrib
& (DDL_READWRITE
| DDL_READONLY
| DDL_HIDDEN
| DDL_SYSTEM
)) {
676 if (ListBoxAddString(lphl
, dp
->filename
) == LB_ERR
) break;
679 if (ListBoxAddString(lphl
, dp
->filename
) == LB_ERR
) break;
683 DOS_closedir(dp_old
);
685 if (attrib
& DDL_DRIVES
) {
687 for (x
= 0; x
!= MAX_DOS_DRIVES
; x
++) {
688 if (DOS_ValidDrive(x
)) {
689 sprintf(temp
, "[-%c-]", 'a'+x
);
690 if (ListBoxInsertString(lphl
, (UINT
)-1, temp
) == LB_ERR
) break;
697 /* ------------------------- dimensions ------------------------- */
699 int ListBoxGetItemRect(LPHEADLIST lphl
, WORD wIndex
, LPRECT lprect
)
701 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
,wIndex
);
703 if (lpls
== NULL
) return LB_ERR
;
704 *lprect
= lpls
->itemRect
;
709 int ListBoxSetItemHeight(LPHEADLIST lphl
, WORD wIndex
, long height
)
713 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) & LBS_OWNERDRAWVARIABLE
)) {
714 lphl
->StdItemHeight
= (short)height
;
718 lpls
= ListBoxGetItem(lphl
, wIndex
);
719 if (lpls
== NULL
) return LB_ERR
;
721 lpls
->mis
.itemHeight
= height
;
725 /* -------------------------- string search ------------------------ */
727 int ListBoxFindNextMatch(LPHEADLIST lphl
, WORD wChar
)
732 if ((char)wChar
< ' ') return LB_ERR
;
733 if (!lphl
->HasStrings
) return LB_ERR
;
735 lpls
= lphl
->lpFirst
;
737 for (count
= 0; lpls
!= NULL
; lpls
= lpls
->lpNext
, count
++) {
738 if (tolower(*lpls
->itemText
) == tolower((char)wChar
)) break;
740 if (lpls
== NULL
) return LB_ERR
;
742 for(; lpls
!= NULL
; lpls
= lpls
->lpNext
, count
++) {
743 if (*lpls
->itemText
!= (char)wChar
)
745 if (count
> lphl
->ItemFocused
)
751 /***********************************************************************
754 static LONG
LBCreate(HWND hwnd
, WORD wParam
, LONG lParam
)
757 LONG dwStyle
= GetWindowLong(hwnd
,GWL_STYLE
);
760 CreateListBoxStruct(hwnd
, ODT_LISTBOX
, dwStyle
, GetParent(hwnd
));
761 lphl
= ListBoxGetStorageHeader(hwnd
);
762 dprintf_listbox(stddeb
,"ListBox created: lphl = %p dwStyle = %04x:%04x\n",
763 lphl
, HIWORD(dwStyle
), LOWORD(dwStyle
));
765 GetClientRect(hwnd
,&rect
);
766 lphl
->ColumnsWidth
= rect
.right
- rect
.left
;
768 SetScrollRange(hwnd
, SB_VERT
, 0, ListMaxFirstVisible(lphl
), TRUE
);
769 SetScrollRange(hwnd
, SB_HORZ
, 1, 1, TRUE
);
774 /***********************************************************************
777 static LONG
LBDestroy(HWND hwnd
, WORD wParam
, LONG lParam
)
779 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
781 ListBoxResetContent(lphl
);
783 DestroyListBoxStruct(lphl
);
784 dprintf_listbox(stddeb
,"ListBox destroyed: lphl = %p\n",lphl
);
788 /***********************************************************************
791 static LONG
LBVScroll(HWND hwnd
, WORD wParam
, LONG lParam
)
793 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
796 dprintf_listbox(stddeb
,"ListBox WM_VSCROLL w=%04X l=%08lX !\n",
798 y
= lphl
->FirstVisible
;
802 if (lphl
->FirstVisible
> 0)
803 lphl
->FirstVisible
--;
807 lphl
->FirstVisible
++;
811 if (lphl
->FirstVisible
> lphl
->ItemsVisible
) {
812 lphl
->FirstVisible
-= lphl
->ItemsVisible
;
814 lphl
->FirstVisible
= 0;
819 lphl
->FirstVisible
+= lphl
->ItemsVisible
;
823 lphl
->FirstVisible
= LOWORD(lParam
);
827 if (lphl
->FirstVisible
> ListMaxFirstVisible(lphl
))
828 lphl
->FirstVisible
= ListMaxFirstVisible(lphl
);
830 if (y
!= lphl
->FirstVisible
) {
831 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
832 InvalidateRect(hwnd
, NULL
, TRUE
);
837 /***********************************************************************
840 static LONG
LBHScroll(HWND hwnd
, WORD wParam
, LONG lParam
)
845 dprintf_listbox(stddeb
,"ListBox WM_HSCROLL w=%04X l=%08lX !\n",
847 lphl
= ListBoxGetStorageHeader(hwnd
);
848 y
= lphl
->FirstVisible
;
851 if (lphl
->FirstVisible
> lphl
->ItemsPerColumn
) {
852 lphl
->FirstVisible
-= lphl
->ItemsPerColumn
;
854 lphl
->FirstVisible
= 0;
858 lphl
->FirstVisible
+= lphl
->ItemsPerColumn
;
861 if (lphl
->ItemsPerColumn
!= 0) {
862 int lbsub
= lphl
->ItemsVisible
/ lphl
->ItemsPerColumn
* lphl
->ItemsPerColumn
;
863 if (lphl
->FirstVisible
> lbsub
) {
864 lphl
->FirstVisible
-= lbsub
;
866 lphl
->FirstVisible
= 0;
871 if (lphl
->ItemsPerColumn
!= 0)
872 lphl
->FirstVisible
+= lphl
->ItemsVisible
/
873 lphl
->ItemsPerColumn
* lphl
->ItemsPerColumn
;
876 lphl
->FirstVisible
= lphl
->ItemsPerColumn
* LOWORD(lParam
);
879 if (lphl
->FirstVisible
> ListMaxFirstVisible(lphl
))
880 lphl
->FirstVisible
= ListMaxFirstVisible(lphl
);
882 if (lphl
->ItemsPerColumn
!= 0) {
883 lphl
->FirstVisible
= lphl
->FirstVisible
/
884 lphl
->ItemsPerColumn
* lphl
->ItemsPerColumn
+ 1;
885 if (y
!= lphl
->FirstVisible
) {
886 SetScrollPos(hwnd
, SB_HORZ
, lphl
->FirstVisible
/
887 lphl
->ItemsPerColumn
+ 1, TRUE
);
888 InvalidateRect(hwnd
, NULL
, TRUE
);
894 /***********************************************************************
897 static LONG
LBLButtonDown(HWND hwnd
, WORD wParam
, LONG lParam
)
899 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
903 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
905 tmpPOINT
.x
= LOWORD(lParam
); tmpPOINT
.y
= HIWORD(lParam
);
910 lphl
->PrevFocused
= lphl
->ItemFocused
;
912 y
= ListBoxFindMouse(lphl
, LOWORD(lParam
), HIWORD(lParam
));
916 if (dwStyle
& LBS_MULTIPLESEL
) {
917 lphl
->ItemFocused
= y
;
918 wRet
= ListBoxGetSel(lphl
, y
);
919 ListBoxSetSel(lphl
, y
, !wRet
);
921 InvalidateRect(hwnd
, NULL
, TRUE
);
923 ListBoxSetCurSel(lphl
, y
);
925 ListBoxGetItemRect(lphl
, y
, &rectsel
);
926 InvalidateRect(hwnd
, &rectsel
, TRUE
);
927 if(lphl
->PrevFocused
) {
928 ListBoxGetItemRect(lphl
, lphl
->PrevFocused
, &rectsel
);
929 InvalidateRect(hwnd
, &rectsel
, TRUE
);
933 if (dwStyle
& (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
))
934 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
936 if (dwStyle
& LBS_NOTIFY
)
937 SendMessage(lphl
->hParent
, WM_LBTRACKPOINT
, y
, lParam
);
939 if (GetWindowLong(lphl
->hSelf
,GWL_EXSTYLE
) & WS_EX_DRAGDETECT
)
940 if( DragDetect(lphl
->hSelf
,tmpPOINT
) )
941 SendMessage(lphl
->hParent
, WM_BEGINDRAG
,0,0L);
946 /***********************************************************************
949 static LONG
LBLButtonUp(HWND hwnd
, WORD wParam
, LONG lParam
)
951 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
953 if (GetCapture() == hwnd
) ReleaseCapture();
955 if (lphl
->PrevFocused
!= lphl
->ItemFocused
)
956 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
961 /***********************************************************************
964 static LONG
LBRButtonUp(HWND hwnd
, WORD wParam
, LONG lParam
)
966 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
969 SendMessage(lphl
->hParent
, WM_COMMAND
,
970 MAKEWPARAM(GetWindowWord(hwnd
,GWW_ID
),LBN_DBLCLK
),
973 SendMessage(lphl
->hParent
, WM_COMMAND
, GetWindowWord(hwnd
,GWW_ID
),
974 MAKELONG(hwnd
, LBN_DBLCLK
));
980 /***********************************************************************
983 static LONG
LBMouseMove(HWND hwnd
, WORD wParam
, LONG lParam
)
985 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
988 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
989 RECT rect
, rectsel
; /* XXX Broken */
991 dprintf_listbox(stddeb
,"LBMouseMove %d %d\n",SLOWORD(lParam
),SHIWORD(lParam
));
992 if ((wParam
& MK_LBUTTON
) != 0) {
995 if (lphl
->FirstVisible
> 0) {
996 lphl
->FirstVisible
--;
997 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
998 InvalidateRect(hwnd
, NULL
, TRUE
);
1002 GetClientRect(hwnd
, &rect
);
1003 if (y
>= rect
.bottom
) {
1004 if (lphl
->FirstVisible
< ListMaxFirstVisible(lphl
)) {
1005 lphl
->FirstVisible
++;
1006 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1007 InvalidateRect(hwnd
, NULL
, TRUE
);
1011 if ((y
> 0) && (y
< (rect
.bottom
- 4))) {
1012 if ((y
< rectsel
.top
) || (y
> rectsel
.bottom
)) {
1013 wRet
= ListBoxFindMouse(lphl
, LOWORD(lParam
), HIWORD(lParam
));
1014 if (wRet
== lphl
->ItemFocused
) {
1017 if (dwStyle
& LBS_MULTIPLESEL
) {
1018 lphl
->ItemFocused
= wRet
;
1019 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
1021 ListBoxSetCurSel(lphl
, wRet
);
1022 if(dwStyle
& LBS_EXTENDEDSEL
)
1023 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
1025 ListBoxGetItemRect(lphl
, wRet
, &rectsel
);
1026 InvalidateRect(hwnd
, &rectsel
, TRUE
);
1034 /***********************************************************************
1037 * Doesn't yet handle properly VK_SHIFT with LB_EXTENDEDSEL
1039 static LONG
LBKeyDown(HWND hwnd
, WORD wParam
, LONG lParam
)
1041 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1042 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
1043 WORD newFocused
= 0xFFFF;
1046 ListBoxGetItemRect(lphl
,lphl
->ItemFocused
,&rect
);
1049 /* ugly kludge that belongs in TranslateMessage */
1059 if ( dwStyle
& LBS_WANTKEYBOARDINPUT
)
1061 newFocused
= (WORD
)(INT
)SendMessage(lphl
->hParent
,WM_VKEYTOITEM
,
1062 wParam
,MAKELPARAM(lphl
->ItemFocused
,hwnd
));
1063 if ( newFocused
== 0xFFFE ) return 0L;
1065 if ( newFocused
== 0xFFFF )
1067 newFocused
= lphl
->ItemFocused
;
1076 newFocused
= lphl
->ItemsCount
- 1;
1079 if (dwStyle
& LBS_MULTICOLUMN
) {
1080 if (newFocused
>= lphl
->ItemsPerColumn
) {
1081 newFocused
-= lphl
->ItemsPerColumn
;
1088 if (newFocused
> 0) newFocused
--;
1091 if (dwStyle
& LBS_MULTICOLUMN
)
1092 newFocused
+= lphl
->ItemsPerColumn
;
1098 if (newFocused
> lphl
->ItemsVisible
)
1099 newFocused
-= lphl
->ItemsVisible
;
1100 else newFocused
= 0;
1103 newFocused
+= lphl
->ItemsVisible
;
1108 /* end of nested switch */
1112 if (dwStyle
& LBS_MULTIPLESEL
)
1114 WORD wRet
= ListBoxGetSel(lphl
, lphl
->ItemFocused
);
1115 ListBoxSetSel(lphl
, lphl
->ItemFocused
, !wRet
);
1119 /* chars are handled in LBChar */
1124 /* at this point newFocused is set up */
1126 if (newFocused
>= lphl
->ItemsCount
)
1127 newFocused
= lphl
->ItemsCount
- 1;
1129 if (!(dwStyle
& LBS_MULTIPLESEL
))
1131 ListBoxSetCurSel(lphl
, newFocused
);
1132 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
1135 lphl
->ItemFocused
= newFocused
;
1137 if( ListBoxScrollToFocus(lphl
) || (dwStyle
&
1138 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
)) )
1139 InvalidateRect(hwnd
, NULL
, TRUE
);
1142 InvalidateRect(hwnd
, &rect
, TRUE
);
1143 if( newFocused
< 0x8000 )
1145 ListBoxGetItemRect(lphl
, newFocused
, &rect
);
1146 InvalidateRect(hwnd
, &rect
, TRUE
);
1150 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1155 /***********************************************************************
1158 static LONG
LBChar(HWND hwnd
, WORD wParam
, LONG lParam
)
1160 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1161 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
1162 WORD newFocused
= 0xFFFF;
1164 if ( (dwStyle
& LBS_WANTKEYBOARDINPUT
) && !(lphl
->HasStrings
))
1166 newFocused
= (WORD
)(INT
)SendMessage(lphl
->hParent
,WM_CHARTOITEM
,
1167 wParam
,MAKELPARAM(lphl
->ItemFocused
,hwnd
));
1168 if ( newFocused
== 0xFFFE ) return 0L;
1171 if (newFocused
== 0xFFFF )
1172 newFocused
= ListBoxFindNextMatch(lphl
, wParam
);
1174 if (newFocused
== (WORD
)LB_ERR
) return 0;
1176 if (newFocused
>= lphl
->ItemsCount
)
1177 newFocused
= lphl
->ItemsCount
- 1;
1179 if (!(dwStyle
& LBS_MULTIPLESEL
))
1181 ListBoxSetCurSel(lphl
, newFocused
);
1182 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
1185 lphl
->ItemFocused
= newFocused
;
1186 ListBoxScrollToFocus(lphl
);
1187 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1189 InvalidateRect(hwnd
, NULL
, TRUE
);
1194 /***********************************************************************
1197 static LONG
LBSetRedraw(HWND hwnd
, WORD wParam
, LONG lParam
)
1199 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1201 dprintf_listbox(stddeb
,"ListBox WM_SETREDRAW hWnd="NPFMT
" w=%04X !\n",
1203 lphl
->bRedrawFlag
= wParam
;
1208 /***********************************************************************
1211 static LONG
LBSetFont(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1213 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1216 lphl
->hFont
= GetStockObject(SYSTEM_FONT
);
1218 lphl
->hFont
= (HFONT
) wParam
;
1223 /***********************************************************************
1226 static LONG
LBPaint(HWND hwnd
, WORD wParam
, LONG lParam
)
1228 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1229 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
1236 int i
, top
, height
, maxwidth
, ipc
;
1239 hdc
= BeginPaint( hwnd
, &ps
);
1241 if (!IsWindowVisible(hwnd
) || !lphl
->bRedrawFlag
) {
1242 EndPaint(hwnd
, &ps
);
1246 hOldFont
= SelectObject(hdc
, lphl
->hFont
);
1249 hBrush
= (HBRUSH
) SendMessage(lphl
->hParent
, WM_CTLCOLORLISTBOX
, (WPARAM
)hdc
,
1252 hBrush
= SendMessage(lphl
->hParent
, WM_CTLCOLOR
, hdc
,
1253 MAKELONG(hwnd
, CTLCOLOR_LISTBOX
));
1256 if (hBrush
== 0) hBrush
= GetStockObject(WHITE_BRUSH
);
1258 GetClientRect(hwnd
, &rect
);
1259 FillRect(hdc
, &rect
, hBrush
);
1261 maxwidth
= rect
.right
;
1262 if (dwStyle
& LBS_MULTICOLUMN
) {
1263 rect
.right
= lphl
->ColumnsWidth
;
1265 lpls
= lphl
->lpFirst
;
1267 lphl
->ItemsVisible
= 0;
1268 lphl
->ItemsPerColumn
= ipc
= 0;
1270 for(i
= 0; i
< lphl
->ItemsCount
; i
++) {
1271 if (lpls
== NULL
) break;
1273 if (i
>= lphl
->FirstVisible
) {
1274 height
= lpls
->mis
.itemHeight
;
1276 if (top
> rect
.bottom
) {
1277 if (dwStyle
& LBS_MULTICOLUMN
) {
1278 lphl
->ItemsPerColumn
= MAX(lphl
->ItemsPerColumn
, ipc
);
1281 rect
.left
+= lphl
->ColumnsWidth
;
1282 rect
.right
+= lphl
->ColumnsWidth
;
1283 if (rect
.left
> maxwidth
) break;
1289 lpls
->itemRect
.top
= top
;
1290 lpls
->itemRect
.bottom
= top
+ height
;
1291 lpls
->itemRect
.left
= rect
.left
;
1292 lpls
->itemRect
.right
= rect
.right
;
1294 dprintf_listbox(stddeb
,"drawing item: %ld %d %ld %d %d\n",(LONG
)rect
.left
,top
,(LONG
)rect
.right
,top
+height
,lpls
->itemState
);
1295 if (lphl
->OwnerDrawn
) {
1296 ListBoxDrawItem (hwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_DRAWENTIRE
, 0);
1297 if (lpls
->itemState
)
1298 ListBoxDrawItem (hwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_SELECT
, ODS_SELECTED
);
1300 ListBoxDrawItem (hwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_DRAWENTIRE
,
1303 if ((lphl
->ItemFocused
== i
) && GetFocus() == hwnd
)
1304 ListBoxDrawItem (hwnd
,lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_FOCUS
, ODS_FOCUS
);
1307 lphl
->ItemsVisible
++;
1311 lpls
= lpls
->lpNext
;
1313 ListBoxUpdateWindow(hwnd
,lphl
,FALSE
);
1314 SelectObject(hdc
,hOldFont
);
1315 EndPaint( hwnd
, &ps
);
1319 /***********************************************************************
1322 static LONG
LBSetFocus(HWND hwnd
, WORD wParam
, LONG lParam
)
1324 dprintf_listbox(stddeb
,"ListBox WM_SETFOCUS !\n");
1329 /***********************************************************************
1332 static LONG
LBKillFocus(HWND hwnd
, WORD wParam
, LONG lParam
)
1334 dprintf_listbox(stddeb
,"ListBox WM_KILLFOCUS !\n");
1336 InvalidateRect(hwnd
, NULL
, TRUE
);
1341 /***********************************************************************
1344 static LONG
LBResetContent(HWND hwnd
, WORD wParam
, LONG lParam
)
1346 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1348 dprintf_listbox(stddeb
,"ListBox LB_RESETCONTENT !\n");
1349 ListBoxResetContent(lphl
);
1350 ListBoxUpdateWindow(hwnd
, lphl
, TRUE
);
1354 /***********************************************************************
1357 static LONG
LBDir(HWND hwnd
, WORD wParam
, LONG lParam
)
1360 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1361 dprintf_listbox(stddeb
,"ListBox LB_DIR !\n");
1363 wRet
= ListBoxDirectory(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
1364 ListBoxUpdateWindow(hwnd
, lphl
, TRUE
);
1368 /***********************************************************************
1371 static LONG
LBAddString(HWND hwnd
, WORD wParam
, LONG lParam
)
1374 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1376 if (lphl
->HasStrings
)
1377 wRet
= ListBoxAddString(lphl
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
1379 wRet
= ListBoxAddString(lphl
, (LPSTR
)lParam
);
1381 ListBoxUpdateWindow(hwnd
,lphl
,TRUE
);
1385 /***********************************************************************
1388 static LONG
LBGetText(HWND hwnd
, WORD wParam
, LONG lParam
)
1391 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1393 dprintf_listbox(stddeb
, "LB_GETTEXT wParam=%d\n",wParam
);
1394 wRet
= ListBoxGetText(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
1399 /***********************************************************************
1402 static LONG
LBInsertString(HWND hwnd
, WORD wParam
, LONG lParam
)
1405 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1407 if (lphl
->HasStrings
)
1408 wRet
= ListBoxInsertString(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
1410 wRet
= ListBoxInsertString(lphl
, wParam
, (LPSTR
)lParam
);
1412 ListBoxUpdateWindow(hwnd
,lphl
,TRUE
);
1416 /***********************************************************************
1419 static LONG
LBDeleteString(HWND hwnd
, WORD wParam
, LONG lParam
)
1421 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1422 LONG lRet
= ListBoxDeleteString(lphl
,wParam
);
1424 ListBoxUpdateWindow(hwnd
,lphl
,TRUE
);
1428 /***********************************************************************
1431 static LONG
LBFindString(HWND hwnd
, WORD wParam
, LONG lParam
)
1433 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1434 return ListBoxFindString(lphl
, wParam
, (SEGPTR
)lParam
);
1437 /***********************************************************************
1440 static LONG
LBGetCaretIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1442 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1443 return lphl
->ItemFocused
;
1446 /***********************************************************************
1449 static LONG
LBGetCount(HWND hwnd
, WORD wParam
, LONG lParam
)
1453 lphl
= ListBoxGetStorageHeader(hwnd
);
1454 return lphl
->ItemsCount
;
1457 /***********************************************************************
1460 static LONG
LBGetCurSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1464 lphl
= ListBoxGetStorageHeader(hwnd
);
1465 dprintf_listbox(stddeb
,"ListBox LB_GETCURSEL %u !\n",
1467 return lphl
->ItemFocused
;
1470 /***********************************************************************
1471 * LBGetHorizontalExtent
1473 static LONG
LBGetHorizontalExtent(HWND hwnd
, WORD wParam
, LONG lParam
)
1478 /***********************************************************************
1481 static LONG
LBGetItemHeight(HWND hwnd
, WORD wParam
, LONG lParam
)
1483 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1484 LPLISTSTRUCT lpls
= ListBoxGetItem (lphl
, wParam
);
1486 if (lpls
== NULL
) return LB_ERR
;
1487 return lpls
->mis
.itemHeight
;
1490 /***********************************************************************
1493 static LONG
LBGetItemRect(HWND hwnd
, WORD wParam
, LONG lParam
)
1495 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1496 return ListBoxGetItemRect(lphl
, wParam
, PTR_SEG_TO_LIN(lParam
));
1499 /***********************************************************************
1502 static LONG
LBGetSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1504 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1505 return (ListBoxGetSel(lphl
, wParam
) )? 1 : 0;
1508 /***********************************************************************
1511 static LONG
LBGetSelCount(HWND hwnd
, WORD wParam
, LONG lParam
)
1513 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1518 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) &
1519 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
1522 for( lpls
= lphl
->lpFirst
;
1524 lpls
= lpls
->lpNext
)
1527 if (lpls
->itemState
)
1534 /***********************************************************************
1537 static LONG
LBGetSelItems(HWND hwnd
, WORD wParam
, LONG lParam
)
1539 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1542 int *lpItems
= PTR_SEG_TO_LIN(lParam
);
1544 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) &
1545 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
1548 if (wParam
== 0) return 0;
1550 lpls
= lphl
->lpFirst
;
1553 while (lpls
!= NULL
) {
1554 if (lpls
->itemState
> 0) lpItems
[cnt
++] = idx
;
1556 if (cnt
== wParam
) break;
1558 lpls
= lpls
->lpNext
;
1564 /***********************************************************************
1567 static LONG
LBGetTextLen(HWND hwnd
, WORD wParam
, LONG lParam
)
1569 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1570 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
,wParam
);
1572 if (lpls
== NULL
|| !lphl
->HasStrings
) return LB_ERR
;
1573 return strlen(lpls
->itemText
);
1576 /***********************************************************************
1579 static LONG
LBGetDlgCode(HWND hwnd
, WORD wParam
, LONG lParam
)
1581 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1584 /***********************************************************************
1587 static LONG
LBGetTopIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1589 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1591 return lphl
->FirstVisible
;
1595 /***********************************************************************
1598 static LONG
LBSelectString(HWND hwnd
, WORD wParam
, LONG lParam
)
1600 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1603 wRet
= ListBoxFindString(lphl
, wParam
, (SEGPTR
)lParam
);
1605 /* XXX add functionality here */
1610 /***********************************************************************
1613 static LONG
LBSelItemRange(HWND hwnd
, WORD wParam
, LONG lParam
)
1615 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1618 WORD first
= LOWORD(lParam
);
1619 WORD last
= HIWORD(lParam
);
1620 BOOL select
= wParam
;
1622 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) &
1623 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
1626 if (first
>= lphl
->ItemsCount
||
1627 last
>= lphl
->ItemsCount
) return LB_ERR
;
1629 lpls
= lphl
->lpFirst
;
1632 while (lpls
!= NULL
) {
1634 lpls
->itemState
= select
? ODS_SELECTED
: 0;
1639 lpls
= lpls
->lpNext
;
1645 /***********************************************************************
1648 static LONG
LBSetCaretIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1650 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1652 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) & LBS_MULTIPLESEL
)) return 0;
1653 if (wParam
>= lphl
->ItemsCount
) return LB_ERR
;
1655 lphl
->ItemFocused
= wParam
;
1656 ListBoxScrollToFocus (lphl
);
1658 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1659 InvalidateRect(hwnd
, NULL
, TRUE
);
1663 /***********************************************************************
1666 static LONG
LBSetColumnWidth(HWND hwnd
, WORD wParam
, LONG lParam
)
1668 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1669 lphl
->ColumnsWidth
= wParam
;
1670 InvalidateRect(hwnd
,NULL
,TRUE
);
1674 /***********************************************************************
1675 * LBSetHorizontalExtent
1677 static LONG
LBSetHorizontalExtent(HWND hwnd
, WORD wParam
, LONG lParam
)
1682 /***********************************************************************
1685 static LONG
LBGetItemData(HWND hwnd
, WORD wParam
, LONG lParam
)
1687 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1688 dprintf_listbox(stddeb
, "LB_GETITEMDATA wParam=%x\n", wParam
);
1689 return ListBoxGetItemData(lphl
, wParam
);
1692 /***********************************************************************
1695 static LONG
LBSetItemData(HWND hwnd
, WORD wParam
, LONG lParam
)
1697 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1698 dprintf_listbox(stddeb
, "LB_SETITEMDATA wParam=%x lParam=%lx\n", wParam
, lParam
);
1699 return ListBoxSetItemData(lphl
, wParam
, lParam
);
1702 /***********************************************************************
1705 static LONG
LBSetTabStops(HWND hwnd
, WORD wParam
, LONG lParam
)
1709 lphl
= ListBoxGetStorageHeader(hwnd
);
1711 if (lphl
->TabStops
!= NULL
) {
1712 lphl
->iNumStops
= 0;
1713 free (lphl
->TabStops
);
1716 lphl
->TabStops
= malloc (wParam
* sizeof (short));
1717 if (lphl
->TabStops
) {
1718 lphl
->iNumStops
= wParam
;
1719 memcpy (lphl
->TabStops
, PTR_SEG_TO_LIN(lParam
), wParam
* sizeof (short));
1726 /***********************************************************************
1729 static LONG
LBSetCurSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1731 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1734 dprintf_listbox(stddeb
,"ListBox LB_SETCURSEL wParam=%x !\n",
1737 wRet
= ListBoxSetCurSel(lphl
, wParam
);
1739 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1740 InvalidateRect(hwnd
, NULL
, TRUE
);
1745 /***********************************************************************
1748 static LONG
LBSetSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1750 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1753 dprintf_listbox(stddeb
,"ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam
, lParam
);
1755 wRet
= ListBoxSetSel(lphl
, LOWORD(lParam
), wParam
);
1756 InvalidateRect(hwnd
, NULL
, TRUE
);
1761 /***********************************************************************
1764 static LONG
LBSetTopIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1766 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1768 dprintf_listbox(stddeb
,"ListBox LB_SETTOPINDEX wParam=%x !\n",
1770 lphl
->FirstVisible
= wParam
;
1771 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1773 InvalidateRect(hwnd
, NULL
, TRUE
);
1778 /***********************************************************************
1781 static LONG
LBSetItemHeight(HWND hwnd
, WORD wParam
, LONG lParam
)
1783 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1786 dprintf_listbox(stddeb
,"ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam
, lParam
);
1787 wRet
= ListBoxSetItemHeight(lphl
, wParam
, lParam
);
1788 InvalidateRect(hwnd
,NULL
,TRUE
);
1792 /***********************************************************************
1795 static LRESULT
LBPassToParent(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1797 WND
* ptrWnd
= WIN_FindWndPtr(hwnd
);
1800 if( /* !(ptrWnd->dwExStyle & WS_EX_NOPARENTNOTIFY) && */
1801 ptrWnd
->hwndParent
)
1802 return SendMessage(ptrWnd
->hwndParent
,message
,wParam
,lParam
);
1806 /***********************************************************************
1809 LRESULT
ListBoxWndProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1812 case WM_CREATE
: return LBCreate(hwnd
, wParam
, lParam
);
1813 case WM_DESTROY
: return LBDestroy(hwnd
, wParam
, lParam
);
1814 case WM_GETDLGCODE
: return LBGetDlgCode(hwnd
, wParam
, lParam
);
1815 case WM_VSCROLL
: return LBVScroll(hwnd
, wParam
, lParam
);
1816 case WM_HSCROLL
: return LBHScroll(hwnd
, wParam
, lParam
);
1817 case WM_LBUTTONDOWN
: return LBLButtonDown(hwnd
, wParam
, lParam
);
1818 case WM_LBUTTONUP
: return LBLButtonUp(hwnd
, wParam
, lParam
);
1819 case WM_RBUTTONUP
: return LBRButtonUp(hwnd
, wParam
, lParam
);
1820 case WM_LBUTTONDBLCLK
: return LBRButtonUp(hwnd
, wParam
, lParam
);
1821 case WM_MOUSEMOVE
: return LBMouseMove(hwnd
, wParam
, lParam
);
1822 case WM_KEYDOWN
: return LBKeyDown(hwnd
, wParam
, lParam
);
1823 case WM_CHAR
: return LBChar(hwnd
, wParam
, lParam
);
1824 case WM_SETFONT
: return LBSetFont(hwnd
, wParam
, lParam
);
1825 case WM_SETREDRAW
: return LBSetRedraw(hwnd
, wParam
, lParam
);
1826 case WM_PAINT
: return LBPaint(hwnd
, wParam
, lParam
);
1827 case WM_SETFOCUS
: return LBSetFocus(hwnd
, wParam
, lParam
);
1828 case WM_KILLFOCUS
: return LBKillFocus(hwnd
, wParam
, lParam
);
1829 case LB_RESETCONTENT
: return LBResetContent(hwnd
, wParam
, lParam
);
1830 case LB_DIR
: return LBDir(hwnd
, wParam
, lParam
);
1831 case LB_ADDSTRING
: return LBAddString(hwnd
, wParam
, lParam
);
1832 case LB_INSERTSTRING
: return LBInsertString(hwnd
, wParam
, lParam
);
1833 case LB_DELETESTRING
: return LBDeleteString(hwnd
, wParam
, lParam
);
1834 case LB_FINDSTRING
: return LBFindString(hwnd
, wParam
, lParam
);
1835 case LB_GETCARETINDEX
: return LBGetCaretIndex(hwnd
, wParam
, lParam
);
1836 case LB_GETCOUNT
: return LBGetCount(hwnd
, wParam
, lParam
);
1837 case LB_GETCURSEL
: return LBGetCurSel(hwnd
, wParam
, lParam
);
1838 case LB_GETHORIZONTALEXTENT
: return LBGetHorizontalExtent(hwnd
, wParam
, lParam
);
1839 case LB_GETITEMDATA
: return LBGetItemData(hwnd
, wParam
, lParam
);
1840 case LB_GETITEMHEIGHT
: return LBGetItemHeight(hwnd
, wParam
, lParam
);
1841 case LB_GETITEMRECT
: return LBGetItemRect(hwnd
, wParam
, lParam
);
1842 case LB_GETSEL
: return LBGetSel(hwnd
, wParam
, lParam
);
1843 case LB_GETSELCOUNT
: return LBGetSelCount(hwnd
, wParam
, lParam
);
1844 case LB_GETSELITEMS
: return LBGetSelItems(hwnd
, wParam
, lParam
);
1845 case LB_GETTEXT
: return LBGetText(hwnd
, wParam
, lParam
);
1846 case LB_GETTEXTLEN
: return LBGetTextLen(hwnd
, wParam
, lParam
);
1847 case LB_GETTOPINDEX
: return LBGetTopIndex(hwnd
, wParam
, lParam
);
1848 case LB_SELECTSTRING
: return LBSelectString(hwnd
, wParam
, lParam
);
1849 case LB_SELITEMRANGE
: return LBSelItemRange(hwnd
, wParam
, lParam
);
1850 case LB_SETCARETINDEX
: return LBSetCaretIndex(hwnd
, wParam
, lParam
);
1851 case LB_SETCOLUMNWIDTH
: return LBSetColumnWidth(hwnd
, wParam
, lParam
);
1852 case LB_SETHORIZONTALEXTENT
: return LBSetHorizontalExtent(hwnd
, wParam
, lParam
);
1853 case LB_SETITEMDATA
: return LBSetItemData(hwnd
, wParam
, lParam
);
1854 case LB_SETTABSTOPS
: return LBSetTabStops(hwnd
, wParam
, lParam
);
1855 case LB_SETCURSEL
: return LBSetCurSel(hwnd
, wParam
, lParam
);
1856 case LB_SETSEL
: return LBSetSel(hwnd
, wParam
, lParam
);
1857 case LB_SETTOPINDEX
: return LBSetTopIndex(hwnd
, wParam
, lParam
);
1858 case LB_SETITEMHEIGHT
: return LBSetItemHeight(hwnd
, wParam
, lParam
);
1860 case WM_DROPFILES
: return LBPassToParent(hwnd
, message
, wParam
, lParam
);
1863 case WM_QUERYDROPOBJECT
:
1867 LPDRAGINFO lpDragInfo
= (LPDRAGINFO
) PTR_SEG_TO_LIN((SEGPTR
)lParam
);
1868 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1870 /* more undocumented Microsoft crap - drag&drop depends on it - AK */
1872 lpDragInfo
->l
= ListBoxFindMouse(lphl
,lpDragInfo
->pt
.x
,
1875 return LBPassToParent(hwnd
, message
, wParam
, lParam
);
1879 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
1882 /************************************************************************
1883 * DlgDirSelect [USER.99]
1885 BOOL
DlgDirSelect(HWND hDlg
, LPSTR lpStr
, int nIDLBox
)
1891 dprintf_listbox( stddeb
, "DlgDirSelect("NPFMT
", '%s', %d) \n", hDlg
, lpStr
,
1894 hwnd
= GetDlgItem(hDlg
, nIDLBox
);
1895 lphl
= ListBoxGetStorageHeader(hwnd
);
1896 if(lphl
->ItemFocused
== -1) {
1897 dprintf_listbox(stddeb
, "Nothing selected!\n");
1900 ListBoxGetText(lphl
, lphl
->ItemFocused
, s
);
1901 dprintf_listbox(stddeb
, "Selection is %s\n", s
);
1904 strncpy( lpStr
, s
+2, strlen(s
)-4 ); /* device name */
1905 lpStr
[ strlen(s
)-4 ] = 0;
1906 strcat( lpStr
, ":" );
1909 strncpy( lpStr
, s
+1, strlen(s
)-2 ); /* directory name */
1910 lpStr
[ strlen(s
)-2 ] = 0;
1911 strcat( lpStr
, "\\" );
1913 dprintf_listbox( stddeb
, "Returning %s\n", lpStr
);
1916 strcpy( lpStr
, s
); /* file name */
1917 dprintf_listbox( stddeb
, "Returning %s\n", lpStr
);
1923 /************************************************************************
1924 * DlgDirList [USER.100]
1926 int DlgDirList(HWND hDlg
, LPSTR lpPathSpec
,
1927 int nIDLBox
, int nIDStat
, WORD wType
)
1932 dprintf_listbox(stddeb
,"DlgDirList("NPFMT
", '%s', %d, %d, %04X) \n",
1933 hDlg
, lpPathSpec
, nIDLBox
, nIDStat
, wType
);
1936 hWnd
= GetDlgItem(hDlg
, nIDLBox
);
1937 lphl
= ListBoxGetStorageHeader(hWnd
);
1938 ListBoxResetContent(lphl
);
1939 ret
= ListBoxDirectory(lphl
, wType
, lpPathSpec
);
1940 ListBoxUpdateWindow(hWnd
, lphl
, TRUE
);
1948 drive
= DOS_GetDefaultDrive();
1949 hTemp
= USER_HEAP_ALLOC( 256 );
1950 temp
= (char *) USER_HEAP_LIN_ADDR( hTemp
);
1951 strcpy( temp
+3, DOS_GetCurrentDir(drive
) );
1952 if( temp
[3] == '\\' ) {
1953 temp
[1] = 'A'+drive
;
1955 SendDlgItemMessage( hDlg
, nIDStat
, WM_SETTEXT
, 0,
1956 (LPARAM
)(USER_HEAP_SEG_ADDR(hTemp
) + 1) );
1958 temp
[0] = 'A'+drive
;
1961 SendDlgItemMessage( hDlg
, nIDStat
, WM_SETTEXT
, 0,
1962 (LPARAM
)USER_HEAP_SEG_ADDR(hTemp
) );
1964 USER_HEAP_FREE( hTemp
);