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