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 lphl
->HeapSel
= GlobalAlloc(GMEM_FIXED
,LIST_HEAP_SIZE
);
115 LocalInit( lphl
->HeapSel
, 0, LIST_HEAP_SIZE
-1);
118 void DestroyListBoxStruct(LPHEADLIST lphl
)
120 if (lphl
->hDrawItemStruct
)
121 USER_HEAP_FREE(lphl
->hDrawItemStruct
);
123 /* XXX need to free lphl->Heap */
124 GlobalFree(lphl
->HeapSel
);
128 static LPHEADLIST
ListBoxGetStorageHeader(HWND hwnd
)
130 return (LPHEADLIST
)GetWindowLong(hwnd
,0);
133 /* Send notification "code" as part of a WM_COMMAND-message if hwnd
134 has the LBS_NOTIFY style */
135 void ListBoxSendNotification(LPHEADLIST lphl
, WORD code
)
137 DWORD dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
139 if (dwStyle
& LBS_NOTIFY
)
141 SendMessage(lphl
->hParent
, WM_COMMAND
,
142 MAKEWPARAM(lphl
->CtlID
,code
), (LPARAM
)lphl
->hSelf
);
144 SendMessage(lphl
->hParent
, WM_COMMAND
,
145 lphl
->CtlID
, MAKELONG(lphl
->hSelf
, code
));
150 /* get the maximum value of lphl->FirstVisible */
151 int ListMaxFirstVisible(LPHEADLIST lphl
)
153 int m
= lphl
->ItemsCount
-lphl
->ItemsVisible
;
154 return (m
< 0) ? 0 : m
;
158 void ListBoxUpdateWindow(HWND hwnd
, LPHEADLIST lphl
, BOOL repaint
)
160 SetScrollRange(hwnd
, SB_VERT
, 0, ListMaxFirstVisible(lphl
), TRUE
);
161 if (lphl
->ItemsPerColumn
!= 0) {
162 SetScrollRange(hwnd
, SB_HORZ
, 1, lphl
->ItemsVisible
/
163 lphl
->ItemsPerColumn
+ 1, TRUE
);
165 if (repaint
&& lphl
->bRedrawFlag
) {
166 InvalidateRect(hwnd
, NULL
, TRUE
);
170 /* Returns: 0 if nothing needs to be changed */
171 /* 1 if FirstVisible changed */
173 int ListBoxScrollToFocus(LPHEADLIST lphl
)
177 if (lphl
->ItemsCount
== 0) return 0;
178 if (lphl
->ItemFocused
== -1) return 0;
180 end
= lphl
->FirstVisible
+ lphl
->ItemsVisible
- 1;
182 if (lphl
->ItemFocused
< lphl
->FirstVisible
) {
183 lphl
->FirstVisible
= lphl
->ItemFocused
;
186 if (lphl
->ItemFocused
> end
) {
187 WORD maxFirstVisible
= ListMaxFirstVisible(lphl
);
189 lphl
->FirstVisible
= lphl
->ItemFocused
;
191 if (lphl
->FirstVisible
> maxFirstVisible
) {
192 lphl
->FirstVisible
= maxFirstVisible
;
201 LPLISTSTRUCT
ListBoxGetItem(LPHEADLIST lphl
, UINT uIndex
)
206 if (uIndex
>= lphl
->ItemsCount
) return NULL
;
208 lpls
= lphl
->lpFirst
;
209 while (Count
++ < uIndex
) lpls
= lpls
->lpNext
;
214 void ListBoxDrawItem (HWND hwnd
, LPHEADLIST lphl
, HDC hdc
, LPLISTSTRUCT lpls
,
215 RECT
*rect
, WORD itemAction
, WORD itemState
)
217 LONG dwStyle
= GetWindowLong(hwnd
,GWL_STYLE
);
219 if (lphl
->OwnerDrawn
) {
220 DRAWITEMSTRUCT
*dis
= USER_HEAP_LIN_ADDR(lphl
->hDrawItemStruct
);
222 dis
->CtlID
= lpls
->mis
.CtlID
;
223 dis
->CtlType
= lpls
->mis
.CtlType
;
224 dis
->itemID
= lpls
->mis
.itemID
;
226 dis
->hwndItem
= hwnd
;
227 dis
->itemData
= lpls
->mis
.itemData
;
228 dis
->itemAction
= itemAction
;
229 dis
->itemState
= itemState
;
231 SendMessage(lphl
->hParent
, WM_DRAWITEM
,
232 0, (LPARAM
)USER_HEAP_SEG_ADDR(lphl
->hDrawItemStruct
));
234 if (itemAction
== ODA_DRAWENTIRE
|| itemAction
== ODA_SELECT
) {
236 DWORD dwOldTextColor
= 0;
238 OldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
240 if (itemState
!= 0) {
241 dwOldTextColor
= SetTextColor(hdc
, 0x00FFFFFFL
);
242 FillRect(hdc
, rect
, GetStockObject(BLACK_BRUSH
));
245 if (dwStyle
& LBS_USETABSTOPS
) {
246 TabbedTextOut(hdc
, rect
->left
+ 5, rect
->top
+ 2,
247 (char *)lpls
->itemText
, strlen((char *)lpls
->itemText
),
248 lphl
->iNumStops
, lphl
->TabStops
, 0);
250 TextOut(hdc
, rect
->left
+ 5, rect
->top
+ 2,
251 (char *)lpls
->itemText
, strlen((char *)lpls
->itemText
));
254 if (itemState
!= 0) {
255 SetTextColor(hdc
, dwOldTextColor
);
258 SetBkMode(hdc
, OldBkMode
);
259 } else DrawFocusRect(hdc
, rect
);
266 int ListBoxFindMouse(LPHEADLIST lphl
, int X
, int Y
)
268 LPLISTSTRUCT lpls
= lphl
->lpFirst
;
272 point
.x
= X
; point
.y
= Y
;
273 if (lphl
->ItemsCount
== 0) return LB_ERR
;
275 for(i
= 0; i
< lphl
->FirstVisible
; i
++) {
276 if (lpls
== NULL
) return LB_ERR
;
279 for(j
= 0; j
< lphl
->ItemsVisible
; i
++, j
++) {
280 if (lpls
== NULL
) return LB_ERR
;
281 if (PtInRect(&lpls
->itemRect
,point
)) {
286 dprintf_listbox(stddeb
,"ListBoxFindMouse: not found\n");
291 void ListBoxAskMeasure(LPHEADLIST lphl
, LPLISTSTRUCT lpls
)
293 HANDLE hTemp
= USER_HEAP_ALLOC( sizeof(MEASUREITEMSTRUCT
) );
294 MEASUREITEMSTRUCT
*lpmeasure
= (MEASUREITEMSTRUCT
*) USER_HEAP_LIN_ADDR(hTemp
);
296 if (lpmeasure
== NULL
) {
297 fprintf(stdnimp
,"ListBoxAskMeasure() out of memory !\n");
301 *lpmeasure
= lpls
->mis
;
302 lpmeasure
->itemHeight
= lphl
->StdItemHeight
;
303 SendMessage(lphl
->hParent
, WM_MEASUREITEM
, 0, (LPARAM
)USER_HEAP_SEG_ADDR(hTemp
));
305 if (GetWindowLong(lphl
->hSelf
,GWL_STYLE
) & LBS_OWNERDRAWFIXED
) {
306 lphl
->StdItemHeight
= lpmeasure
->itemHeight
;
307 lphl
->needMeasure
= FALSE
;
310 USER_HEAP_FREE(hTemp
);
313 /* -------------------- strings and item data ---------------------- */
315 LPLISTSTRUCT
ListBoxCreateItem(LPHEADLIST lphl
, int id
)
317 LPLISTSTRUCT lplsnew
= (LPLISTSTRUCT
)malloc(sizeof(LISTSTRUCT
));
319 if (lplsnew
== NULL
) return NULL
;
321 lplsnew
->itemState
= 0;
322 lplsnew
->mis
.CtlType
= lphl
->DrawCtlType
;
323 lplsnew
->mis
.CtlID
= lphl
->CtlID
;
324 lplsnew
->mis
.itemID
= id
;
325 lplsnew
->mis
.itemHeight
= lphl
->StdItemHeight
;
326 lplsnew
->mis
.itemWidth
= 0; /* ignored */
327 lplsnew
->mis
.itemData
= 0;
328 SetRect(&lplsnew
->itemRect
, 0, 0, 0, 0);
334 int ListBoxInsertString(LPHEADLIST lphl
, UINT uIndex
, LPSTR newstr
)
336 LPLISTSTRUCT
*lppls
, lplsnew
, lpls
;
341 dprintf_listbox(stddeb
,"ListBoxInsertString(%d, %p);\n", uIndex
, newstr
);
343 if (!newstr
) return -1;
345 if (uIndex
== (UINT
)-1)
346 uIndex
= lphl
->ItemsCount
;
348 lppls
= &lphl
->lpFirst
;
349 for(Count
= 0; Count
< uIndex
; Count
++) {
350 if (*lppls
== NULL
) return LB_ERR
;
351 lppls
= (LPLISTSTRUCT
*) &(*lppls
)->lpNext
;
354 lplsnew
= ListBoxCreateItem(lphl
, Count
);
356 if (lplsnew
== NULL
) {
357 fprintf(stdnimp
,"ListBoxInsertString() out of memory !\n");
361 lplsnew
->lpNext
= *lppls
;
366 if (lphl
->HasStrings
) {
367 dprintf_listbox(stddeb
," string: %s\n", newstr
);
368 hStr
= LIST_HEAP_ALLOC(lphl
, LMEM_MOVEABLE
, strlen(newstr
) + 1);
369 str
= (LPSTR
)LIST_HEAP_ADDR(lphl
, hStr
);
370 if (str
== NULL
) return LB_ERRSPACE
;
372 lplsnew
->itemText
= str
;
373 /* I'm not so sure about the next one */
374 lplsnew
->mis
.itemData
= 0;
376 lplsnew
->itemText
= NULL
;
377 lplsnew
->mis
.itemData
= (DWORD
)newstr
;
380 lplsnew
->mis
.itemID
= uIndex
;
381 lplsnew
->hData
= hStr
;
383 /* adjust the itemID field of the following entries */
384 for(lpls
= lplsnew
->lpNext
; lpls
!= NULL
; lpls
= lpls
->lpNext
) {
388 if (lphl
->needMeasure
) {
389 ListBoxAskMeasure(lphl
, lplsnew
);
392 dprintf_listbox(stddeb
,"ListBoxInsertString // count=%d\n", lphl
->ItemsCount
);
397 int ListBoxAddString(LPHEADLIST lphl
, LPSTR newstr
)
399 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
400 UINT pos
= (UINT
) -1;
402 if (lphl
->HasStrings
&& (dwStyle
& LBS_SORT
)) {
403 LPLISTSTRUCT lpls
= lphl
->lpFirst
;
404 for (pos
= 0; lpls
!= NULL
; lpls
= lpls
->lpNext
, pos
++)
405 if (strcmp(lpls
->itemText
, newstr
) >= 0)
408 return ListBoxInsertString(lphl
, pos
, newstr
);
412 int ListBoxGetText(LPHEADLIST lphl
, UINT uIndex
, LPSTR OutStr
)
417 dprintf_listbox(stddeb
, "ListBoxGetText // OutStr==NULL\n");
421 lpls
= ListBoxGetItem (lphl
, uIndex
);
422 if (lpls
== NULL
) return LB_ERR
;
424 if (!lphl
->HasStrings
) {
425 *((long *)OutStr
) = lpls
->mis
.itemData
;
429 strcpy(OutStr
, lpls
->itemText
);
430 return strlen(OutStr
);
434 DWORD
ListBoxGetItemData(LPHEADLIST lphl
, UINT uIndex
)
438 lpls
= ListBoxGetItem (lphl
, uIndex
);
439 if (lpls
== NULL
) return LB_ERR
;
440 return lpls
->mis
.itemData
;
444 int ListBoxSetItemData(LPHEADLIST lphl
, UINT uIndex
, DWORD ItemData
)
446 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
, uIndex
);
448 if (lpls
== NULL
) return LB_ERR
;
449 lpls
->mis
.itemData
= ItemData
;
454 int ListBoxDeleteString(LPHEADLIST lphl
, UINT uIndex
)
456 LPLISTSTRUCT lpls
, lpls2
;
459 if (uIndex
>= lphl
->ItemsCount
) return LB_ERR
;
461 lpls
= lphl
->lpFirst
;
462 if (lpls
== NULL
) return LB_ERR
;
465 lphl
->lpFirst
= lpls
->lpNext
;
467 LPLISTSTRUCT lpls2
= NULL
;
468 for(Count
= 0; Count
< uIndex
; Count
++) {
469 if (lpls
->lpNext
== NULL
) return LB_ERR
;
472 lpls
= (LPLISTSTRUCT
)lpls
->lpNext
;
474 lpls2
->lpNext
= lpls
->lpNext
;
477 /* adjust the itemID field of the following entries */
478 for(lpls2
= lpls
->lpNext
; lpls2
!= NULL
; lpls2
= lpls2
->lpNext
) {
484 if (lpls
->hData
!= 0) LIST_HEAP_FREE(lphl
, lpls
->hData
);
487 return lphl
->ItemsCount
;
491 int ListBoxFindString(LPHEADLIST lphl
, UINT nFirst
, SEGPTR MatchStr
)
495 UINT First
= nFirst
+ 1;
496 LPSTR lpMatchStr
= (LPSTR
)MatchStr
;
497 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
499 if (First
> lphl
->ItemsCount
) return LB_ERR
;
501 if (lphl
->HasStrings
) lpMatchStr
= PTR_SEG_TO_LIN(MatchStr
);
503 lpls
= ListBoxGetItem(lphl
, First
);
505 while(lpls
!= NULL
) {
506 if (lphl
->HasStrings
) {
507 if (strstr(lpls
->itemText
, lpMatchStr
) == lpls
->itemText
) return Count
;
508 } else if (dwStyle
& LBS_SORT
) {
509 /* XXX Do a compare item */
512 if (lpls
->mis
.itemData
== (DWORD
)lpMatchStr
) return Count
;
518 /* Start over at top */
520 lpls
= lphl
->lpFirst
;
522 while (Count
< First
) {
523 if (lphl
->HasStrings
) {
524 if (strstr(lpls
->itemText
, lpMatchStr
) == lpls
->itemText
) return Count
;
525 } else if (dwStyle
& LBS_SORT
) {
526 /* XXX Do a compare item */
528 if (lpls
->mis
.itemData
== (DWORD
)lpMatchStr
) return Count
;
538 int ListBoxResetContent(LPHEADLIST lphl
)
543 if (lphl
->ItemsCount
== 0) return 0;
545 dprintf_listbox(stddeb
, "ListBoxResetContent // ItemCount = %d\n",
548 for(i
= 0; i
< lphl
->ItemsCount
; i
++) {
549 lpls
= lphl
->lpFirst
;
550 if (lpls
== NULL
) return LB_ERR
;
552 lphl
->lpFirst
= lpls
->lpNext
;
553 if (lpls
->hData
!= 0) LIST_HEAP_FREE(lphl
, lpls
->hData
);
556 ListBoxInitialize(lphl
);
561 /* --------------------- selection ------------------------- */
563 int ListBoxSetCurSel(LPHEADLIST lphl
, WORD wIndex
)
566 DWORD dwStyle
= GetWindowWord(lphl
->hSelf
,GWL_STYLE
);
568 /* use ListBoxSetSel instead */
569 if (dwStyle
& LBS_MULTIPLESEL
) return 0;
571 /* unselect all previously selected */
572 if (dwStyle
& LBS_EXTENDEDSEL
)
573 ListBoxSetSel(lphl
,-1,0);
575 /* unselect previous item */
576 if (lphl
->ItemFocused
!= -1) {
577 lpls
= ListBoxGetItem(lphl
, lphl
->ItemFocused
);
578 if (lpls
== 0) return LB_ERR
;
582 if (wIndex
!= (UINT
)-1) {
583 lphl
->ItemFocused
= wIndex
;
584 lpls
= ListBoxGetItem(lphl
, wIndex
);
585 if (lpls
== 0) return LB_ERR
;
586 lpls
->itemState
= ODS_SELECTED
| ODS_FOCUS
;
595 int ListBoxSetSel(LPHEADLIST lphl
, WORD wIndex
, WORD state
)
599 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) &
600 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
603 if (wIndex
== (UINT
)-1) {
604 for (lpls
= lphl
->lpFirst
; lpls
!= NULL
; lpls
= lpls
->lpNext
) {
605 lpls
->itemState
= state
;
610 if (wIndex
>= lphl
->ItemsCount
) return LB_ERR
;
612 lpls
= ListBoxGetItem(lphl
, wIndex
);
613 lpls
->itemState
= state
;
619 int ListBoxGetSel(LPHEADLIST lphl
, WORD wIndex
)
621 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
, wIndex
);
623 if (lpls
== NULL
) return LB_ERR
;
624 return lpls
->itemState
;
627 /* ------------------------- dir listing ------------------------ */
629 int ListBoxDirectory(LPHEADLIST lphl
, UINT attrib
, LPSTR filespec
)
631 struct dosdirent
*dp
, *dp_old
;
636 dprintf_listbox(stddeb
,"ListBoxDirectory: %s, %4x\n",filespec
,attrib
);
638 if (strchr(filespec
, '\\') || strchr(filespec
, ':')) {
639 drive
= DOS_GetDefaultDrive();
640 if (filespec
[1] == ':') {
641 drive
= toupper(filespec
[0]) - 'A';
644 strcpy(temp
,filespec
);
645 tstr
= strrchr(temp
, '\\');
648 filespec
+= tstr
- temp
+ 1;
649 if (!DOS_ChangeDir( drive
, temp
)) return 0;
651 DOS_SetDefaultDrive( drive
);
652 dprintf_listbox(stddeb
,"Changing directory to %c:%s, filemask is %s\n",
653 drive
+'A', temp
, filespec
);
656 if ((dp
= (struct dosdirent
*)DOS_opendir(filespec
)) ==NULL
) return 0;
658 while ((dp
= (struct dosdirent
*)DOS_readdir(dp
))) {
659 if (!dp
->inuse
) break;
660 dprintf_listbox(stddeb
, "ListBoxDirectory %p '%s' !\n", dp
->filename
,
662 if (dp
->attribute
& FA_DIREC
) {
663 if (attrib
& DDL_DIRECTORY
&& strcmp(dp
->filename
, ".") != 0) {
664 sprintf(temp
, "[%s]", dp
->filename
);
665 if (ListBoxAddString(lphl
, temp
) == LB_ERR
) break;
669 if (attrib
& DDL_EXCLUSIVE
) {
670 if (attrib
& (DDL_READWRITE
| DDL_READONLY
| DDL_HIDDEN
| DDL_SYSTEM
)) {
671 if (ListBoxAddString(lphl
, dp
->filename
) == LB_ERR
) break;
674 if (ListBoxAddString(lphl
, dp
->filename
) == LB_ERR
) break;
678 DOS_closedir(dp_old
);
680 if (attrib
& DDL_DRIVES
) {
682 for (x
= 0; x
!= MAX_DOS_DRIVES
; x
++) {
683 if (DOS_ValidDrive(x
)) {
684 sprintf(temp
, "[-%c-]", 'a'+x
);
685 if (ListBoxInsertString(lphl
, (UINT
)-1, temp
) == LB_ERR
) break;
692 /* ------------------------- dimensions ------------------------- */
694 int ListBoxGetItemRect(LPHEADLIST lphl
, WORD wIndex
, LPRECT lprect
)
696 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
,wIndex
);
698 if (lpls
== NULL
) return LB_ERR
;
699 *lprect
= lpls
->itemRect
;
704 int ListBoxSetItemHeight(LPHEADLIST lphl
, WORD wIndex
, long height
)
708 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) & LBS_OWNERDRAWVARIABLE
)) {
709 lphl
->StdItemHeight
= (short)height
;
713 lpls
= ListBoxGetItem(lphl
, wIndex
);
714 if (lpls
== NULL
) return LB_ERR
;
716 lpls
->mis
.itemHeight
= height
;
720 /* -------------------------- string search ------------------------ */
722 int ListBoxFindNextMatch(LPHEADLIST lphl
, WORD wChar
)
727 if ((char)wChar
< ' ') return LB_ERR
;
728 if (!lphl
->HasStrings
) return LB_ERR
;
730 lpls
= lphl
->lpFirst
;
732 for (count
= 0; lpls
!= NULL
; lpls
= lpls
->lpNext
, count
++) {
733 if (tolower(*lpls
->itemText
) == tolower((char)wChar
)) break;
735 if (lpls
== NULL
) return LB_ERR
;
737 for(; lpls
!= NULL
; lpls
= lpls
->lpNext
, count
++) {
738 if (*lpls
->itemText
!= (char)wChar
)
740 if (count
> lphl
->ItemFocused
)
746 /***********************************************************************
749 static LONG
LBCreate(HWND hwnd
, WORD wParam
, LONG lParam
)
752 LONG dwStyle
= GetWindowLong(hwnd
,GWL_STYLE
);
755 CreateListBoxStruct(hwnd
, ODT_LISTBOX
, dwStyle
, GetParent(hwnd
));
756 lphl
= ListBoxGetStorageHeader(hwnd
);
757 dprintf_listbox(stddeb
,"ListBox created: lphl = %p dwStyle = "NPFMT
":"NPFMT
"\n",
758 lphl
, HIWORD(dwStyle
), LOWORD(dwStyle
));
760 GetClientRect(hwnd
,&rect
);
761 lphl
->ColumnsWidth
= rect
.right
- rect
.left
;
763 SetScrollRange(hwnd
, SB_VERT
, 0, ListMaxFirstVisible(lphl
), TRUE
);
764 SetScrollRange(hwnd
, SB_HORZ
, 1, 1, TRUE
);
769 /***********************************************************************
772 static LONG
LBDestroy(HWND hwnd
, WORD wParam
, LONG lParam
)
774 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
776 ListBoxResetContent(lphl
);
778 DestroyListBoxStruct(lphl
);
779 dprintf_listbox(stddeb
,"ListBox destroyed: lphl = %p\n",lphl
);
783 /***********************************************************************
786 static LONG
LBVScroll(HWND hwnd
, WORD wParam
, LONG lParam
)
788 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
791 dprintf_listbox(stddeb
,"ListBox WM_VSCROLL w=%04X l=%08lX !\n",
793 y
= lphl
->FirstVisible
;
797 if (lphl
->FirstVisible
> 0)
798 lphl
->FirstVisible
--;
802 lphl
->FirstVisible
++;
806 if (lphl
->FirstVisible
> lphl
->ItemsVisible
) {
807 lphl
->FirstVisible
-= lphl
->ItemsVisible
;
809 lphl
->FirstVisible
= 0;
814 lphl
->FirstVisible
+= lphl
->ItemsVisible
;
818 lphl
->FirstVisible
= LOWORD(lParam
);
822 if (lphl
->FirstVisible
> ListMaxFirstVisible(lphl
))
823 lphl
->FirstVisible
= ListMaxFirstVisible(lphl
);
825 if (y
!= lphl
->FirstVisible
) {
826 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
827 InvalidateRect(hwnd
, NULL
, TRUE
);
832 /***********************************************************************
835 static LONG
LBHScroll(HWND hwnd
, WORD wParam
, LONG lParam
)
840 dprintf_listbox(stddeb
,"ListBox WM_HSCROLL w=%04X l=%08lX !\n",
842 lphl
= ListBoxGetStorageHeader(hwnd
);
843 y
= lphl
->FirstVisible
;
846 if (lphl
->FirstVisible
> lphl
->ItemsPerColumn
) {
847 lphl
->FirstVisible
-= lphl
->ItemsPerColumn
;
849 lphl
->FirstVisible
= 0;
853 lphl
->FirstVisible
+= lphl
->ItemsPerColumn
;
856 if (lphl
->ItemsPerColumn
!= 0) {
857 int lbsub
= lphl
->ItemsVisible
/ lphl
->ItemsPerColumn
* lphl
->ItemsPerColumn
;
858 if (lphl
->FirstVisible
> lbsub
) {
859 lphl
->FirstVisible
-= lbsub
;
861 lphl
->FirstVisible
= 0;
866 if (lphl
->ItemsPerColumn
!= 0)
867 lphl
->FirstVisible
+= lphl
->ItemsVisible
/
868 lphl
->ItemsPerColumn
* lphl
->ItemsPerColumn
;
871 lphl
->FirstVisible
= lphl
->ItemsPerColumn
* LOWORD(lParam
);
874 if (lphl
->FirstVisible
> ListMaxFirstVisible(lphl
))
875 lphl
->FirstVisible
= ListMaxFirstVisible(lphl
);
877 if (lphl
->ItemsPerColumn
!= 0) {
878 lphl
->FirstVisible
= lphl
->FirstVisible
/
879 lphl
->ItemsPerColumn
* lphl
->ItemsPerColumn
+ 1;
880 if (y
!= lphl
->FirstVisible
) {
881 SetScrollPos(hwnd
, SB_HORZ
, lphl
->FirstVisible
/
882 lphl
->ItemsPerColumn
+ 1, TRUE
);
883 InvalidateRect(hwnd
, NULL
, TRUE
);
889 /***********************************************************************
892 static LONG
LBLButtonDown(HWND hwnd
, WORD wParam
, LONG lParam
)
894 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
898 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
903 lphl
->PrevFocused
= lphl
->ItemFocused
;
905 y
= ListBoxFindMouse(lphl
, LOWORD(lParam
), HIWORD(lParam
));
909 if (dwStyle
& LBS_MULTIPLESEL
) {
910 lphl
->ItemFocused
= y
;
911 wRet
= ListBoxGetSel(lphl
, y
);
912 ListBoxSetSel(lphl
, y
, !wRet
);
914 InvalidateRect(hwnd
, NULL
, TRUE
);
916 ListBoxSetCurSel(lphl
, y
);
918 ListBoxGetItemRect(lphl
, y
, &rectsel
);
919 InvalidateRect(hwnd
, &rectsel
, TRUE
);
920 if(lphl
->PrevFocused
) {
921 ListBoxGetItemRect(lphl
, lphl
->PrevFocused
, &rectsel
);
922 InvalidateRect(hwnd
, &rectsel
, TRUE
);
926 if (dwStyle
& (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
))
927 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
929 if (dwStyle
& LBS_NOTIFY
)
930 SendMessage(lphl
->hParent
, WM_LBTRACKPOINT
, y
, lParam
);
932 if (GetWindowLong(lphl
->hSelf
,GWL_EXSTYLE
) & WS_EX_DRAGDETECT
)
933 if( DragDetect(lphl
->hSelf
,MAKEPOINT(lParam
)) )
934 SendMessage(lphl
->hParent
, WM_BEGINDRAG
,0,0L);
939 /***********************************************************************
942 static LONG
LBLButtonUp(HWND hwnd
, WORD wParam
, LONG lParam
)
944 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
946 if (GetCapture() == hwnd
) ReleaseCapture();
948 if (lphl
->PrevFocused
!= lphl
->ItemFocused
)
949 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
954 /***********************************************************************
957 static LONG
LBRButtonUp(HWND hwnd
, WORD wParam
, LONG lParam
)
959 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
962 SendMessage(lphl
->hParent
, WM_COMMAND
,
963 MAKEWPARAM(GetWindowWord(hwnd
,GWW_ID
),LBN_DBLCLK
),
966 SendMessage(lphl
->hParent
, WM_COMMAND
, GetWindowWord(hwnd
,GWW_ID
),
967 MAKELONG(hwnd
, LBN_DBLCLK
));
973 /***********************************************************************
976 static LONG
LBMouseMove(HWND hwnd
, WORD wParam
, LONG lParam
)
978 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
981 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
982 RECT rect
, rectsel
; /* XXX Broken */
984 dprintf_listbox(stddeb
,"LBMouseMove %d %d\n",SLOWORD(lParam
),SHIWORD(lParam
));
985 if ((wParam
& MK_LBUTTON
) != 0) {
988 if (lphl
->FirstVisible
> 0) {
989 lphl
->FirstVisible
--;
990 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
991 InvalidateRect(hwnd
, NULL
, TRUE
);
995 GetClientRect(hwnd
, &rect
);
996 if (y
>= rect
.bottom
) {
997 if (lphl
->FirstVisible
< ListMaxFirstVisible(lphl
)) {
998 lphl
->FirstVisible
++;
999 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1000 InvalidateRect(hwnd
, NULL
, TRUE
);
1004 if ((y
> 0) && (y
< (rect
.bottom
- 4))) {
1005 if ((y
< rectsel
.top
) || (y
> rectsel
.bottom
)) {
1006 wRet
= ListBoxFindMouse(lphl
, LOWORD(lParam
), HIWORD(lParam
));
1007 if (wRet
== lphl
->ItemFocused
) {
1010 if (dwStyle
& LBS_MULTIPLESEL
) {
1011 lphl
->ItemFocused
= wRet
;
1012 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
1014 ListBoxSetCurSel(lphl
, wRet
);
1015 if(dwStyle
& LBS_EXTENDEDSEL
)
1016 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
1018 ListBoxGetItemRect(lphl
, wRet
, &rectsel
);
1019 InvalidateRect(hwnd
, &rectsel
, TRUE
);
1027 /***********************************************************************
1030 * Doesn't yet handle properly VK_SHIFT with LB_EXTENDEDSEL
1032 static LONG
LBKeyDown(HWND hwnd
, WORD wParam
, LONG lParam
)
1034 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1035 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
1036 WORD newFocused
= 0xFFFF;
1039 ListBoxGetItemRect(lphl
,lphl
->ItemFocused
,&rect
);
1042 /* ugly kludge that belongs in TranslateMessage */
1052 if ( dwStyle
& LBS_WANTKEYBOARDINPUT
)
1054 newFocused
= (WORD
)(INT
)SendMessage(lphl
->hParent
,WM_VKEYTOITEM
,
1055 wParam
,MAKELPARAM(lphl
->ItemFocused
,hwnd
));
1056 if ( newFocused
== 0xFFFE ) return 0L;
1058 if ( newFocused
== 0xFFFF )
1060 newFocused
= lphl
->ItemFocused
;
1069 newFocused
= lphl
->ItemsCount
- 1;
1072 if (dwStyle
& LBS_MULTICOLUMN
) {
1073 if (newFocused
>= lphl
->ItemsPerColumn
) {
1074 newFocused
-= lphl
->ItemsPerColumn
;
1081 if (newFocused
> 0) newFocused
--;
1084 if (dwStyle
& LBS_MULTICOLUMN
)
1085 newFocused
+= lphl
->ItemsPerColumn
;
1091 if (newFocused
> lphl
->ItemsVisible
)
1092 newFocused
-= lphl
->ItemsVisible
;
1093 else newFocused
= 0;
1096 newFocused
+= lphl
->ItemsVisible
;
1101 /* end of nested switch */
1105 if (dwStyle
& LBS_MULTIPLESEL
)
1107 WORD wRet
= ListBoxGetSel(lphl
, lphl
->ItemFocused
);
1108 ListBoxSetSel(lphl
, lphl
->ItemFocused
, !wRet
);
1112 /* chars are handled in LBChar */
1117 /* at this point newFocused is set up */
1119 if (newFocused
>= lphl
->ItemsCount
)
1120 newFocused
= lphl
->ItemsCount
- 1;
1122 if (!(dwStyle
& LBS_MULTIPLESEL
))
1124 ListBoxSetCurSel(lphl
, newFocused
);
1125 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
1128 lphl
->ItemFocused
= newFocused
;
1130 if( ListBoxScrollToFocus(lphl
) || (dwStyle
&
1131 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
)) )
1132 InvalidateRect(hwnd
, NULL
, TRUE
);
1135 InvalidateRect(hwnd
, &rect
, TRUE
);
1136 if( newFocused
< 0x8000 )
1138 ListBoxGetItemRect(lphl
, newFocused
, &rect
);
1139 InvalidateRect(hwnd
, &rect
, TRUE
);
1143 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1148 /***********************************************************************
1151 static LONG
LBChar(HWND hwnd
, WORD wParam
, LONG lParam
)
1153 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1154 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
1155 WORD newFocused
= 0xFFFF;
1157 if ( (dwStyle
& LBS_WANTKEYBOARDINPUT
) && !(lphl
->HasStrings
))
1159 newFocused
= (WORD
)(INT
)SendMessage(lphl
->hParent
,WM_CHARTOITEM
,
1160 wParam
,MAKELPARAM(lphl
->ItemFocused
,hwnd
));
1161 if ( newFocused
== 0xFFFE ) return 0L;
1164 if (newFocused
== 0xFFFF )
1165 newFocused
= ListBoxFindNextMatch(lphl
, wParam
);
1167 if (newFocused
== (WORD
)LB_ERR
) return 0;
1169 if (newFocused
>= lphl
->ItemsCount
)
1170 newFocused
= lphl
->ItemsCount
- 1;
1172 if (!(dwStyle
& LBS_MULTIPLESEL
))
1174 ListBoxSetCurSel(lphl
, newFocused
);
1175 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
1178 lphl
->ItemFocused
= newFocused
;
1179 ListBoxScrollToFocus(lphl
);
1180 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1182 InvalidateRect(hwnd
, NULL
, TRUE
);
1187 /***********************************************************************
1190 static LONG
LBSetRedraw(HWND hwnd
, WORD wParam
, LONG lParam
)
1192 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1194 dprintf_listbox(stddeb
,"ListBox WM_SETREDRAW hWnd="NPFMT
" w=%04X !\n",
1196 lphl
->bRedrawFlag
= wParam
;
1201 /***********************************************************************
1204 static LONG
LBSetFont(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1206 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1209 lphl
->hFont
= GetStockObject(SYSTEM_FONT
);
1211 lphl
->hFont
= (HFONT
) wParam
;
1216 /***********************************************************************
1219 static LONG
LBPaint(HWND hwnd
, WORD wParam
, LONG lParam
)
1221 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1222 LONG dwStyle
= GetWindowLong(lphl
->hSelf
,GWL_STYLE
);
1229 int i
, top
, height
, maxwidth
, ipc
;
1232 hdc
= BeginPaint( hwnd
, &ps
);
1234 if (!IsWindowVisible(hwnd
) || !lphl
->bRedrawFlag
) {
1235 EndPaint(hwnd
, &ps
);
1239 hOldFont
= SelectObject(hdc
, lphl
->hFont
);
1242 hBrush
= (HBRUSH
) SendMessage(lphl
->hParent
, WM_CTLCOLORLISTBOX
, (WPARAM
)hdc
,
1245 hBrush
= SendMessage(lphl
->hParent
, WM_CTLCOLOR
, hdc
,
1246 MAKELONG(hwnd
, CTLCOLOR_LISTBOX
));
1249 if (hBrush
== 0) hBrush
= GetStockObject(WHITE_BRUSH
);
1251 GetClientRect(hwnd
, &rect
);
1252 FillRect(hdc
, &rect
, hBrush
);
1254 maxwidth
= rect
.right
;
1255 if (dwStyle
& LBS_MULTICOLUMN
) {
1256 rect
.right
= lphl
->ColumnsWidth
;
1258 lpls
= lphl
->lpFirst
;
1260 lphl
->ItemsVisible
= 0;
1261 lphl
->ItemsPerColumn
= ipc
= 0;
1263 for(i
= 0; i
< lphl
->ItemsCount
; i
++) {
1264 if (lpls
== NULL
) break;
1266 if (i
>= lphl
->FirstVisible
) {
1267 height
= lpls
->mis
.itemHeight
;
1269 if (top
> rect
.bottom
) {
1270 if (dwStyle
& LBS_MULTICOLUMN
) {
1271 lphl
->ItemsPerColumn
= MAX(lphl
->ItemsPerColumn
, ipc
);
1274 rect
.left
+= lphl
->ColumnsWidth
;
1275 rect
.right
+= lphl
->ColumnsWidth
;
1276 if (rect
.left
> maxwidth
) break;
1282 lpls
->itemRect
.top
= top
;
1283 lpls
->itemRect
.bottom
= top
+ height
;
1284 lpls
->itemRect
.left
= rect
.left
;
1285 lpls
->itemRect
.right
= rect
.right
;
1287 dprintf_listbox(stddeb
,"drawing item: %ld %d %ld %d %d\n",(LONG
)rect
.left
,top
,(LONG
)rect
.right
,top
+height
,lpls
->itemState
);
1288 if (lphl
->OwnerDrawn
) {
1289 ListBoxDrawItem (hwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_DRAWENTIRE
, 0);
1290 if (lpls
->itemState
)
1291 ListBoxDrawItem (hwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_SELECT
, ODS_SELECTED
);
1293 ListBoxDrawItem (hwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_DRAWENTIRE
,
1296 if ((lphl
->ItemFocused
== i
) && GetFocus() == hwnd
)
1297 ListBoxDrawItem (hwnd
,lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_FOCUS
, ODS_FOCUS
);
1300 lphl
->ItemsVisible
++;
1304 lpls
= lpls
->lpNext
;
1306 ListBoxUpdateWindow(hwnd
,lphl
,FALSE
);
1307 SelectObject(hdc
,hOldFont
);
1308 EndPaint( hwnd
, &ps
);
1312 /***********************************************************************
1315 static LONG
LBSetFocus(HWND hwnd
, WORD wParam
, LONG lParam
)
1317 dprintf_listbox(stddeb
,"ListBox WM_SETFOCUS !\n");
1322 /***********************************************************************
1325 static LONG
LBKillFocus(HWND hwnd
, WORD wParam
, LONG lParam
)
1327 dprintf_listbox(stddeb
,"ListBox WM_KILLFOCUS !\n");
1329 InvalidateRect(hwnd
, NULL
, TRUE
);
1334 /***********************************************************************
1337 static LONG
LBResetContent(HWND hwnd
, WORD wParam
, LONG lParam
)
1339 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1341 dprintf_listbox(stddeb
,"ListBox LB_RESETCONTENT !\n");
1342 ListBoxResetContent(lphl
);
1343 ListBoxUpdateWindow(hwnd
, lphl
, TRUE
);
1347 /***********************************************************************
1350 static LONG
LBDir(HWND hwnd
, WORD wParam
, LONG lParam
)
1353 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1354 dprintf_listbox(stddeb
,"ListBox LB_DIR !\n");
1356 wRet
= ListBoxDirectory(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
1357 ListBoxUpdateWindow(hwnd
, lphl
, TRUE
);
1361 /***********************************************************************
1364 static LONG
LBAddString(HWND hwnd
, WORD wParam
, LONG lParam
)
1367 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1369 if (lphl
->HasStrings
)
1370 wRet
= ListBoxAddString(lphl
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
1372 wRet
= ListBoxAddString(lphl
, (LPSTR
)lParam
);
1374 ListBoxUpdateWindow(hwnd
,lphl
,TRUE
);
1378 /***********************************************************************
1381 static LONG
LBGetText(HWND hwnd
, WORD wParam
, LONG lParam
)
1384 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1386 dprintf_listbox(stddeb
, "LB_GETTEXT wParam=%d\n",wParam
);
1387 wRet
= ListBoxGetText(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
1392 /***********************************************************************
1395 static LONG
LBInsertString(HWND hwnd
, WORD wParam
, LONG lParam
)
1398 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1400 if (lphl
->HasStrings
)
1401 wRet
= ListBoxInsertString(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
1403 wRet
= ListBoxInsertString(lphl
, wParam
, (LPSTR
)lParam
);
1405 ListBoxUpdateWindow(hwnd
,lphl
,TRUE
);
1409 /***********************************************************************
1412 static LONG
LBDeleteString(HWND hwnd
, WORD wParam
, LONG lParam
)
1414 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1415 LONG lRet
= ListBoxDeleteString(lphl
,wParam
);
1417 ListBoxUpdateWindow(hwnd
,lphl
,TRUE
);
1421 /***********************************************************************
1424 static LONG
LBFindString(HWND hwnd
, WORD wParam
, LONG lParam
)
1426 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1427 return ListBoxFindString(lphl
, wParam
, lParam
);
1430 /***********************************************************************
1433 static LONG
LBGetCaretIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1435 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1436 return lphl
->ItemFocused
;
1439 /***********************************************************************
1442 static LONG
LBGetCount(HWND hwnd
, WORD wParam
, LONG lParam
)
1446 lphl
= ListBoxGetStorageHeader(hwnd
);
1447 return lphl
->ItemsCount
;
1450 /***********************************************************************
1453 static LONG
LBGetCurSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1457 lphl
= ListBoxGetStorageHeader(hwnd
);
1458 dprintf_listbox(stddeb
,"ListBox LB_GETCURSEL %u !\n",
1460 return lphl
->ItemFocused
;
1463 /***********************************************************************
1464 * LBGetHorizontalExtent
1466 static LONG
LBGetHorizontalExtent(HWND hwnd
, WORD wParam
, LONG lParam
)
1471 /***********************************************************************
1474 static LONG
LBGetItemHeight(HWND hwnd
, WORD wParam
, LONG lParam
)
1476 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1477 LPLISTSTRUCT lpls
= ListBoxGetItem (lphl
, wParam
);
1479 if (lpls
== NULL
) return LB_ERR
;
1480 return lpls
->mis
.itemHeight
;
1483 /***********************************************************************
1486 static LONG
LBGetItemRect(HWND hwnd
, WORD wParam
, LONG lParam
)
1488 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1489 return ListBoxGetItemRect(lphl
, wParam
, PTR_SEG_TO_LIN(lParam
));
1492 /***********************************************************************
1495 static LONG
LBGetSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1497 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1498 return (ListBoxGetSel(lphl
, wParam
) )? 1 : 0;
1501 /***********************************************************************
1504 static LONG
LBGetSelCount(HWND hwnd
, WORD wParam
, LONG lParam
)
1506 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1511 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) &
1512 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
1515 for( lpls
= lphl
->lpFirst
;
1517 lpls
= lpls
->lpNext
)
1520 if (lpls
->itemState
)
1527 /***********************************************************************
1530 static LONG
LBGetSelItems(HWND hwnd
, WORD wParam
, LONG lParam
)
1532 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1535 int *lpItems
= PTR_SEG_TO_LIN(lParam
);
1537 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) &
1538 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
1541 if (wParam
== 0) return 0;
1543 lpls
= lphl
->lpFirst
;
1546 while (lpls
!= NULL
) {
1547 if (lpls
->itemState
> 0) lpItems
[cnt
++] = idx
;
1549 if (cnt
== wParam
) break;
1551 lpls
= lpls
->lpNext
;
1557 /***********************************************************************
1560 static LONG
LBGetTextLen(HWND hwnd
, WORD wParam
, LONG lParam
)
1562 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1563 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
,wParam
);
1565 if (lpls
== NULL
|| !lphl
->HasStrings
) return LB_ERR
;
1566 return strlen(lpls
->itemText
);
1569 /***********************************************************************
1572 static LONG
LBGetDlgCode(HWND hwnd
, WORD wParam
, LONG lParam
)
1574 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1577 /***********************************************************************
1580 static LONG
LBGetTopIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1582 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1584 return lphl
->FirstVisible
;
1588 /***********************************************************************
1591 static LONG
LBSelectString(HWND hwnd
, WORD wParam
, LONG lParam
)
1593 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1596 wRet
= ListBoxFindString(lphl
, wParam
, lParam
);
1598 /* XXX add functionality here */
1603 /***********************************************************************
1606 static LONG
LBSelItemRange(HWND hwnd
, WORD wParam
, LONG lParam
)
1608 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1611 WORD first
= LOWORD(lParam
);
1612 WORD last
= HIWORD(lParam
);
1613 BOOL select
= wParam
;
1615 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) &
1616 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
1619 if (first
>= lphl
->ItemsCount
||
1620 last
>= lphl
->ItemsCount
) return LB_ERR
;
1622 lpls
= lphl
->lpFirst
;
1625 while (lpls
!= NULL
) {
1627 lpls
->itemState
= select
? ODS_SELECTED
: 0;
1632 lpls
= lpls
->lpNext
;
1638 /***********************************************************************
1641 static LONG
LBSetCaretIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1643 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1645 if (!(GetWindowLong(lphl
->hSelf
,GWL_STYLE
) & LBS_MULTIPLESEL
)) return 0;
1646 if (wParam
>= lphl
->ItemsCount
) return LB_ERR
;
1648 lphl
->ItemFocused
= wParam
;
1649 ListBoxScrollToFocus (lphl
);
1651 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1652 InvalidateRect(hwnd
, NULL
, TRUE
);
1656 /***********************************************************************
1659 static LONG
LBSetColumnWidth(HWND hwnd
, WORD wParam
, LONG lParam
)
1661 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1662 lphl
->ColumnsWidth
= wParam
;
1663 InvalidateRect(hwnd
,NULL
,TRUE
);
1667 /***********************************************************************
1668 * LBSetHorizontalExtent
1670 static LONG
LBSetHorizontalExtent(HWND hwnd
, WORD wParam
, LONG lParam
)
1675 /***********************************************************************
1678 static LONG
LBGetItemData(HWND hwnd
, WORD wParam
, LONG lParam
)
1680 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1681 dprintf_listbox(stddeb
, "LB_GETITEMDATA wParam=%x\n", wParam
);
1682 return ListBoxGetItemData(lphl
, wParam
);
1685 /***********************************************************************
1688 static LONG
LBSetItemData(HWND hwnd
, WORD wParam
, LONG lParam
)
1690 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1691 dprintf_listbox(stddeb
, "LB_SETITEMDATA wParam=%x lParam=%lx\n", wParam
, lParam
);
1692 return ListBoxSetItemData(lphl
, wParam
, lParam
);
1695 /***********************************************************************
1698 static LONG
LBSetTabStops(HWND hwnd
, WORD wParam
, LONG lParam
)
1702 lphl
= ListBoxGetStorageHeader(hwnd
);
1704 if (lphl
->TabStops
!= NULL
) {
1705 lphl
->iNumStops
= 0;
1706 free (lphl
->TabStops
);
1709 lphl
->TabStops
= malloc (wParam
* sizeof (short));
1710 if (lphl
->TabStops
) {
1711 lphl
->iNumStops
= wParam
;
1712 memcpy (lphl
->TabStops
, PTR_SEG_TO_LIN(lParam
), wParam
* sizeof (short));
1719 /***********************************************************************
1722 static LONG
LBSetCurSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1724 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1727 dprintf_listbox(stddeb
,"ListBox LB_SETCURSEL wParam=%x !\n",
1730 wRet
= ListBoxSetCurSel(lphl
, wParam
);
1732 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1733 InvalidateRect(hwnd
, NULL
, TRUE
);
1738 /***********************************************************************
1741 static LONG
LBSetSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1743 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1746 dprintf_listbox(stddeb
,"ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam
, lParam
);
1748 wRet
= ListBoxSetSel(lphl
, LOWORD(lParam
), wParam
);
1749 InvalidateRect(hwnd
, NULL
, TRUE
);
1754 /***********************************************************************
1757 static LONG
LBSetTopIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1759 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1761 dprintf_listbox(stddeb
,"ListBox LB_SETTOPINDEX wParam=%x !\n",
1763 lphl
->FirstVisible
= wParam
;
1764 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1766 InvalidateRect(hwnd
, NULL
, TRUE
);
1771 /***********************************************************************
1774 static LONG
LBSetItemHeight(HWND hwnd
, WORD wParam
, LONG lParam
)
1776 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1779 dprintf_listbox(stddeb
,"ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam
, lParam
);
1780 wRet
= ListBoxSetItemHeight(lphl
, wParam
, lParam
);
1781 InvalidateRect(hwnd
,NULL
,TRUE
);
1785 /***********************************************************************
1788 static LRESULT
LBPassToParent(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1790 WND
* ptrWnd
= WIN_FindWndPtr(hwnd
);
1793 if( /* !(ptrWnd->dwExStyle & WS_EX_NOPARENTNOTIFY) && */
1794 ptrWnd
->hwndParent
)
1795 return SendMessage(ptrWnd
->hwndParent
,message
,wParam
,lParam
);
1799 /***********************************************************************
1802 LRESULT
ListBoxWndProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1805 case WM_CREATE
: return LBCreate(hwnd
, wParam
, lParam
);
1806 case WM_DESTROY
: return LBDestroy(hwnd
, wParam
, lParam
);
1807 case WM_GETDLGCODE
: return LBGetDlgCode(hwnd
, wParam
, lParam
);
1808 case WM_VSCROLL
: return LBVScroll(hwnd
, wParam
, lParam
);
1809 case WM_HSCROLL
: return LBHScroll(hwnd
, wParam
, lParam
);
1810 case WM_LBUTTONDOWN
: return LBLButtonDown(hwnd
, wParam
, lParam
);
1811 case WM_LBUTTONUP
: return LBLButtonUp(hwnd
, wParam
, lParam
);
1812 case WM_RBUTTONUP
: return LBRButtonUp(hwnd
, wParam
, lParam
);
1813 case WM_LBUTTONDBLCLK
: return LBRButtonUp(hwnd
, wParam
, lParam
);
1814 case WM_MOUSEMOVE
: return LBMouseMove(hwnd
, wParam
, lParam
);
1815 case WM_KEYDOWN
: return LBKeyDown(hwnd
, wParam
, lParam
);
1816 case WM_CHAR
: return LBChar(hwnd
, wParam
, lParam
);
1817 case WM_SETFONT
: return LBSetFont(hwnd
, wParam
, lParam
);
1818 case WM_SETREDRAW
: return LBSetRedraw(hwnd
, wParam
, lParam
);
1819 case WM_PAINT
: return LBPaint(hwnd
, wParam
, lParam
);
1820 case WM_SETFOCUS
: return LBSetFocus(hwnd
, wParam
, lParam
);
1821 case WM_KILLFOCUS
: return LBKillFocus(hwnd
, wParam
, lParam
);
1822 case LB_RESETCONTENT
: return LBResetContent(hwnd
, wParam
, lParam
);
1823 case LB_DIR
: return LBDir(hwnd
, wParam
, lParam
);
1824 case LB_ADDSTRING
: return LBAddString(hwnd
, wParam
, lParam
);
1825 case LB_INSERTSTRING
: return LBInsertString(hwnd
, wParam
, lParam
);
1826 case LB_DELETESTRING
: return LBDeleteString(hwnd
, wParam
, lParam
);
1827 case LB_FINDSTRING
: return LBFindString(hwnd
, wParam
, lParam
);
1828 case LB_GETCARETINDEX
: return LBGetCaretIndex(hwnd
, wParam
, lParam
);
1829 case LB_GETCOUNT
: return LBGetCount(hwnd
, wParam
, lParam
);
1830 case LB_GETCURSEL
: return LBGetCurSel(hwnd
, wParam
, lParam
);
1831 case LB_GETHORIZONTALEXTENT
: return LBGetHorizontalExtent(hwnd
, wParam
, lParam
);
1832 case LB_GETITEMDATA
: return LBGetItemData(hwnd
, wParam
, lParam
);
1833 case LB_GETITEMHEIGHT
: return LBGetItemHeight(hwnd
, wParam
, lParam
);
1834 case LB_GETITEMRECT
: return LBGetItemRect(hwnd
, wParam
, lParam
);
1835 case LB_GETSEL
: return LBGetSel(hwnd
, wParam
, lParam
);
1836 case LB_GETSELCOUNT
: return LBGetSelCount(hwnd
, wParam
, lParam
);
1837 case LB_GETSELITEMS
: return LBGetSelItems(hwnd
, wParam
, lParam
);
1838 case LB_GETTEXT
: return LBGetText(hwnd
, wParam
, lParam
);
1839 case LB_GETTEXTLEN
: return LBGetTextLen(hwnd
, wParam
, lParam
);
1840 case LB_GETTOPINDEX
: return LBGetTopIndex(hwnd
, wParam
, lParam
);
1841 case LB_SELECTSTRING
: return LBSelectString(hwnd
, wParam
, lParam
);
1842 case LB_SELITEMRANGE
: return LBSelItemRange(hwnd
, wParam
, lParam
);
1843 case LB_SETCARETINDEX
: return LBSetCaretIndex(hwnd
, wParam
, lParam
);
1844 case LB_SETCOLUMNWIDTH
: return LBSetColumnWidth(hwnd
, wParam
, lParam
);
1845 case LB_SETHORIZONTALEXTENT
: return LBSetHorizontalExtent(hwnd
, wParam
, lParam
);
1846 case LB_SETITEMDATA
: return LBSetItemData(hwnd
, wParam
, lParam
);
1847 case LB_SETTABSTOPS
: return LBSetTabStops(hwnd
, wParam
, lParam
);
1848 case LB_SETCURSEL
: return LBSetCurSel(hwnd
, wParam
, lParam
);
1849 case LB_SETSEL
: return LBSetSel(hwnd
, wParam
, lParam
);
1850 case LB_SETTOPINDEX
: return LBSetTopIndex(hwnd
, wParam
, lParam
);
1851 case LB_SETITEMHEIGHT
: return LBSetItemHeight(hwnd
, wParam
, lParam
);
1853 case WM_DROPFILES
: return LBPassToParent(hwnd
, message
, wParam
, lParam
);
1856 case WM_QUERYDROPOBJECT
:
1860 LPDRAGINFO lpDragInfo
= (LPDRAGINFO
) PTR_SEG_TO_LIN((SEGPTR
)lParam
);
1861 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1863 /* more undocumented Microsoft crap - drag&drop depends on it - AK */
1865 lpDragInfo
->l
= ListBoxFindMouse(lphl
,lpDragInfo
->pt
.x
,
1868 return LBPassToParent(hwnd
, message
, wParam
, lParam
);
1872 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
1875 /************************************************************************
1876 * DlgDirSelect [USER.99]
1878 BOOL
DlgDirSelect(HWND hDlg
, LPSTR lpStr
, int nIDLBox
)
1884 dprintf_listbox( stddeb
, "DlgDirSelect("NPFMT
", '%s', %d) \n", hDlg
, lpStr
,
1887 hwnd
= GetDlgItem(hDlg
, nIDLBox
);
1888 lphl
= ListBoxGetStorageHeader(hwnd
);
1889 if(lphl
->ItemFocused
== -1) {
1890 dprintf_listbox(stddeb
, "Nothing selected!\n");
1893 ListBoxGetText(lphl
, lphl
->ItemFocused
, s
);
1894 dprintf_listbox(stddeb
, "Selection is %s\n", s
);
1897 strncpy( lpStr
, s
+2, strlen(s
)-4 ); /* device name */
1898 lpStr
[ strlen(s
)-4 ] = 0;
1899 strcat( lpStr
, ":" );
1902 strncpy( lpStr
, s
+1, strlen(s
)-2 ); /* directory name */
1903 lpStr
[ strlen(s
)-2 ] = 0;
1904 strcat( lpStr
, "\\" );
1906 dprintf_listbox( stddeb
, "Returning %s\n", lpStr
);
1909 strcpy( lpStr
, s
); /* file name */
1910 dprintf_listbox( stddeb
, "Returning %s\n", lpStr
);
1916 /************************************************************************
1917 * DlgDirList [USER.100]
1919 int DlgDirList(HWND hDlg
, LPSTR lpPathSpec
,
1920 int nIDLBox
, int nIDStat
, WORD wType
)
1925 dprintf_listbox(stddeb
,"DlgDirList("NPFMT
", '%s', %d, %d, %04X) \n",
1926 hDlg
, lpPathSpec
, nIDLBox
, nIDStat
, wType
);
1929 hWnd
= GetDlgItem(hDlg
, nIDLBox
);
1930 lphl
= ListBoxGetStorageHeader(hWnd
);
1931 ListBoxResetContent(lphl
);
1932 ret
= ListBoxDirectory(lphl
, wType
, lpPathSpec
);
1933 ListBoxUpdateWindow(hWnd
, lphl
, TRUE
);
1941 drive
= DOS_GetDefaultDrive();
1942 hTemp
= USER_HEAP_ALLOC( 256 );
1943 temp
= (char *) USER_HEAP_LIN_ADDR( hTemp
);
1944 strcpy( temp
+3, DOS_GetCurrentDir(drive
) );
1945 if( temp
[3] == '\\' ) {
1946 temp
[1] = 'A'+drive
;
1948 SendDlgItemMessage( hDlg
, nIDStat
, WM_SETTEXT
, 0,
1949 (LPARAM
)(USER_HEAP_SEG_ADDR(hTemp
) + 1) );
1951 temp
[0] = 'A'+drive
;
1954 SendDlgItemMessage( hDlg
, nIDStat
, WM_SETTEXT
, 0,
1955 (LPARAM
)USER_HEAP_SEG_ADDR(hTemp
) );
1957 USER_HEAP_FREE( hTemp
);