Release 940405
[wine] / controls / listbox.c
1 /*
2  * Interface code to listbox widgets
3  *
4  * Copyright  Martin Ayotte, 1993
5  *
6  */
7
8 /*
9 #define DEBUG_LISTBOX
10 */
11
12 static char Copyright[] = "Copyright Martin Ayotte, 1993";
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include "windows.h"
19 #include "user.h"
20 #include "heap.h"
21 #include "win.h"
22 #include "msdos.h"
23 #include "wine.h"
24 #include "listbox.h"
25 #include "scroll.h"
26 #include "prototypes.h"
27
28 #define GMEM_ZEROINIT 0x0040
29
30
31 LPHEADLIST ListBoxGetWindowAndStorage(HWND hwnd, WND **wndPtr);
32 LPHEADLIST ListBoxGetStorageHeader(HWND hwnd);
33 void StdDrawListBox(HWND hwnd);
34 void OwnerDrawListBox(HWND hwnd);
35 int ListBoxFindMouse(HWND hwnd, int X, int Y);
36 int CreateListBoxStruct(HWND hwnd);
37 void ListBoxAskMeasure(WND *wndPtr, LPHEADLIST lphl, LPLISTSTRUCT lpls);
38 int ListBoxAddString(HWND hwnd, LPSTR newstr);
39 int ListBoxInsertString(HWND hwnd, UINT uIndex, LPSTR newstr);
40 int ListBoxGetText(HWND hwnd, UINT uIndex, LPSTR OutStr);
41 int ListBoxDeleteString(HWND hwnd, UINT uIndex);
42 int ListBoxFindString(HWND hwnd, UINT nFirst, LPSTR MatchStr);
43 int ListBoxResetContent(HWND hwnd);
44 int ListBoxSetCurSel(HWND hwnd, WORD wIndex);
45 int ListBoxSetSel(HWND hwnd, WORD wIndex, WORD state);
46 int ListBoxGetSel(HWND hwnd, WORD wIndex);
47 int ListBoxDirectory(HWND hwnd, UINT attrib, LPSTR filespec);
48 int ListBoxGetItemRect(HWND hwnd, WORD wIndex, LPRECT rect);
49 int ListBoxSetItemHeight(HWND hwnd, WORD wIndex, long height);
50 int ListBoxDefaultItem(HWND hwnd, WND *wndPtr, 
51         LPHEADLIST lphl, LPLISTSTRUCT lpls);
52 int ListBoxFindNextMatch(HWND hwnd, WORD wChar);
53
54
55 /***********************************************************************
56  *           ListBoxWndProc 
57  */
58 LONG ListBoxWndProc( HWND hwnd, WORD message, WORD wParam, LONG lParam )
59 {    
60         WND  *wndPtr;
61         LPHEADLIST  lphl;
62         HWND    hWndCtl;
63         WORD    wRet;
64         RECT    rect;
65         int             y;
66         CREATESTRUCT *createStruct;
67         static RECT rectsel;
68     switch(message) {
69         case WM_CREATE:
70                 CreateListBoxStruct(hwnd);
71                 lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
72 #ifdef DEBUG_LISTBOX
73                 printf("ListBox WM_CREATE %lX !\n", lphl);
74 #endif
75                 createStruct = (CREATESTRUCT *)lParam;
76                 if (HIWORD(createStruct->lpCreateParams) != 0)
77                         lphl->hWndLogicParent = (HWND)HIWORD(createStruct->lpCreateParams);
78                 else
79                         lphl->hWndLogicParent = GetParent(hwnd);
80                 lphl->ColumnsWidth = wndPtr->rectClient.right - wndPtr->rectClient.left;
81                 if (wndPtr->dwStyle & WS_VSCROLL) {
82                         SetScrollRange(hwnd, SB_VERT, 1, lphl->ItemsCount, TRUE);
83                         ShowScrollBar(hwnd, SB_VERT, FALSE);
84                         }
85                 if (wndPtr->dwStyle & WS_HSCROLL) {
86                         SetScrollRange(hwnd, SB_HORZ, 1, 1, TRUE);
87                         ShowScrollBar(hwnd, SB_HORZ, FALSE);
88                         }
89                 if ((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) == LBS_OWNERDRAWFIXED) {
90                         }
91                 return 0;
92         case WM_DESTROY:
93                 lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
94                 if (lphl == 0) return 0;
95                 ListBoxResetContent(hwnd);
96                 free(lphl);
97                 *((LPHEADLIST *)&wndPtr->wExtra[1]) = 0;
98 #ifdef DEBUG_LISTBOX
99                 printf("ListBox WM_DESTROY %lX !\n", lphl);
100 #endif
101                 return 0;
102
103         case WM_VSCROLL:
104 #ifdef DEBUG_LISTBOX
105                 printf("ListBox WM_VSCROLL w=%04X l=%08X !\n", wParam, lParam);
106 #endif
107                 lphl = ListBoxGetStorageHeader(hwnd);
108                 if (lphl == NULL) return 0;
109                 y = lphl->FirstVisible;
110                 switch(wParam) {
111                         case SB_LINEUP:
112                                 if (lphl->FirstVisible > 1)     
113                                         lphl->FirstVisible--;
114                                 break;
115                         case SB_LINEDOWN:
116                                 if (lphl->FirstVisible < lphl->ItemsCount)
117                                         lphl->FirstVisible++;
118                                 break;
119                         case SB_PAGEUP:
120                                 if (lphl->FirstVisible > 1)  
121                                         lphl->FirstVisible -= lphl->ItemsVisible;
122                                 break;
123                         case SB_PAGEDOWN:
124                                 if (lphl->FirstVisible < lphl->ItemsCount)  
125                                         lphl->FirstVisible += lphl->ItemsVisible;
126                                 break;
127                         case SB_THUMBTRACK:
128                                 lphl->FirstVisible = LOWORD(lParam);
129                                 break;
130                         }
131                 if (lphl->FirstVisible < 1)    lphl->FirstVisible = 1;
132                 if (lphl->FirstVisible > lphl->ItemsCount)
133                         lphl->FirstVisible = lphl->ItemsCount;
134                 if (y != lphl->FirstVisible) {
135                         SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
136                         InvalidateRect(hwnd, NULL, TRUE);
137                         UpdateWindow(hwnd);
138                         }
139                 return 0;
140         
141         case WM_HSCROLL:
142 #ifdef DEBUG_LISTBOX
143                 printf("ListBox WM_HSCROLL w=%04X l=%08X !\n", wParam, lParam);
144 #endif
145                 lphl = ListBoxGetStorageHeader(hwnd);
146                 if (lphl == NULL) return 0;
147                 y = lphl->FirstVisible;
148                 switch(wParam) {
149                         case SB_LINEUP:
150                                 if (lphl->FirstVisible > 1)
151                                         lphl->FirstVisible -= lphl->ItemsPerColumn;
152                                 break;
153                         case SB_LINEDOWN:
154                                 if (lphl->FirstVisible < lphl->ItemsCount)
155                                         lphl->FirstVisible += lphl->ItemsPerColumn;
156                                 break;
157                         case SB_PAGEUP:
158                                 if (lphl->FirstVisible > 1 && lphl->ItemsPerColumn != 0)  
159                                         lphl->FirstVisible -= lphl->ItemsVisible /
160                                         lphl->ItemsPerColumn * lphl->ItemsPerColumn;
161                                 break;
162                         case SB_PAGEDOWN:
163                                 if (lphl->FirstVisible < lphl->ItemsCount &&
164                                                         lphl->ItemsPerColumn != 0)  
165                                         lphl->FirstVisible += lphl->ItemsVisible /
166                                         lphl->ItemsPerColumn * lphl->ItemsPerColumn;
167                                 break;
168                         case SB_THUMBTRACK:
169                                 lphl->FirstVisible = lphl->ItemsPerColumn * 
170                                                                 (LOWORD(lParam) - 1) + 1;
171                                 break;
172                         }
173                 if (lphl->FirstVisible < 1)    lphl->FirstVisible = 1;
174                 if (lphl->FirstVisible > lphl->ItemsCount)
175                         lphl->FirstVisible = lphl->ItemsCount;
176                 if (lphl->ItemsPerColumn != 0) {
177                         lphl->FirstVisible = lphl->FirstVisible /
178                                 lphl->ItemsPerColumn * lphl->ItemsPerColumn + 1;
179                         if (y != lphl->FirstVisible) {
180                                 SetScrollPos(hwnd, SB_HORZ, lphl->FirstVisible / 
181                                 lphl->ItemsPerColumn + 1, TRUE);
182                                 InvalidateRect(hwnd, NULL, TRUE);
183                                 UpdateWindow(hwnd);
184                                 }
185                         }
186                 return 0;
187         
188         case WM_LBUTTONDOWN:
189                 SetFocus(hwnd);
190                 SetCapture(hwnd);
191                 lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
192                 if (lphl == NULL) return 0;
193                 lphl->PrevFocused = lphl->ItemFocused;
194                 y = ListBoxFindMouse(hwnd, LOWORD(lParam), HIWORD(lParam));
195                 if ((wndPtr->dwStyle & LBS_MULTIPLESEL) == LBS_MULTIPLESEL) {
196                     lphl->ItemFocused = y;
197                     wRet = ListBoxGetSel(hwnd, y);
198                     ListBoxSetSel(hwnd, y, !wRet);
199                     }
200                 else {
201                     ListBoxSetCurSel(hwnd, y);
202                     }
203                 ListBoxGetItemRect(hwnd, y, &rectsel);
204                 InvalidateRect(hwnd, NULL, TRUE);
205                 UpdateWindow(hwnd);
206                 return 0;
207         case WM_LBUTTONUP:
208                 ReleaseCapture();
209                 lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
210                 if (lphl == NULL) return 0;
211                 if (lphl->PrevFocused != lphl->ItemFocused)
212                         SendMessage(lphl->hWndLogicParent, WM_COMMAND, wndPtr->wIDmenu,
213                                                                                         MAKELONG(hwnd, LBN_SELCHANGE));
214                 return 0;
215         case WM_RBUTTONUP:
216         case WM_LBUTTONDBLCLK:
217                 lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
218                 if (lphl == NULL) return 0;
219                 SendMessage(lphl->hWndLogicParent, WM_COMMAND, wndPtr->wIDmenu,
220                                                                                 MAKELONG(hwnd, LBN_DBLCLK));
221                 printf("ListBox Send LBN_DBLCLK !\n");
222                 return 0;
223         case WM_MOUSEMOVE:
224                 if ((wParam & MK_LBUTTON) != 0) {
225                         y = HIWORD(lParam);
226                         if (y < 4) {
227                                 lphl = ListBoxGetStorageHeader(hwnd);
228                                 if (lphl->FirstVisible > 1) {
229                                         lphl->FirstVisible--;
230                                         if (wndPtr->dwStyle & WS_VSCROLL)
231                                         SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
232                                         InvalidateRect(hwnd, NULL, TRUE);
233                                         UpdateWindow(hwnd);
234                                         break;
235                                         }
236                                 }
237                         GetClientRect(hwnd, &rect);
238                         if (y > (rect.bottom - 4)) {
239                                 lphl = ListBoxGetStorageHeader(hwnd);
240                                 if (lphl->FirstVisible < lphl->ItemsCount) {
241                                         lphl->FirstVisible++;
242                                         if (wndPtr->dwStyle & WS_VSCROLL)
243                                         SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
244                                         InvalidateRect(hwnd, NULL, TRUE);
245                                         UpdateWindow(hwnd);
246                                         break;
247                                         }
248                                 }
249                         if ((y > 0) && (y < (rect.bottom - 4))) {
250                                 if ((y < rectsel.top) || (y > rectsel.bottom)) {
251                                         wRet = ListBoxFindMouse(hwnd, LOWORD(lParam), HIWORD(lParam));
252                                         if ((wndPtr->dwStyle & LBS_MULTIPLESEL) == LBS_MULTIPLESEL) {
253                                                 lphl->ItemFocused = wRet;
254                                                 }
255                                         else {
256                                                 ListBoxSetCurSel(hwnd, wRet);
257                                                 }
258                                         ListBoxGetItemRect(hwnd, wRet, &rectsel);
259                                         InvalidateRect(hwnd, NULL, TRUE);
260                                         UpdateWindow(hwnd);
261                                         }
262                                 }
263                         }
264                 break;
265         case WM_KEYDOWN:
266                 lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
267                 if (lphl == NULL) return 0;
268                 switch(wParam) {
269                         case VK_TAB:
270                                 hWndCtl = GetNextDlgTabItem(lphl->hWndLogicParent,
271                                         hwnd, !(GetKeyState(VK_SHIFT) < 0));
272                                 SetFocus(hWndCtl);
273                                 if ((GetKeyState(VK_SHIFT) < 0))
274                                         printf("ListBox PreviousDlgTabItem %04X !\n", hWndCtl);
275                                 else
276                                         printf("ListBox NextDlgTabItem %04X !\n", hWndCtl);
277                                 break;
278                         case VK_HOME:
279                                 lphl->ItemFocused = 0;
280                                 break;
281                         case VK_END:
282                                 lphl->ItemFocused = lphl->ItemsCount - 1;
283                                 break;
284                         case VK_LEFT:
285                                 if ((wndPtr->dwStyle & LBS_MULTICOLUMN) == LBS_MULTICOLUMN) {
286                                         lphl->ItemFocused -= lphl->ItemsPerColumn;
287                                         }
288                                 break;
289                         case VK_UP:
290                                 lphl->ItemFocused--;
291                                 break;
292                         case VK_RIGHT:
293                                 if ((wndPtr->dwStyle & LBS_MULTICOLUMN) == LBS_MULTICOLUMN) {
294                                         lphl->ItemFocused += lphl->ItemsPerColumn;
295                                         }
296                                 break;
297                         case VK_DOWN:
298                                 lphl->ItemFocused++;
299                                 break;
300                         case VK_PRIOR:
301                                 lphl->ItemFocused -= lphl->ItemsVisible;
302                                 break;
303                         case VK_NEXT:
304                                 lphl->ItemFocused += lphl->ItemsVisible;
305                                 break;
306                         case VK_SPACE:
307                                 wRet = ListBoxGetSel(hwnd, lphl->ItemFocused);
308                                 ListBoxSetSel(hwnd, lphl->ItemFocused, !wRet);
309                                 break;
310                         default:
311                                 ListBoxFindNextMatch(hwnd, wParam);
312                                 return 0;
313                         }
314                 if (lphl->ItemFocused < 0) lphl->ItemFocused = 0;
315                 if (lphl->ItemFocused >= lphl->ItemsCount)
316                         lphl->ItemFocused = lphl->ItemsCount - 1;
317                 lphl->FirstVisible = lphl->ItemFocused / lphl->ItemsVisible * 
318                                                                                         lphl->ItemsVisible + 1;
319                 if (lphl->FirstVisible < 1) lphl->FirstVisible = 1;
320                 if ((wndPtr->dwStyle & LBS_MULTIPLESEL) != LBS_MULTIPLESEL) {
321                         ListBoxSetCurSel(hwnd, lphl->ItemFocused);
322                         }
323                 if (wndPtr->dwStyle & WS_VSCROLL)
324                         SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
325                 InvalidateRect(hwnd, NULL, TRUE);
326                 UpdateWindow(hwnd);
327                 break;
328         case WM_PAINT:
329                 wndPtr = WIN_FindWndPtr(hwnd);
330                 if ((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) == LBS_OWNERDRAWFIXED) {
331                         OwnerDrawListBox(hwnd);
332                         break;
333                         }
334                 if ((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) == LBS_OWNERDRAWVARIABLE) {
335                         OwnerDrawListBox(hwnd);
336                         break;
337                         }
338                 StdDrawListBox(hwnd);
339                 break;
340         case WM_SETFOCUS:
341 #ifdef DEBUG_LISTBOX
342                 printf("ListBox WM_SETFOCUS !\n");
343 #endif
344                 lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
345                 break;
346         case WM_KILLFOCUS:
347 #ifdef DEBUG_LISTBOX
348                 printf("ListBox WM_KILLFOCUS !\n");
349 #endif
350                 InvalidateRect(hwnd, NULL, TRUE);
351                 UpdateWindow(hwnd);
352                 break;
353
354     case LB_RESETCONTENT:
355 #ifdef DEBUG_LISTBOX
356                 printf("ListBox LB_RESETCONTENT !\n");
357 #endif
358                 ListBoxResetContent(hwnd);
359                 return 0;
360     case LB_DIR:
361 #ifdef DEBUG_LISTBOX
362                 printf("ListBox LB_DIR !\n");
363 #endif
364                 wRet = ListBoxDirectory(hwnd, wParam, (LPSTR)lParam);
365                 InvalidateRect(hwnd, NULL, TRUE);
366                 UpdateWindow(hwnd);
367                 return wRet;
368         case LB_ADDSTRING:
369                 wRet = ListBoxAddString(hwnd, (LPSTR)lParam);
370                 return wRet;
371         case LB_GETTEXT:
372                 wRet = ListBoxGetText(hwnd, wParam, (LPSTR)lParam);
373 #ifdef DEBUG_LISTBOX
374                 printf("ListBox LB_GETTEXT #%u '%s' !\n", wParam, (LPSTR)lParam);
375 #endif
376                 return wRet;
377         case LB_INSERTSTRING:
378                 wRet = ListBoxInsertString(hwnd, wParam, (LPSTR)lParam);
379                 return wRet;
380         case LB_DELETESTRING:
381                 printf("ListBox LB_DELETESTRING #%u !\n", wParam);
382                 wRet = ListBoxDeleteString(hwnd, wParam);
383                 return wRet;
384         case LB_FINDSTRING:
385                 wRet = ListBoxFindString(hwnd, wParam, (LPSTR)lParam);
386                 return wRet;
387         case LB_GETCARETINDEX:
388                 return wRet;
389         case LB_GETCOUNT:
390                 lphl = ListBoxGetStorageHeader(hwnd);
391                 return lphl->ItemsCount;
392         case LB_GETCURSEL:
393                 lphl = ListBoxGetStorageHeader(hwnd);
394 #ifdef DEBUG_LISTBOX
395                 printf("ListBox LB_GETCURSEL %u !\n", lphl->ItemFocused);
396 #endif
397                 return lphl->ItemFocused;
398         case LB_GETHORIZONTALEXTENT:
399                 return wRet;
400         case LB_GETITEMDATA:
401                 return wRet;
402         case LB_GETITEMHEIGHT:
403                 return wRet;
404         case LB_GETITEMRECT:
405                 return wRet;
406         case LB_GETSEL:
407                 wRet = ListBoxGetSel(hwnd, wParam);
408                 return wRet;
409         case LB_GETSELCOUNT:
410                 return wRet;
411         case LB_GETSELITEMS:
412                 return wRet;
413         case LB_GETTEXTLEN:
414                 return wRet;
415         case LB_GETTOPINDEX:
416                 return wRet;
417         case LB_SELECTSTRING:
418                 return wRet;
419         case LB_SELITEMRANGE:
420                 return wRet;
421         case LB_SETCARETINDEX:
422                 return wRet;
423         case LB_SETCOLUMNWIDTH:
424                 lphl = ListBoxGetStorageHeader(hwnd);
425                 lphl->ColumnsWidth = wParam;
426                 break;
427         case LB_SETHORIZONTALEXTENT:
428                 return wRet;
429         case LB_SETITEMDATA:
430                 return wRet;
431         case LB_SETTABSTOPS:
432                 return wRet;
433         case LB_SETCURSEL:
434 #ifdef DEBUG_LISTBOX
435                 printf("ListBox LB_SETCURSEL wParam=%x !\n", wParam);
436 #endif
437                 wRet = ListBoxSetCurSel(hwnd, wParam);
438                 InvalidateRect(hwnd, NULL, TRUE);
439                 UpdateWindow(hwnd);
440                 return wRet;
441         case LB_SETSEL:
442                 printf("ListBox LB_SETSEL wParam=%x lParam=%lX !\n", wParam, lParam);
443                 wRet = ListBoxSetSel(hwnd, LOWORD(lParam), wParam);
444                 InvalidateRect(hwnd, NULL, TRUE);
445                 UpdateWindow(hwnd);
446                 return wRet;
447         case LB_SETTOPINDEX:
448                 printf("ListBox LB_SETTOPINDEX wParam=%x !\n", wParam);
449                 lphl = ListBoxGetStorageHeader(hwnd);
450                 lphl->FirstVisible = wParam;
451                 if (wndPtr->dwStyle & WS_VSCROLL)
452                 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
453                 InvalidateRect(hwnd, NULL, TRUE);
454                 UpdateWindow(hwnd);
455                 break;
456         case LB_SETITEMHEIGHT:
457 #ifdef DEBUG_LISTBOX
458                 printf("ListBox LB_SETITEMHEIGHT wParam=%x lParam=%lX !\n", wParam, lParam);
459 #endif
460                 wRet = ListBoxSetItemHeight(hwnd, wParam, lParam);
461                 return wRet;
462
463         default:
464                 return DefWindowProc( hwnd, message, wParam, lParam );
465     }
466 return 0;
467 }
468
469
470 LPHEADLIST ListBoxGetWindowAndStorage(HWND hwnd, WND **wndPtr)
471 {
472     WND  *Ptr;
473     LPHEADLIST lphl;
474     *(wndPtr) = Ptr = WIN_FindWndPtr(hwnd);
475     lphl = *((LPHEADLIST *)&Ptr->wExtra[1]);
476     return lphl;
477 }
478
479
480 LPHEADLIST ListBoxGetStorageHeader(HWND hwnd)
481 {
482     WND  *wndPtr;
483     LPHEADLIST lphl;
484     wndPtr = WIN_FindWndPtr(hwnd);
485     lphl = *((LPHEADLIST *)&wndPtr->wExtra[1]);
486     return lphl;
487 }
488
489
490 void StdDrawListBox(HWND hwnd)
491 {
492         WND     *wndPtr;
493         LPHEADLIST  lphl;
494         LPLISTSTRUCT lpls;
495         PAINTSTRUCT ps;
496         HBRUSH  hBrush;
497         int     OldBkMode;
498         DWORD   dwOldTextColor;
499         HWND    hWndParent;
500         HDC     hdc;
501         RECT    rect;
502         UINT    i, h, h2, maxwidth, ipc;
503         char    C[128];
504         h = 0;
505         hdc = BeginPaint( hwnd, &ps );
506         if (!IsWindowVisible(hwnd)) {
507             EndPaint( hwnd, &ps );
508             return;
509             }
510         lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
511         if (lphl == NULL) goto EndOfPaint;
512         hBrush = SendMessage(lphl->hWndLogicParent, WM_CTLCOLOR, (WORD)hdc,
513                     MAKELONG(hwnd, CTLCOLOR_LISTBOX));
514         if (hBrush == (HBRUSH)NULL)  hBrush = GetStockObject(WHITE_BRUSH);
515         GetClientRect(hwnd, &rect);
516 /*
517         if (wndPtr->dwStyle & WS_VSCROLL) rect.right -= 16;
518         if (wndPtr->dwStyle & WS_HSCROLL) rect.bottom -= 16;
519 */
520         FillRect(hdc, &rect, hBrush);
521         maxwidth = rect.right;
522         rect.right = lphl->ColumnsWidth;
523         if (lphl->ItemsCount == 0) goto EndOfPaint;
524         lpls = lphl->lpFirst;
525         if (lpls == NULL) goto EndOfPaint;
526         lphl->ItemsVisible = 0;
527         lphl->ItemsPerColumn = ipc = 0;
528         for(i = 1; i <= lphl->ItemsCount; i++) {
529             if (i >= lphl->FirstVisible) {
530                 if (lpls == NULL) break;
531                 if ((h + lpls->dis.rcItem.bottom - lpls->dis.rcItem.top) > rect.bottom) {
532                     if ((wndPtr->dwStyle & LBS_MULTICOLUMN) == LBS_MULTICOLUMN) {
533                         lphl->ItemsPerColumn = max(lphl->ItemsPerColumn, ipc);
534                         ipc = 0;
535                         h = 0;
536                         rect.left += lphl->ColumnsWidth;
537                         rect.right += lphl->ColumnsWidth;
538                         if (rect.left > maxwidth) break;
539                         }
540                     else 
541                         break;
542                     }
543                 h2 = lpls->dis.rcItem.bottom - lpls->dis.rcItem.top;
544                 lpls->dis.rcItem.top = h;
545                 lpls->dis.rcItem.bottom = h + h2;
546                 lpls->dis.rcItem.left = rect.left;
547                 lpls->dis.rcItem.right = rect.right;
548                 OldBkMode = SetBkMode(hdc, TRANSPARENT);
549                 if (lpls->dis.itemState != 0) {
550                         dwOldTextColor = SetTextColor(hdc, 0x00FFFFFFL);
551                     FillRect(hdc, &lpls->dis.rcItem, GetStockObject(BLACK_BRUSH));
552                     }
553                 TextOut(hdc, rect.left + 5, h + 2, (char *)lpls->dis.itemData, 
554                         strlen((char *)lpls->dis.itemData));
555                 if (lpls->dis.itemState != 0) {
556                         SetTextColor(hdc, dwOldTextColor);
557                     }
558                 SetBkMode(hdc, OldBkMode);
559                 if ((lphl->ItemFocused == i - 1) && GetFocus() == hwnd) {
560                     DrawFocusRect(hdc, &lpls->dis.rcItem);
561                     }
562                 h += h2;
563                 lphl->ItemsVisible++;
564                 ipc++;
565                 }
566             if (lpls->lpNext == NULL) goto EndOfPaint;
567             lpls = (LPLISTSTRUCT)lpls->lpNext;
568         }
569 EndOfPaint:
570     EndPaint( hwnd, &ps );
571     if ((lphl->ItemsCount > lphl->ItemsVisible) &
572         (wndPtr->dwStyle & WS_VSCROLL)) {
573 /*
574         InvalidateRect(wndPtr->hWndVScroll, NULL, TRUE);
575         UpdateWindow(wndPtr->hWndVScroll);
576 */
577         }
578 }
579
580
581
582 void OwnerDrawListBox(HWND hwnd)
583 {
584         WND     *wndPtr;
585         LPHEADLIST  lphl;
586         LPLISTSTRUCT lpls;
587         PAINTSTRUCT ps;
588         HBRUSH  hBrush;
589         HWND    hWndParent;
590         HDC hdc;
591         RECT rect;
592         UINT  i, h, h2, maxwidth;
593         char    C[128];
594         h = 0;
595         hdc = BeginPaint(hwnd, &ps);
596         if (!IsWindowVisible(hwnd)) {
597             EndPaint( hwnd, &ps );
598             return;
599             }
600         lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
601         if (lphl == NULL) goto EndOfPaint;
602         hBrush = SendMessage(lphl->hWndLogicParent, WM_CTLCOLOR, (WORD)hdc,
603                     MAKELONG(hwnd, CTLCOLOR_LISTBOX));
604         if (hBrush == (HBRUSH)NULL)  hBrush = GetStockObject(WHITE_BRUSH);
605         GetClientRect(hwnd, &rect);
606         if (wndPtr->dwStyle & WS_VSCROLL) rect.right -= 16;
607         if (wndPtr->dwStyle & WS_HSCROLL) rect.bottom -= 16;
608         FillRect(hdc, &rect, hBrush);
609         maxwidth = rect.right;
610         rect.right = lphl->ColumnsWidth;
611         if (lphl->ItemsCount == 0) goto EndOfPaint;
612         lpls = lphl->lpFirst;
613         if (lpls == NULL) goto EndOfPaint;
614         lphl->ItemsVisible = 0;
615         for (i = 1; i <= lphl->ItemsCount; i++) {
616             if (i >= lphl->FirstVisible) {
617                 lpls->dis.hDC = hdc;
618                 lpls->dis.itemID = i - 1;
619                 h2 = lpls->dis.rcItem.bottom - lpls->dis.rcItem.top;
620                 lpls->dis.rcItem.top = h;
621                 lpls->dis.rcItem.bottom = h + h2;
622                 lpls->dis.rcItem.left = rect.left;
623                 lpls->dis.rcItem.right = rect.right;
624                 lpls->dis.itemAction = ODA_DRAWENTIRE;
625                 if (lpls->dis.itemState != 0) {
626                     lpls->dis.itemAction |= ODA_SELECT;
627                     }
628                 if (lphl->ItemFocused == i - 1) {
629                     lpls->dis.itemAction |= ODA_FOCUS;
630                     }
631 #ifdef DEBUT_LISTBOX
632                 printf("LBOX WM_DRAWITEM #%d left=%d top=%d right=%d bottom=%d !\n", 
633                         i, lpls->dis.rcItem.left, lpls->dis.rcItem.top, 
634                         lpls->dis.rcItem.right, lpls->dis.rcItem.bottom);
635                 printf("LBOX WM_DRAWITEM Parent=%X &dis=%lX CtlID=%u !\n", 
636                         hWndParent, (LONG)&lpls->dis, lpls->dis.CtlID);
637                 printf("LBOX WM_DRAWITEM '%s' !\n", lpls->dis.itemData);
638 #endif
639                 SendMessage(lphl->hWndLogicParent, WM_DRAWITEM, i, (LPARAM)&lpls->dis);
640                 if (lpls->dis.itemState != 0) {
641                     InvertRect(hdc, &lpls->dis.rcItem);
642                     }
643                 h += h2;
644                 lphl->ItemsVisible++;
645                 if (h > rect.bottom) goto EndOfPaint;
646                 }
647             if (lpls->lpNext == NULL) goto EndOfPaint;
648             lpls = (LPLISTSTRUCT)lpls->lpNext;
649         }
650 EndOfPaint:
651     EndPaint( hwnd, &ps );
652     if ((lphl->ItemsCount > lphl->ItemsVisible) &
653         (wndPtr->dwStyle & WS_VSCROLL)) {
654 /*
655         InvalidateRect(wndPtr->hWndVScroll, NULL, TRUE);
656         UpdateWindow(wndPtr->hWndVScroll);
657 */
658         }
659 }
660
661
662
663 int ListBoxFindMouse(HWND hwnd, int X, int Y)
664 {
665     WND                 *wndPtr;
666     LPHEADLIST          lphl;
667     LPLISTSTRUCT        lpls;
668     RECT                rect;
669     UINT                i, h, h2, w, w2;
670     char                C[128];
671     lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
672     if (lphl == NULL) return LB_ERR;
673     if (lphl->ItemsCount == 0) return LB_ERR;
674     lpls = lphl->lpFirst;
675     if (lpls == NULL) return LB_ERR;
676     GetClientRect(hwnd, &rect);
677     if (wndPtr->dwStyle & WS_VSCROLL) rect.right -= 16;
678     if (wndPtr->dwStyle & WS_HSCROLL) rect.bottom -= 16;
679     h = w2 = 0;
680     w = lphl->ColumnsWidth;
681     for(i = 1; i <= lphl->ItemsCount; i++) {
682         if (i >= lphl->FirstVisible) {
683             h2 = h;
684             h += lpls->dis.rcItem.bottom - lpls->dis.rcItem.top;
685             if ((Y > h2) && (Y < h) &&
686                 (X > w2) && (X < w)) return(i - 1);
687             if (h > rect.bottom) {
688                 if ((wndPtr->dwStyle & LBS_MULTICOLUMN) != LBS_MULTICOLUMN) return LB_ERR;
689                 h = 0;
690                 w2 = w;
691                 w += lphl->ColumnsWidth;
692                 if (w2 > rect.right) return LB_ERR;
693                 }
694             }
695         if (lpls->lpNext == NULL) return LB_ERR;
696         lpls = (LPLISTSTRUCT)lpls->lpNext;
697         }
698     return(LB_ERR);
699 }
700
701
702
703 int CreateListBoxStruct(HWND hwnd)
704 {
705     WND  *wndPtr;
706     LPHEADLIST lphl;
707     wndPtr = WIN_FindWndPtr(hwnd);
708     lphl = (LPHEADLIST)malloc(sizeof(HEADLIST));
709     lphl->lpFirst = NULL;
710     *((LPHEADLIST *)&wndPtr->wExtra[1]) = lphl;         /* HEAD of List */
711     lphl->ItemsCount = 0;
712     lphl->ItemsVisible = 0;
713     lphl->FirstVisible = 1;
714     lphl->StdItemHeight = 15;
715     lphl->DrawCtlType = ODT_LISTBOX;
716     return TRUE;
717 }
718
719
720 void ListBoxAskMeasure(WND *wndPtr, LPHEADLIST lphl, LPLISTSTRUCT lpls)  
721 {
722         MEASUREITEMSTRUCT *measure;
723         HANDLE hTemp = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(MEASUREITEMSTRUCT));
724         measure = (MEASUREITEMSTRUCT *) USER_HEAP_ADDR(hTemp);
725         if (measure == NULL) return;
726         measure->CtlType = ODT_LISTBOX;
727         measure->CtlID = wndPtr->wIDmenu;
728         measure->itemID = lpls->dis.itemID;
729         measure->itemWidth = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
730         measure->itemHeight = 0;
731         measure->itemData = lpls->dis.itemData;
732         SendMessage(lphl->hWndLogicParent, WM_MEASUREITEM, 0, (DWORD)measure);
733         lpls->dis.rcItem.right = lpls->dis.rcItem.left + measure->itemWidth;
734         lpls->dis.rcItem.bottom = lpls->dis.rcItem.top + measure->itemHeight;
735         USER_HEAP_FREE(hTemp);                  
736 }
737
738
739 int ListBoxAddString(HWND hwnd, LPSTR newstr)
740 {
741     WND         *wndPtr;
742     LPHEADLIST  lphl;
743     LPLISTSTRUCT lpls, lplsnew;
744     HANDLE      hTemp;
745     LPSTR       str;
746     lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
747     if (lphl == NULL) return LB_ERR;
748     hTemp = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(LISTSTRUCT));
749     lplsnew = (LPLISTSTRUCT) USER_HEAP_ADDR(hTemp);
750     lpls = lphl->lpFirst;
751     if (lpls != NULL) {
752         while(lpls->lpNext != NULL) {
753             lpls = (LPLISTSTRUCT)lpls->lpNext;
754             }
755         lpls->lpNext = lplsnew;
756         }
757     else
758         lphl->lpFirst = lplsnew;
759     lphl->ItemsCount++;
760 #ifdef DEBUG_LISTBOX
761     printf("Items Count = %u\n", lphl->ItemsCount);
762 #endif
763     hTemp = 0;
764     if ((wndPtr->dwStyle & LBS_HASSTRINGS) != LBS_HASSTRINGS) {
765         if (((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) != LBS_OWNERDRAWFIXED) &&
766             ((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) != LBS_OWNERDRAWVARIABLE)) {
767             hTemp = USER_HEAP_ALLOC(GMEM_MOVEABLE, strlen(newstr) + 1);
768             str = (LPSTR)USER_HEAP_ADDR(hTemp);
769             if (str == NULL) return LB_ERRSPACE;
770             strcpy(str, newstr);
771             newstr = str;
772 #ifdef DEBUG_LISTBOX
773             printf("ListBoxAddString// after strcpy '%s'\n", str);
774 #endif
775             }
776         }
777     ListBoxDefaultItem(hwnd, wndPtr, lphl, lplsnew);
778     lplsnew->hMem = hTemp;
779     lplsnew->lpNext = NULL;
780     lplsnew->dis.itemID = lphl->ItemsCount;
781     lplsnew->dis.itemData = (DWORD)newstr;
782     lplsnew->hData = hTemp;
783         if ((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) == LBS_OWNERDRAWVARIABLE) 
784                 ListBoxAskMeasure(wndPtr, lphl, lplsnew);
785     if (wndPtr->dwStyle & WS_VSCROLL)
786         SetScrollRange(hwnd, SB_VERT, 1, lphl->ItemsCount, 
787             (lphl->FirstVisible != 1));
788     if ((wndPtr->dwStyle & WS_HSCROLL) && lphl->ItemsPerColumn != 0)
789         SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible / 
790             lphl->ItemsPerColumn + 1, (lphl->FirstVisible != 1));
791     if (lphl->FirstVisible >= (lphl->ItemsCount - lphl->ItemsVisible)) {
792         InvalidateRect(hwnd, NULL, TRUE);
793         UpdateWindow(hwnd);
794         }
795     if ((lphl->ItemsCount - lphl->FirstVisible) == lphl->ItemsVisible) {
796         if (wndPtr->dwStyle & WS_VSCROLL)
797             ShowScrollBar(hwnd, SB_VERT, TRUE);
798         if (wndPtr->dwStyle & WS_HSCROLL)
799             ShowScrollBar(hwnd, SB_HORZ, TRUE);
800         }
801     return lphl->ItemsCount;
802 }
803
804
805 int ListBoxInsertString(HWND hwnd, UINT uIndex, LPSTR newstr)
806 {
807         WND     *wndPtr;
808         LPHEADLIST      lphl;
809         LPLISTSTRUCT lpls, lplsnew;
810         HANDLE  hTemp;
811         LPSTR   str;
812         UINT    Count;
813         lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
814         if (lphl == NULL) return LB_ERR;
815         if (uIndex >= lphl->ItemsCount) return LB_ERR;
816         lpls = lphl->lpFirst;
817         if (lpls == NULL) return LB_ERR;
818         if (uIndex > lphl->ItemsCount) return LB_ERR;
819         for(Count = 1; Count < uIndex; Count++) {
820                 if (lpls->lpNext == NULL) return LB_ERR;
821                 lpls = (LPLISTSTRUCT)lpls->lpNext;
822                 }
823         hTemp = USER_HEAP_ALLOC(GMEM_MOVEABLE, sizeof(LISTSTRUCT));
824         lplsnew = (LPLISTSTRUCT) USER_HEAP_ADDR(hTemp);
825         ListBoxDefaultItem(hwnd, wndPtr, lphl, lplsnew);
826         lplsnew->hMem = hTemp;
827         lpls->lpNext = lplsnew;
828         lphl->ItemsCount++;
829         hTemp = 0;
830         if ((wndPtr->dwStyle & LBS_HASSTRINGS) != LBS_HASSTRINGS) {
831                 if (((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) != LBS_OWNERDRAWFIXED) &&
832                         ((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) != LBS_OWNERDRAWVARIABLE)) {
833                         hTemp = USER_HEAP_ALLOC(GMEM_MOVEABLE, strlen(newstr) + 1);
834                         str = (LPSTR)USER_HEAP_ADDR(hTemp);
835                         if (str == NULL) return LB_ERRSPACE;
836                         strcpy(str, newstr);
837                         newstr = str;
838                         }
839                 }
840         lplsnew->lpNext = NULL;
841         lplsnew->dis.itemID = lphl->ItemsCount;
842         lplsnew->dis.itemData = (DWORD)newstr;
843         lplsnew->hData = hTemp;
844         if ((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) == LBS_OWNERDRAWVARIABLE) 
845                 ListBoxAskMeasure(wndPtr, lphl, lplsnew);
846         if (wndPtr->dwStyle & WS_VSCROLL)
847                 SetScrollRange(hwnd, SB_VERT, 1, lphl->ItemsCount, 
848                                                     (lphl->FirstVisible != 1));
849         if ((wndPtr->dwStyle & WS_HSCROLL) && lphl->ItemsPerColumn != 0)
850                 SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible / 
851                         lphl->ItemsPerColumn + 1, (lphl->FirstVisible != 1));
852         if (((lphl->ItemsCount - lphl->FirstVisible) == lphl->ItemsVisible) && 
853                 (lphl->ItemsVisible != 0)) {
854                 if (wndPtr->dwStyle & WS_VSCROLL) ShowScrollBar(hwnd, SB_VERT, TRUE);
855                 if (wndPtr->dwStyle & WS_HSCROLL) ShowScrollBar(hwnd, SB_HORZ, TRUE);
856                 }
857         if ((lphl->FirstVisible <= uIndex) &&
858                 ((lphl->FirstVisible + lphl->ItemsVisible) >= uIndex)) {
859                 InvalidateRect(hwnd, NULL, TRUE);
860                 UpdateWindow(hwnd);
861                 }
862         return lphl->ItemsCount;
863 }
864
865
866 int ListBoxGetText(HWND hwnd, UINT uIndex, LPSTR OutStr)
867 {
868     WND         *wndPtr;
869     LPHEADLIST  lphl;
870     LPLISTSTRUCT lpls;
871     UINT        Count;
872     lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
873     if (lphl == NULL) return LB_ERR;
874     if (uIndex >= lphl->ItemsCount) return LB_ERR;
875     lpls = lphl->lpFirst;
876     if (lpls == NULL) return LB_ERR;
877     if (uIndex > lphl->ItemsCount) return LB_ERR;
878     for(Count = 0; Count < uIndex; Count++) {
879         if (lpls->lpNext == NULL) return LB_ERR;
880         lpls = (LPLISTSTRUCT)lpls->lpNext;
881     }
882     if (((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) == LBS_OWNERDRAWFIXED) ||
883             ((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) == LBS_OWNERDRAWVARIABLE)) {
884         if ((wndPtr->dwStyle & LBS_HASSTRINGS) != LBS_HASSTRINGS) { 
885             *((long *)OutStr) = lpls->dis.itemData;
886             return 4;
887             }
888         }
889         
890     strcpy(OutStr, (char *)lpls->dis.itemData);
891     return strlen(OutStr);
892 }
893
894
895 int ListBoxDeleteString(HWND hwnd, UINT uIndex)
896 {
897     WND         *wndPtr;
898     LPHEADLIST  lphl;
899     LPLISTSTRUCT lpls, lpls2;
900     UINT        Count;
901     lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
902     if (lphl == NULL) return LB_ERR;
903     if (uIndex >= lphl->ItemsCount) return LB_ERR;
904     lpls = lphl->lpFirst;
905     if (lpls == NULL) return LB_ERR;
906     if (uIndex > lphl->ItemsCount) return LB_ERR;
907     for(Count = 1; Count < uIndex; Count++) {
908         if (lpls->lpNext == NULL) return LB_ERR;
909         lpls2 = lpls;
910         lpls = (LPLISTSTRUCT)lpls->lpNext;
911     }
912     lpls2->lpNext = (LPLISTSTRUCT)lpls->lpNext;
913     lphl->ItemsCount--;
914     if (lpls->hData != 0) USER_HEAP_FREE(lpls->hData);
915     if (lpls->hMem != 0) USER_HEAP_FREE(lpls->hMem);
916     if (wndPtr->dwStyle & WS_VSCROLL)
917         SetScrollRange(hwnd, SB_VERT, 1, lphl->ItemsCount, TRUE);
918     if ((wndPtr->dwStyle & WS_HSCROLL) && lphl->ItemsPerColumn != 0)
919         SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible / 
920             lphl->ItemsPerColumn + 1, TRUE);
921     if (lphl->ItemsCount < lphl->ItemsVisible) {
922         if (wndPtr->dwStyle & WS_VSCROLL)
923             ShowScrollBar(hwnd, SB_VERT, FALSE);
924         if (wndPtr->dwStyle & WS_HSCROLL)
925             ShowScrollBar(hwnd, SB_HORZ, FALSE);
926         }
927     if ((lphl->FirstVisible <= uIndex) &&
928         ((lphl->FirstVisible + lphl->ItemsVisible) >= uIndex)) {
929         InvalidateRect(hwnd, NULL, TRUE);
930         UpdateWindow(hwnd);
931         }
932     return lphl->ItemsCount;
933 }
934
935
936 int ListBoxFindString(HWND hwnd, UINT nFirst, LPSTR MatchStr)
937 {
938     LPHEADLIST  lphl;
939     LPLISTSTRUCT lpls;
940     UINT        Count;
941     lphl = ListBoxGetStorageHeader(hwnd);
942     if (lphl == NULL) return LB_ERR;
943     if (nFirst > lphl->ItemsCount) return LB_ERR;
944     lpls = lphl->lpFirst;
945     if (lpls == NULL) return LB_ERR;
946     Count = 0;
947     while(lpls != NULL) {
948         if (strcmp((char *)lpls->dis.itemData, MatchStr) == 0) return Count;
949         lpls = (LPLISTSTRUCT)lpls->lpNext;
950         Count++;
951         }
952     return LB_ERR;
953 }
954
955
956 int ListBoxResetContent(HWND hwnd)
957 {
958     WND  *wndPtr;
959     LPHEADLIST  lphl;
960     LPLISTSTRUCT lpls, lpls2;
961     UINT        i;
962     lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
963     if (lphl == NULL) return LB_ERR;
964     lpls = lphl->lpFirst;
965     if (lpls == NULL) return LB_ERR;
966     for(i = 0; i <= lphl->ItemsCount; i++) {
967         lpls2 = lpls;
968         lpls = (LPLISTSTRUCT)lpls->lpNext;
969         if (i != 0) {
970 #ifdef DEBUG_LISTBOX
971             printf("ResetContent #%u\n", i);
972 #endif
973             if (lpls2->hData != 0) USER_HEAP_FREE(lpls->hData);
974             if (lpls2->hMem != 0) USER_HEAP_FREE(lpls->hMem);
975             }  
976         if (lpls == NULL)  break;
977     }
978     lphl->lpFirst = NULL;
979     lphl->FirstVisible = 1;
980     lphl->ItemsCount = 0;
981     lphl->ItemFocused = 0;
982     lphl->PrevFocused = 0;
983     if ((wndPtr->dwStyle && LBS_NOTIFY) != 0)
984         SendMessage(wndPtr->hwndParent, WM_COMMAND, 
985             wndPtr->wIDmenu, MAKELONG(hwnd, LBN_SELCHANGE));
986
987     if (wndPtr->dwStyle & WS_VSCROLL)
988         SetScrollRange(hwnd, SB_VERT, 1, lphl->ItemsCount, TRUE);
989     if ((wndPtr->dwStyle & WS_HSCROLL) && lphl->ItemsPerColumn != 0)
990         SetScrollRange(hwnd, SB_HORZ, 1, lphl->ItemsVisible / 
991             lphl->ItemsPerColumn + 1, TRUE);
992     if (wndPtr->dwStyle & WS_VSCROLL)
993         ShowScrollBar(hwnd, SB_VERT, FALSE);
994     if (wndPtr->dwStyle & WS_HSCROLL)
995         ShowScrollBar(hwnd, SB_HORZ, FALSE);
996     InvalidateRect(hwnd, NULL, TRUE);
997     UpdateWindow(hwnd);
998     return TRUE;
999 }
1000
1001
1002 int ListBoxSetCurSel(HWND hwnd, WORD wIndex)
1003 {
1004     WND  *wndPtr;
1005     LPHEADLIST  lphl;
1006     LPLISTSTRUCT lpls, lpls2;
1007     UINT        i;
1008     lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
1009     if (lphl == NULL) return LB_ERR;
1010     lphl->ItemFocused = LB_ERR;
1011     if (wIndex >= lphl->ItemsCount) return LB_ERR;
1012     lpls = lphl->lpFirst;
1013     if (lpls == NULL) return LB_ERR;
1014     for(i = 0; i < lphl->ItemsCount; i++) {
1015         lpls2 = lpls;
1016         lpls = (LPLISTSTRUCT)lpls->lpNext;
1017         if (i == wIndex)
1018             lpls2->dis.itemState = 1;
1019         else 
1020             if (lpls2->dis.itemState != 0)
1021                 lpls2->dis.itemState = 0;
1022         if (lpls == NULL)  break;
1023     }
1024     lphl->ItemFocused = wIndex;
1025     if ((wndPtr->dwStyle && LBS_NOTIFY) != 0)
1026         SendMessage(wndPtr->hwndParent, WM_COMMAND, 
1027             wndPtr->wIDmenu, MAKELONG(hwnd, LBN_SELCHANGE));
1028     return LB_ERR;
1029 }
1030
1031
1032
1033 int ListBoxSetSel(HWND hwnd, WORD wIndex, WORD state)
1034 {
1035     LPHEADLIST  lphl;
1036     LPLISTSTRUCT lpls, lpls2;
1037     UINT        i;
1038     lphl = ListBoxGetStorageHeader(hwnd);
1039     if (lphl == NULL) return LB_ERR;
1040     if (wIndex >= lphl->ItemsCount) return LB_ERR;
1041     lpls = lphl->lpFirst;
1042     if (lpls == NULL) return LB_ERR;
1043     for(i = 0; i < lphl->ItemsCount; i++) {
1044         lpls2 = lpls;
1045         lpls = (LPLISTSTRUCT)lpls->lpNext;
1046         if ((i == wIndex) || (wIndex == (WORD)-1)) {
1047             lpls2->dis.itemState = state;
1048             break;
1049             }  
1050         if (lpls == NULL)  break;
1051     }
1052     return LB_ERR;
1053 }
1054
1055
1056 int ListBoxGetSel(HWND hwnd, WORD wIndex)
1057 {
1058     LPHEADLIST  lphl;
1059     LPLISTSTRUCT lpls, lpls2;
1060     UINT        i;
1061     lphl = ListBoxGetStorageHeader(hwnd);
1062     if (lphl == NULL) return LB_ERR;
1063     if (wIndex >= lphl->ItemsCount) return LB_ERR;
1064     lpls = lphl->lpFirst;
1065     if (lpls == NULL) return LB_ERR;
1066     for(i = 0; i < lphl->ItemsCount; i++) {
1067         lpls2 = lpls;
1068         lpls = (LPLISTSTRUCT)lpls->lpNext;
1069         if (i == wIndex) {
1070             return lpls2->dis.itemState;
1071             }  
1072         if (lpls == NULL)  break;
1073     }
1074     return LB_ERR;
1075 }
1076
1077
1078 int ListBoxDirectory(HWND hwnd, UINT attrib, LPSTR filespec)
1079 {
1080         struct dosdirent *dp;
1081         struct stat     st;
1082         int     x, wRet;
1083         char    temp[256];
1084 #ifdef DEBUG_LISTBOX
1085         fprintf(stderr,"ListBoxDirectory: %s, %4x\n",filespec,attrib);
1086 #endif
1087         if ((dp = (struct dosdirent *)DOS_opendir(filespec)) ==NULL) return 0;
1088         while (1) {
1089                 dp = (struct dosdirent *)DOS_readdir(dp);
1090                 if (!dp->inuse) break;
1091 #ifdef DEBUG_LISTBOX
1092                 printf("ListBoxDirectory %08X '%s' !\n", dp->filename, dp->filename);
1093 #endif
1094                 if (dp->attribute & FA_DIREC) {
1095                         if (attrib & DDL_DIRECTORY) {
1096                                 sprintf(temp, "[%s]", dp->filename);
1097                                 if ( (wRet = ListBoxAddString(hwnd, temp)) == LB_ERR) break;
1098                         }
1099                 } else 
1100                 if (attrib & DDL_EXCLUSIVE) {
1101                         if (attrib & (DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM) )
1102                                 if ( (wRet = ListBoxAddString(hwnd, dp->filename)) == LB_ERR)
1103                                         break;
1104                 } else {
1105                         if ( (wRet = ListBoxAddString(hwnd, dp->filename)) == LB_ERR)
1106                                 break;
1107                 }
1108         }
1109         DOS_closedir(dp);
1110         
1111         if (attrib & DDL_DRIVES)
1112         {
1113                 for (x=0;x!=MAX_DOS_DRIVES;x++)
1114                 {
1115                         if (DOS_ValidDrive(x))
1116                         {
1117                                 sprintf(temp, "[-%c-]", 'A'+x);
1118                                 if ( (wRet = ListBoxAddString(hwnd, temp)) == LB_ERR)
1119                                         break;
1120                         }               
1121                 }
1122         }
1123 #ifdef DEBUG_LISTBOX
1124         printf("End of ListBoxDirectory !\n");
1125 #endif
1126         return wRet;
1127 }
1128
1129
1130 int ListBoxGetItemRect(HWND hwnd, WORD wIndex, LPRECT lprect)
1131 {
1132     LPHEADLIST  lphl;
1133     LPLISTSTRUCT lpls, lpls2;
1134     UINT        i;
1135     lphl = ListBoxGetStorageHeader(hwnd);
1136     if (lphl == NULL) return LB_ERR;
1137     if (wIndex > lphl->ItemsCount) return LB_ERR;
1138     lpls = lphl->lpFirst;
1139     if (lpls == NULL) return LB_ERR;
1140     for(i = 0; i < lphl->ItemsCount; i++) {
1141         lpls2 = lpls;
1142         lpls = (LPLISTSTRUCT)lpls->lpNext;
1143         if (i == wIndex) {
1144             *(lprect) = lpls2->dis.rcItem;
1145             break;
1146             }  
1147         if (lpls == NULL)  break;
1148     }
1149     return LB_ERR;
1150 }
1151
1152
1153
1154 int ListBoxSetItemHeight(HWND hwnd, WORD wIndex, long height)
1155 {
1156     LPHEADLIST  lphl;
1157     LPLISTSTRUCT lpls, lpls2;
1158     UINT        i;
1159     lphl = ListBoxGetStorageHeader(hwnd);
1160     if (lphl == NULL) return LB_ERR;
1161     if (wIndex > lphl->ItemsCount) return LB_ERR;
1162     lpls = lphl->lpFirst;
1163     if (lpls == NULL) return LB_ERR;
1164     for(i = 0; i < lphl->ItemsCount; i++) {
1165         lpls2 = lpls;
1166         lpls = (LPLISTSTRUCT)lpls->lpNext;
1167         if (i == wIndex) {
1168             lpls2->dis.rcItem.bottom = lpls2->dis.rcItem.top + (short)height;
1169             InvalidateRect(hwnd, NULL, TRUE);
1170             UpdateWindow(hwnd);
1171             break;
1172             }  
1173         if (lpls == NULL)  break;
1174     }
1175     return LB_ERR;
1176 }
1177
1178
1179
1180
1181
1182 int ListBoxDefaultItem(HWND hwnd, WND *wndPtr, 
1183         LPHEADLIST lphl, LPLISTSTRUCT lpls)
1184 {
1185     RECT        rect;
1186     GetClientRect(hwnd, &rect);
1187     SetRect(&lpls->dis.rcItem, 0, 0, rect.right, lphl->StdItemHeight);
1188     lpls->dis.CtlType = lphl->DrawCtlType;
1189     lpls->dis.CtlID = wndPtr->wIDmenu;
1190     lpls->dis.itemID = 0;
1191     lpls->dis.itemAction = 0;
1192     lpls->dis.itemState = 0;
1193     lpls->dis.hwndItem = hwnd;
1194     lpls->dis.hDC = 0;
1195     lpls->dis.itemData = 0;
1196 }
1197
1198
1199
1200 int ListBoxFindNextMatch(HWND hwnd, WORD wChar)
1201 {
1202     WND         *wndPtr;
1203     LPHEADLIST  lphl;
1204     LPLISTSTRUCT lpls;
1205     UINT        Count;
1206     lphl = ListBoxGetWindowAndStorage(hwnd, &wndPtr);
1207     if (lphl == NULL) return LB_ERR;
1208     lpls = lphl->lpFirst;
1209     if (lpls == NULL) return LB_ERR;
1210     if (wChar < ' ') return LB_ERR;
1211     if (((wndPtr->dwStyle & LBS_OWNERDRAWFIXED) == LBS_OWNERDRAWFIXED) ||
1212             ((wndPtr->dwStyle & LBS_OWNERDRAWVARIABLE) == LBS_OWNERDRAWVARIABLE)) {
1213         if ((wndPtr->dwStyle & LBS_HASSTRINGS) != LBS_HASSTRINGS) { 
1214             return LB_ERR;
1215             }
1216         }
1217     Count = 0;
1218     while(lpls != NULL) {
1219         if (Count > lphl->ItemFocused) {
1220             if (*((char *)lpls->dis.itemData) == (char)wChar) {
1221                 lphl->FirstVisible = Count - lphl->ItemsVisible / 2;
1222                 if (lphl->FirstVisible < 1) lphl->FirstVisible = 1;
1223                 if ((wndPtr->dwStyle & LBS_MULTIPLESEL) == LBS_MULTIPLESEL) {
1224                     lphl->ItemFocused = Count;
1225                     }
1226                 else {
1227                     ListBoxSetCurSel(hwnd, Count);
1228                     }
1229                 SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1230                 InvalidateRect(hwnd, NULL, TRUE);
1231                 UpdateWindow(hwnd);
1232                 return Count;
1233                 }
1234             }
1235         lpls = (LPLISTSTRUCT)lpls->lpNext;
1236         Count++;
1237         }
1238     Count = 0;
1239     lpls = lphl->lpFirst;
1240     while(lpls != NULL) {
1241         if (*((char *)lpls->dis.itemData) == (char)wChar) {
1242             if (Count == lphl->ItemFocused)    return LB_ERR;
1243             lphl->FirstVisible = Count - lphl->ItemsVisible / 2;
1244             if (lphl->FirstVisible < 1) lphl->FirstVisible = 1;
1245             if ((wndPtr->dwStyle & LBS_MULTIPLESEL) == LBS_MULTIPLESEL) {
1246                 lphl->ItemFocused = Count;
1247                 }
1248             else {
1249                 ListBoxSetCurSel(hwnd, Count);
1250                 }
1251             SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1252             InvalidateRect(hwnd, NULL, TRUE);
1253             UpdateWindow(hwnd);
1254             return Count;
1255             }
1256         lpls = (LPLISTSTRUCT)lpls->lpNext;
1257         Count++;
1258         }
1259     return LB_ERR;
1260 }
1261
1262