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!!!!
29 #include "stackframe.h"
35 #define LIST_HEAP_ALLOC(lphl,f,size) ((int)HEAP_Alloc(&lphl->Heap,f,size) & 0xffff)
36 #define LIST_HEAP_FREE(lphl,handle) (HEAP_Free(&lphl->Heap,LIST_HEAP_ADDR(lphl,handle)))
37 #define LIST_HEAP_ADDR(lphl,handle) \
38 ((void *)((handle) ? ((handle) | ((int)lphl->Heap & 0xffff0000)) : 0))
40 /* FIXME: shouldn't each listbox have its own heap? */
42 #define LIST_HEAP_ALLOC(lphl,f,size) USER_HEAP_ALLOC(size)
43 #define LIST_HEAP_FREE(lphl,handle) USER_HEAP_FREE(handle)
44 #define LIST_HEAP_ADDR(lphl,handle) USER_HEAP_LIN_ADDR(handle)
45 #define LIST_HEAP_SEG_ADDR(lphl,handle) USER_HEAP_SEG_ADDR(handle)
47 /* Something like this maybe ? */
48 #define LIST_HEAP_ALLOC(lphl,f,size) \
49 LOCAL_Alloc( lphl->HeapSel, LMEM_FIXED, (size) )
51 #define LIST_HEAP_REALLOC(handle,size) \
52 LOCAL_ReAlloc( USER_HeapSel, (handle), (size), LMEM_FIXED )
54 #define LIST_HEAP_FREE(lphl,handle) \
55 LOCAL_Free( lphl->HeapSel, (handle) )
56 #define LIST_HEAP_ADDR(lphl,handle) \
57 ((handle) ? PTR_SEG_OFF_TO_LIN(lphl->HeapSel, (handle)) : NULL)
58 #define LIST_HEAP_SEG_ADDR(lphl,handle) \
59 ((handle) ? MAKELONG((handle), lphl->HeapSel) : 0)
63 #define LIST_HEAP_SIZE 0x10000
65 static void ListBoxInitialize(LPHEADLIST lphl
)
69 lphl
->ItemsVisible
= 0;
70 lphl
->FirstVisible
= 0;
71 lphl
->ColumnsVisible
= 1;
72 lphl
->ItemsPerColumn
= 0;
73 lphl
->ItemFocused
= -1;
74 lphl
->PrevFocused
= -1;
77 void CreateListBoxStruct(HWND hwnd
, WORD CtlType
, LONG styles
, HWND parent
)
81 lphl
= (LPHEADLIST
)xmalloc(sizeof(HEADLIST
));
82 SetWindowLong(hwnd
, 0, (LONG
)lphl
);
83 ListBoxInitialize(lphl
);
84 lphl
->DrawCtlType
= CtlType
;
85 lphl
->CtlID
= GetWindowWord(hwnd
,GWW_ID
);
86 lphl
->bRedrawFlag
= TRUE
;
88 lphl
->TabStops
= NULL
;
89 lphl
->hFont
= GetStockObject(SYSTEM_FONT
);
91 lphl
->hParent
= parent
;
92 lphl
->StdItemHeight
= 15; /* FIXME: should get the font height */
93 lphl
->OwnerDrawn
= styles
& (LBS_OWNERDRAWFIXED
| LBS_OWNERDRAWVARIABLE
);
94 lphl
->HasStrings
= (styles
& LBS_HASSTRINGS
) || !lphl
->OwnerDrawn
;
96 if (lphl
->OwnerDrawn
) {
99 lphl
->hDrawItemStruct
= USER_HEAP_ALLOC(sizeof(DRAWITEMSTRUCT
));
100 lphl
->needMeasure
= TRUE
;
101 dummyls
.mis
.CtlType
= lphl
->DrawCtlType
;
102 dummyls
.mis
.CtlID
= lphl
->CtlID
;
103 dummyls
.mis
.itemID
= -1;
104 dummyls
.mis
.itemWidth
= 0; /* ignored */
105 dummyls
.mis
.itemData
= 0;
107 ListBoxAskMeasure(lphl
,&dummyls
);
109 lphl
->hDrawItemStruct
= 0;
113 HeapHandle
= GlobalAlloc(GMEM_FIXED
, LIST_HEAP_SIZE
);
114 HeapBase
= GlobalLock(HeapHandle
);
115 HEAP_Init(&lphl
->Heap
, HeapBase
, LIST_HEAP_SIZE
);
117 /* WINELIBS list boxes do not operate on local heaps */
119 lphl
->HeapSel
= GlobalAlloc(GMEM_FIXED
,LIST_HEAP_SIZE
);
120 LocalInit( lphl
->HeapSel
, 0, LIST_HEAP_SIZE
-1);
126 void DestroyListBoxStruct(LPHEADLIST lphl
)
128 if (lphl
->hDrawItemStruct
)
129 USER_HEAP_FREE(lphl
->hDrawItemStruct
);
131 /* XXX need to free lphl->Heap */
132 GlobalFree(lphl
->HeapSel
);
136 static LPHEADLIST
ListBoxGetStorageHeader(HWND hwnd
)
138 return (LPHEADLIST
)GetWindowLong(hwnd
,0);
141 /* Send notification "code" as part of a WM_COMMAND-message if hwnd
142 has the LBS_NOTIFY style */
143 void ListBoxSendNotification(LPHEADLIST lphl
, WORD code
)
145 DWORD dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
147 if (dwStyle
& LBS_NOTIFY
)
149 SendMessage(lphl
->hParent
, WM_COMMAND
,
150 MAKEWPARAM(lphl
->CtlID
,code
), (LPARAM
)lphl
->hSelf
);
152 SendMessage(lphl
->hParent
, WM_COMMAND
,
153 lphl
->CtlID
, MAKELONG(lphl
->hSelf
, code
));
158 /* get the maximum value of lphl->FirstVisible */
159 int ListMaxFirstVisible(LPHEADLIST lphl
)
161 int m
= lphl
->ItemsCount
-lphl
->ItemsVisible
;
162 return (m
< 0) ? 0 : m
;
166 void ListBoxUpdateWindow(HWND hwnd
, LPHEADLIST lphl
, BOOL repaint
)
168 SetScrollRange(hwnd
, SB_VERT
, 0, ListMaxFirstVisible(lphl
), TRUE
);
169 if (lphl
->ItemsPerColumn
!= 0) {
170 SetScrollRange(hwnd
, SB_HORZ
, 1, lphl
->ItemsVisible
/
171 lphl
->ItemsPerColumn
+ 1, TRUE
);
173 if (repaint
&& lphl
->bRedrawFlag
) {
174 InvalidateRect(hwnd
, NULL
, TRUE
);
178 /* Returns: 0 if nothing needs to be changed */
179 /* 1 if FirstVisible changed */
181 int ListBoxScrollToFocus(LPHEADLIST lphl
)
185 if (lphl
->ItemsCount
== 0) return 0;
186 if (lphl
->ItemFocused
== -1) return 0;
188 end
= lphl
->FirstVisible
+ lphl
->ItemsVisible
- 1;
190 if (lphl
->ItemFocused
< lphl
->FirstVisible
) {
191 lphl
->FirstVisible
= lphl
->ItemFocused
;
194 if (lphl
->ItemFocused
> end
) {
195 WORD maxFirstVisible
= ListMaxFirstVisible(lphl
);
197 lphl
->FirstVisible
= lphl
->ItemFocused
;
199 if (lphl
->FirstVisible
> maxFirstVisible
) {
200 lphl
->FirstVisible
= maxFirstVisible
;
209 LPLISTSTRUCT
ListBoxGetItem(LPHEADLIST lphl
, UINT uIndex
)
214 if (uIndex
>= lphl
->ItemsCount
) return NULL
;
216 lpls
= lphl
->lpFirst
;
217 while (Count
++ < uIndex
) lpls
= lpls
->lpNext
;
222 void ListBoxDrawItem (HWND hwnd
, LPHEADLIST lphl
, HDC hdc
, LPLISTSTRUCT lpls
,
223 RECT
*rect
, WORD itemAction
, WORD itemState
)
225 LONG dwStyle
= GetWindowLong(hwnd
,GWL_STYLE
);
227 if (lphl
->OwnerDrawn
) {
228 DRAWITEMSTRUCT
*dis
= USER_HEAP_LIN_ADDR(lphl
->hDrawItemStruct
);
230 dis
->CtlID
= lpls
->mis
.CtlID
;
231 dis
->CtlType
= lpls
->mis
.CtlType
;
232 dis
->itemID
= lpls
->mis
.itemID
;
234 dis
->hwndItem
= hwnd
;
235 dis
->itemData
= lpls
->mis
.itemData
;
236 dis
->itemAction
= itemAction
;
237 dis
->itemState
= itemState
;
239 SendMessage(lphl
->hParent
, WM_DRAWITEM
,
240 0, (LPARAM
)USER_HEAP_SEG_ADDR(lphl
->hDrawItemStruct
));
242 if (itemAction
== ODA_DRAWENTIRE
|| itemAction
== ODA_SELECT
) {
244 DWORD dwOldTextColor
= 0;
246 OldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
248 if (itemState
!= 0) {
249 dwOldTextColor
= SetTextColor(hdc
, 0x00FFFFFFL
);
250 FillRect(hdc
, rect
, GetStockObject(BLACK_BRUSH
));
253 if (dwStyle
& LBS_USETABSTOPS
) {
254 TabbedTextOut(hdc
, rect
->left
+ 5, rect
->top
+ 2,
255 (char *)lpls
->itemText
, strlen((char *)lpls
->itemText
),
256 lphl
->iNumStops
, lphl
->TabStops
, 0);
258 TextOut(hdc
, rect
->left
+ 5, rect
->top
+ 2,
259 (char *)lpls
->itemText
, strlen((char *)lpls
->itemText
));
262 if (itemState
!= 0) {
263 SetTextColor(hdc
, dwOldTextColor
);
266 SetBkMode(hdc
, OldBkMode
);
267 } else DrawFocusRect(hdc
, rect
);
274 int ListBoxFindMouse(LPHEADLIST lphl
, int X
, int Y
)
276 LPLISTSTRUCT lpls
= lphl
->lpFirst
;
280 point
.x
= X
; point
.y
= Y
;
281 if (lphl
->ItemsCount
== 0) return LB_ERR
;
283 for(i
= 0; i
< lphl
->FirstVisible
; i
++) {
284 if (lpls
== NULL
) return LB_ERR
;
287 for(j
= 0; j
< lphl
->ItemsVisible
; i
++, j
++) {
288 if (lpls
== NULL
) return LB_ERR
;
289 if (PtInRect(&lpls
->itemRect
,point
)) {
294 dprintf_listbox(stddeb
,"ListBoxFindMouse: not found\n");
299 void ListBoxAskMeasure(LPHEADLIST lphl
, LPLISTSTRUCT lpls
)
301 HANDLE hTemp
= USER_HEAP_ALLOC( sizeof(MEASUREITEMSTRUCT
) );
302 MEASUREITEMSTRUCT
*lpmeasure
= (MEASUREITEMSTRUCT
*) USER_HEAP_LIN_ADDR(hTemp
);
304 if (lpmeasure
== NULL
) {
305 fprintf(stdnimp
,"ListBoxAskMeasure() out of memory !\n");
309 *lpmeasure
= lpls
->mis
;
310 lpmeasure
->itemHeight
= lphl
->StdItemHeight
;
311 SendMessage(lphl
->hParent
, WM_MEASUREITEM
, 0, (LPARAM
)USER_HEAP_SEG_ADDR(hTemp
));
313 if (GetWindowLong(lphl
->hSelf
,GWL_STYLE
) & LBS_OWNERDRAWFIXED
) {
314 lphl
->StdItemHeight
= lpmeasure
->itemHeight
;
315 lphl
->needMeasure
= FALSE
;
318 USER_HEAP_FREE(hTemp
);
321 /* -------------------- strings and item data ---------------------- */
323 LPLISTSTRUCT
ListBoxCreateItem(LPHEADLIST lphl
, int id
)
325 LPLISTSTRUCT lplsnew
= (LPLISTSTRUCT
)malloc(sizeof(LISTSTRUCT
));
327 if (lplsnew
== NULL
) return NULL
;
329 lplsnew
->itemState
= 0;
330 lplsnew
->mis
.CtlType
= lphl
->DrawCtlType
;
331 lplsnew
->mis
.CtlID
= lphl
->CtlID
;
332 lplsnew
->mis
.itemID
= id
;
333 lplsnew
->mis
.itemHeight
= lphl
->StdItemHeight
;
334 lplsnew
->mis
.itemWidth
= 0; /* ignored */
335 lplsnew
->mis
.itemData
= 0;
336 SetRect(&lplsnew
->itemRect
, 0, 0, 0, 0);
342 int ListBoxInsertString(LPHEADLIST lphl
, UINT uIndex
, LPCSTR newstr
)
344 LPLISTSTRUCT
*lppls
, lplsnew
, lpls
;
349 dprintf_listbox(stddeb
,"ListBoxInsertString(%d, %p);\n", uIndex
, newstr
);
351 if (!newstr
) return -1;
353 if (uIndex
== (UINT
)-1)
354 uIndex
= lphl
->ItemsCount
;
356 lppls
= &lphl
->lpFirst
;
357 for(Count
= 0; Count
< uIndex
; Count
++) {
358 if (*lppls
== NULL
) return LB_ERR
;
359 lppls
= (LPLISTSTRUCT
*) &(*lppls
)->lpNext
;
362 lplsnew
= ListBoxCreateItem(lphl
, Count
);
364 if (lplsnew
== NULL
) {
365 fprintf(stdnimp
,"ListBoxInsertString() out of memory !\n");
369 lplsnew
->lpNext
= *lppls
;
374 if (lphl
->HasStrings
) {
375 dprintf_listbox(stddeb
," string: %s\n", newstr
);
376 hStr
= LIST_HEAP_ALLOC(lphl
, LMEM_MOVEABLE
, strlen(newstr
) + 1);
377 str
= (LPSTR
)LIST_HEAP_ADDR(lphl
, hStr
);
378 if (str
== NULL
) return LB_ERRSPACE
;
380 lplsnew
->itemText
= str
;
381 /* I'm not so sure about the next one */
382 lplsnew
->mis
.itemData
= 0;
384 lplsnew
->itemText
= NULL
;
385 lplsnew
->mis
.itemData
= (DWORD
)newstr
;
388 lplsnew
->mis
.itemID
= uIndex
;
389 lplsnew
->hData
= hStr
;
391 /* adjust the itemID field of the following entries */
392 for(lpls
= lplsnew
->lpNext
; lpls
!= NULL
; lpls
= lpls
->lpNext
) {
396 if (lphl
->needMeasure
) {
397 ListBoxAskMeasure(lphl
, lplsnew
);
400 dprintf_listbox(stddeb
,"ListBoxInsertString // count=%d\n", lphl
->ItemsCount
);
405 int ListBoxAddString(LPHEADLIST lphl
, LPCSTR newstr
)
407 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
408 UINT pos
= (UINT
) -1;
410 if (lphl
->HasStrings
&& (dwStyle
& LBS_SORT
)) {
411 LPLISTSTRUCT lpls
= lphl
->lpFirst
;
412 for (pos
= 0; lpls
!= NULL
; lpls
= lpls
->lpNext
, pos
++)
413 if (strcmp(lpls
->itemText
, newstr
) >= 0)
416 return ListBoxInsertString(lphl
, pos
, newstr
);
420 int ListBoxGetText(LPHEADLIST lphl
, UINT uIndex
, LPSTR OutStr
)
425 dprintf_listbox(stddeb
, "ListBoxGetText // OutStr==NULL\n");
429 lpls
= ListBoxGetItem (lphl
, uIndex
);
430 if (lpls
== NULL
) return LB_ERR
;
432 if (!lphl
->HasStrings
) {
433 *((long *)OutStr
) = lpls
->mis
.itemData
;
437 strcpy(OutStr
, lpls
->itemText
);
438 return strlen(OutStr
);
442 DWORD
ListBoxGetItemData(LPHEADLIST lphl
, UINT uIndex
)
446 lpls
= ListBoxGetItem (lphl
, uIndex
);
447 if (lpls
== NULL
) return LB_ERR
;
448 return lpls
->mis
.itemData
;
452 int ListBoxSetItemData(LPHEADLIST lphl
, UINT uIndex
, DWORD ItemData
)
454 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
, uIndex
);
456 if (lpls
== NULL
) return LB_ERR
;
457 lpls
->mis
.itemData
= ItemData
;
462 int ListBoxDeleteString(LPHEADLIST lphl
, UINT uIndex
)
464 LPLISTSTRUCT lpls
, lpls2
;
467 if (uIndex
>= lphl
->ItemsCount
) return LB_ERR
;
469 lpls
= lphl
->lpFirst
;
470 if (lpls
== NULL
) return LB_ERR
;
473 lphl
->lpFirst
= lpls
->lpNext
;
475 LPLISTSTRUCT lpls2
= NULL
;
476 for(Count
= 0; Count
< uIndex
; Count
++) {
477 if (lpls
->lpNext
== NULL
) return LB_ERR
;
480 lpls
= (LPLISTSTRUCT
)lpls
->lpNext
;
482 lpls2
->lpNext
= lpls
->lpNext
;
485 /* adjust the itemID field of the following entries */
486 for(lpls2
= lpls
->lpNext
; lpls2
!= NULL
; lpls2
= lpls2
->lpNext
) {
492 if (lpls
->hData
!= 0) LIST_HEAP_FREE(lphl
, lpls
->hData
);
495 return lphl
->ItemsCount
;
499 int ListBoxFindString(LPHEADLIST lphl
, UINT nFirst
, SEGPTR MatchStr
)
503 UINT First
= nFirst
+ 1;
504 LPSTR lpMatchStr
= (LPSTR
)MatchStr
;
505 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
507 if (First
> lphl
->ItemsCount
) return LB_ERR
;
509 if (lphl
->HasStrings
) lpMatchStr
= PTR_SEG_TO_LIN(MatchStr
);
511 lpls
= ListBoxGetItem(lphl
, First
);
513 while(lpls
!= NULL
) {
514 if (lphl
->HasStrings
) {
515 if (strstr(lpls
->itemText
, lpMatchStr
) == lpls
->itemText
) return Count
;
516 } else if (dwStyle
& LBS_SORT
) {
517 /* XXX Do a compare item */
520 if (lpls
->mis
.itemData
== (DWORD
)lpMatchStr
) return Count
;
526 /* Start over at top */
528 lpls
= lphl
->lpFirst
;
530 while (Count
< First
) {
531 if (lphl
->HasStrings
) {
532 if (strstr(lpls
->itemText
, lpMatchStr
) == lpls
->itemText
) return Count
;
533 } else if (dwStyle
& LBS_SORT
) {
534 /* XXX Do a compare item */
536 if (lpls
->mis
.itemData
== (DWORD
)lpMatchStr
) return Count
;
546 int ListBoxResetContent(LPHEADLIST lphl
)
551 if (lphl
->ItemsCount
== 0) return 0;
553 dprintf_listbox(stddeb
, "ListBoxResetContent // ItemCount = %d\n",
556 for(i
= 0; i
< lphl
->ItemsCount
; i
++) {
557 lpls
= lphl
->lpFirst
;
558 if (lpls
== NULL
) return LB_ERR
;
560 lphl
->lpFirst
= lpls
->lpNext
;
561 if (lpls
->hData
!= 0) LIST_HEAP_FREE(lphl
, lpls
->hData
);
564 ListBoxInitialize(lphl
);
569 /* --------------------- selection ------------------------- */
571 int ListBoxSetCurSel(LPHEADLIST lphl
, WORD wIndex
)
574 DWORD dwStyle
= GetWindowWord(lphl
->hSelf
,GWL_STYLE
);
576 /* use ListBoxSetSel instead */
577 if (dwStyle
& LBS_MULTIPLESEL
) return 0;
579 /* unselect all previously selected */
580 if (dwStyle
& LBS_EXTENDEDSEL
)
581 ListBoxSetSel(lphl
,-1,0);
583 /* unselect previous item */
584 if (lphl
->ItemFocused
!= -1) {
585 lpls
= ListBoxGetItem(lphl
, lphl
->ItemFocused
);
586 if (lpls
== 0) return LB_ERR
;
590 if (wIndex
!= (UINT
)-1) {
591 lphl
->ItemFocused
= wIndex
;
592 lpls
= ListBoxGetItem(lphl
, wIndex
);
593 if (lpls
== 0) return LB_ERR
;
594 lpls
->itemState
= ODS_SELECTED
| ODS_FOCUS
;
603 int ListBoxSetSel(LPHEADLIST lphl
, WORD wIndex
, WORD state
)
607 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) &
608 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
611 if (wIndex
== (UINT
)-1) {
612 for (lpls
= lphl
->lpFirst
; lpls
!= NULL
; lpls
= lpls
->lpNext
) {
613 lpls
->itemState
= state
;
618 if (wIndex
>= lphl
->ItemsCount
) return LB_ERR
;
620 lpls
= ListBoxGetItem(lphl
, wIndex
);
621 lpls
->itemState
= state
;
627 int ListBoxGetSel(LPHEADLIST lphl
, WORD wIndex
)
629 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
, wIndex
);
631 if (lpls
== NULL
) return LB_ERR
;
632 return lpls
->itemState
;
635 /* ------------------------- dir listing ------------------------ */
637 LONG
ListBoxDirectory(LPHEADLIST lphl
, UINT attrib
, LPCSTR filespec
)
639 char temp
[16], mask
[13];
646 dprintf_listbox(stddeb
, "ListBoxDirectory: '%s' %04x\n", filespec
, attrib
);
647 if (!filespec
) return LB_ERR
;
648 if (!(ptr
= DOSFS_GetUnixFileName( filespec
, FALSE
))) return LB_ERR
;
650 p
= strrchr( path
, '/' );
652 if (!(ptr
= DOSFS_ToDosFCBFormat( p
)))
659 dprintf_listbox(stddeb
, "ListBoxDirectory: path=%s mask=%s\n", path
, mask
);
663 while ((count
= DOSFS_FindNext( path
, mask
, 0, attrib
, skip
, &entry
)) > 0)
666 if (entry
.attr
& FA_DIRECTORY
)
668 if ((attrib
& DDL_DIRECTORY
) && strcmp(entry
.name
, ". "))
670 sprintf(temp
, "[%s]", DOSFS_ToDosDTAFormat( entry
.name
) );
672 if ((ret
= ListBoxAddString(lphl
, temp
)) == LB_ERR
) break;
675 else /* not a directory */
677 if (!(attrib
& DDL_EXCLUSIVE
) ||
678 ((attrib
& (FA_RDONLY
|FA_HIDDEN
|FA_SYSTEM
|FA_ARCHIVE
)) ==
679 (entry
.attr
& (FA_RDONLY
|FA_HIDDEN
|FA_SYSTEM
|FA_ARCHIVE
))))
681 strcpy( temp
, DOSFS_ToDosDTAFormat( entry
.name
) );
683 if ((ret
= ListBoxAddString(lphl
, temp
)) == LB_ERR
) break;
687 if (attrib
& DDL_DRIVES
)
690 strcpy( temp
, "[-a-]" );
691 for (x
= 0; x
< MAX_DOS_DRIVES
; x
++, temp
[2]++)
693 if (DRIVE_IsValid(x
))
694 if ((ret
= ListBoxAddString(lphl
, temp
)) == LB_ERR
) break;
701 /* ------------------------- dimensions ------------------------- */
703 int ListBoxGetItemRect(LPHEADLIST lphl
, WORD wIndex
, LPRECT lprect
)
705 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
,wIndex
);
707 if (lpls
== NULL
) return LB_ERR
;
708 *lprect
= lpls
->itemRect
;
713 int ListBoxSetItemHeight(LPHEADLIST lphl
, WORD wIndex
, long height
)
717 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) & LBS_OWNERDRAWVARIABLE
)) {
718 lphl
->StdItemHeight
= (short)height
;
722 lpls
= ListBoxGetItem(lphl
, wIndex
);
723 if (lpls
== NULL
) return LB_ERR
;
725 lpls
->mis
.itemHeight
= height
;
729 /* -------------------------- string search ------------------------ */
731 int ListBoxFindNextMatch(LPHEADLIST lphl
, WORD wChar
)
736 if ((char)wChar
< ' ') return LB_ERR
;
737 if (!lphl
->HasStrings
) return LB_ERR
;
739 lpls
= lphl
->lpFirst
;
741 for (count
= 0; lpls
!= NULL
; lpls
= lpls
->lpNext
, count
++) {
742 if (tolower(*lpls
->itemText
) == tolower((char)wChar
)) break;
744 if (lpls
== NULL
) return LB_ERR
;
746 for(; lpls
!= NULL
; lpls
= lpls
->lpNext
, count
++) {
747 if (*lpls
->itemText
!= (char)wChar
)
749 if (count
> lphl
->ItemFocused
)
755 /***********************************************************************
758 static LONG
LBCreate(HWND hwnd
, WORD wParam
, LONG lParam
)
761 LONG dwStyle
= GetWindowLong(hwnd
,GWL_STYLE
);
764 CreateListBoxStruct(hwnd
, ODT_LISTBOX
, dwStyle
, GetParent(hwnd
));
765 lphl
= ListBoxGetStorageHeader(hwnd
);
766 dprintf_listbox(stddeb
,"ListBox created: lphl = %p dwStyle = %04x:%04x\n",
767 lphl
, HIWORD(dwStyle
), LOWORD(dwStyle
));
769 GetClientRect(hwnd
,&rect
);
770 lphl
->ColumnsWidth
= rect
.right
- rect
.left
;
772 SetScrollRange(hwnd
, SB_VERT
, 0, ListMaxFirstVisible(lphl
), TRUE
);
773 SetScrollRange(hwnd
, SB_HORZ
, 1, 1, TRUE
);
778 /***********************************************************************
781 static LONG
LBDestroy(HWND hwnd
, WORD wParam
, LONG lParam
)
783 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
785 ListBoxResetContent(lphl
);
787 DestroyListBoxStruct(lphl
);
788 dprintf_listbox(stddeb
,"ListBox destroyed: lphl = %p\n",lphl
);
792 /***********************************************************************
795 static LONG
LBVScroll(HWND hwnd
, WORD wParam
, LONG lParam
)
797 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
800 dprintf_listbox(stddeb
,"ListBox WM_VSCROLL w=%04X l=%08lX !\n",
802 y
= lphl
->FirstVisible
;
806 if (lphl
->FirstVisible
> 0)
807 lphl
->FirstVisible
--;
811 lphl
->FirstVisible
++;
815 if (lphl
->FirstVisible
> lphl
->ItemsVisible
) {
816 lphl
->FirstVisible
-= lphl
->ItemsVisible
;
818 lphl
->FirstVisible
= 0;
823 lphl
->FirstVisible
+= lphl
->ItemsVisible
;
827 lphl
->FirstVisible
= LOWORD(lParam
);
831 if (lphl
->FirstVisible
> ListMaxFirstVisible(lphl
))
832 lphl
->FirstVisible
= ListMaxFirstVisible(lphl
);
834 if (y
!= lphl
->FirstVisible
) {
835 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
836 InvalidateRect(hwnd
, NULL
, TRUE
);
841 /***********************************************************************
844 static LONG
LBHScroll(HWND hwnd
, WORD wParam
, LONG lParam
)
849 dprintf_listbox(stddeb
,"ListBox WM_HSCROLL w=%04X l=%08lX !\n",
851 lphl
= ListBoxGetStorageHeader(hwnd
);
852 y
= lphl
->FirstVisible
;
855 if (lphl
->FirstVisible
> lphl
->ItemsPerColumn
) {
856 lphl
->FirstVisible
-= lphl
->ItemsPerColumn
;
858 lphl
->FirstVisible
= 0;
862 lphl
->FirstVisible
+= lphl
->ItemsPerColumn
;
865 if (lphl
->ItemsPerColumn
!= 0) {
866 int lbsub
= lphl
->ItemsVisible
/ lphl
->ItemsPerColumn
* lphl
->ItemsPerColumn
;
867 if (lphl
->FirstVisible
> lbsub
) {
868 lphl
->FirstVisible
-= lbsub
;
870 lphl
->FirstVisible
= 0;
875 if (lphl
->ItemsPerColumn
!= 0)
876 lphl
->FirstVisible
+= lphl
->ItemsVisible
/
877 lphl
->ItemsPerColumn
* lphl
->ItemsPerColumn
;
880 lphl
->FirstVisible
= lphl
->ItemsPerColumn
* LOWORD(lParam
);
883 if (lphl
->FirstVisible
> ListMaxFirstVisible(lphl
))
884 lphl
->FirstVisible
= ListMaxFirstVisible(lphl
);
886 if (lphl
->ItemsPerColumn
!= 0) {
887 lphl
->FirstVisible
= lphl
->FirstVisible
/
888 lphl
->ItemsPerColumn
* lphl
->ItemsPerColumn
+ 1;
889 if (y
!= lphl
->FirstVisible
) {
890 SetScrollPos(hwnd
, SB_HORZ
, lphl
->FirstVisible
/
891 lphl
->ItemsPerColumn
+ 1, TRUE
);
892 InvalidateRect(hwnd
, NULL
, TRUE
);
898 /***********************************************************************
901 static LONG
LBLButtonDown(HWND hwnd
, WORD wParam
, LONG lParam
)
903 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
907 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
909 tmpPOINT
.x
= LOWORD(lParam
); tmpPOINT
.y
= HIWORD(lParam
);
914 lphl
->PrevFocused
= lphl
->ItemFocused
;
916 y
= ListBoxFindMouse(lphl
, LOWORD(lParam
), HIWORD(lParam
));
920 if (dwStyle
& LBS_MULTIPLESEL
) {
921 lphl
->ItemFocused
= y
;
922 wRet
= ListBoxGetSel(lphl
, y
);
923 ListBoxSetSel(lphl
, y
, !wRet
);
925 InvalidateRect(hwnd
, NULL
, TRUE
);
927 ListBoxSetCurSel(lphl
, y
);
929 ListBoxGetItemRect(lphl
, y
, &rectsel
);
930 InvalidateRect(hwnd
, &rectsel
, TRUE
);
931 if(lphl
->PrevFocused
) {
932 ListBoxGetItemRect(lphl
, lphl
->PrevFocused
, &rectsel
);
933 InvalidateRect(hwnd
, &rectsel
, TRUE
);
937 if (dwStyle
& (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
))
938 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
940 if (dwStyle
& LBS_NOTIFY
)
941 SendMessage(lphl
->hParent
, WM_LBTRACKPOINT
, y
, lParam
);
943 if (GetWindowLong(lphl
->hSelf
,GWL_EXSTYLE
) & WS_EX_DRAGDETECT
)
944 if( DragDetect(lphl
->hSelf
,tmpPOINT
) )
945 SendMessage(lphl
->hParent
, WM_BEGINDRAG
,0,0L);
950 /***********************************************************************
953 static LONG
LBLButtonUp(HWND hwnd
, WORD wParam
, LONG lParam
)
955 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
957 if (GetCapture() == hwnd
) ReleaseCapture();
959 if (lphl
->PrevFocused
!= lphl
->ItemFocused
)
960 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
965 /***********************************************************************
968 static LONG
LBRButtonUp(HWND hwnd
, WORD wParam
, LONG lParam
)
970 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
973 SendMessage(lphl
->hParent
, WM_COMMAND
,
974 MAKEWPARAM(GetWindowWord(hwnd
,GWW_ID
),LBN_DBLCLK
),
977 SendMessage(lphl
->hParent
, WM_COMMAND
, GetWindowWord(hwnd
,GWW_ID
),
978 MAKELONG(hwnd
, LBN_DBLCLK
));
984 /***********************************************************************
987 static LONG
LBMouseMove(HWND hwnd
, WORD wParam
, LONG lParam
)
989 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
992 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
993 RECT rect
, rectsel
; /* XXX Broken */
995 dprintf_listbox(stddeb
,"LBMouseMove %d %d\n",SLOWORD(lParam
),SHIWORD(lParam
));
996 if ((wParam
& MK_LBUTTON
) != 0) {
999 if (lphl
->FirstVisible
> 0) {
1000 lphl
->FirstVisible
--;
1001 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1002 InvalidateRect(hwnd
, NULL
, TRUE
);
1006 GetClientRect(hwnd
, &rect
);
1007 if (y
>= rect
.bottom
) {
1008 if (lphl
->FirstVisible
< ListMaxFirstVisible(lphl
)) {
1009 lphl
->FirstVisible
++;
1010 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1011 InvalidateRect(hwnd
, NULL
, TRUE
);
1015 if ((y
> 0) && (y
< (rect
.bottom
- 4))) {
1016 if ((y
< rectsel
.top
) || (y
> rectsel
.bottom
)) {
1017 wRet
= ListBoxFindMouse(lphl
, LOWORD(lParam
), HIWORD(lParam
));
1018 if (wRet
== lphl
->ItemFocused
) {
1021 if (dwStyle
& LBS_MULTIPLESEL
) {
1022 lphl
->ItemFocused
= wRet
;
1023 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
1025 ListBoxSetCurSel(lphl
, wRet
);
1026 if(dwStyle
& LBS_EXTENDEDSEL
)
1027 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
1029 ListBoxGetItemRect(lphl
, wRet
, &rectsel
);
1030 InvalidateRect(hwnd
, &rectsel
, TRUE
);
1038 /***********************************************************************
1041 * Doesn't yet handle properly VK_SHIFT with LB_EXTENDEDSEL
1043 static LONG
LBKeyDown(HWND hwnd
, WORD wParam
, LONG lParam
)
1045 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1046 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
1047 WORD newFocused
= 0xFFFF;
1050 ListBoxGetItemRect(lphl
,lphl
->ItemFocused
,&rect
);
1053 /* ugly kludge that belongs in TranslateMessage */
1063 if ( dwStyle
& LBS_WANTKEYBOARDINPUT
)
1065 newFocused
= (WORD
)(INT
)SendMessage(lphl
->hParent
,WM_VKEYTOITEM
,
1066 wParam
,MAKELPARAM(lphl
->ItemFocused
,hwnd
));
1067 if ( newFocused
== 0xFFFE ) return 0L;
1069 if ( newFocused
== 0xFFFF )
1071 newFocused
= lphl
->ItemFocused
;
1080 newFocused
= lphl
->ItemsCount
- 1;
1083 if (dwStyle
& LBS_MULTICOLUMN
) {
1084 if (newFocused
>= lphl
->ItemsPerColumn
) {
1085 newFocused
-= lphl
->ItemsPerColumn
;
1092 if (newFocused
> 0) newFocused
--;
1095 if (dwStyle
& LBS_MULTICOLUMN
)
1096 newFocused
+= lphl
->ItemsPerColumn
;
1102 if (newFocused
> lphl
->ItemsVisible
)
1103 newFocused
-= lphl
->ItemsVisible
;
1104 else newFocused
= 0;
1107 newFocused
+= lphl
->ItemsVisible
;
1112 /* end of nested switch */
1116 if (dwStyle
& LBS_MULTIPLESEL
)
1118 WORD wRet
= ListBoxGetSel(lphl
, lphl
->ItemFocused
);
1119 ListBoxSetSel(lphl
, lphl
->ItemFocused
, !wRet
);
1123 /* chars are handled in LBChar */
1128 /* at this point newFocused is set up */
1130 if (newFocused
>= lphl
->ItemsCount
)
1131 newFocused
= lphl
->ItemsCount
- 1;
1133 if (!(dwStyle
& LBS_MULTIPLESEL
))
1135 ListBoxSetCurSel(lphl
, newFocused
);
1136 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
1139 lphl
->ItemFocused
= newFocused
;
1141 if( ListBoxScrollToFocus(lphl
) || (dwStyle
&
1142 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
)) )
1143 InvalidateRect(hwnd
, NULL
, TRUE
);
1146 InvalidateRect(hwnd
, &rect
, TRUE
);
1147 if( newFocused
< 0x8000 )
1149 ListBoxGetItemRect(lphl
, newFocused
, &rect
);
1150 InvalidateRect(hwnd
, &rect
, TRUE
);
1154 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1159 /***********************************************************************
1162 static LONG
LBChar(HWND hwnd
, WORD wParam
, LONG lParam
)
1164 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1165 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
1166 WORD newFocused
= 0xFFFF;
1168 if ( (dwStyle
& LBS_WANTKEYBOARDINPUT
) && !(lphl
->HasStrings
))
1170 newFocused
= (WORD
)(INT
)SendMessage(lphl
->hParent
,WM_CHARTOITEM
,
1171 wParam
,MAKELPARAM(lphl
->ItemFocused
,hwnd
));
1172 if ( newFocused
== 0xFFFE ) return 0L;
1175 if (newFocused
== 0xFFFF )
1176 newFocused
= ListBoxFindNextMatch(lphl
, wParam
);
1178 if (newFocused
== (WORD
)LB_ERR
) return 0;
1180 if (newFocused
>= lphl
->ItemsCount
)
1181 newFocused
= lphl
->ItemsCount
- 1;
1183 if (!(dwStyle
& LBS_MULTIPLESEL
))
1185 ListBoxSetCurSel(lphl
, newFocused
);
1186 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
1189 lphl
->ItemFocused
= newFocused
;
1190 ListBoxScrollToFocus(lphl
);
1191 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1193 InvalidateRect(hwnd
, NULL
, TRUE
);
1198 /***********************************************************************
1201 static LONG
LBSetRedraw(HWND hwnd
, WORD wParam
, LONG lParam
)
1203 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1205 dprintf_listbox(stddeb
,"ListBox WM_SETREDRAW hWnd="NPFMT
" w=%04X !\n",
1207 lphl
->bRedrawFlag
= wParam
;
1212 /***********************************************************************
1215 static LONG
LBSetFont(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1217 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1220 lphl
->hFont
= GetStockObject(SYSTEM_FONT
);
1222 lphl
->hFont
= (HFONT
) wParam
;
1227 /***********************************************************************
1230 static LONG
LBPaint(HWND hwnd
, WORD wParam
, LONG lParam
)
1232 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1233 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
1240 int i
, top
, height
, maxwidth
, ipc
;
1243 hdc
= BeginPaint( hwnd
, &ps
);
1245 if (!IsWindowVisible(hwnd
) || !lphl
->bRedrawFlag
) {
1246 EndPaint(hwnd
, &ps
);
1250 hOldFont
= SelectObject(hdc
, lphl
->hFont
);
1253 hBrush
= (HBRUSH
) SendMessage(lphl
->hParent
, WM_CTLCOLORLISTBOX
, (WPARAM
)hdc
,
1256 hBrush
= SendMessage(lphl
->hParent
, WM_CTLCOLOR
, hdc
,
1257 MAKELONG(hwnd
, CTLCOLOR_LISTBOX
));
1260 if (hBrush
== 0) hBrush
= GetStockObject(WHITE_BRUSH
);
1262 GetClientRect(hwnd
, &rect
);
1263 FillRect(hdc
, &rect
, hBrush
);
1265 maxwidth
= rect
.right
;
1266 if (dwStyle
& LBS_MULTICOLUMN
) {
1267 rect
.right
= lphl
->ColumnsWidth
;
1269 lpls
= lphl
->lpFirst
;
1271 lphl
->ItemsVisible
= 0;
1272 lphl
->ItemsPerColumn
= ipc
= 0;
1274 for(i
= 0; i
< lphl
->ItemsCount
; i
++) {
1275 if (lpls
== NULL
) break;
1277 if (i
>= lphl
->FirstVisible
) {
1278 height
= lpls
->mis
.itemHeight
;
1280 if (top
> rect
.bottom
) {
1281 if (dwStyle
& LBS_MULTICOLUMN
) {
1282 lphl
->ItemsPerColumn
= MAX(lphl
->ItemsPerColumn
, ipc
);
1285 rect
.left
+= lphl
->ColumnsWidth
;
1286 rect
.right
+= lphl
->ColumnsWidth
;
1287 if (rect
.left
> maxwidth
) break;
1293 lpls
->itemRect
.top
= top
;
1294 lpls
->itemRect
.bottom
= top
+ height
;
1295 lpls
->itemRect
.left
= rect
.left
;
1296 lpls
->itemRect
.right
= rect
.right
;
1298 dprintf_listbox(stddeb
,"drawing item: %ld %d %ld %d %d\n",(LONG
)rect
.left
,top
,(LONG
)rect
.right
,top
+height
,lpls
->itemState
);
1299 if (lphl
->OwnerDrawn
) {
1300 ListBoxDrawItem (hwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_DRAWENTIRE
, 0);
1301 if (lpls
->itemState
)
1302 ListBoxDrawItem (hwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_SELECT
, ODS_SELECTED
);
1304 ListBoxDrawItem (hwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_DRAWENTIRE
,
1307 if ((lphl
->ItemFocused
== i
) && GetFocus() == hwnd
)
1308 ListBoxDrawItem (hwnd
,lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_FOCUS
, ODS_FOCUS
);
1311 lphl
->ItemsVisible
++;
1315 lpls
= lpls
->lpNext
;
1317 ListBoxUpdateWindow(hwnd
,lphl
,FALSE
);
1318 SelectObject(hdc
,hOldFont
);
1319 EndPaint( hwnd
, &ps
);
1323 /***********************************************************************
1326 static LONG
LBSetFocus(HWND hwnd
, WORD wParam
, LONG lParam
)
1328 dprintf_listbox(stddeb
,"ListBox WM_SETFOCUS !\n");
1333 /***********************************************************************
1336 static LONG
LBKillFocus(HWND hwnd
, WORD wParam
, LONG lParam
)
1338 dprintf_listbox(stddeb
,"ListBox WM_KILLFOCUS !\n");
1340 InvalidateRect(hwnd
, NULL
, TRUE
);
1345 /***********************************************************************
1348 static LONG
LBResetContent(HWND hwnd
, WORD wParam
, LONG lParam
)
1350 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1352 dprintf_listbox(stddeb
,"ListBox LB_RESETCONTENT !\n");
1353 ListBoxResetContent(lphl
);
1354 ListBoxUpdateWindow(hwnd
, lphl
, TRUE
);
1358 /***********************************************************************
1361 static LONG
LBDir(HWND hwnd
, WORD wParam
, LONG lParam
)
1364 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1365 dprintf_listbox(stddeb
,"ListBox LB_DIR !\n");
1367 ret
= ListBoxDirectory(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
1368 ListBoxUpdateWindow(hwnd
, lphl
, TRUE
);
1372 /***********************************************************************
1375 static LONG
LBAddString(HWND hwnd
, WORD wParam
, LONG lParam
)
1378 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1380 if (lphl
->HasStrings
)
1381 wRet
= ListBoxAddString(lphl
, (LPCSTR
)PTR_SEG_TO_LIN(lParam
));
1383 wRet
= ListBoxAddString(lphl
, (LPCSTR
)lParam
);
1385 ListBoxUpdateWindow(hwnd
,lphl
,TRUE
);
1389 /***********************************************************************
1392 static LONG
LBGetText(HWND hwnd
, WORD wParam
, LONG lParam
)
1395 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1397 dprintf_listbox(stddeb
, "LB_GETTEXT wParam=%d\n",wParam
);
1398 wRet
= ListBoxGetText(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
1403 /***********************************************************************
1406 static LONG
LBInsertString(HWND hwnd
, WORD wParam
, LONG lParam
)
1409 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1411 if (lphl
->HasStrings
)
1412 wRet
= ListBoxInsertString(lphl
, wParam
, (LPCSTR
)PTR_SEG_TO_LIN(lParam
));
1414 wRet
= ListBoxInsertString(lphl
, wParam
, (LPCSTR
)lParam
);
1416 ListBoxUpdateWindow(hwnd
,lphl
,TRUE
);
1420 /***********************************************************************
1423 static LONG
LBDeleteString(HWND hwnd
, WORD wParam
, LONG lParam
)
1425 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1426 LONG lRet
= ListBoxDeleteString(lphl
,wParam
);
1428 ListBoxUpdateWindow(hwnd
,lphl
,TRUE
);
1432 /***********************************************************************
1435 static LONG
LBFindString(HWND hwnd
, WORD wParam
, LONG lParam
)
1437 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1438 return ListBoxFindString(lphl
, wParam
, (SEGPTR
)lParam
);
1441 /***********************************************************************
1444 static LONG
LBGetCaretIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1446 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1447 return lphl
->ItemFocused
;
1450 /***********************************************************************
1453 static LONG
LBGetCount(HWND hwnd
, WORD wParam
, LONG lParam
)
1457 lphl
= ListBoxGetStorageHeader(hwnd
);
1458 return lphl
->ItemsCount
;
1461 /***********************************************************************
1464 static LONG
LBGetCurSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1468 lphl
= ListBoxGetStorageHeader(hwnd
);
1469 dprintf_listbox(stddeb
,"ListBox LB_GETCURSEL %u !\n",
1471 return lphl
->ItemFocused
;
1474 /***********************************************************************
1475 * LBGetHorizontalExtent
1477 static LONG
LBGetHorizontalExtent(HWND hwnd
, WORD wParam
, LONG lParam
)
1482 /***********************************************************************
1485 static LONG
LBGetItemHeight(HWND hwnd
, WORD wParam
, LONG lParam
)
1487 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1488 LPLISTSTRUCT lpls
= ListBoxGetItem (lphl
, wParam
);
1490 if (lpls
== NULL
) return LB_ERR
;
1491 return lpls
->mis
.itemHeight
;
1494 /***********************************************************************
1497 static LONG
LBGetItemRect(HWND hwnd
, WORD wParam
, LONG lParam
)
1499 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1500 return ListBoxGetItemRect(lphl
, wParam
, PTR_SEG_TO_LIN(lParam
));
1503 /***********************************************************************
1506 static LONG
LBGetSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1508 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1509 return (ListBoxGetSel(lphl
, wParam
) )? 1 : 0;
1512 /***********************************************************************
1515 static LONG
LBGetSelCount(HWND hwnd
, WORD wParam
, LONG lParam
)
1517 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1522 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) &
1523 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
1526 for( lpls
= lphl
->lpFirst
;
1528 lpls
= lpls
->lpNext
)
1531 if (lpls
->itemState
)
1538 /***********************************************************************
1541 static LONG
LBGetSelItems(HWND hwnd
, WORD wParam
, LONG lParam
)
1543 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1546 int *lpItems
= PTR_SEG_TO_LIN(lParam
);
1548 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) &
1549 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
1552 if (wParam
== 0) return 0;
1554 lpls
= lphl
->lpFirst
;
1557 while (lpls
!= NULL
) {
1558 if (lpls
->itemState
> 0) lpItems
[cnt
++] = idx
;
1560 if (cnt
== wParam
) break;
1562 lpls
= lpls
->lpNext
;
1568 /***********************************************************************
1571 static LONG
LBGetTextLen(HWND hwnd
, WORD wParam
, LONG lParam
)
1573 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1574 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
,wParam
);
1576 if (lpls
== NULL
|| !lphl
->HasStrings
) return LB_ERR
;
1577 return strlen(lpls
->itemText
);
1580 /***********************************************************************
1583 static LONG
LBGetDlgCode(HWND hwnd
, WORD wParam
, LONG lParam
)
1585 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1588 /***********************************************************************
1591 static LONG
LBGetTopIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1593 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1595 return lphl
->FirstVisible
;
1599 /***********************************************************************
1602 static LONG
LBSelectString(HWND hwnd
, WORD wParam
, LONG lParam
)
1604 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1607 wRet
= ListBoxFindString(lphl
, wParam
, (SEGPTR
)lParam
);
1609 /* XXX add functionality here */
1614 /***********************************************************************
1617 static LONG
LBSelItemRange(HWND hwnd
, WORD wParam
, LONG lParam
)
1619 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1622 WORD first
= LOWORD(lParam
);
1623 WORD last
= HIWORD(lParam
);
1624 BOOL select
= wParam
;
1626 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) &
1627 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
1630 if (first
>= lphl
->ItemsCount
||
1631 last
>= lphl
->ItemsCount
) return LB_ERR
;
1633 lpls
= lphl
->lpFirst
;
1636 while (lpls
!= NULL
) {
1638 lpls
->itemState
= select
? ODS_SELECTED
: 0;
1643 lpls
= lpls
->lpNext
;
1649 /***********************************************************************
1652 static LONG
LBSetCaretIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1654 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1656 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) & LBS_MULTIPLESEL
)) return 0;
1657 if (wParam
>= lphl
->ItemsCount
) return LB_ERR
;
1659 lphl
->ItemFocused
= wParam
;
1660 ListBoxScrollToFocus (lphl
);
1662 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1663 InvalidateRect(hwnd
, NULL
, TRUE
);
1667 /***********************************************************************
1670 static LONG
LBSetColumnWidth(HWND hwnd
, WORD wParam
, LONG lParam
)
1672 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1673 lphl
->ColumnsWidth
= wParam
;
1674 InvalidateRect(hwnd
,NULL
,TRUE
);
1678 /***********************************************************************
1679 * LBSetHorizontalExtent
1681 static LONG
LBSetHorizontalExtent(HWND hwnd
, WORD wParam
, LONG lParam
)
1686 /***********************************************************************
1689 static LONG
LBGetItemData(HWND hwnd
, WORD wParam
, LONG lParam
)
1691 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1692 dprintf_listbox(stddeb
, "LB_GETITEMDATA wParam=%x\n", wParam
);
1693 return ListBoxGetItemData(lphl
, wParam
);
1696 /***********************************************************************
1699 static LONG
LBSetItemData(HWND hwnd
, WORD wParam
, LONG lParam
)
1701 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1702 dprintf_listbox(stddeb
, "LB_SETITEMDATA wParam=%x lParam=%lx\n", wParam
, lParam
);
1703 return ListBoxSetItemData(lphl
, wParam
, lParam
);
1706 /***********************************************************************
1709 static LONG
LBSetTabStops(HWND hwnd
, WORD wParam
, LONG lParam
)
1713 lphl
= ListBoxGetStorageHeader(hwnd
);
1715 if (lphl
->TabStops
!= NULL
) {
1716 lphl
->iNumStops
= 0;
1717 free (lphl
->TabStops
);
1720 lphl
->TabStops
= malloc (wParam
* sizeof (short));
1721 if (lphl
->TabStops
) {
1722 lphl
->iNumStops
= wParam
;
1723 memcpy (lphl
->TabStops
, PTR_SEG_TO_LIN(lParam
), wParam
* sizeof (short));
1730 /***********************************************************************
1733 static LONG
LBSetCurSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1735 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1738 dprintf_listbox(stddeb
,"ListBox LB_SETCURSEL wParam=%x !\n",
1741 wRet
= ListBoxSetCurSel(lphl
, wParam
);
1743 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1744 InvalidateRect(hwnd
, NULL
, TRUE
);
1749 /***********************************************************************
1752 static LONG
LBSetSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1754 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1757 dprintf_listbox(stddeb
,"ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam
, lParam
);
1759 wRet
= ListBoxSetSel(lphl
, LOWORD(lParam
), wParam
);
1760 InvalidateRect(hwnd
, NULL
, TRUE
);
1765 /***********************************************************************
1768 static LONG
LBSetTopIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1770 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1772 dprintf_listbox(stddeb
,"ListBox LB_SETTOPINDEX wParam=%x !\n",
1774 lphl
->FirstVisible
= wParam
;
1775 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1777 InvalidateRect(hwnd
, NULL
, TRUE
);
1782 /***********************************************************************
1785 static LONG
LBSetItemHeight(HWND hwnd
, WORD wParam
, LONG lParam
)
1787 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1790 dprintf_listbox(stddeb
,"ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam
, lParam
);
1791 wRet
= ListBoxSetItemHeight(lphl
, wParam
, lParam
);
1792 InvalidateRect(hwnd
,NULL
,TRUE
);
1796 /***********************************************************************
1799 static LRESULT
LBPassToParent(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1801 WND
* ptrWnd
= WIN_FindWndPtr(hwnd
);
1804 if( /* !(ptrWnd->dwExStyle & WS_EX_NOPARENTNOTIFY) && */
1805 ptrWnd
->hwndParent
)
1806 return SendMessage(ptrWnd
->hwndParent
,message
,wParam
,lParam
);
1810 /***********************************************************************
1813 LRESULT
ListBoxWndProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1816 case WM_CREATE
: return LBCreate(hwnd
, wParam
, lParam
);
1817 case WM_DESTROY
: return LBDestroy(hwnd
, wParam
, lParam
);
1818 case WM_GETDLGCODE
: return LBGetDlgCode(hwnd
, wParam
, lParam
);
1819 case WM_VSCROLL
: return LBVScroll(hwnd
, wParam
, lParam
);
1820 case WM_HSCROLL
: return LBHScroll(hwnd
, wParam
, lParam
);
1821 case WM_LBUTTONDOWN
: return LBLButtonDown(hwnd
, wParam
, lParam
);
1822 case WM_LBUTTONUP
: return LBLButtonUp(hwnd
, wParam
, lParam
);
1823 case WM_RBUTTONUP
: return LBRButtonUp(hwnd
, wParam
, lParam
);
1824 case WM_LBUTTONDBLCLK
: return LBRButtonUp(hwnd
, wParam
, lParam
);
1825 case WM_MOUSEMOVE
: return LBMouseMove(hwnd
, wParam
, lParam
);
1826 case WM_KEYDOWN
: return LBKeyDown(hwnd
, wParam
, lParam
);
1827 case WM_CHAR
: return LBChar(hwnd
, wParam
, lParam
);
1828 case WM_SETFONT
: return LBSetFont(hwnd
, wParam
, lParam
);
1829 case WM_SETREDRAW
: return LBSetRedraw(hwnd
, wParam
, lParam
);
1830 case WM_PAINT
: return LBPaint(hwnd
, wParam
, lParam
);
1831 case WM_SETFOCUS
: return LBSetFocus(hwnd
, wParam
, lParam
);
1832 case WM_KILLFOCUS
: return LBKillFocus(hwnd
, wParam
, lParam
);
1833 case LB_RESETCONTENT
: return LBResetContent(hwnd
, wParam
, lParam
);
1834 case LB_DIR
: return LBDir(hwnd
, wParam
, lParam
);
1835 case LB_ADDSTRING
: return LBAddString(hwnd
, wParam
, lParam
);
1836 case LB_INSERTSTRING
: return LBInsertString(hwnd
, wParam
, lParam
);
1837 case LB_DELETESTRING
: return LBDeleteString(hwnd
, wParam
, lParam
);
1838 case LB_FINDSTRING
: return LBFindString(hwnd
, wParam
, lParam
);
1839 case LB_GETCARETINDEX
: return LBGetCaretIndex(hwnd
, wParam
, lParam
);
1840 case LB_GETCOUNT
: return LBGetCount(hwnd
, wParam
, lParam
);
1841 case LB_GETCURSEL
: return LBGetCurSel(hwnd
, wParam
, lParam
);
1842 case LB_GETHORIZONTALEXTENT
: return LBGetHorizontalExtent(hwnd
, wParam
, lParam
);
1843 case LB_GETITEMDATA
: return LBGetItemData(hwnd
, wParam
, lParam
);
1844 case LB_GETITEMHEIGHT
: return LBGetItemHeight(hwnd
, wParam
, lParam
);
1845 case LB_GETITEMRECT
: return LBGetItemRect(hwnd
, wParam
, lParam
);
1846 case LB_GETSEL
: return LBGetSel(hwnd
, wParam
, lParam
);
1847 case LB_GETSELCOUNT
: return LBGetSelCount(hwnd
, wParam
, lParam
);
1848 case LB_GETSELITEMS
: return LBGetSelItems(hwnd
, wParam
, lParam
);
1849 case LB_GETTEXT
: return LBGetText(hwnd
, wParam
, lParam
);
1850 case LB_GETTEXTLEN
: return LBGetTextLen(hwnd
, wParam
, lParam
);
1851 case LB_GETTOPINDEX
: return LBGetTopIndex(hwnd
, wParam
, lParam
);
1852 case LB_SELECTSTRING
: return LBSelectString(hwnd
, wParam
, lParam
);
1853 case LB_SELITEMRANGE
: return LBSelItemRange(hwnd
, wParam
, lParam
);
1854 case LB_SETCARETINDEX
: return LBSetCaretIndex(hwnd
, wParam
, lParam
);
1855 case LB_SETCOLUMNWIDTH
: return LBSetColumnWidth(hwnd
, wParam
, lParam
);
1856 case LB_SETHORIZONTALEXTENT
: return LBSetHorizontalExtent(hwnd
, wParam
, lParam
);
1857 case LB_SETITEMDATA
: return LBSetItemData(hwnd
, wParam
, lParam
);
1858 case LB_SETTABSTOPS
: return LBSetTabStops(hwnd
, wParam
, lParam
);
1859 case LB_SETCURSEL
: return LBSetCurSel(hwnd
, wParam
, lParam
);
1860 case LB_SETSEL
: return LBSetSel(hwnd
, wParam
, lParam
);
1861 case LB_SETTOPINDEX
: return LBSetTopIndex(hwnd
, wParam
, lParam
);
1862 case LB_SETITEMHEIGHT
: return LBSetItemHeight(hwnd
, wParam
, lParam
);
1864 case WM_DROPFILES
: return LBPassToParent(hwnd
, message
, wParam
, lParam
);
1867 case WM_QUERYDROPOBJECT
:
1871 LPDRAGINFO lpDragInfo
= (LPDRAGINFO
) PTR_SEG_TO_LIN((SEGPTR
)lParam
);
1872 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1874 /* more undocumented Microsoft crap - drag&drop depends on it - AK */
1876 lpDragInfo
->l
= ListBoxFindMouse(lphl
,lpDragInfo
->pt
.x
,
1879 return LBPassToParent(hwnd
, message
, wParam
, lParam
);
1883 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
1887 /**********************************************************************
1888 * DlgDirSelect (USER.99)
1890 BOOL
DlgDirSelect( HWND hDlg
, LPSTR lpStr
, INT id
)
1895 dprintf_listbox( stddeb
, "DlgDirSelect: "NPFMT
" '%s' %d\n",
1897 if ((i
= SendDlgItemMessage( hDlg
, id
, LB_GETCURSEL
, 0, 0 )) == LB_ERR
)
1899 SendDlgItemMessage( hDlg
, id
, LB_GETTEXT
, i
, MAKE_SEGPTR(buffer
) );
1900 if (buffer
[0] == '[') /* drive or directory */
1902 if (buffer
[1] == '-') /* drive */
1904 lpStr
[0] = buffer
[2];
1907 dprintf_listbox( stddeb
, "Returning drive '%s'\n", lpStr
);
1910 strcpy( lpStr
, buffer
+ 1 );
1911 lpStr
[strlen(lpStr
)-1] = '\\';
1912 dprintf_listbox( stddeb
, "Returning directory '%s'\n", lpStr
);
1915 strcpy( lpStr
, buffer
);
1916 dprintf_listbox( stddeb
, "Returning file '%s'\n", lpStr
);
1921 /**********************************************************************
1922 * DlgDirList (USER.100)
1924 INT
DlgDirList( HWND hDlg
, SEGPTR spec
, INT idLBox
, INT idStatic
, UINT attrib
)
1926 char *filespec
= (char *)PTR_SEG_TO_LIN( spec
);
1930 #define SENDMSG(msg,wparam,lparam) \
1931 ((attrib & DDL_POSTMSGS) ? PostMessage( hwnd, msg, wparam, lparam ) \
1932 : SendMessage( hwnd, msg, wparam, lparam ))
1934 dprintf_listbox( stddeb
, "DlgDirList: "NPFMT
" '%s' %d %d %04x\n",
1935 hDlg
, filespec
? filespec
: "NULL",
1936 idLBox
, idStatic
, attrib
);
1938 if (filespec
&& filespec
[0] && (filespec
[1] == ':'))
1940 drive
= toupper( filespec
[0] ) - 'A';
1942 if (!DRIVE_SetCurrentDrive( drive
)) return FALSE
;
1944 else drive
= DRIVE_GetCurrentDrive();
1946 if (idLBox
&& ((hwnd
= GetDlgItem( hDlg
, idLBox
)) != 0))
1949 char temp
[] = "*.*";
1951 if (!filespec
[0]) strcpy( mask
, "*.*" );
1956 if (((ptr
= DOSFS_GetUnixFileName( filespec
, TRUE
)) != NULL
) &&
1957 FILE_Stat( ptr
, &attr
, NULL
, NULL
, NULL
) &&
1958 (attr
& FA_DIRECTORY
))
1960 /* If the path exists and is a directory, chdir to it */
1961 if (!DRIVE_Chdir( drive
, filespec
)) return FALSE
;
1962 strcpy( mask
, "*.*" );
1968 if ((p2
= strrchr( p
, '\\' ))) p
= p2
+ 1;
1969 if ((p2
= strrchr( p
, '/' ))) p
= p2
+ 1;
1970 lstrcpyn( mask
, p
, sizeof(mask
) );
1974 if (!DRIVE_Chdir( drive
, filespec
)) return FALSE
;
1979 strcpy( (char *)PTR_SEG_TO_LIN(spec
), mask
);
1981 dprintf_listbox(stddeb
, "ListBoxDirectory: path=%c:\\%s mask=%s\n",
1982 'A' + drive
, DRIVE_GetDosCwd(drive
), mask
);
1984 SENDMSG( LB_RESETCONTENT
, 0, 0 );
1985 if ((attrib
& DDL_DIRECTORY
) && !(attrib
& DDL_EXCLUSIVE
))
1987 if (SENDMSG( LB_DIR
, attrib
& ~(DDL_DIRECTORY
| DDL_DRIVES
),
1988 (LPARAM
)spec
) == LB_ERR
) return FALSE
;
1989 if (SENDMSG( LB_DIR
, (attrib
& (DDL_DIRECTORY
| DDL_DRIVES
)) | DDL_EXCLUSIVE
,
1990 (LPARAM
)MAKE_SEGPTR(temp
) ) == LB_ERR
) return FALSE
;
1994 if (SENDMSG( LB_DIR
, attrib
, (LPARAM
)spec
) == LB_ERR
) return FALSE
;
1998 if (idStatic
&& ((hwnd
= GetDlgItem( hDlg
, idStatic
)) != 0))
2001 strcpy( temp
, "A:\\" );
2003 lstrcpyn( temp
+3, DRIVE_GetDosCwd(drive
), 253 );
2005 SENDMSG( WM_SETTEXT
, 0, (LPARAM
)MAKE_SEGPTR(temp
) );