Release 961222
[wine/multimedia.git] / controls / oldlbox.c
blobc1577ce013ba520aae50482fc055c8c27805c71f
1 /*
2 * Listbox controls
3 *
4 * Copyright Martin Ayotte, 1993
5 * Constantine Sapuntzakis, 1995
6 * Alex Korobka, 1995, 1996
7 *
8 */
11 * FIXME:
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
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include "windows.h"
24 #include "win.h"
25 #include "gdi.h"
26 #include "msdos.h"
27 #include "listbox.h"
28 #include "dos_fs.h"
29 #include "drive.h"
30 #include "file.h"
31 #include "heap.h"
32 #include "stddebug.h"
33 #include "debug.h"
34 #include "xmalloc.h"
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
49 #define MATCH_EXACT 1
50 #define MATCH_NEAREST 0
52 static void ListBoxInitialize(LPHEADLIST lphl)
54 lphl->lpFirst = NULL;
55 lphl->ItemsCount = 0;
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)
66 LPHEADLIST lphl;
67 HDC32 hdc;
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;
75 lphl->iNumStops = 0;
76 lphl->TabStops = NULL;
77 lphl->hFont = GetStockObject32(SYSTEM_FONT);
78 lphl->hSelf = hwnd;
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)));
82 else
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)))
92 TEXTMETRIC16 tm;
93 GetTextMetrics16( hdc, &tm );
94 lphl->StdItemHeight = tm.tmHeight;
95 dprintf_listbox(stddeb,"CreateListBoxStruct: font height %d\n",
96 lphl->StdItemHeight);
97 ReleaseDC32( 0, hdc );
100 if (lphl->OwnerDrawn)
102 LISTSTRUCT dummyls;
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)
141 short end;
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;
150 return 1;
151 } else {
152 if (lphl->ItemFocused > end) {
153 WORD maxFirstVisible = ListMaxFirstVisible(lphl);
155 lphl->FirstVisible = lphl->ItemFocused;
157 if (lphl->FirstVisible > maxFirstVisible) {
158 lphl->FirstVisible = maxFirstVisible;
160 return 1;
163 return 0;
167 LPLISTSTRUCT ListBoxGetItem(LPHEADLIST lphl, UINT uIndex)
169 LPLISTSTRUCT lpls;
170 UINT Count = 0;
172 if (uIndex >= lphl->ItemsCount) return NULL;
174 lpls = lphl->lpFirst;
175 while (Count++ < uIndex) lpls = lpls->lpNext;
176 return lpls;
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;
190 dis.hDC = hdc;
191 dis.hwndItem = hwnd;
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 );
197 return;
199 if (itemAction == ODA_DRAWENTIRE || itemAction == ODA_SELECT) {
200 int OldBkMode;
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);
214 } else {
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;
232 int i, j;
233 POINT16 point;
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;
240 lpls = lpls->lpNext;
242 for(j = 0; j < lphl->ItemsVisible; i++, j++) {
243 if (lpls == NULL) return LB_ERR;
244 if (PtInRect16(&lpls->itemRect,point)) {
245 return i;
247 lpls = lpls->lpNext;
249 dprintf_listbox(stddeb,"ListBoxFindMouse: not found\n");
250 return LB_ERR;
253 BOOL32 lbDeleteItemNotify(LPHEADLIST lphl, LPLISTSTRUCT lpls)
255 /* called only for owner drawn listboxes */
256 BOOL32 ret;
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);
269 return ret;
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 );
307 return lplsnew;
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;
326 /* check if empty */
328 if( !lphl->ItemsCount )
329 return (exactMatch)? LB_ERR: 0;
331 /* set up variables */
333 if( exactMatch == MATCH_NEAREST )
334 startItem = 0;
335 else if( ++startItem )
337 loop = 2;
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 */
358 while ( loop-- )
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);
370 else
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) );
382 if( b == 0 )
384 SEGPTR_FREE(itemCmp);
385 return pos; /* found exact match */
387 else
388 if( b < 0 ) head = ++pos;
389 else
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;
411 HANDLE16 hStr;
412 LPSTR str;
413 UINT Count;
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");
432 return LB_ERRSPACE;
435 lplsnew->lpNext = *lppls;
436 *lppls = lplsnew;
437 lphl->ItemsCount++;
439 hStr = 0;
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;
445 strcpy(str, newstr);
446 lplsnew->itemText = str;
447 /* I'm not so sure about the next one */
448 lplsnew->mis.itemData = 0;
449 } else {
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) {
459 lpls->mis.itemID++;
462 if (lphl->needMeasure) {
463 ListBoxAskMeasure(lphl, lplsnew);
466 dprintf_listbox(stddeb,"ListBoxInsertString // count=%d\n", lphl->ItemsCount);
467 return uIndex;
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)
485 LPLISTSTRUCT lpls;
487 if (!OutStr) {
488 dprintf_listbox(stddeb, "ListBoxGetText // OutStr==NULL\n");
489 return 0;
491 *OutStr = '\0';
492 lpls = ListBoxGetItem (lphl, uIndex);
493 if (lpls == NULL) return LB_ERR;
495 if (!lphl->HasStrings) {
496 *((long *)OutStr) = lpls->mis.itemData;
497 return 4;
500 strcpy(OutStr, lpls->itemText);
501 return strlen(OutStr);
505 DWORD ListBoxGetItemData(LPHEADLIST lphl, UINT uIndex)
507 LPLISTSTRUCT lpls;
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;
521 return 1;
525 int ListBoxDeleteString(LPHEADLIST lphl, UINT uIndex)
527 LPLISTSTRUCT lpls, lpls2;
528 UINT Count;
530 if (uIndex >= lphl->ItemsCount) return LB_ERR;
532 lpls = lphl->lpFirst;
533 if (lpls == NULL) return LB_ERR;
535 if (uIndex == 0)
537 if( lphl->OwnerDrawn )
538 lbDeleteItemNotify( lphl, lpls);
539 lphl->lpFirst = lpls->lpNext;
541 else
543 LPLISTSTRUCT lpls2 = NULL;
544 for(Count = 0; Count < uIndex; Count++) {
545 if (lpls->lpNext == NULL) return LB_ERR;
547 lpls2 = lpls;
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) {
557 lpls2->mis.itemID--;
560 lphl->ItemsCount--;
562 if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
563 free(lpls);
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 */
572 LPLISTSTRUCT lpls;
573 UINT Count;
574 UINT First = nFirst + 1;
575 int s_length = 0;
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);
595 Count = 0;
596 while(lpls != NULL)
598 if (lphl->HasStrings)
600 if ( ( s_length )? !lstrncmpi32A(lpls->itemText, lpMatchStr, s_length)
601 : !lstrcmpi32A(lpls->itemText, lpMatchStr) ) return Count;
603 else
604 if ( lpls->mis.itemData == (DWORD)lpMatchStr ) return Count;
606 lpls = lpls->lpNext;
607 Count++;
610 /* Start over at top */
611 Count = 0;
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;
621 else
622 if ( lpls->mis.itemData == (DWORD)lpMatchStr ) return Count;
624 lpls = lpls->lpNext;
625 Count++;
628 return LB_ERR;
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)
643 LPLISTSTRUCT lpls;
644 int i;
646 if (lphl->ItemsCount == 0) return 0;
648 dprintf_listbox(stddeb, "ListBoxResetContent // ItemCount = %d\n",
649 lphl->ItemsCount);
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);
659 free(lpls);
661 ListBoxInitialize(lphl);
663 return TRUE;
666 /* --------------------- selection ------------------------- */
668 int ListBoxSetCurSel(LPHEADLIST lphl, WORD wIndex)
670 LPLISTSTRUCT lpls;
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;
680 lpls->itemState = 0;
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;
690 return 0;
693 return LB_ERR;
698 /* ------------------------- dir listing ------------------------ */
700 LONG ListBoxDirectory(LPHEADLIST lphl, UINT attrib, LPCSTR filespec)
702 char mask[13];
703 char* temp = NULL;
704 const char* ptr;
705 int skip, count;
706 LONG ret;
707 DOS_DIRENT entry;
708 char *path, *p;
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;
713 path = xstrdup(ptr);
714 p = strrchr( path, '/' );
715 *p++ = '\0';
716 if (!(ptr = DOSFS_ToDosFCBFormat( p )) ||
717 !(temp = SEGPTR_ALLOC( sizeof(char) * 16 )) )
719 free( path );
720 return LB_ERR;
723 strcpy( mask, ptr );
725 dprintf_listbox(stddeb, "ListBoxDirectory: path=%s mask=%s\n", path, mask);
727 skip = ret = 0;
728 attrib &= ~FA_LABEL;
729 while ((count = DOSFS_FindNext( path, mask, NULL, 0,
730 attrib, skip, &entry )) > 0)
732 skip += count;
733 if (entry.attr & FA_DIRECTORY)
735 if ((attrib & DDL_DIRECTORY) && strcmp(entry.name, ". "))
737 sprintf(temp, "[%s]", DOSFS_ToDosDTAFormat( entry.name ) );
738 AnsiLower( temp );
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 ) );
749 AnsiLower( temp );
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)
758 int x;
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;
771 free( path );
772 SEGPTR_FREE( temp );
774 return ret;
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);
784 if (lpls == NULL)
786 if (lphl->dwStyle & LBS_OWNERDRAWVARIABLE)
787 return LB_ERR;
788 else
790 GetClientRect16(lphl->hSelf,lprect);
791 lprect->bottom=lphl->StdItemHeight;
792 if (lprect->right<0) lprect->right=0;
795 else
796 *lprect = lpls->itemRect;
797 dprintf_listbox(stddeb," = %d,%d %d,%d\n", lprect->left,lprect->top,
798 lprect->right,lprect->bottom);
799 return 0;
803 int ListBoxSetItemHeight(LPHEADLIST lphl, WORD wIndex, long height)
805 LPLISTSTRUCT lpls;
807 if (!(lphl->dwStyle & LBS_OWNERDRAWVARIABLE)) {
808 lphl->StdItemHeight = (short)height;
809 return 0;
812 lpls = ListBoxGetItem(lphl, wIndex);
813 if (lpls == NULL) return LB_ERR;
815 lpls->mis.itemHeight = height;
816 return 0;
819 /* -------------------------- string search ------------------------ */
821 int ListBoxFindNextMatch(LPHEADLIST lphl, WORD wChar)
823 LPLISTSTRUCT lpls;
824 UINT count,first;
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;
835 first = count;
836 for(; lpls != NULL; lpls = lpls->lpNext, count++) {
837 if (*lpls->itemText != (char)wChar)
838 break;
839 if ((short) count > lphl->ItemFocused)
840 return count;
842 return first;