4 * Copyright Martin Ayotte, 1993
5 * Constantine Sapuntzakis, 1995
12 * - check if multi-column listboxes work
13 * - implement more messages and styles
14 * - implement caret for LBS_EXTENDEDSEL
34 #define LIST_HEAP_ALLOC(lphl,f,size) \
35 LOCAL_Alloc( lphl->HeapSel, LMEM_FIXED, (size) )
36 #define LIST_HEAP_FREE(lphl,handle) \
37 LOCAL_Free( lphl->HeapSel, (handle) )
38 #define LIST_HEAP_ADDR(lphl,handle) \
39 ((handle) ? PTR_SEG_OFF_TO_LIN(lphl->HeapSel, (handle)) : NULL)
41 #define LIST_HEAP_SIZE 0x10000
43 #define LBMM_EDGE 4 /* distance inside box which is same as moving mouse
44 outside box, to trigger scrolling of LB */
46 static void ListBoxInitialize(LPHEADLIST lphl
)
50 lphl
->ItemsVisible
= 0;
51 lphl
->FirstVisible
= 0;
52 lphl
->ColumnsVisible
= 1;
53 lphl
->ItemsPerColumn
= 0;
54 lphl
->ItemFocused
= -1;
55 lphl
->PrevFocused
= -1;
58 void CreateListBoxStruct(HWND hwnd
, WORD CtlType
, LONG styles
, HWND parent
)
63 lphl
= (LPHEADLIST
)xmalloc(sizeof(HEADLIST
));
64 SetWindowLong32A(hwnd
, 0, (LONG
)lphl
);
65 ListBoxInitialize(lphl
);
66 lphl
->DrawCtlType
= CtlType
;
67 lphl
->CtlID
= GetWindowWord(hwnd
,GWW_ID
);
68 lphl
->bRedrawFlag
= TRUE
;
70 lphl
->TabStops
= NULL
;
71 lphl
->hFont
= GetStockObject(SYSTEM_FONT
);
73 if (CtlType
==ODT_COMBOBOX
) /* use the "faked" style for COMBOLBOX */
74 /* LBS_SORT instead CBS_SORT e.g. */
75 lphl
->dwStyle
= MAKELONG(LOWORD(styles
),HIWORD(GetWindowLong32A(hwnd
,GWL_STYLE
)));
77 lphl
->dwStyle
= GetWindowLong32A(hwnd
,GWL_STYLE
); /* use original style dword */
78 lphl
->hParent
= parent
;
79 lphl
->StdItemHeight
= 15; /* FIXME: should get the font height */
80 lphl
->OwnerDrawn
= styles
& (LBS_OWNERDRAWFIXED
| LBS_OWNERDRAWVARIABLE
);
81 lphl
->HasStrings
= (styles
& LBS_HASSTRINGS
) || !lphl
->OwnerDrawn
;
83 /* create dummy hdc to set text height */
87 GetTextMetrics16( hdc
, &tm
);
88 lphl
->StdItemHeight
= tm
.tmHeight
;
89 dprintf_listbox(stddeb
,"CreateListBoxStruct: font height %d\n",
98 lphl
->needMeasure
= TRUE
;
99 dummyls
.mis
.CtlType
= lphl
->DrawCtlType
;
100 dummyls
.mis
.CtlID
= lphl
->CtlID
;
101 dummyls
.mis
.itemID
= -1;
102 dummyls
.mis
.itemWidth
= 0; /* ignored */
103 dummyls
.mis
.itemData
= 0;
105 ListBoxAskMeasure(lphl
,&dummyls
);
108 lphl
->HeapSel
= GlobalAlloc16(GMEM_FIXED
,LIST_HEAP_SIZE
);
109 LocalInit( lphl
->HeapSel
, 0, LIST_HEAP_SIZE
-1);
112 void DestroyListBoxStruct(LPHEADLIST lphl
)
114 /* XXX need to free lphl->Heap */
115 GlobalFree16(lphl
->HeapSel
);
119 static LPHEADLIST
ListBoxGetStorageHeader(HWND hwnd
)
121 return (LPHEADLIST
)GetWindowLong32A(hwnd
,0);
124 /* Send notification "code" as part of a WM_COMMAND-message if hwnd
125 has the LBS_NOTIFY style */
126 void ListBoxSendNotification(LPHEADLIST lphl
, WORD code
)
128 if (lphl
->dwStyle
& LBS_NOTIFY
)
129 SendMessage32A( lphl
->hParent
, WM_COMMAND
,
130 MAKEWPARAM( lphl
->CtlID
, code
), (LPARAM
)lphl
->hSelf
);
134 /* get the maximum value of lphl->FirstVisible */
135 int ListMaxFirstVisible(LPHEADLIST lphl
)
137 int m
= lphl
->ItemsCount
-lphl
->ItemsVisible
;
138 return (m
< 0) ? 0 : m
;
142 void ListBoxUpdateWindow(HWND hwnd
, LPHEADLIST lphl
, BOOL repaint
)
144 if (lphl
->dwStyle
& WS_VSCROLL
)
145 SetScrollRange(hwnd
, SB_VERT
, 0, ListMaxFirstVisible(lphl
), TRUE
);
146 if ((lphl
->dwStyle
& WS_HSCROLL
) && (lphl
->ItemsPerColumn
!= 0))
147 SetScrollRange(hwnd
, SB_HORZ
, 1, lphl
->ItemsVisible
/
148 lphl
->ItemsPerColumn
+ 1, TRUE
);
150 if (repaint
&& lphl
->bRedrawFlag
) InvalidateRect32( hwnd
, NULL
, TRUE
);
153 /* Returns: 0 if nothing needs to be changed */
154 /* 1 if FirstVisible changed */
156 int ListBoxScrollToFocus(LPHEADLIST lphl
)
160 if (lphl
->ItemsCount
== 0) return 0;
161 if (lphl
->ItemFocused
== -1) return 0;
163 end
= lphl
->FirstVisible
+ lphl
->ItemsVisible
- 1;
165 if (lphl
->ItemFocused
< lphl
->FirstVisible
) {
166 lphl
->FirstVisible
= lphl
->ItemFocused
;
169 if (lphl
->ItemFocused
> end
) {
170 WORD maxFirstVisible
= ListMaxFirstVisible(lphl
);
172 lphl
->FirstVisible
= lphl
->ItemFocused
;
174 if (lphl
->FirstVisible
> maxFirstVisible
) {
175 lphl
->FirstVisible
= maxFirstVisible
;
184 LPLISTSTRUCT
ListBoxGetItem(LPHEADLIST lphl
, UINT uIndex
)
189 if (uIndex
>= lphl
->ItemsCount
) return NULL
;
191 lpls
= lphl
->lpFirst
;
192 while (Count
++ < uIndex
) lpls
= lpls
->lpNext
;
197 void ListBoxDrawItem (HWND hwnd
, LPHEADLIST lphl
, HDC hdc
, LPLISTSTRUCT lpls
,
198 RECT16
*rect
, WORD itemAction
, WORD itemState
)
200 if (lphl
->OwnerDrawn
)
202 DRAWITEMSTRUCT32 dis
;
204 dis
.CtlID
= lpls
->mis
.CtlID
;
205 dis
.CtlType
= lpls
->mis
.CtlType
;
206 dis
.itemID
= lpls
->mis
.itemID
;
209 dis
.itemData
= lpls
->mis
.itemData
;
210 dis
.itemAction
= itemAction
;
211 dis
.itemState
= itemState
;
212 CONV_RECT16TO32( rect
, &dis
.rcItem
);
213 SendMessage32A( lphl
->hParent
, WM_DRAWITEM
, dis
.CtlID
, (LPARAM
)&dis
);
216 if (itemAction
== ODA_DRAWENTIRE
|| itemAction
== ODA_SELECT
) {
218 DWORD dwOldTextColor
= 0;
220 OldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
222 if (itemState
!= 0) {
223 dwOldTextColor
= SetTextColor(hdc
, 0x00FFFFFFL
);
224 FillRect16(hdc
, rect
, GetStockObject(BLACK_BRUSH
));
227 if (lphl
->dwStyle
& LBS_USETABSTOPS
) {
228 TabbedTextOut(hdc
, rect
->left
+ 5, rect
->top
+ 2,
229 (char *)lpls
->itemText
, strlen((char *)lpls
->itemText
),
230 lphl
->iNumStops
, lphl
->TabStops
, 0);
232 TextOut16(hdc
, rect
->left
+ 5, rect
->top
+ 2,
233 (char *)lpls
->itemText
, strlen((char *)lpls
->itemText
));
236 if (itemState
!= 0) {
237 SetTextColor(hdc
, dwOldTextColor
);
240 SetBkMode(hdc
, OldBkMode
);
242 else DrawFocusRect16(hdc
, rect
);
246 int ListBoxFindMouse(LPHEADLIST lphl
, int X
, int Y
)
248 LPLISTSTRUCT lpls
= lphl
->lpFirst
;
252 point
.x
= X
; point
.y
= Y
;
253 if (lphl
->ItemsCount
== 0) return LB_ERR
;
255 for(i
= 0; i
< lphl
->FirstVisible
; i
++) {
256 if (lpls
== NULL
) return LB_ERR
;
259 for(j
= 0; j
< lphl
->ItemsVisible
; i
++, j
++) {
260 if (lpls
== NULL
) return LB_ERR
;
261 if (PtInRect16(&lpls
->itemRect
,point
)) {
266 dprintf_listbox(stddeb
,"ListBoxFindMouse: not found\n");
271 void ListBoxAskMeasure(LPHEADLIST lphl
, LPLISTSTRUCT lpls
)
273 MEASUREITEMSTRUCT16
*lpmeasure
= SEGPTR_NEW(MEASUREITEMSTRUCT16
);
274 if (!lpmeasure
) return;
275 *lpmeasure
= lpls
->mis
;
276 lpmeasure
->itemHeight
= lphl
->StdItemHeight
;
277 SendMessage16( lphl
->hParent
, WM_MEASUREITEM
, lphl
->CtlID
,
278 (LPARAM
)SEGPTR_GET(lpmeasure
) );
280 if (lphl
->dwStyle
& LBS_OWNERDRAWFIXED
)
282 if (lpmeasure
->itemHeight
> lphl
->StdItemHeight
)
283 lphl
->StdItemHeight
= lpmeasure
->itemHeight
;
284 lpls
->mis
.itemHeight
= lpmeasure
->itemHeight
;
286 SEGPTR_FREE(lpmeasure
);
289 /* -------------------- strings and item data ---------------------- */
291 LPLISTSTRUCT
ListBoxCreateItem(LPHEADLIST lphl
, int id
)
293 LPLISTSTRUCT lplsnew
= (LPLISTSTRUCT
)malloc(sizeof(LISTSTRUCT
));
295 if (lplsnew
== NULL
) return NULL
;
297 lplsnew
->itemState
= 0;
298 lplsnew
->mis
.CtlType
= lphl
->DrawCtlType
;
299 lplsnew
->mis
.CtlID
= lphl
->CtlID
;
300 lplsnew
->mis
.itemID
= id
;
301 lplsnew
->mis
.itemHeight
= lphl
->StdItemHeight
;
302 lplsnew
->mis
.itemWidth
= 0; /* ignored */
303 lplsnew
->mis
.itemData
= 0;
304 SetRectEmpty16( &lplsnew
->itemRect
);
311 int ListBoxInsertString(LPHEADLIST lphl
, UINT uIndex
, LPCSTR newstr
)
313 LPLISTSTRUCT
*lppls
, lplsnew
, lpls
;
318 dprintf_listbox(stddeb
,"ListBoxInsertString(%d, %p);\n", uIndex
, newstr
);
320 if (!newstr
) return -1;
322 if (uIndex
== (UINT
)-1)
323 uIndex
= lphl
->ItemsCount
;
325 lppls
= &lphl
->lpFirst
;
326 for(Count
= 0; Count
< uIndex
; Count
++) {
327 if (*lppls
== NULL
) return LB_ERR
;
328 lppls
= (LPLISTSTRUCT
*) &(*lppls
)->lpNext
;
331 lplsnew
= ListBoxCreateItem(lphl
, Count
);
333 if (lplsnew
== NULL
) {
334 fprintf(stdnimp
,"ListBoxInsertString() out of memory !\n");
338 lplsnew
->lpNext
= *lppls
;
343 if (lphl
->HasStrings
) {
344 dprintf_listbox(stddeb
," string: %s\n", newstr
);
345 hStr
= LIST_HEAP_ALLOC(lphl
, LMEM_MOVEABLE
, strlen(newstr
) + 1);
346 str
= (LPSTR
)LIST_HEAP_ADDR(lphl
, hStr
);
347 if (str
== NULL
) return LB_ERRSPACE
;
349 lplsnew
->itemText
= str
;
350 /* I'm not so sure about the next one */
351 lplsnew
->mis
.itemData
= 0;
353 lplsnew
->itemText
= NULL
;
354 lplsnew
->mis
.itemData
= (DWORD
)newstr
;
357 lplsnew
->mis
.itemID
= uIndex
;
358 lplsnew
->hData
= hStr
;
360 /* adjust the itemID field of the following entries */
361 for(lpls
= lplsnew
->lpNext
; lpls
!= NULL
; lpls
= lpls
->lpNext
) {
365 if (lphl
->needMeasure
) {
366 ListBoxAskMeasure(lphl
, lplsnew
);
369 dprintf_listbox(stddeb
,"ListBoxInsertString // count=%d\n", lphl
->ItemsCount
);
374 int ListBoxAddString(LPHEADLIST lphl
, LPCSTR newstr
)
376 UINT pos
= (UINT
) -1;
378 if (lphl
->HasStrings
&& (lphl
->dwStyle
& LBS_SORT
)) {
379 LPLISTSTRUCT lpls
= lphl
->lpFirst
;
380 for (pos
= 0; lpls
!= NULL
; lpls
= lpls
->lpNext
, pos
++)
381 if (strcmp(lpls
->itemText
, newstr
) >= 0)
384 return ListBoxInsertString(lphl
, pos
, newstr
);
388 int ListBoxGetText(LPHEADLIST lphl
, UINT uIndex
, LPSTR OutStr
)
393 dprintf_listbox(stddeb
, "ListBoxGetText // OutStr==NULL\n");
397 lpls
= ListBoxGetItem (lphl
, uIndex
);
398 if (lpls
== NULL
) return LB_ERR
;
400 if (!lphl
->HasStrings
) {
401 *((long *)OutStr
) = lpls
->mis
.itemData
;
405 strcpy(OutStr
, lpls
->itemText
);
406 return strlen(OutStr
);
410 DWORD
ListBoxGetItemData(LPHEADLIST lphl
, UINT uIndex
)
414 lpls
= ListBoxGetItem (lphl
, uIndex
);
415 if (lpls
== NULL
) return LB_ERR
;
416 return lpls
->mis
.itemData
;
420 int ListBoxSetItemData(LPHEADLIST lphl
, UINT uIndex
, DWORD ItemData
)
422 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
, uIndex
);
424 if (lpls
== NULL
) return LB_ERR
;
425 lpls
->mis
.itemData
= ItemData
;
430 int ListBoxDeleteString(LPHEADLIST lphl
, UINT uIndex
)
432 LPLISTSTRUCT lpls
, lpls2
;
435 if (uIndex
>= lphl
->ItemsCount
) return LB_ERR
;
437 lpls
= lphl
->lpFirst
;
438 if (lpls
== NULL
) return LB_ERR
;
441 lphl
->lpFirst
= lpls
->lpNext
;
443 LPLISTSTRUCT lpls2
= NULL
;
444 for(Count
= 0; Count
< uIndex
; Count
++) {
445 if (lpls
->lpNext
== NULL
) return LB_ERR
;
448 lpls
= (LPLISTSTRUCT
)lpls
->lpNext
;
450 lpls2
->lpNext
= lpls
->lpNext
;
453 /* adjust the itemID field of the following entries */
454 for(lpls2
= lpls
->lpNext
; lpls2
!= NULL
; lpls2
= lpls2
->lpNext
) {
460 if (lpls
->hData
!= 0) LIST_HEAP_FREE(lphl
, lpls
->hData
);
463 return lphl
->ItemsCount
;
467 int ListBoxFindString(LPHEADLIST lphl
, UINT nFirst
, SEGPTR MatchStr
)
471 UINT First
= nFirst
+ 1;
472 LPSTR lpMatchStr
= (LPSTR
)MatchStr
;
474 if (First
> lphl
->ItemsCount
) return LB_ERR
;
476 if (lphl
->HasStrings
) lpMatchStr
= PTR_SEG_TO_LIN(MatchStr
);
478 lpls
= ListBoxGetItem(lphl
, First
);
480 while(lpls
!= NULL
) {
481 if (lphl
->HasStrings
) {
482 if (strstr(lpls
->itemText
, lpMatchStr
) == lpls
->itemText
) return Count
;
483 } else if (lphl
->dwStyle
& LBS_SORT
) {
484 /* XXX Do a compare item */
487 if (lpls
->mis
.itemData
== (DWORD
)lpMatchStr
) return Count
;
493 /* Start over at top */
495 lpls
= lphl
->lpFirst
;
497 while (Count
< First
) {
498 if (lphl
->HasStrings
) {
499 if (strstr(lpls
->itemText
, lpMatchStr
) == lpls
->itemText
) return Count
;
500 } else if (lphl
->dwStyle
& LBS_SORT
) {
501 /* XXX Do a compare item */
503 if (lpls
->mis
.itemData
== (DWORD
)lpMatchStr
) return Count
;
513 int ListBoxResetContent(LPHEADLIST lphl
)
518 if (lphl
->ItemsCount
== 0) return 0;
520 dprintf_listbox(stddeb
, "ListBoxResetContent // ItemCount = %d\n",
523 for(i
= 0; i
< lphl
->ItemsCount
; i
++) {
524 lpls
= lphl
->lpFirst
;
525 if (lpls
== NULL
) return LB_ERR
;
527 lphl
->lpFirst
= lpls
->lpNext
;
528 if (lpls
->hData
!= 0) LIST_HEAP_FREE(lphl
, lpls
->hData
);
531 ListBoxInitialize(lphl
);
536 /* --------------------- selection ------------------------- */
538 int ListBoxSetCurSel(LPHEADLIST lphl
, WORD wIndex
)
542 /* use ListBoxSetSel instead */
543 if (lphl
->dwStyle
& (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ) return 0;
545 /* unselect previous item */
546 if (lphl
->ItemFocused
!= -1) {
547 lphl
->PrevFocused
= lphl
->ItemFocused
;
548 lpls
= ListBoxGetItem(lphl
, lphl
->ItemFocused
);
549 if (lpls
== 0) return LB_ERR
;
553 if ((wIndex
!= (UINT
)-1) && (wIndex
< lphl
->ItemsCount
))
555 lphl
->ItemFocused
= wIndex
;
556 lpls
= ListBoxGetItem(lphl
, wIndex
);
557 if (lpls
== 0) return LB_ERR
;
558 lpls
->itemState
= ODS_SELECTED
| ODS_FOCUS
;
567 int ListBoxSetSel(LPHEADLIST lphl
, WORD wIndex
, WORD state
)
572 if (!(lphl
->dwStyle
& (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
575 if (wIndex
== (UINT
)-1) {
576 for (lpls
= lphl
->lpFirst
; lpls
!= NULL
; lpls
= lpls
->lpNext
) {
577 if( lpls
->itemState
& ODS_SELECTED
) n
++;
578 lpls
->itemState
= state
? lpls
->itemState
| ODS_SELECTED
579 : lpls
->itemState
& ~ODS_SELECTED
;
584 if (wIndex
>= lphl
->ItemsCount
) return LB_ERR
;
586 lpls
= ListBoxGetItem(lphl
, wIndex
);
587 lpls
->itemState
= state
? lpls
->itemState
| ODS_SELECTED
588 : lpls
->itemState
& ~ODS_SELECTED
;
594 int ListBoxGetSel(LPHEADLIST lphl
, WORD wIndex
)
596 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
, wIndex
);
598 if (lpls
== NULL
) return LB_ERR
;
599 return lpls
->itemState
& ODS_SELECTED
;
602 /* ------------------------- dir listing ------------------------ */
604 LONG
ListBoxDirectory(LPHEADLIST lphl
, UINT attrib
, LPCSTR filespec
)
606 char temp
[16], mask
[13];
613 dprintf_listbox(stddeb
, "ListBoxDirectory: '%s' %04x\n", filespec
, attrib
);
614 if (!filespec
) return LB_ERR
;
615 if (!(ptr
= DOSFS_GetUnixFileName( filespec
, FALSE
))) return LB_ERR
;
617 p
= strrchr( path
, '/' );
619 if (!(ptr
= DOSFS_ToDosFCBFormat( p
)))
626 dprintf_listbox(stddeb
, "ListBoxDirectory: path=%s mask=%s\n", path
, mask
);
630 while ((count
= DOSFS_FindNext( path
, mask
, 0, attrib
, skip
, &entry
)) > 0)
633 if (entry
.attr
& FA_DIRECTORY
)
635 if ((attrib
& DDL_DIRECTORY
) && strcmp(entry
.name
, ". "))
637 sprintf(temp
, "[%s]", DOSFS_ToDosDTAFormat( entry
.name
) );
639 if ((ret
= ListBoxAddString(lphl
, temp
)) == LB_ERR
) break;
642 else /* not a directory */
644 if (!(attrib
& DDL_EXCLUSIVE
) ||
645 ((attrib
& (FA_RDONLY
|FA_HIDDEN
|FA_SYSTEM
|FA_ARCHIVE
)) ==
646 (entry
.attr
& (FA_RDONLY
|FA_HIDDEN
|FA_SYSTEM
|FA_ARCHIVE
))))
648 strcpy( temp
, DOSFS_ToDosDTAFormat( entry
.name
) );
650 if ((ret
= ListBoxAddString(lphl
, temp
)) == LB_ERR
) break;
654 if (attrib
& DDL_DRIVES
)
657 strcpy( temp
, "[-a-]" );
658 for (x
= 0; x
< MAX_DOS_DRIVES
; x
++, temp
[2]++)
660 if (DRIVE_IsValid(x
))
661 if ((ret
= ListBoxAddString(lphl
, temp
)) == LB_ERR
) break;
668 /* ------------------------- dimensions ------------------------- */
670 int ListBoxGetItemRect(LPHEADLIST lphl
, WORD wIndex
, LPRECT16 lprect
)
672 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
,wIndex
);
674 if (lpls
== NULL
) return LB_ERR
;
675 *lprect
= lpls
->itemRect
;
680 int ListBoxSetItemHeight(LPHEADLIST lphl
, WORD wIndex
, long height
)
684 if (!(lphl
->dwStyle
& LBS_OWNERDRAWVARIABLE
)) {
685 lphl
->StdItemHeight
= (short)height
;
689 lpls
= ListBoxGetItem(lphl
, wIndex
);
690 if (lpls
== NULL
) return LB_ERR
;
692 lpls
->mis
.itemHeight
= height
;
696 /* -------------------------- string search ------------------------ */
698 int ListBoxFindNextMatch(LPHEADLIST lphl
, WORD wChar
)
703 if ((char)wChar
< ' ') return LB_ERR
;
704 if (!lphl
->HasStrings
) return LB_ERR
;
706 lpls
= lphl
->lpFirst
;
708 for (count
= 0; lpls
!= NULL
; lpls
= lpls
->lpNext
, count
++) {
709 if (tolower(*lpls
->itemText
) == tolower((char)wChar
)) break;
711 if (lpls
== NULL
) return LB_ERR
;
713 for(; lpls
!= NULL
; lpls
= lpls
->lpNext
, count
++) {
714 if (*lpls
->itemText
!= (char)wChar
)
716 if ((short) count
> lphl
->ItemFocused
)
722 /***********************************************************************
725 static LONG
LBCreate(HWND hwnd
, WORD wParam
, LONG lParam
)
728 LONG dwStyle
= GetWindowLong32A(hwnd
,GWL_STYLE
);
731 CreateListBoxStruct(hwnd
, ODT_LISTBOX
, dwStyle
, GetParent(hwnd
));
732 lphl
= ListBoxGetStorageHeader(hwnd
);
733 dprintf_listbox(stddeb
,"ListBox created: lphl = %p dwStyle = %04x:%04x\n",
734 lphl
, HIWORD(dwStyle
), LOWORD(dwStyle
));
736 GetClientRect16(hwnd
,&rect
);
737 lphl
->ColumnsWidth
= rect
.right
- rect
.left
;
739 if (dwStyle
& WS_VSCROLL
)
740 SetScrollRange(hwnd
, SB_VERT
, 0, ListMaxFirstVisible(lphl
), TRUE
);
741 if (dwStyle
& WS_HSCROLL
)
742 SetScrollRange(hwnd
, SB_HORZ
, 1, 1, TRUE
);
748 /***********************************************************************
751 static LONG
LBDestroy(HWND hwnd
, WORD wParam
, LONG lParam
)
753 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
755 ListBoxResetContent(lphl
);
757 DestroyListBoxStruct(lphl
);
758 dprintf_listbox(stddeb
,"ListBox destroyed: lphl = %p\n",lphl
);
762 /***********************************************************************
765 static LONG
LBVScroll(HWND hwnd
, WORD wParam
, LONG lParam
)
767 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
770 dprintf_listbox(stddeb
,"ListBox WM_VSCROLL w=%04X l=%08lX !\n",
772 y
= lphl
->FirstVisible
;
776 if (lphl
->FirstVisible
> 0)
777 lphl
->FirstVisible
--;
781 lphl
->FirstVisible
++;
785 if (lphl
->FirstVisible
> lphl
->ItemsVisible
) {
786 lphl
->FirstVisible
-= lphl
->ItemsVisible
;
788 lphl
->FirstVisible
= 0;
793 lphl
->FirstVisible
+= lphl
->ItemsVisible
;
797 lphl
->FirstVisible
= LOWORD(lParam
);
801 if (lphl
->FirstVisible
> ListMaxFirstVisible(lphl
))
802 lphl
->FirstVisible
= ListMaxFirstVisible(lphl
);
804 if (y
!= lphl
->FirstVisible
) {
805 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
806 InvalidateRect32( hwnd
, NULL
, TRUE
);
811 /***********************************************************************
814 static LONG
LBHScroll(HWND hwnd
, WORD wParam
, LONG lParam
)
819 dprintf_listbox(stddeb
,"ListBox WM_HSCROLL w=%04X l=%08lX !\n",
821 lphl
= ListBoxGetStorageHeader(hwnd
);
822 y
= lphl
->FirstVisible
;
825 if (lphl
->FirstVisible
> lphl
->ItemsPerColumn
) {
826 lphl
->FirstVisible
-= lphl
->ItemsPerColumn
;
828 lphl
->FirstVisible
= 0;
832 lphl
->FirstVisible
+= lphl
->ItemsPerColumn
;
835 if (lphl
->ItemsPerColumn
!= 0) {
836 int lbsub
= lphl
->ItemsVisible
/ lphl
->ItemsPerColumn
* lphl
->ItemsPerColumn
;
837 if (lphl
->FirstVisible
> lbsub
) {
838 lphl
->FirstVisible
-= lbsub
;
840 lphl
->FirstVisible
= 0;
845 if (lphl
->ItemsPerColumn
!= 0)
846 lphl
->FirstVisible
+= lphl
->ItemsVisible
/
847 lphl
->ItemsPerColumn
* lphl
->ItemsPerColumn
;
850 lphl
->FirstVisible
= lphl
->ItemsPerColumn
* LOWORD(lParam
);
853 if (lphl
->FirstVisible
> ListMaxFirstVisible(lphl
))
854 lphl
->FirstVisible
= ListMaxFirstVisible(lphl
);
856 if (lphl
->ItemsPerColumn
!= 0) {
857 lphl
->FirstVisible
= lphl
->FirstVisible
/
858 lphl
->ItemsPerColumn
* lphl
->ItemsPerColumn
+ 1;
859 if (y
!= lphl
->FirstVisible
) {
860 SetScrollPos(hwnd
, SB_HORZ
, lphl
->FirstVisible
/
861 lphl
->ItemsPerColumn
+ 1, TRUE
);
862 InvalidateRect32( hwnd
, NULL
, TRUE
);
868 /***********************************************************************
871 static LONG
LBLButtonDown(HWND hwnd
, WORD wParam
, LONG lParam
)
873 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
881 lphl
->PrevFocused
= lphl
->ItemFocused
;
883 y
= ListBoxFindMouse(lphl
, LOWORD(lParam
), HIWORD(lParam
));
885 if (y
== -1) return 0;
887 if (lphl
->dwStyle
& LBS_NOTIFY
&& y
!= LB_ERR
)
888 if( SendMessage16(lphl
->hParent
, WM_LBTRACKPOINT
, y
, lParam
) )
892 switch( lphl
->dwStyle
& (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) )
894 case LBS_MULTIPLESEL
:
895 lphl
->ItemFocused
= y
;
896 wRet
= ListBoxGetSel(lphl
, y
);
897 ListBoxSetSel(lphl
, y
, !wRet
);
899 case LBS_EXTENDEDSEL
:
900 /* should handle extended mode here and in kbd handler
903 if ( lphl
->PrevFocused
!= y
&& y
!= LB_ERR
)
905 LPLISTSTRUCT lpls
= ListBoxGetItem( lphl
, lphl
->ItemFocused
= y
);
906 n
= ListBoxSetSel(lphl
,-1,FALSE
);
908 lpls
->itemState
= ODS_FOCUS
| ODS_SELECTED
;
910 if( n
> 1 && n
!= LB_ERR
)
911 InvalidateRect32( hwnd
,NULL
,TRUE
);
918 if( y
!=lphl
->ItemFocused
)
919 ListBoxSetCurSel(lphl
, y
);
924 fprintf(stdnimp
,"Listbox: LBS_MULTIPLESEL and LBS_EXTENDEDSEL are on!\n");
928 /* invalidate changed items */
929 if( lphl
->dwStyle
& LBS_MULTIPLESEL
|| y
!=lphl
->PrevFocused
)
931 ListBoxGetItemRect(lphl
, y
, &rectsel
);
932 InvalidateRect16( hwnd
, &rectsel
, TRUE
);
934 if( lphl
->PrevFocused
!=-1 && y
!=lphl
->PrevFocused
)
936 ListBoxGetItemRect(lphl
, lphl
->PrevFocused
, &rectsel
);
937 InvalidateRect16( hwnd
, &rectsel
, TRUE
);
940 if (GetWindowLong32A(lphl
->hSelf
,GWL_EXSTYLE
) & WS_EX_DRAGDETECT
)
941 if( DragDetect(lphl
->hSelf
,MAKEPOINT16(lParam
)) )
942 SendMessage16(lphl
->hParent
, WM_BEGINDRAG
,0,0L);
946 /***********************************************************************
949 static LONG
LBLButtonUp(HWND hwnd
, WORD wParam
, LONG lParam
)
951 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
953 if (GetCapture() == hwnd
) ReleaseCapture();
955 if (lphl
->PrevFocused
!= lphl
->ItemFocused
)
956 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
961 /***********************************************************************
964 static LONG
LBRButtonUp(HWND hwnd
, WORD wParam
, LONG lParam
)
966 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
968 SendMessage16(lphl
->hParent
, WM_COMMAND
, GetWindowWord(hwnd
,GWW_ID
),
969 MAKELONG(hwnd
, LBN_DBLCLK
));
973 /***********************************************************************
976 static LONG
LBMouseMove(HWND hwnd
, WORD wParam
, LONG lParam
)
978 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
979 int y
,redraw_prev
= 0;
981 RECT16 rect
, rectsel
; /* XXX Broken */
983 dprintf_listbox(stddeb
,"LBMouseMove %d %d\n",SLOWORD(lParam
),SHIWORD(lParam
));
984 if ((wParam
& MK_LBUTTON
) != 0) {
987 if (lphl
->FirstVisible
> 0) {
988 lphl
->FirstVisible
--;
989 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
990 InvalidateRect32( hwnd
, NULL
, TRUE
);
994 GetClientRect16(hwnd
, &rect
);
995 if (y
>= (rect
.bottom
-LBMM_EDGE
)) {
996 if (lphl
->FirstVisible
< ListMaxFirstVisible(lphl
)) {
997 lphl
->FirstVisible
++;
998 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
999 InvalidateRect32( hwnd
, NULL
, TRUE
);
1003 if ((y
> 0) && (y
< (rect
.bottom
- LBMM_EDGE
))) {
1004 if ((y
< rectsel
.top
) || (y
> rectsel
.bottom
)) {
1005 iRet
= ListBoxFindMouse(lphl
, LOWORD(lParam
), HIWORD(lParam
));
1006 if (iRet
== lphl
->ItemFocused
|| iRet
== -1) {
1009 if (lphl
->dwStyle
& LBS_MULTIPLESEL
) {
1010 lphl
->ItemFocused
= iRet
;
1011 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
1012 } else if ( lphl
->dwStyle
& LBS_EXTENDEDSEL
)
1014 /* Fixme: extended selection mode */
1015 ListBoxSetSel( lphl
, lphl
->ItemFocused
, 0);
1016 lphl
->PrevFocused
= lphl
->ItemFocused
;
1017 lphl
->ItemFocused
= iRet
;
1018 ListBoxSetSel( lphl
, iRet
, TRUE
);
1023 ListBoxSetCurSel(lphl
, (WORD
)iRet
);
1026 if( lphl
->PrevFocused
!=-1 && redraw_prev
)
1028 ListBoxGetItemRect(lphl
, lphl
->PrevFocused
, &rectsel
);
1029 InvalidateRect16( hwnd
, &rectsel
, TRUE
);
1031 ListBoxGetItemRect(lphl
, iRet
, &rectsel
);
1032 InvalidateRect16( hwnd
, &rectsel
, TRUE
);
1040 /***********************************************************************
1043 * Doesn't yet handle properly VK_SHIFT with LB_EXTENDEDSEL
1045 static LONG
LBKeyDown(HWND hwnd
, WORD wParam
, LONG lParam
)
1047 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1048 WORD newFocused
= 0xFFFF;
1051 ListBoxGetItemRect(lphl
,lphl
->ItemFocused
,&rect
);
1062 if ( lphl
->dwStyle
& LBS_WANTKEYBOARDINPUT
)
1064 newFocused
= (WORD
)(INT
)SendMessage16(lphl
->hParent
,WM_VKEYTOITEM
,
1065 wParam
,MAKELPARAM(lphl
->ItemFocused
,hwnd
));
1066 if ( newFocused
== 0xFFFE ) return 0L;
1068 if ( newFocused
== 0xFFFF )
1070 newFocused
= lphl
->ItemFocused
;
1079 newFocused
= lphl
->ItemsCount
- 1;
1082 if (lphl
->dwStyle
& LBS_MULTICOLUMN
) {
1083 if (newFocused
>= lphl
->ItemsPerColumn
) {
1084 newFocused
-= lphl
->ItemsPerColumn
;
1091 if (newFocused
> 0) newFocused
--;
1094 if (lphl
->dwStyle
& LBS_MULTICOLUMN
)
1095 newFocused
+= lphl
->ItemsPerColumn
;
1101 if (newFocused
> lphl
->ItemsVisible
)
1102 newFocused
-= lphl
->ItemsVisible
;
1103 else newFocused
= 0;
1106 newFocused
+= lphl
->ItemsVisible
;
1111 /* end of nested switch */
1115 if (lphl
->dwStyle
& LBS_MULTIPLESEL
)
1117 WORD wRet
= ListBoxGetSel(lphl
, lphl
->ItemFocused
);
1118 ListBoxSetSel(lphl
, lphl
->ItemFocused
, !wRet
);
1122 /* chars are handled in LBChar */
1127 /* at this point newFocused is set up */
1129 if (newFocused
>= lphl
->ItemsCount
)
1130 newFocused
= lphl
->ItemsCount
- 1;
1132 if (!(lphl
->dwStyle
& LBS_MULTIPLESEL
))
1134 ListBoxSetCurSel(lphl
, newFocused
);
1135 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
1138 lphl
->ItemFocused
= newFocused
;
1140 if( ListBoxScrollToFocus(lphl
) || (lphl
->dwStyle
&
1141 (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
)) )
1142 InvalidateRect32( hwnd
, NULL
, TRUE
);
1145 InvalidateRect16( hwnd
, &rect
, TRUE
);
1146 if( newFocused
< 0x8000 )
1148 ListBoxGetItemRect(lphl
, newFocused
, &rect
);
1149 InvalidateRect16( hwnd
, &rect
, TRUE
);
1153 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1158 /***********************************************************************
1161 static LONG
LBChar(HWND hwnd
, WORD wParam
, LONG lParam
)
1163 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1164 WORD newFocused
= 0xFFFF;
1166 if ( (lphl
->dwStyle
& LBS_WANTKEYBOARDINPUT
) && !(lphl
->HasStrings
))
1168 newFocused
= (WORD
)(INT
)SendMessage16(lphl
->hParent
,WM_CHARTOITEM
,
1169 wParam
,MAKELPARAM(lphl
->ItemFocused
,hwnd
));
1170 if ( newFocused
== 0xFFFE ) return 0L;
1173 if (newFocused
== 0xFFFF )
1174 newFocused
= ListBoxFindNextMatch(lphl
, wParam
);
1176 if (newFocused
== (WORD
)LB_ERR
) return 0;
1178 if (newFocused
>= lphl
->ItemsCount
)
1179 newFocused
= lphl
->ItemsCount
- 1;
1181 if (!(lphl
->dwStyle
& LBS_MULTIPLESEL
))
1183 ListBoxSetCurSel(lphl
, newFocused
);
1184 ListBoxSendNotification(lphl
, LBN_SELCHANGE
);
1187 lphl
->ItemFocused
= newFocused
;
1188 ListBoxScrollToFocus(lphl
);
1189 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1191 InvalidateRect32( hwnd
, NULL
, TRUE
);
1196 /***********************************************************************
1199 static LONG
LBSetRedraw(HWND hwnd
, WORD wParam
, LONG lParam
)
1201 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1203 dprintf_listbox(stddeb
,"ListBox WM_SETREDRAW hWnd=%04x w=%04x !\n",
1205 lphl
->bRedrawFlag
= wParam
;
1210 /***********************************************************************
1213 static LONG
LBSetFont(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1215 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1219 lphl
->hFont
= GetStockObject(SYSTEM_FONT
);
1221 lphl
->hFont
= (HFONT
) wParam
;
1223 /* a new font means possible new text height */
1224 /* does this mean the height of each entry must be separately changed? */
1225 /* or are we guaranteed to get a LBSetFont before the first insert/add? */
1226 if ((hdc
= GetDC(0)))
1229 GetTextMetrics16( hdc
, &tm
);
1230 lphl
->StdItemHeight
= tm
.tmHeight
;
1231 dprintf_listbox(stddeb
,"LBSetFont: new font %d with height %d\n",
1232 lphl
->hFont
, lphl
->StdItemHeight
);
1233 ReleaseDC( 0, hdc
);
1239 /***********************************************************************
1242 static LONG
LBPaint(HWND hwnd
, WORD wParam
, LONG lParam
)
1244 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1249 HDC16 hdc
= BeginPaint16( hwnd
, &ps
);
1250 DC
*dc
= (DC
*)GDI_GetObjPtr(hdc
, DC_MAGIC
);
1251 RECT16 rect
, paintRect
, scratchRect
;
1252 int i
, top
, height
, maxwidth
, ipc
;
1256 if (!IsWindowVisible(hwnd
) || !lphl
->bRedrawFlag
) {
1257 EndPaint16(hwnd
, &ps
);
1261 GetRgnBox16(dc
->w
.hGCClipRgn
,&paintRect
);
1262 GetClientRect16(hwnd
, &rect
);
1263 IntersectRect16(&paintRect
,&rect
,&paintRect
);
1265 hOldFont
= SelectObject(hdc
, lphl
->hFont
);
1267 hBrush
= (HBRUSH
)SendMessage32A( lphl
->hParent
, WM_CTLCOLORLISTBOX
,
1268 (WPARAM
)hdc
, (LPARAM
)hwnd
);
1269 if (hBrush
== 0) hBrush
= GetStockObject(WHITE_BRUSH
);
1271 FillRect16(hdc
, &rect
, hBrush
);
1273 maxwidth
= rect
.right
;
1274 if (lphl
->dwStyle
& LBS_MULTICOLUMN
) {
1275 rect
.right
= lphl
->ColumnsWidth
;
1277 lpls
= lphl
->lpFirst
;
1279 lphl
->ItemsVisible
= 0;
1280 lphl
->ItemsPerColumn
= ipc
= 0;
1282 for(i
= 0; i
< lphl
->ItemsCount
; i
++) {
1283 if (lpls
== NULL
) break;
1285 if (i
>= lphl
->FirstVisible
) {
1286 height
= lpls
->mis
.itemHeight
;
1288 if (top
> (rect
.bottom
-height
+1)) {
1289 if (lphl
->dwStyle
& LBS_MULTICOLUMN
) {
1290 lphl
->ItemsPerColumn
= MAX(lphl
->ItemsPerColumn
, ipc
);
1293 rect
.left
+= lphl
->ColumnsWidth
;
1294 rect
.right
+= lphl
->ColumnsWidth
;
1295 if (rect
.left
> maxwidth
) break;
1301 lpls
->itemRect
.top
= top
;
1302 lpls
->itemRect
.bottom
= top
+ height
;
1303 lpls
->itemRect
.left
= rect
.left
;
1304 lpls
->itemRect
.right
= rect
.right
;
1306 if( IntersectRect16(&scratchRect
,&paintRect
,&lpls
->itemRect
) )
1308 dprintf_listbox(stddeb
,"LBPaint: drawing item: %d %d %d %d %d\n",
1309 rect
.left
,top
,rect
.right
,top
+height
,lpls
->itemState
);
1311 if (lphl
->OwnerDrawn
&& (lphl
->ItemFocused
== i
) && GetFocus() == hwnd
)
1313 ListBoxDrawItem (hwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_FOCUS
,
1314 lpls
->itemState
& ~ODS_FOCUS
);
1315 ListBoxDrawItem (hwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_DRAWENTIRE
,
1316 lpls
->itemState
& ~ODS_FOCUS
);
1317 ListBoxDrawItem (hwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_FOCUS
, lpls
->itemState
);
1320 ListBoxDrawItem (hwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_DRAWENTIRE
,
1325 lphl
->ItemsVisible
++;
1329 lpls
= lpls
->lpNext
;
1331 ListBoxUpdateWindow(hwnd
,lphl
,FALSE
);
1332 SelectObject(hdc
,hOldFont
);
1333 EndPaint16( hwnd
, &ps
);
1337 /***********************************************************************
1340 static LONG
LBSetFocus(HWND hwnd
, WORD wParam
, LONG lParam
)
1342 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1344 dprintf_listbox(stddeb
,"ListBox WM_SETFOCUS for %04x\n",hwnd
);
1345 if(!(lphl
->dwStyle
& LBS_MULTIPLESEL
) )
1346 if( lphl
->ItemsCount
&& lphl
->ItemFocused
!= -1)
1348 HDC hDC
= GetDC(hwnd
);
1349 HFONT hOldFont
= SelectObject(hDC
, lphl
->hFont
);
1352 lpls
= ListBoxGetItem(lphl
,lphl
->ItemFocused
);
1353 lpls
->itemState
|= ODS_FOCUS
;
1355 ListBoxDrawItem(hwnd
,lphl
,hDC
,lpls
,&lpls
->itemRect
, ODA_FOCUS
, lpls
->itemState
);
1356 SelectObject(hDC
, hOldFont
);
1357 ReleaseDC(hwnd
,hDC
);
1360 ListBoxSendNotification(lphl
, LBN_SETFOCUS
);
1365 /***********************************************************************
1368 static LONG
LBKillFocus(HWND hwnd
, WORD wParam
, LONG lParam
)
1370 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1372 dprintf_listbox(stddeb
,"ListBox WM_KILLFOCUS for %04x\n",hwnd
);
1373 if (!(lphl
->dwStyle
& LBS_MULTIPLESEL
))
1375 if( lphl
->ItemsCount
)
1376 if( lphl
->ItemFocused
!= -1 )
1378 HDC hDC
= GetDC(hwnd
);
1379 HFONT hOldFont
= SelectObject(hDC
, lphl
->hFont
);
1382 lpls
= ListBoxGetItem(lphl
,lphl
->ItemFocused
);
1383 lpls
->itemState
&= ~ODS_FOCUS
;
1385 ListBoxDrawItem(hwnd
,lphl
,hDC
,lpls
,&lpls
->itemRect
, ODA_FOCUS
, lpls
->itemState
);
1386 SelectObject(hDC
, hOldFont
);
1387 ReleaseDC(hwnd
,hDC
);
1390 dprintf_listbox(stddeb
,"LBKillFocus: no focused item!\n");
1393 InvalidateRect32( hwnd
, NULL
, TRUE
);
1395 ListBoxSendNotification(lphl
, LBN_KILLFOCUS
);
1400 /***********************************************************************
1403 static LONG
LBResetContent(HWND hwnd
, WORD wParam
, LONG lParam
)
1405 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1407 dprintf_listbox(stddeb
,"ListBox LB_RESETCONTENT !\n");
1408 ListBoxResetContent(lphl
);
1409 ListBoxUpdateWindow(hwnd
, lphl
, TRUE
);
1413 /***********************************************************************
1416 static LONG
LBDir(HWND hwnd
, WORD wParam
, LONG lParam
)
1419 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1420 dprintf_listbox(stddeb
,"ListBox LB_DIR !\n");
1422 ret
= ListBoxDirectory(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
1423 ListBoxUpdateWindow(hwnd
, lphl
, TRUE
);
1427 /***********************************************************************
1430 static LONG
LBAddString(HWND hwnd
, WORD wParam
, LONG lParam
)
1433 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1435 if (lphl
->HasStrings
)
1436 wRet
= ListBoxAddString(lphl
, (LPCSTR
)PTR_SEG_TO_LIN(lParam
));
1438 wRet
= ListBoxAddString(lphl
, (LPCSTR
)lParam
);
1440 ListBoxUpdateWindow(hwnd
,lphl
,TRUE
);
1444 /***********************************************************************
1447 static LONG
LBGetText(HWND hwnd
, WORD wParam
, LONG lParam
)
1450 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1452 dprintf_listbox(stddeb
, "LB_GETTEXT wParam=%d\n",wParam
);
1453 wRet
= ListBoxGetText(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
1458 /***********************************************************************
1461 static LONG
LBInsertString(HWND hwnd
, WORD wParam
, LONG lParam
)
1464 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1466 if (lphl
->HasStrings
)
1467 wRet
= ListBoxInsertString(lphl
, wParam
, (LPCSTR
)PTR_SEG_TO_LIN(lParam
));
1469 wRet
= ListBoxInsertString(lphl
, wParam
, (LPCSTR
)lParam
);
1471 ListBoxUpdateWindow(hwnd
,lphl
,TRUE
);
1475 /***********************************************************************
1478 static LONG
LBDeleteString(HWND hwnd
, WORD wParam
, LONG lParam
)
1480 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1481 LONG lRet
= ListBoxDeleteString(lphl
,wParam
);
1483 ListBoxUpdateWindow(hwnd
,lphl
,TRUE
);
1487 /***********************************************************************
1490 static LONG
LBFindString(HWND hwnd
, WORD wParam
, LONG lParam
)
1492 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1493 return ListBoxFindString(lphl
, wParam
, (SEGPTR
)lParam
);
1496 /***********************************************************************
1499 static LONG
LBGetCaretIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1501 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1502 return lphl
->ItemFocused
;
1505 /***********************************************************************
1508 static LONG
LBGetCount(HWND hwnd
, WORD wParam
, LONG lParam
)
1512 lphl
= ListBoxGetStorageHeader(hwnd
);
1513 return lphl
->ItemsCount
;
1516 /***********************************************************************
1519 static LONG
LBGetCurSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1523 lphl
= ListBoxGetStorageHeader(hwnd
);
1524 dprintf_listbox(stddeb
,"ListBox LB_GETCURSEL %i !\n",
1526 return lphl
->ItemFocused
;
1529 /***********************************************************************
1530 * LBGetHorizontalExtent
1532 static LONG
LBGetHorizontalExtent(HWND hwnd
, WORD wParam
, LONG lParam
)
1537 /***********************************************************************
1540 static LONG
LBGetItemHeight(HWND hwnd
, WORD wParam
, LONG lParam
)
1542 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1543 LPLISTSTRUCT lpls
= ListBoxGetItem (lphl
, wParam
);
1545 if (lpls
== NULL
) return LB_ERR
;
1546 return lpls
->mis
.itemHeight
;
1549 /***********************************************************************
1552 static LONG
LBGetItemRect(HWND hwnd
, WORD wParam
, LONG lParam
)
1554 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1555 return ListBoxGetItemRect(lphl
, wParam
, PTR_SEG_TO_LIN(lParam
));
1558 /***********************************************************************
1561 static LONG
LBGetSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1563 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1564 int iSel
= ListBoxGetSel(lphl
, wParam
);
1566 dprintf_listbox(stdnimp
,"LBGetSel: item %u - %i\n",wParam
,iSel
);
1568 return (iSel
)? 1 : 0;
1571 /***********************************************************************
1574 static LONG
LBGetSelCount(HWND hwnd
, WORD wParam
, LONG lParam
)
1576 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1581 if (!(lphl
->dwStyle
& (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
1584 for( lpls
= lphl
->lpFirst
;
1586 lpls
= lpls
->lpNext
)
1589 if (lpls
->itemState
)
1596 /***********************************************************************
1599 static LONG
LBGetSelItems(HWND hwnd
, WORD wParam
, LONG lParam
)
1601 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1604 int *lpItems
= PTR_SEG_TO_LIN(lParam
);
1606 if (!(lphl
->dwStyle
& (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
1609 if (wParam
== 0) return 0;
1611 lpls
= lphl
->lpFirst
;
1614 while (lpls
!= NULL
) {
1615 if (lpls
->itemState
> 0) lpItems
[cnt
++] = idx
;
1617 if (cnt
== wParam
) break;
1619 lpls
= lpls
->lpNext
;
1625 /***********************************************************************
1628 static LONG
LBGetTextLen(HWND hwnd
, WORD wParam
, LONG lParam
)
1630 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1631 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
,wParam
);
1633 if (lpls
== NULL
|| !lphl
->HasStrings
) return LB_ERR
;
1634 return strlen(lpls
->itemText
);
1637 /***********************************************************************
1640 static LONG
LBGetDlgCode(HWND hwnd
, WORD wParam
, LONG lParam
)
1642 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1645 /***********************************************************************
1648 static LONG
LBGetTopIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1650 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1652 return lphl
->FirstVisible
;
1656 /***********************************************************************
1659 static LONG
LBSelectString(HWND hwnd
, WORD wParam
, LONG lParam
)
1661 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1664 iRet
= ListBoxFindString(lphl
, wParam
, (SEGPTR
)lParam
);
1668 if( lphl
->dwStyle
& (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) )
1669 ListBoxSetSel(lphl
,iRet
,TRUE
);
1671 ListBoxSetCurSel(lphl
,iRet
);
1673 lphl
->ItemFocused
= iRet
;
1674 InvalidateRect32( hwnd
, 0, TRUE
);
1679 /***********************************************************************
1682 static LONG
LBSelItemRange(HWND hwnd
, WORD wParam
, LONG lParam
)
1684 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1687 WORD first
= LOWORD(lParam
);
1688 WORD last
= HIWORD(lParam
);
1689 BOOL select
= wParam
;
1691 if (!(lphl
->dwStyle
& (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ))
1694 if (first
>= lphl
->ItemsCount
||
1695 last
>= lphl
->ItemsCount
) return LB_ERR
;
1697 lpls
= lphl
->lpFirst
;
1700 while (lpls
!= NULL
) {
1702 lpls
->itemState
= select
? lpls
->itemState
| ODS_SELECTED
: 0;
1707 lpls
= lpls
->lpNext
;
1713 /***********************************************************************
1716 static LONG
LBSetCaretIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1718 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1721 if (!(lphl
->dwStyle
& (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) )) return 0;
1723 dprintf_listbox(stddeb
,"LBSetCaretIndex: hwnd %04x n=%i\n",hwnd
,wParam
);
1725 if (wParam
>= lphl
->ItemsCount
) return LB_ERR
;
1727 lphl
->ItemFocused
= wParam
;
1728 i
= ListBoxScrollToFocus (lphl
);
1730 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1732 InvalidateRect32( hwnd
, NULL
, TRUE
);
1737 /***********************************************************************
1740 static LONG
LBSetColumnWidth(HWND hwnd
, WORD wParam
, LONG lParam
)
1742 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1743 lphl
->ColumnsWidth
= wParam
;
1744 InvalidateRect32( hwnd
, NULL
, TRUE
);
1748 /***********************************************************************
1749 * LBSetHorizontalExtent
1751 static LONG
LBSetHorizontalExtent(HWND hwnd
, WORD wParam
, LONG lParam
)
1756 /***********************************************************************
1759 static LONG
LBGetItemData(HWND hwnd
, WORD wParam
, LONG lParam
)
1761 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1762 dprintf_listbox(stddeb
, "LB_GETITEMDATA wParam=%x\n", wParam
);
1763 return ListBoxGetItemData(lphl
, wParam
);
1766 /***********************************************************************
1769 static LONG
LBSetItemData(HWND hwnd
, WORD wParam
, LONG lParam
)
1771 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1772 dprintf_listbox(stddeb
, "LB_SETITEMDATA wParam=%x lParam=%lx\n", wParam
, lParam
);
1773 return ListBoxSetItemData(lphl
, wParam
, lParam
);
1776 /***********************************************************************
1779 static LONG
LBSetTabStops(HWND hwnd
, WORD wParam
, LONG lParam
)
1783 lphl
= ListBoxGetStorageHeader(hwnd
);
1785 if (lphl
->TabStops
!= NULL
) {
1786 lphl
->iNumStops
= 0;
1787 free (lphl
->TabStops
);
1790 lphl
->TabStops
= malloc (wParam
* sizeof (short));
1791 if (lphl
->TabStops
) {
1792 lphl
->iNumStops
= wParam
;
1793 memcpy (lphl
->TabStops
, PTR_SEG_TO_LIN(lParam
), wParam
* sizeof (short));
1800 /***********************************************************************
1803 static LONG
LBSetCurSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1805 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1808 dprintf_listbox(stddeb
,"ListBox LB_SETCURSEL wParam=%x !\n",
1811 wRet
= ListBoxSetCurSel(lphl
, wParam
);
1813 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1814 InvalidateRect32( hwnd
, NULL
, TRUE
);
1819 /***********************************************************************
1822 static LONG
LBSetSel(HWND hwnd
, WORD wParam
, LONG lParam
)
1824 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1828 dprintf_listbox(stddeb
,"ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam
, lParam
);
1830 iRet
= ListBoxSetSel(lphl
, LOWORD(lParam
), wParam
);
1832 if( iRet
> 1 ) InvalidateRect32( hwnd
, NULL
, TRUE
);
1833 else if( iRet
!= LB_ERR
)
1835 if( lphl
->dwStyle
& LBS_EXTENDEDSEL
&&
1836 lphl
->ItemFocused
!= LOWORD(lParam
) )
1838 ListBoxGetItemRect(lphl
, lphl
->ItemFocused
, &rect
);
1839 InvalidateRect16( hwnd
, &rect
, TRUE
);
1840 lphl
->ItemFocused
= LOWORD(lParam
);
1842 ListBoxGetItemRect(lphl
,LOWORD(lParam
),&rect
);
1843 InvalidateRect16( hwnd
, &rect
, TRUE
);
1846 return (iRet
== (WORD
)LB_ERR
)? LB_ERR
: 0;
1849 /***********************************************************************
1852 static LONG
LBSetTopIndex(HWND hwnd
, WORD wParam
, LONG lParam
)
1854 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1856 dprintf_listbox(stddeb
,"ListBox LB_SETTOPINDEX wParam=%x !\n",
1858 lphl
->FirstVisible
= wParam
;
1859 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1861 InvalidateRect32( hwnd
, NULL
, TRUE
);
1866 /***********************************************************************
1869 static LONG
LBSetItemHeight(HWND hwnd
, WORD wParam
, LONG lParam
)
1871 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1874 dprintf_listbox(stddeb
,"ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam
, lParam
);
1875 wRet
= ListBoxSetItemHeight(lphl
, wParam
, lParam
);
1876 InvalidateRect32( hwnd
, NULL
, TRUE
);
1880 /***********************************************************************
1883 static LRESULT
LBPassToParent(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1885 WND
* ptrWnd
= WIN_FindWndPtr(hwnd
);
1888 if( /* !(ptrWnd->dwExStyle & WS_EX_NOPARENTNOTIFY) && */
1890 return SendMessage16(ptrWnd
->parent
->hwndSelf
,message
,wParam
,lParam
);
1894 /***********************************************************************
1897 LRESULT
ListBoxWndProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1900 case WM_CREATE
: return LBCreate(hwnd
, wParam
, lParam
);
1901 case WM_DESTROY
: return LBDestroy(hwnd
, wParam
, lParam
);
1902 case WM_GETDLGCODE
: return LBGetDlgCode(hwnd
, wParam
, lParam
);
1903 case WM_VSCROLL
: return LBVScroll(hwnd
, wParam
, lParam
);
1904 case WM_HSCROLL
: return LBHScroll(hwnd
, wParam
, lParam
);
1905 case WM_LBUTTONDOWN
: return LBLButtonDown(hwnd
, wParam
, lParam
);
1906 case WM_LBUTTONUP
: return LBLButtonUp(hwnd
, wParam
, lParam
);
1907 case WM_RBUTTONUP
: return LBRButtonUp(hwnd
, wParam
, lParam
);
1908 case WM_LBUTTONDBLCLK
: return LBRButtonUp(hwnd
, wParam
, lParam
);
1909 case WM_MOUSEMOVE
: return LBMouseMove(hwnd
, wParam
, lParam
);
1910 case WM_KEYDOWN
: return LBKeyDown(hwnd
, wParam
, lParam
);
1911 case WM_CHAR
: return LBChar(hwnd
, wParam
, lParam
);
1912 case WM_SETFONT
: return LBSetFont(hwnd
, wParam
, lParam
);
1913 case WM_SETREDRAW
: return LBSetRedraw(hwnd
, wParam
, lParam
);
1914 case WM_PAINT
: return LBPaint(hwnd
, wParam
, lParam
);
1915 case WM_SETFOCUS
: return LBSetFocus(hwnd
, wParam
, lParam
);
1916 case WM_KILLFOCUS
: return LBKillFocus(hwnd
, wParam
, lParam
);
1917 case LB_RESETCONTENT
: return LBResetContent(hwnd
, wParam
, lParam
);
1918 case LB_DIR
: return LBDir(hwnd
, wParam
, lParam
);
1919 case LB_ADDSTRING
: return LBAddString(hwnd
, wParam
, lParam
);
1920 case LB_INSERTSTRING
: return LBInsertString(hwnd
, wParam
, lParam
);
1921 case LB_DELETESTRING
: return LBDeleteString(hwnd
, wParam
, lParam
);
1922 case LB_FINDSTRING
: return LBFindString(hwnd
, wParam
, lParam
);
1923 case LB_GETCARETINDEX
: return LBGetCaretIndex(hwnd
, wParam
, lParam
);
1924 case LB_GETCOUNT
: return LBGetCount(hwnd
, wParam
, lParam
);
1925 case LB_GETCURSEL
: return LBGetCurSel(hwnd
, wParam
, lParam
);
1926 case LB_GETHORIZONTALEXTENT
: return LBGetHorizontalExtent(hwnd
, wParam
, lParam
);
1927 case LB_GETITEMDATA
: return LBGetItemData(hwnd
, wParam
, lParam
);
1928 case LB_GETITEMHEIGHT
: return LBGetItemHeight(hwnd
, wParam
, lParam
);
1929 case LB_GETITEMRECT
: return LBGetItemRect(hwnd
, wParam
, lParam
);
1930 case LB_GETSEL
: return LBGetSel(hwnd
, wParam
, lParam
);
1931 case LB_GETSELCOUNT
: return LBGetSelCount(hwnd
, wParam
, lParam
);
1932 case LB_GETSELITEMS
: return LBGetSelItems(hwnd
, wParam
, lParam
);
1933 case LB_GETTEXT
: return LBGetText(hwnd
, wParam
, lParam
);
1934 case LB_GETTEXTLEN
: return LBGetTextLen(hwnd
, wParam
, lParam
);
1935 case LB_GETTOPINDEX
: return LBGetTopIndex(hwnd
, wParam
, lParam
);
1936 case LB_SELECTSTRING
: return LBSelectString(hwnd
, wParam
, lParam
);
1937 case LB_SELITEMRANGE
: return LBSelItemRange(hwnd
, wParam
, lParam
);
1938 case LB_SETCARETINDEX
: return LBSetCaretIndex(hwnd
, wParam
, lParam
);
1939 case LB_SETCOLUMNWIDTH
: return LBSetColumnWidth(hwnd
, wParam
, lParam
);
1940 case LB_SETHORIZONTALEXTENT
: return LBSetHorizontalExtent(hwnd
, wParam
, lParam
);
1941 case LB_SETITEMDATA
: return LBSetItemData(hwnd
, wParam
, lParam
);
1942 case LB_SETTABSTOPS
: return LBSetTabStops(hwnd
, wParam
, lParam
);
1943 case LB_SETCURSEL
: return LBSetCurSel(hwnd
, wParam
, lParam
);
1944 case LB_SETSEL
: return LBSetSel(hwnd
, wParam
, lParam
);
1945 case LB_SETTOPINDEX
: return LBSetTopIndex(hwnd
, wParam
, lParam
);
1946 case LB_SETITEMHEIGHT
: return LBSetItemHeight(hwnd
, wParam
, lParam
);
1948 case WM_DROPFILES
: return LBPassToParent(hwnd
, message
, wParam
, lParam
);
1950 /* these will have to be implemented for proper LBS_EXTENDEDSEL -
1952 * anchor item is an item that with caret (focused) item defines a
1953 * range of currently selected items when listbox is in the extended
1956 case LB_SETANCHORINDEX
: return LB_SETANCHORINDEX
; /* that's what Windows returns */
1957 case LB_GETANCHORINDEX
: return 0;
1960 case WM_QUERYDROPOBJECT
:
1964 LPDRAGINFO lpDragInfo
= (LPDRAGINFO
) PTR_SEG_TO_LIN((SEGPTR
)lParam
);
1965 LPHEADLIST lphl
= ListBoxGetStorageHeader(hwnd
);
1967 lpDragInfo
->l
= ListBoxFindMouse(lphl
,lpDragInfo
->pt
.x
,
1970 return LBPassToParent(hwnd
, message
, wParam
, lParam
);
1974 return DefWindowProc16(hwnd
, message
, wParam
, lParam
);
1978 /**********************************************************************
1979 * DlgDirSelect (USER.99)
1981 BOOL
DlgDirSelect( HWND hDlg
, LPSTR lpStr
, INT id
)
1986 dprintf_listbox( stddeb
, "DlgDirSelect: %04x '%s' %d\n", hDlg
, lpStr
, id
);
1987 if ((i
= SendDlgItemMessage16( hDlg
, id
, LB_GETCURSEL
, 0, 0 )) == LB_ERR
)
1989 if (!(buffer
= SEGPTR_ALLOC( 20 * sizeof(char) ))) return FALSE
;
1990 SendDlgItemMessage16(hDlg
, id
, LB_GETTEXT
, i
, (LPARAM
)SEGPTR_GET(buffer
) );
1991 if (buffer
[0] == '[') /* drive or directory */
1993 if (buffer
[1] == '-') /* drive */
1995 lpStr
[0] = buffer
[2];
1998 dprintf_listbox( stddeb
, "Returning drive '%s'\n", lpStr
);
1999 SEGPTR_FREE(buffer
);
2002 strcpy( lpStr
, buffer
+ 1 );
2003 lpStr
[strlen(lpStr
)-1] = '\\';
2004 dprintf_listbox( stddeb
, "Returning directory '%s'\n", lpStr
);
2005 SEGPTR_FREE(buffer
);
2008 strcpy( lpStr
, buffer
);
2009 dprintf_listbox( stddeb
, "Returning file '%s'\n", lpStr
);
2010 SEGPTR_FREE(buffer
);
2015 /**********************************************************************
2016 * DlgDirList (USER.100)
2018 INT
DlgDirList( HWND hDlg
, SEGPTR spec
, INT idLBox
, INT idStatic
, UINT attrib
)
2020 char *filespec
= (char *)PTR_SEG_TO_LIN( spec
);
2024 #define SENDMSG(msg,wparam,lparam) \
2025 ((attrib & DDL_POSTMSGS) ? PostMessage( hwnd, msg, wparam, lparam ) \
2026 : SendMessage16( hwnd, msg, wparam, lparam ))
2028 dprintf_listbox( stddeb
, "DlgDirList: %04x '%s' %d %d %04x\n",
2029 hDlg
, filespec
? filespec
: "NULL",
2030 idLBox
, idStatic
, attrib
);
2032 if (filespec
&& filespec
[0] && (filespec
[1] == ':'))
2034 drive
= toupper( filespec
[0] ) - 'A';
2036 if (!DRIVE_SetCurrentDrive( drive
)) return FALSE
;
2038 else drive
= DRIVE_GetCurrentDrive();
2040 if (idLBox
&& ((hwnd
= GetDlgItem( hDlg
, idLBox
)) != 0))
2044 if (!filespec
|| !filespec
[0]) strcpy( mask
, "*.*" );
2047 /* If the path exists and is a directory, chdir to it */
2048 if (DRIVE_Chdir( drive
, filespec
)) strcpy( mask
, "*.*" );
2053 if ((p2
= strrchr( p
, '\\' ))) p
= p2
+ 1;
2054 if ((p2
= strrchr( p
, '/' ))) p
= p2
+ 1;
2055 lstrcpyn32A( mask
, p
, sizeof(mask
) );
2059 if (!DRIVE_Chdir( drive
, filespec
)) return FALSE
;
2064 strcpy( (char *)PTR_SEG_TO_LIN(spec
), mask
);
2066 dprintf_listbox(stddeb
, "ListBoxDirectory: path=%c:\\%s mask=%s\n",
2067 'A' + drive
, DRIVE_GetDosCwd(drive
), mask
);
2069 SENDMSG( LB_RESETCONTENT
, 0, 0 );
2070 if ((attrib
& DDL_DIRECTORY
) && !(attrib
& DDL_EXCLUSIVE
))
2073 if (SENDMSG( LB_DIR
, attrib
& ~(DDL_DIRECTORY
| DDL_DRIVES
),
2074 (LPARAM
)spec
) == LB_ERR
) return FALSE
;
2075 if (!(temp
= SEGPTR_ALLOC( 4*sizeof(char) ))) return FALSE
;
2076 strcpy( temp
, "*.*" );
2077 /* FIXME: this won't work with PostMessage(), as temp will */
2078 /* have been freed by the time we do a DispatchMessage(). */
2079 if (SENDMSG( LB_DIR
, (attrib
& (DDL_DIRECTORY
| DDL_DRIVES
)) | DDL_EXCLUSIVE
,
2080 (LPARAM
)SEGPTR_GET(temp
) ) == LB_ERR
)
2089 if (SENDMSG( LB_DIR
, attrib
, (LPARAM
)spec
) == LB_ERR
) return FALSE
;
2093 if (idStatic
&& ((hwnd
= GetDlgItem( hDlg
, idStatic
)) != 0))
2096 int drive
= DRIVE_GetCurrentDrive();
2097 strcpy( temp
, "A:\\" );
2099 lstrcpyn32A( temp
+ 3, DRIVE_GetDosCwd(drive
), sizeof(temp
)-3 );
2101 /* Can't use PostMessage() here, because the string is on the stack */
2102 SetDlgItemText32A( hDlg
, idStatic
, temp
);