4 * Copyright Martin Ayotte, 1993
5 * Constantine Sapuntzakis, 1995
6 * Alex Korobka, 1995, 1996
12 * - proper scrolling for multicolumn style
13 * - anchor and caret for LBS_EXTENDEDSEL
14 * - proper selection with keyboard
15 * - how to handle (LBS_EXTENDEDSEL | LBS_MULTIPLESEL) style
16 * - support for LBS_NOINTEGRALHEIGHT and LBS_OWNERDRAWVARIABLE styles
36 #define LIST_HEAP_ALLOC(lphl,f,size) \
37 LOCAL_Alloc( lphl->HeapSel, LMEM_FIXED, (size) )
38 #define LIST_HEAP_FREE(lphl,handle) \
39 LOCAL_Free( lphl->HeapSel, (handle) )
40 #define LIST_HEAP_ADDR(lphl,handle) \
41 ((handle) ? PTR_SEG_OFF_TO_LIN(lphl->HeapSel, (handle)) : NULL)
43 #define LIST_HEAP_SIZE 0x10000
45 #define LBMM_EDGE 4 /* distance inside box which is same as moving mouse
46 outside box, to trigger scrolling of LB */
48 #define MATCH_SUBSTR 2
50 #define MATCH_NEAREST 0
52 static void ListBoxInitialize(LPHEADLIST lphl
)
56 lphl
->ItemsVisible
= 0;
57 lphl
->FirstVisible
= 0;
58 lphl
->ColumnsVisible
= 1;
59 lphl
->ItemsPerColumn
= 0;
60 lphl
->ItemFocused
= -1;
61 lphl
->PrevFocused
= -1;
64 void CreateListBoxStruct(HWND hwnd
, WORD CtlType
, LONG styles
, HWND parent
)
69 lphl
= (LPHEADLIST
)xmalloc(sizeof(HEADLIST
));
70 SetWindowLong32A(hwnd
, 0, (LONG
)lphl
);
71 ListBoxInitialize(lphl
);
72 lphl
->DrawCtlType
= CtlType
;
73 lphl
->CtlID
= GetWindowWord(hwnd
,GWW_ID
);
74 lphl
->bRedrawFlag
= TRUE
;
76 lphl
->TabStops
= NULL
;
77 lphl
->hFont
= GetStockObject32(SYSTEM_FONT
);
79 if (CtlType
==ODT_COMBOBOX
) /* use the "faked" style for COMBOLBOX */
80 /* LBS_SORT instead CBS_SORT e.g. */
81 lphl
->dwStyle
= MAKELONG(LOWORD(styles
),HIWORD(GetWindowLong32A(hwnd
,GWL_STYLE
)));
83 lphl
->dwStyle
= GetWindowLong32A(hwnd
,GWL_STYLE
); /* use original style dword */
84 lphl
->hParent
= parent
;
85 lphl
->StdItemHeight
= 15; /* FIXME: should get the font height */
86 lphl
->OwnerDrawn
= styles
& (LBS_OWNERDRAWFIXED
| LBS_OWNERDRAWVARIABLE
);
87 lphl
->HasStrings
= (styles
& LBS_HASSTRINGS
) || !lphl
->OwnerDrawn
;
89 /* create dummy hdc to set text height */
90 if ((hdc
= GetDC32(0)))
93 GetTextMetrics16( hdc
, &tm
);
94 lphl
->StdItemHeight
= tm
.tmHeight
;
95 dprintf_listbox(stddeb
,"CreateListBoxStruct: font height %d\n",
97 ReleaseDC32( 0, hdc
);
100 if (lphl
->OwnerDrawn
)
104 lphl
->needMeasure
= TRUE
;
105 dummyls
.mis
.CtlType
= lphl
->DrawCtlType
;
106 dummyls
.mis
.CtlID
= lphl
->CtlID
;
107 dummyls
.mis
.itemID
= -1;
108 dummyls
.mis
.itemWidth
= 0; /* ignored */
109 dummyls
.mis
.itemData
= 0;
111 ListBoxAskMeasure(lphl
,&dummyls
);
114 lphl
->HeapSel
= GlobalAlloc16(GMEM_FIXED
,LIST_HEAP_SIZE
);
115 LocalInit( lphl
->HeapSel
, 0, LIST_HEAP_SIZE
-1);
118 /* Send notification "code" as part of a WM_COMMAND-message if hwnd
119 has the LBS_NOTIFY style */
120 void ListBoxSendNotification(LPHEADLIST lphl
, WORD code
)
122 if (lphl
->dwStyle
& LBS_NOTIFY
)
123 SendMessage32A( lphl
->hParent
, WM_COMMAND
,
124 MAKEWPARAM( lphl
->CtlID
, code
), (LPARAM
)lphl
->hSelf
);
128 /* get the maximum value of lphl->FirstVisible */
129 int ListMaxFirstVisible(LPHEADLIST lphl
)
131 int m
= lphl
->ItemsCount
-lphl
->ItemsVisible
;
132 return (m
< 0) ? 0 : m
;
136 /* Returns: 0 if nothing needs to be changed */
137 /* 1 if FirstVisible changed */
139 int ListBoxScrollToFocus(LPHEADLIST lphl
)
143 if (lphl
->ItemsCount
== 0) return 0;
144 if (lphl
->ItemFocused
== -1) return 0;
146 end
= lphl
->FirstVisible
+ lphl
->ItemsVisible
- 1;
148 if (lphl
->ItemFocused
< lphl
->FirstVisible
) {
149 lphl
->FirstVisible
= lphl
->ItemFocused
;
152 if (lphl
->ItemFocused
> end
) {
153 WORD maxFirstVisible
= ListMaxFirstVisible(lphl
);
155 lphl
->FirstVisible
= lphl
->ItemFocused
;
157 if (lphl
->FirstVisible
> maxFirstVisible
) {
158 lphl
->FirstVisible
= maxFirstVisible
;
167 LPLISTSTRUCT
ListBoxGetItem(LPHEADLIST lphl
, UINT uIndex
)
172 if (uIndex
>= lphl
->ItemsCount
) return NULL
;
174 lpls
= lphl
->lpFirst
;
175 while (Count
++ < uIndex
) lpls
= lpls
->lpNext
;
180 void ListBoxDrawItem(HWND hwnd
, LPHEADLIST lphl
, HDC16 hdc
, LPLISTSTRUCT lpls
,
181 RECT16
*rect
, WORD itemAction
, WORD itemState
)
183 if (lphl
->OwnerDrawn
)
185 DRAWITEMSTRUCT32 dis
;
187 dis
.CtlID
= lpls
->mis
.CtlID
;
188 dis
.CtlType
= lpls
->mis
.CtlType
;
189 dis
.itemID
= lpls
->mis
.itemID
;
192 dis
.itemData
= lpls
->mis
.itemData
;
193 dis
.itemAction
= itemAction
;
194 dis
.itemState
= itemState
;
195 CONV_RECT16TO32( rect
, &dis
.rcItem
);
196 SendMessage32A( lphl
->hParent
, WM_DRAWITEM
, dis
.CtlID
, (LPARAM
)&dis
);
199 if (itemAction
== ODA_DRAWENTIRE
|| itemAction
== ODA_SELECT
) {
201 DWORD dwOldTextColor
= 0;
203 OldBkMode
= SetBkMode32(hdc
, TRANSPARENT
);
205 if (itemState
!= 0) {
206 dwOldTextColor
= SetTextColor(hdc
, 0x00FFFFFFL
);
207 FillRect16(hdc
, rect
, GetStockObject32(BLACK_BRUSH
));
210 if (lphl
->dwStyle
& LBS_USETABSTOPS
) {
211 TabbedTextOut(hdc
, rect
->left
+ 5, rect
->top
+ 2,
212 (char *)lpls
->itemText
, strlen((char *)lpls
->itemText
),
213 lphl
->iNumStops
, lphl
->TabStops
, 0);
215 TextOut16(hdc
, rect
->left
+ 5, rect
->top
+ 2,
216 (char *)lpls
->itemText
, strlen((char *)lpls
->itemText
));
219 if (itemState
!= 0) {
220 SetTextColor(hdc
, dwOldTextColor
);
223 SetBkMode32(hdc
, OldBkMode
);
225 else DrawFocusRect16(hdc
, rect
);
229 int ListBoxFindMouse(LPHEADLIST lphl
, int X
, int Y
)
231 LPLISTSTRUCT lpls
= lphl
->lpFirst
;
235 point
.x
= X
; point
.y
= Y
;
236 if (lphl
->ItemsCount
== 0) return LB_ERR
;
238 for(i
= 0; i
< lphl
->FirstVisible
; i
++) {
239 if (lpls
== NULL
) return LB_ERR
;
242 for(j
= 0; j
< lphl
->ItemsVisible
; i
++, j
++) {
243 if (lpls
== NULL
) return LB_ERR
;
244 if (PtInRect16(&lpls
->itemRect
,point
)) {
249 dprintf_listbox(stddeb
,"ListBoxFindMouse: not found\n");
253 BOOL32
lbDeleteItemNotify(LPHEADLIST lphl
, LPLISTSTRUCT lpls
)
255 /* called only for owner drawn listboxes */
257 DELETEITEMSTRUCT16
*delItem
= SEGPTR_NEW(DELETEITEMSTRUCT16
);
258 if (!delItem
) return FALSE
;
260 delItem
->CtlType
= lphl
->DrawCtlType
;
261 delItem
->CtlID
= lphl
->CtlID
;
262 delItem
->itemID
= lpls
->mis
.itemID
;
263 delItem
->hwndItem
= lphl
->hSelf
;
264 delItem
->itemData
= lpls
->mis
.itemData
;
266 ret
= SendMessage16( lphl
->hParent
, WM_DELETEITEM
, (WPARAM16
)lphl
->CtlID
,
267 (LPARAM
)SEGPTR_GET(delItem
) );
268 SEGPTR_FREE(delItem
);
272 /* -------------------- strings and item data ---------------------- */
274 void ListBoxAskMeasure(LPHEADLIST lphl
, LPLISTSTRUCT lpls
)
276 MEASUREITEMSTRUCT16
*lpmeasure
= SEGPTR_NEW(MEASUREITEMSTRUCT16
);
277 if (!lpmeasure
) return;
278 *lpmeasure
= lpls
->mis
;
279 lpmeasure
->itemHeight
= lphl
->StdItemHeight
;
280 SendMessage16( lphl
->hParent
, WM_MEASUREITEM
, lphl
->CtlID
,
281 (LPARAM
)SEGPTR_GET(lpmeasure
) );
283 if (lphl
->dwStyle
& LBS_OWNERDRAWFIXED
)
285 if (lpmeasure
->itemHeight
> lphl
->StdItemHeight
)
286 lphl
->StdItemHeight
= lpmeasure
->itemHeight
;
287 lpls
->mis
.itemHeight
= lpmeasure
->itemHeight
;
289 SEGPTR_FREE(lpmeasure
);
292 static LPLISTSTRUCT
ListBoxCreateItem(LPHEADLIST lphl
, int id
)
294 LPLISTSTRUCT lplsnew
= (LPLISTSTRUCT
)malloc(sizeof(LISTSTRUCT
));
296 if (lplsnew
== NULL
) return NULL
;
298 lplsnew
->itemState
= 0;
299 lplsnew
->mis
.CtlType
= lphl
->DrawCtlType
;
300 lplsnew
->mis
.CtlID
= lphl
->CtlID
;
301 lplsnew
->mis
.itemID
= id
;
302 lplsnew
->mis
.itemHeight
= lphl
->StdItemHeight
;
303 lplsnew
->mis
.itemWidth
= 0; /* ignored */
304 lplsnew
->mis
.itemData
= 0;
305 SetRectEmpty16( &lplsnew
->itemRect
);
310 static int ListBoxAskCompare(LPHEADLIST lphl
, int startItem
, SEGPTR matchData
, BOOL exactMatch
)
312 /* Do binary search for sorted listboxes. Linked list item storage sort of
313 * defeats the purpose ( forces to traverse item list all the time ) but M$ does it this way...
315 * MATCH_NEAREST (0) - return position for insertion - for all styles
316 * MATCH_EXACT (1) - search for an item, return index or LB_ERR
317 * MATCH_SUBSTR (2) - same as exact match but with strncmp for string comparision
320 COMPAREITEMSTRUCT16
*itemCmp
;
321 LPLISTSTRUCT currentItem
= NULL
;
322 LPCSTR matchStr
= (lphl
->HasStrings
)?(LPCSTR
)PTR_SEG_TO_LIN(matchData
):NULL
;
323 int head
, pos
= -1, tail
, loop
= 1;
324 short b
= 0, s_length
= 0;
328 if( !lphl
->ItemsCount
)
329 return (exactMatch
)? LB_ERR
: 0;
331 /* set up variables */
333 if( exactMatch
== MATCH_NEAREST
)
335 else if( ++startItem
)
338 if( startItem
>= lphl
->ItemsCount
) startItem
= lphl
->ItemsCount
- 1;
341 if( exactMatch
== MATCH_SUBSTR
&& lphl
->HasStrings
)
343 s_length
= strlen( matchStr
);
344 if( !s_length
) return 0; /* head of the list - empty string */
347 head
= startItem
; tail
= lphl
->ItemsCount
- 1;
349 dprintf_listbox(stddeb
,"AskCompare: head = %i, tail = %i, data = %08x\n", head
, tail
, (unsigned)matchData
);
351 if (!(itemCmp
= SEGPTR_NEW(COMPAREITEMSTRUCT16
))) return 0;
352 itemCmp
->CtlType
= lphl
->DrawCtlType
;
353 itemCmp
->CtlID
= lphl
->CtlID
;
354 itemCmp
->hwndItem
= lphl
->hSelf
;
356 /* search from startItem */
360 while( head
<= tail
)
362 pos
= (tail
+ head
)/2;
363 currentItem
= ListBoxGetItem( lphl
, pos
);
365 if( lphl
->HasStrings
)
367 b
= ( s_length
)? lstrncmpi32A( currentItem
->itemText
, matchStr
, s_length
)
368 : lstrcmpi32A( currentItem
->itemText
, matchStr
);
372 itemCmp
->itemID1
= pos
;
373 itemCmp
->itemData1
= currentItem
->mis
.itemData
;
374 itemCmp
->itemID2
= -1;
375 itemCmp
->itemData2
= matchData
;
377 b
= SendMessage16( lphl
->hParent
, WM_COMPAREITEM
,
378 (WPARAM16
)lphl
->CtlID
,
379 (LPARAM
)SEGPTR_GET(itemCmp
) );
384 SEGPTR_FREE(itemCmp
);
385 return pos
; /* found exact match */
388 if( b
< 0 ) head
= ++pos
;
390 if( b
> 0 ) tail
= pos
- 1;
393 /* reset to search from the first item */
394 head
= 0; tail
= startItem
- 1;
397 dprintf_listbox(stddeb
,"\t-> pos = %i\n", pos
);
398 SEGPTR_FREE(itemCmp
);
400 /* if we got here match is not exact */
402 if( pos
< 0 ) pos
= 0;
403 else if( pos
> lphl
->ItemsCount
) pos
= lphl
->ItemsCount
;
405 return (exactMatch
)? LB_ERR
: pos
;
408 int ListBoxInsertString(LPHEADLIST lphl
, UINT uIndex
, LPCSTR newstr
)
410 LPLISTSTRUCT
*lppls
, lplsnew
, lpls
;
415 dprintf_listbox(stddeb
,"ListBoxInsertString(%d, %p);\n", uIndex
, newstr
);
417 if (!newstr
) return -1;
419 if (uIndex
== (UINT
)-1)
420 uIndex
= lphl
->ItemsCount
;
422 lppls
= &lphl
->lpFirst
;
423 for(Count
= 0; Count
< uIndex
; Count
++) {
424 if (*lppls
== NULL
) return LB_ERR
;
425 lppls
= (LPLISTSTRUCT
*) &(*lppls
)->lpNext
;
428 lplsnew
= ListBoxCreateItem(lphl
, Count
);
430 if (lplsnew
== NULL
) {
431 fprintf(stdnimp
,"ListBoxInsertString() out of memory !\n");
435 lplsnew
->lpNext
= *lppls
;
440 if (lphl
->HasStrings
) {
441 dprintf_listbox(stddeb
," string: %s\n", newstr
);
442 hStr
= LIST_HEAP_ALLOC(lphl
, LMEM_MOVEABLE
, strlen(newstr
) + 1);
443 str
= (LPSTR
)LIST_HEAP_ADDR(lphl
, hStr
);
444 if (str
== NULL
) return LB_ERRSPACE
;
446 lplsnew
->itemText
= str
;
447 /* I'm not so sure about the next one */
448 lplsnew
->mis
.itemData
= 0;
450 lplsnew
->itemText
= NULL
;
451 lplsnew
->mis
.itemData
= (DWORD
)newstr
;
454 lplsnew
->mis
.itemID
= uIndex
;
455 lplsnew
->hData
= hStr
;
457 /* adjust the itemID field of the following entries */
458 for(lpls
= lplsnew
->lpNext
; lpls
!= NULL
; lpls
= lpls
->lpNext
) {
462 if (lphl
->needMeasure
) {
463 ListBoxAskMeasure(lphl
, lplsnew
);
466 dprintf_listbox(stddeb
,"ListBoxInsertString // count=%d\n", lphl
->ItemsCount
);
471 int ListBoxAddString(LPHEADLIST lphl
, SEGPTR itemData
)
473 UINT pos
= (UINT
) -1;
474 LPCSTR newstr
= (lphl
->HasStrings
)?(LPCSTR
)PTR_SEG_TO_LIN(itemData
):(LPCSTR
)itemData
;
476 if ( lphl
->dwStyle
& LBS_SORT
)
477 pos
= ListBoxAskCompare( lphl
, -1, itemData
, MATCH_NEAREST
);
479 return ListBoxInsertString(lphl
, pos
, newstr
);
483 int ListBoxGetText(LPHEADLIST lphl
, UINT uIndex
, LPSTR OutStr
)
488 dprintf_listbox(stddeb
, "ListBoxGetText // OutStr==NULL\n");
492 lpls
= ListBoxGetItem (lphl
, uIndex
);
493 if (lpls
== NULL
) return LB_ERR
;
495 if (!lphl
->HasStrings
) {
496 *((long *)OutStr
) = lpls
->mis
.itemData
;
500 strcpy(OutStr
, lpls
->itemText
);
501 return strlen(OutStr
);
505 DWORD
ListBoxGetItemData(LPHEADLIST lphl
, UINT uIndex
)
509 lpls
= ListBoxGetItem (lphl
, uIndex
);
510 if (lpls
== NULL
) return LB_ERR
;
511 return lpls
->mis
.itemData
;
515 int ListBoxSetItemData(LPHEADLIST lphl
, UINT uIndex
, DWORD ItemData
)
517 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
, uIndex
);
519 if (lpls
== NULL
) return LB_ERR
;
520 lpls
->mis
.itemData
= ItemData
;
525 int ListBoxDeleteString(LPHEADLIST lphl
, UINT uIndex
)
527 LPLISTSTRUCT lpls
, lpls2
;
530 if (uIndex
>= lphl
->ItemsCount
) return LB_ERR
;
532 lpls
= lphl
->lpFirst
;
533 if (lpls
== NULL
) return LB_ERR
;
537 if( lphl
->OwnerDrawn
)
538 lbDeleteItemNotify( lphl
, lpls
);
539 lphl
->lpFirst
= lpls
->lpNext
;
543 LPLISTSTRUCT lpls2
= NULL
;
544 for(Count
= 0; Count
< uIndex
; Count
++) {
545 if (lpls
->lpNext
== NULL
) return LB_ERR
;
548 lpls
= (LPLISTSTRUCT
)lpls
->lpNext
;
550 if( lphl
->OwnerDrawn
)
551 lbDeleteItemNotify( lphl
, lpls
);
552 lpls2
->lpNext
= lpls
->lpNext
;
555 /* adjust the itemID field of the following entries */
556 for(lpls2
= lpls
->lpNext
; lpls2
!= NULL
; lpls2
= lpls2
->lpNext
) {
562 if (lpls
->hData
!= 0) LIST_HEAP_FREE(lphl
, lpls
->hData
);
565 return lphl
->ItemsCount
;
568 static int lbFindString(LPHEADLIST lphl
, UINT nFirst
, SEGPTR MatchStr
, BOOL match
)
570 /* match is either MATCH_SUBSTR or MATCH_EXACT */
574 UINT First
= nFirst
+ 1;
576 LPSTR lpMatchStr
= (LPSTR
)MatchStr
;
578 if (First
> lphl
->ItemsCount
) return LB_ERR
;
580 if (lphl
->dwStyle
& LBS_SORT
)
581 return ListBoxAskCompare( lphl
, nFirst
, MatchStr
, match
);
583 if (lphl
->HasStrings
)
585 lpMatchStr
= PTR_SEG_TO_LIN(MatchStr
);
587 if( match
== MATCH_SUBSTR
)
589 s_length
= strlen(lpMatchStr
);
590 if( !s_length
) return (lphl
->ItemsCount
)?0:LB_ERR
;
594 lpls
= ListBoxGetItem(lphl
, First
);
598 if (lphl
->HasStrings
)
600 if ( ( s_length
)? !lstrncmpi32A(lpls
->itemText
, lpMatchStr
, s_length
)
601 : !lstrcmpi32A(lpls
->itemText
, lpMatchStr
) ) return Count
;
604 if ( lpls
->mis
.itemData
== (DWORD
)lpMatchStr
) return Count
;
610 /* Start over at top */
612 lpls
= lphl
->lpFirst
;
614 while (Count
< First
)
616 if (lphl
->HasStrings
)
618 if ( ( s_length
)? !lstrncmpi32A(lpls
->itemText
, lpMatchStr
, s_length
)
619 : !lstrcmpi32A(lpls
->itemText
, lpMatchStr
) ) return Count
;
622 if ( lpls
->mis
.itemData
== (DWORD
)lpMatchStr
) return Count
;
631 int ListBoxFindString(LPHEADLIST lphl
, UINT nFirst
, SEGPTR MatchStr
)
633 return lbFindString(lphl
, nFirst
, MatchStr
, MATCH_SUBSTR
);
636 int ListBoxFindStringExact(LPHEADLIST lphl
, UINT nFirst
, SEGPTR MatchStr
)
638 return lbFindString(lphl
, nFirst
, MatchStr
, MATCH_EXACT
);
641 int ListBoxResetContent(LPHEADLIST lphl
)
646 if (lphl
->ItemsCount
== 0) return 0;
648 dprintf_listbox(stddeb
, "ListBoxResetContent // ItemCount = %d\n",
651 for(i
= 0; i
< lphl
->ItemsCount
; i
++) {
652 lpls
= lphl
->lpFirst
;
653 if (lpls
== NULL
) return LB_ERR
;
655 if (lphl
->OwnerDrawn
) lbDeleteItemNotify(lphl
, lpls
);
657 lphl
->lpFirst
= lpls
->lpNext
;
658 if (lpls
->hData
!= 0) LIST_HEAP_FREE(lphl
, lpls
->hData
);
661 ListBoxInitialize(lphl
);
666 /* --------------------- selection ------------------------- */
668 int ListBoxSetCurSel(LPHEADLIST lphl
, WORD wIndex
)
672 /* use ListBoxSetSel instead */
673 if (lphl
->dwStyle
& (LBS_MULTIPLESEL
| LBS_EXTENDEDSEL
) ) return 0;
675 /* unselect previous item */
676 if (lphl
->ItemFocused
!= -1) {
677 lphl
->PrevFocused
= lphl
->ItemFocused
;
678 lpls
= ListBoxGetItem(lphl
, lphl
->ItemFocused
);
679 if (lpls
== 0) return LB_ERR
;
683 if ((wIndex
!= (UINT
)-1) && (wIndex
< lphl
->ItemsCount
))
685 lphl
->ItemFocused
= wIndex
;
686 lpls
= ListBoxGetItem(lphl
, wIndex
);
687 if (lpls
== 0) return LB_ERR
;
688 lpls
->itemState
= ODS_SELECTED
| ODS_FOCUS
;
698 /* ------------------------- dir listing ------------------------ */
700 LONG
ListBoxDirectory(LPHEADLIST lphl
, UINT attrib
, LPCSTR filespec
)
710 dprintf_listbox(stddeb
, "ListBoxDirectory: '%s' %04x\n", filespec
, attrib
);
711 if (!filespec
) return LB_ERR
;
712 if (!(ptr
= DOSFS_GetUnixFileName( filespec
, FALSE
))) return LB_ERR
;
714 p
= strrchr( path
, '/' );
716 if (!(ptr
= DOSFS_ToDosFCBFormat( p
)) ||
717 !(temp
= SEGPTR_ALLOC( sizeof(char) * 16 )) )
725 dprintf_listbox(stddeb
, "ListBoxDirectory: path=%s mask=%s\n", path
, mask
);
729 while ((count
= DOSFS_FindNext( path
, mask
, NULL
, 0,
730 attrib
, skip
, &entry
)) > 0)
733 if (entry
.attr
& FA_DIRECTORY
)
735 if ((attrib
& DDL_DIRECTORY
) && strcmp(entry
.name
, ". "))
737 sprintf(temp
, "[%s]", DOSFS_ToDosDTAFormat( entry
.name
) );
739 if ((ret
= ListBoxAddString(lphl
, SEGPTR_GET(temp
))) == LB_ERR
) break;
742 else /* not a directory */
744 if (!(attrib
& DDL_EXCLUSIVE
) ||
745 ((attrib
& (FA_RDONLY
|FA_HIDDEN
|FA_SYSTEM
|FA_ARCHIVE
)) ==
746 (entry
.attr
& (FA_RDONLY
|FA_HIDDEN
|FA_SYSTEM
|FA_ARCHIVE
))))
748 strcpy( temp
, DOSFS_ToDosDTAFormat( entry
.name
) );
750 if ((ret
= ListBoxAddString(lphl
, SEGPTR_GET(temp
))) == LB_ERR
) break;
754 dprintf_listbox(stddeb
,"\tn - %i, file '%s'\n", count
, temp
);
756 if (attrib
& DDL_DRIVES
)
759 DWORD oldstyle
= lphl
->dwStyle
;
761 lphl
->dwStyle
&= ~LBS_SORT
;
762 strcpy( temp
, "[-a-]" );
763 for (x
= 0; x
< MAX_DOS_DRIVES
; x
++, temp
[2]++)
765 if (DRIVE_IsValid(x
))
766 if ((ret
= ListBoxAddString(lphl
, SEGPTR_GET(temp
))) == LB_ERR
) break;
768 lphl
->dwStyle
= oldstyle
;
777 /* ------------------------- dimensions ------------------------- */
779 int ListBoxGetItemRect(LPHEADLIST lphl
, WORD wIndex
, LPRECT16 lprect
)
781 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
,wIndex
);
783 dprintf_listbox(stddeb
,"ListBox LB_GETITEMRECT %i %p", wIndex
,lpls
);
786 if (lphl
->dwStyle
& LBS_OWNERDRAWVARIABLE
)
790 GetClientRect16(lphl
->hSelf
,lprect
);
791 lprect
->bottom
=lphl
->StdItemHeight
;
792 if (lprect
->right
<0) lprect
->right
=0;
796 *lprect
= lpls
->itemRect
;
797 dprintf_listbox(stddeb
," = %d,%d %d,%d\n", lprect
->left
,lprect
->top
,
798 lprect
->right
,lprect
->bottom
);
803 int ListBoxSetItemHeight(LPHEADLIST lphl
, WORD wIndex
, long height
)
807 if (!(lphl
->dwStyle
& LBS_OWNERDRAWVARIABLE
)) {
808 lphl
->StdItemHeight
= (short)height
;
812 lpls
= ListBoxGetItem(lphl
, wIndex
);
813 if (lpls
== NULL
) return LB_ERR
;
815 lpls
->mis
.itemHeight
= height
;
819 /* -------------------------- string search ------------------------ */
821 int ListBoxFindNextMatch(LPHEADLIST lphl
, WORD wChar
)
826 if ((char)wChar
< ' ') return LB_ERR
;
827 if (!lphl
->HasStrings
) return LB_ERR
;
829 lpls
= lphl
->lpFirst
;
831 for (count
= 0; lpls
!= NULL
; lpls
= lpls
->lpNext
, count
++) {
832 if (tolower(*lpls
->itemText
) == tolower((char)wChar
)) break;
834 if (lpls
== NULL
) return LB_ERR
;
836 for(; lpls
!= NULL
; lpls
= lpls
->lpNext
, count
++) {
837 if (*lpls
->itemText
!= (char)wChar
)
839 if ((short) count
> lphl
->ItemFocused
)