]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/services/gfx/mw/v2_0/src/mwin/winlib/listbox.c
Initial revision
[karo-tx-redboot.git] / packages / services / gfx / mw / v2_0 / src / mwin / winlib / listbox.c
1 /*
2  * Copyright (C) 1999, 2000, Wei Yongming.
3  * Portions Copyright (c) 2000 Greg Haerr <greg@censoft.com>
4  *
5  * Listbox for Microwindows win32 api.
6  */
7
8 /*
9 **  This library is free software; you can redistribute it and/or
10 **  modify it under the terms of the GNU Library General Public
11 **  License as published by the Free Software Foundation; either
12 **  version 2 of the License, or (at your option) any later version.
13 **
14 **  This library is distributed in the hope that it will be useful,
15 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 **  Library General Public License for more details.
18 **
19 **  You should have received a copy of the GNU Library General Public
20 **  License along with this library; if not, write to the Free
21 **  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22 **  MA 02111-1307, USA
23 */
24
25 /*
26 **  Alternatively, the contents of this file may be used under the terms 
27 **  of the Mozilla Public License (the "MPL License") in which case the
28 **  provisions of the MPL License are applicable instead of those above.
29 */
30
31 /* Note:
32 **  Although there was a version by Zhao Jianghua, this version of
33 **  LISTBOX control is written by Wei Yongming from scratch.
34 **
35 ** Modify records:
36 **
37 **  Who             When        Where       For What                Status
38 **-----------------------------------------------------------------------------
39 **  Wei Yongming    1999/10/18  Tsinghua    Item Additional Data    Finished
40 **  Wei Yongming    1999/10/31  Tsinghua    Space bar for checkmark Finished
41 **  Wei Yongming    1999/10/31  Tsinghua    Character match item    Finished
42 **  Wei Yongming    1999/11/07  Tsinghua    Character match item    Bug fixing
43 **  WEI Yongming    2000/01/20  Tsinghua    Thumb dragging          Finished
44 **  WEI Yongming    2000/02/24  Tsinghua    Add MPL License         Finished
45 **  Kevin Tseng     2000/05/26  gv          port to microwin        ported
46 **  Greg Haerr      2000/06/15  Utah        3d look, bug fixes      Finished
47 **  Kevin Tseng     2000/06/22  gv          port to mw-nanox        ported
48 **  Kevin Tseng     2000/06/22  gv          fixed bug if no item    Finished
49 **  Kevin Tseng     2000/08/08  gv          enable scrollbar(V)     porting
50 **  Kevin Tseng     2000/08/10  gv          enable scrollbar(V)     ported
51 **  Kevin Tseng     2000/08/10  gv          WM_CHAR, WM_KEYDOWN     ported
52 **
53 ** TODO:
54 ** 1. Multiple columns support.
55 */
56
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #define MWINCLUDECOLORS
61 #include "windows.h"
62 #include "wintools.h"   /* Draw3dBox */
63 #include "device.h"     /* GdGetTextSize */
64
65 #define FixStrAlloc(n)  malloc((n)+1)
66 #define FreeFixStr(p)   free(p)
67
68 #define LBIF_NORMAL         0x0000L
69 #define LBIF_SELECTED       0x0001L
70 #define LBIF_CHECKED        0x0010L
71 #define LBIF_PARTCHECKED    0x0020L
72 #define LBIF_CHECKMARKMASK  0x00F0L
73
74 #define CMFLAG_BLANK        0
75 #define CMFLAG_CHECKED      1
76 #define CMFLAG_PARTCHECKED  2
77 typedef struct _LISTBOXITEMINFO {
78     int     insPos;         /* insert position */
79     char*   string;         /* item string */
80     int     cmFlag;         /* check mark flag */
81     HICON   hIcon;          /* handle of icon */
82 } LISTBOXITEMINFO, *PLISTBOXITEMINFO;
83
84 typedef struct _LISTBOXITEM {
85     char*   key;                /* item sort key */
86     DWORD   dwFlags;            /* item flags */
87     DWORD   dwData;             /* item data */
88     DWORD   dwAddData;          /* item additional data */
89     struct  _LISTBOXITEM* next;  /* next item */
90 } LISTBOXITEM, *PLISTBOXITEM;
91
92 #define DEF_LB_BUFFER_LEN       5
93
94 #define LBF_FOCUS               0x0001
95 #define LBF_NOTHINGSELECTED     0x0002
96
97 typedef struct _LISTBOXDATA {
98     DWORD dwFlags;          /* listbox flags */
99
100     int itemCount;          /* items count */
101     int itemTop;            /* start display item */
102     int itemVisibles;       /* number of visible items */
103
104     int itemHilighted;      /* current hilighted item */
105     int itemHeight;         /* item height */
106
107     LISTBOXITEM* head;      /* items linked list head */
108
109     int buffLen;            /* buffer length */
110     LISTBOXITEM* buffStart; /* buffer start */
111     LISTBOXITEM* buffEnd;   /* buffer end */
112     LISTBOXITEM* freeList;  /* free list in buffer */
113 } LISTBOXDATA, *PLISTBOXDATA;
114
115 void ListboxControlCleanup ();
116 static LRESULT CALLBACK
117 ListboxCtrlProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
118
119 #define ITEM_BOTTOM(x)  (x->itemTop + x->itemVisibles - 1)
120
121 #define LST_WIDTH_CHECKMARK     11
122 #define LST_HEIGHT_CHECKMARK    11
123 #define LST_INTER_BMPTEXT       2
124
125 int WINAPI MwRegisterListboxControl(HINSTANCE hInstance)
126 {
127         WNDCLASS        wc;
128 #if 0
129     static BITMAP sg_bmpCheckMark;
130     if (!LoadSystemBitmap (&sg_bmpCheckMark, "checkmark")) {
131         fprintf (stderr, "Load ListBox Check Mark Bitmap failure!\n");
132         return FALSE;
133     }
134 #endif
135         wc.style        = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_GLOBALCLASS;
136         wc.lpfnWndProc  = (WNDPROC)ListboxCtrlProc;
137         wc.cbClsExtra   = 0;
138         wc.cbWndExtra   = 0;
139         wc.hInstance    = hInstance;
140         wc.hIcon        = NULL;
141         wc.hCursor      = 0; /*LoadCursor(NULL, IDC_ARROW);*/
142         wc.hbrBackground= GetStockObject(WHITE_BRUSH);
143         wc.lpszMenuName = NULL;
144         wc.lpszClassName= "LISTBOX";
145
146         return RegisterClass(&wc);
147 }
148
149 void ListboxControlCleanup ()
150 {
151 #if 0
152     UnloadBitmap (&sg_bmpCheckMark);
153 #endif
154 }
155
156 static LRESULT NotifyParent (HWND hwnd, int id, int code)
157 {
158     return SendMessage (GetParent (hwnd), WM_COMMAND, 
159                  (WPARAM) MAKELONG (id, code), (LPARAM)hwnd);
160 }
161
162 static BOOL lstInitListBoxData (HWND hwnd,LISTBOXDATA* pData, int len)
163 {
164     int i, xw, xh, xb;
165     PLISTBOXITEM plbi;
166     HDC hdc;
167     
168     memset (pData, 0, sizeof (LISTBOXDATA));
169 #if 0
170     pData->itemHeight = GetSysCharHeight ();
171 #else
172     hdc=GetDC(hwnd);
173 #if MWCLIENT    /* nanox client */
174     GrSetGCFont(hdc->gc,hdc->font->fontid);
175     GrGetGCTextSize(hdc->gc,"X",1,
176                 MWTF_ASCII,&xw,&xh,&xb);
177 #else
178     GdSetFont(hdc->font->pfont);
179     GdGetTextSize(hdc->font->pfont,"X",1,
180                 &xw,&xh,&xb,MWTF_ASCII);
181 #endif
182     ReleaseDC(hwnd,hdc);
183     pData->itemHeight=xh + 1; 
184 #endif
185     pData->itemHilighted = 0;
186     pData->dwFlags = LBF_NOTHINGSELECTED;
187
188     /* init item buffer. */
189     if (!(pData->buffStart = malloc (len * sizeof (LISTBOXITEM))))
190         return FALSE;
191
192     pData->buffLen = len;
193     pData->buffEnd = pData->buffStart + len;
194     pData->freeList = pData->buffStart;
195
196     plbi = pData->freeList;
197     for (i = 0; i < len - 1; i++) {
198         plbi->next = plbi + 1;
199         plbi ++;
200     }
201     plbi->next = NULL;
202
203     return TRUE;
204 }
205
206 static void lstListBoxCleanUp (LISTBOXDATA* pData)
207 {
208     PLISTBOXITEM plbi;
209     PLISTBOXITEM next;
210
211     plbi = pData->head;
212     while (plbi) {
213         FreeFixStr (plbi->key);
214         next = plbi->next;
215         if (plbi < pData->buffStart || plbi > pData->buffEnd)
216             free (plbi);
217
218         plbi = next;
219     }
220     
221     free (pData->buffStart);
222 }
223
224 static void lstResetListBoxContent (PLISTBOXDATA pData)
225 {
226     int i;
227     PLISTBOXITEM plbi, next;
228
229     pData->itemCount = 0;
230     pData->itemTop = 0;
231     pData->itemHilighted = 0;
232 #if 0
233     pData->itemVisibles = 0;
234 #endif
235
236     plbi = pData->head;
237     while (plbi) {
238         FreeFixStr (plbi->key);
239         next = plbi->next;
240         if (plbi < pData->buffStart || plbi > pData->buffEnd)
241             free (plbi);
242
243         plbi = next;
244     }
245
246     pData->head = NULL;
247     pData->freeList = pData->buffStart;
248
249     plbi = pData->freeList;
250     for (i = 0; i < pData->buffLen - 1; i++) {
251         plbi->next = plbi + 1;
252         plbi ++;
253     }
254     plbi->next = NULL;
255 }
256
257 static PLISTBOXITEM lstAllocItem (PLISTBOXDATA pData)
258 {
259     PLISTBOXITEM plbi;
260
261     if (pData->freeList) {
262         plbi = pData->freeList;
263         pData->freeList = plbi->next;
264     }
265     else
266         plbi = (PLISTBOXITEM) malloc (sizeof (LISTBOXITEM));
267     
268     return plbi;
269 }
270
271 static void lstFreeItem (PLISTBOXDATA pData, PLISTBOXITEM plbi)
272 {
273     if (plbi < pData->buffStart || plbi > pData->buffEnd)
274         free (plbi);
275     else {
276         plbi->next = pData->freeList;
277         pData->freeList = plbi;
278     }
279 }
280
281 static int lstAddNewItem (DWORD dwStyle, 
282         PLISTBOXDATA pData, PLISTBOXITEM newItem, int pos)
283 {
284     PLISTBOXITEM plbi;
285     PLISTBOXITEM insPosItem = NULL;
286     int insPos = 0;
287
288     newItem->next = NULL;
289     if (!pData->head)
290         insPosItem = NULL;
291     else if (dwStyle & LBS_SORT) {
292         plbi = pData->head;
293
294         if (strcmp (newItem->key, plbi->key) < 0) {
295             insPosItem = NULL;
296             insPos = 0;
297         }
298         else {
299             while (plbi->next) {
300                 if (strcmp (newItem->key, plbi->next->key) <= 0)
301                     break;
302             
303                 plbi = plbi->next;
304                 insPos ++;
305             }
306             insPosItem = plbi;
307         }
308     }
309     else {
310         plbi = pData->head;
311
312         if (pos < 0) {
313             while (plbi->next) {
314                 plbi = plbi->next;
315                 insPos ++;
316             }
317             insPosItem = plbi;
318         }
319         else if (pos > 0) {
320             int index = 0;
321
322             while (plbi->next) {
323                 if (pos == index)
324                     break;
325                 plbi = plbi->next;
326                 index ++;
327                 insPos ++;
328             }
329             insPosItem = plbi;
330         }
331     }
332
333     if (insPosItem) {
334         plbi = insPosItem->next;
335         insPosItem->next = newItem;
336         newItem->next = plbi;
337
338         insPos ++;
339     }
340     else {
341         plbi = pData->head;
342         pData->head = newItem;
343         newItem->next = plbi;
344     }
345
346     pData->itemCount ++;
347     return insPos;
348 }
349
350 static PLISTBOXITEM lstRemoveItem (PLISTBOXDATA pData, int* pos)
351 {
352     int index = 0;
353     PLISTBOXITEM plbi, prev;
354
355     if (!pData->head)
356         return NULL;
357
358     if (*pos < 0) {
359         prev = pData->head;
360         plbi = pData->head;
361         while (plbi->next) {
362             prev = plbi;
363             plbi = plbi->next;
364             index ++;
365         }
366
367         if (plbi == pData->head) {
368             pData->head = pData->head->next;
369             *pos = 0;
370             return plbi;
371         }
372         else {
373             prev->next = plbi->next;
374             *pos = index;
375             return plbi;
376         }
377     }
378     else if (*pos == 0) {
379         plbi = pData->head;
380         pData->head = plbi->next;
381         return plbi;
382     }
383     else {
384         index = 0;
385         prev = pData->head;
386         plbi = pData->head;
387         while (plbi->next) {
388             if (*pos == index)
389                 break;
390
391             prev = plbi;
392             plbi = plbi->next;
393             index ++;
394         }
395
396         if (plbi == pData->head) {
397             pData->head = pData->head->next;
398             *pos = 0;
399             return plbi;
400         }
401         else {
402             prev->next = plbi->next;
403             *pos = index;
404             return plbi;
405         }
406     }
407
408     return NULL;
409 }
410
411 static void lstGetItemsRect (PLISTBOXDATA pData, int start, int end, RECT* prc)
412 {
413     if (start < 0)
414         start = 0;
415
416     prc->top = (start - pData->itemTop)*pData->itemHeight;
417
418     if (end >= 0)
419         prc->bottom = (end - pData->itemTop + 1)*pData->itemHeight;
420
421 }
422
423 static void lstInvalidateItem (HWND hwnd, PLISTBOXDATA pData, int pos,BOOL fEBk)
424 {
425     RECT rcInv;
426     
427     if (pos < pData->itemTop || pos > (pData->itemTop + pData->itemVisibles))
428         return;
429     
430     GetClientRect (hwnd, &rcInv);
431     rcInv.top = (pos - pData->itemTop)*pData->itemHeight;
432     rcInv.bottom = rcInv.top + pData->itemHeight;
433
434     InvalidateRect (hwnd, &rcInv, fEBk);
435 }
436
437 static BOOL lstInvalidateUnderItem (HWND hwnd, PLISTBOXDATA pData, int pos)
438 {
439     RECT rcInv;
440     
441     if (pos > (pData->itemTop + pData->itemVisibles))
442         return FALSE;
443
444     if (pos <= pData->itemTop) {
445         InvalidateRect (hwnd, NULL, TRUE);
446         return TRUE;
447     }
448     
449     GetClientRect (hwnd, &rcInv);
450
451     lstGetItemsRect (pData, pos, -1, &rcInv);
452
453     if (rcInv.top < rcInv.bottom)
454         InvalidateRect (hwnd, &rcInv, TRUE);
455
456     return TRUE;
457 }
458
459 static PLISTBOXITEM lstGetItem (PLISTBOXDATA pData, int pos)
460 {
461     int i;
462     PLISTBOXITEM plbi;
463
464     plbi = pData->head;
465     for (i=0; i < pos && plbi; i++)
466         plbi = plbi->next;
467
468     return plbi;
469 }
470
471 static int lstFindItem (PLISTBOXDATA pData, int start, char* key, BOOL bExact)
472 {
473     PLISTBOXITEM plbi;
474     int keylen = strlen (key);
475   
476     if (start >= (pData->itemCount - 1))
477         start = 0;
478
479     plbi = lstGetItem (pData, start);
480
481     while (plbi)
482     {
483         if (bExact && (keylen != strlen (plbi->key))) {
484             plbi = plbi->next;
485             start ++;
486             continue;
487         }
488
489         if (strncasecmp (key, plbi->key, keylen) == 0)
490             return start;
491             
492         plbi = plbi->next;
493         start ++;
494     }
495
496     return LB_ERR;
497 }
498
499 static void lstOnDrawSListBoxItems (HDC hdc, DWORD dwStyle, 
500                 PLISTBOXDATA pData, int width)
501 {
502     PLISTBOXITEM plbi;
503     int i;
504     int x = 0, y = 0;
505     int offset;
506     RECT rc;
507     COLORREF bk;
508
509     plbi = lstGetItem (pData, pData->itemTop);
510     
511     for (i = 0; plbi && i < (pData->itemVisibles + 1); i++) {
512
513         if (plbi->dwFlags & LBIF_SELECTED) {
514             SetBkColor (hdc, bk = BLUE);
515             SetTextColor (hdc, WHITE);
516         }
517         else {
518             SetBkColor (hdc, bk = WHITE);
519             SetTextColor (hdc, BLACK);
520         }
521         rc.left = 0;
522         rc.top = y;
523         rc.right = width;
524         rc.bottom = y + pData->itemHeight;
525         FastFillRect(hdc, &rc, bk);
526
527         if (dwStyle & LBS_CHECKBOX) {
528             x = LST_INTER_BMPTEXT;
529             if (plbi->dwFlags & LBIF_CHECKED)
530                 offset = 0;
531             else if (plbi->dwFlags & LBIF_PARTCHECKED)
532                 offset = LST_WIDTH_CHECKMARK << 1;
533             else
534                 offset = LST_WIDTH_CHECKMARK;
535 #if 0   /* fix: no bitmap */
536             FillBoxWithBitmapPart (hdc, 
537                 x, y + ((pData->itemHeight - LST_HEIGHT_CHECKMARK)>>1),
538                 LST_WIDTH_CHECKMARK, LST_HEIGHT_CHECKMARK,
539                 0, 0,
540                 &sg_bmpCheckMark,
541                 offset, 0);
542 #endif
543             x += LST_WIDTH_CHECKMARK + LST_INTER_BMPTEXT;
544         }
545 #if 0   /* fix: no icon */
546         if (dwStyle & LBS_USEICON && plbi->dwData) {
547             DrawIcon (hdc, 
548                 x, y, pData->itemHeight, pData->itemHeight, 
549                 (HICON) plbi->dwData);
550             x += pData->itemHeight + LST_INTER_BMPTEXT;
551         }
552 #endif
553
554 /* jmt: should be SYSTEM_FIXED_FONT because of minigui's GetSysCharXXX() */
555 #if 0
556         SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
557 #endif
558         SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
559         TextOut (hdc, x+2, y, plbi->key,-1);
560
561         y += pData->itemHeight;
562         plbi = plbi->next;
563     }
564 }
565
566 static int lstSelectItem (DWORD dwStyle, PLISTBOXDATA pData, int newSel)
567 {
568     PLISTBOXITEM plbi, newItem;
569     int index;
570     
571     newItem = lstGetItem (pData, newSel);
572 #if 1   /* jmt: fixed if no item added */
573     if (!newItem) return -1;
574 #endif 
575 #ifdef _DEBUG
576     if (!newItem)
577         fprintf (stderr, "ASSERT failed: return value of lstGetItem"
578                          " in lstSelectItem.\n");
579 #endif
580
581     if (dwStyle & LBS_MULTIPLESEL) {
582         newItem->dwFlags ^= LBIF_SELECTED;
583         return newSel;
584     }
585
586     index = 0;
587     plbi = pData->head;
588     while (plbi) {
589         if (plbi->dwFlags & LBIF_SELECTED) {
590             if (index != newSel) {
591                 plbi->dwFlags &= ~LBIF_SELECTED;
592                 newItem->dwFlags |= LBIF_SELECTED;
593                 return index;
594             }
595             break;
596         }
597
598         plbi = plbi->next;
599         index ++;
600     }
601
602     newItem->dwFlags |= LBIF_SELECTED;
603     return -1;
604 }
605
606 static void lstDrawFocusRect (HDC hdc, PLISTBOXDATA pData, RECT* rc)
607 {
608     HGDIOBJ oldbrush,oldpen;
609
610     if (pData->itemHilighted < pData->itemTop
611             || pData->itemHilighted > (pData->itemTop + pData->itemVisibles))
612         return;
613
614     if (pData->dwFlags & LBF_FOCUS) {
615         lstGetItemsRect (pData, pData->itemHilighted, pData->itemHilighted, rc);
616 #if 0
617         InflateRect (rc, -1, -1);
618
619         FocusRect (hdc, rc->left - 1, rc->top, rc->right, rc->bottom);
620 #else
621         oldbrush=SelectObject(hdc, GetStockObject(NULL_BRUSH));
622         oldpen=SelectObject(hdc, CreatePen(PS_SOLID, 1,
623                                 GetSysColor(COLOR_BTNHIGHLIGHT)));
624 #if 0
625         GdSetMode(MWMODE_XOR);
626 #endif
627         Rectangle (hdc, rc->left, rc->top, rc->right, rc->bottom);
628 #if 0
629         GdSetMode(MWMODE_SET);
630 #endif
631         SelectObject(hdc,oldbrush);
632         DeleteObject(SelectObject(hdc,oldpen));
633 #endif
634     }
635 }
636
637 static void lstCalcParams (const RECT* rcClient, PLISTBOXDATA pData)
638 {
639 #define RECTHP(prc)  (prc->bottom - prc->top)
640     pData->itemVisibles = (RECTHP (rcClient)) / pData->itemHeight;
641
642 #if 1   /* test calculation of itemVisibles */
643     if( ((RECTHP (rcClient)) % pData->itemHeight) )
644         pData->itemVisibles++;
645 #endif
646 }
647
648 extern BOOL SetScrollPos (HWND hWnd, int iSBar, int iNewPos);
649 extern BOOL EnableScrollBar (HWND hWnd, int iSBar, BOOL bEnable);
650
651 static void lstSetVScrollInfo (HWND hwnd, PLISTBOXDATA pData, BOOL fRedraw)
652 {
653     SCROLLINFO si;
654
655     if (pData->itemVisibles >= pData->itemCount) 
656     {
657         SetScrollPos (hwnd, SB_VERT, 0);
658         EnableScrollBar (hwnd, SB_VERT, FALSE);
659         return;
660     }
661     
662     si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
663     si.nMax = pData->itemCount - 1;
664     si.nMin = 0;
665     si.nPage = min (pData->itemVisibles, (pData->itemCount - pData->itemTop));
666     si.nPos = pData->itemTop;
667
668     SetScrollInfo (hwnd, SB_VERT, &si, fRedraw);
669     EnableScrollBar (hwnd, SB_VERT, TRUE);
670 }
671
672 LRESULT CALLBACK
673 ListboxCtrlProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
674 {
675     HDC             hdc;
676     HWND            pCtrl;
677     PLISTBOXDATA    pData;
678     DWORD           dwStyle;
679     
680     pCtrl   = hwnd;
681     dwStyle = pCtrl->style;
682
683     switch (message)
684     {
685         case WM_CREATE:
686             pData = (LISTBOXDATA*) malloc (sizeof(LISTBOXDATA));
687             if (pData == NULL) 
688                 return -1;
689
690             pCtrl->userdata = (DWORD)pData;
691             if (!lstInitListBoxData (hwnd, pData, DEF_LB_BUFFER_LEN)) {
692                 free (pData);
693                 return -1;
694             }
695         break;
696
697         case WM_SIZE:
698         {
699             RECT rc;
700
701             pData = (PLISTBOXDATA)pCtrl->userdata;
702             GetClientRect(hwnd, &rc);
703             lstCalcParams (&rc, pData);
704         }
705         break;
706
707         case WM_DESTROY:
708             pData = (PLISTBOXDATA)pCtrl->userdata;
709             lstListBoxCleanUp (pData);
710             free (pData);
711         break;
712
713         case LB_RESETCONTENT:
714             pData = (PLISTBOXDATA)pCtrl->userdata;
715             lstResetListBoxContent (pData);
716             InvalidateRect (hwnd, NULL, TRUE);
717         break;
718         
719         case LB_ADDSTRING:
720         case LB_INSERTSTRING:
721         {
722             char* string = NULL;
723             PLISTBOXITEMINFO plbii = NULL;
724             PLISTBOXITEM newItem;
725             int pos;
726            
727             if (dwStyle & LBS_CHECKBOX || dwStyle & LBS_USEICON) {
728                 plbii = (PLISTBOXITEMINFO)lParam;
729                 if (!plbii)
730                     return LB_ERR;
731
732                 string = plbii->string;
733             }
734             else {
735                 string = (char*)lParam;
736                 if (string == NULL || string [0] == '\0')
737                     return LB_ERR;
738             }
739
740             pData = (PLISTBOXDATA)pCtrl->userdata;
741             newItem = lstAllocItem (pData);
742             if (!newItem) {
743                 NotifyParent (hwnd, pCtrl->id, LBN_ERRSPACE);
744                 return LB_ERRSPACE;
745             }
746
747             newItem->key = FixStrAlloc (strlen (string));
748             strcpy (newItem->key, string);
749             newItem->dwFlags = LBIF_NORMAL;
750             if (plbii) {
751                 switch (plbii->cmFlag) {
752                     case CMFLAG_CHECKED:
753                         newItem->dwFlags |= LBIF_CHECKED;
754                     break;
755                     case CMFLAG_PARTCHECKED:
756                         newItem->dwFlags |= LBIF_PARTCHECKED;
757                     break;
758                 }
759                 
760                 if (dwStyle & LBS_USEICON)
761                     newItem->dwData = (DWORD)plbii->hIcon;
762                 else
763                     newItem->dwData = 0L;
764             }
765             newItem->dwAddData = 0L;
766
767             if (message == LB_ADDSTRING)
768                 pos = lstAddNewItem (dwStyle, pData, newItem, -1);
769             else
770                 pos = lstAddNewItem (dwStyle, pData, newItem, (int)wParam);
771
772             lstInvalidateUnderItem (hwnd, pData, pos);
773
774             lstSetVScrollInfo (hwnd, pData, TRUE);
775
776             return pos;
777         }
778         break;
779         
780         case LB_DELETESTRING:
781         {
782             PLISTBOXITEM removed;
783             int delete;
784
785             delete = (int)wParam;
786
787             pData = (PLISTBOXDATA)pCtrl->userdata;
788             removed = lstRemoveItem (pData, &delete);
789             if (removed) {
790                 FreeFixStr (removed->key);
791                 lstFreeItem (pData, removed);
792                 
793                 pData->itemCount --;
794
795                 if (pData->itemTop != 0 
796                         && pData->itemCount <= pData->itemVisibles) {
797                     pData->itemTop = 0;
798                     InvalidateRect (hwnd, NULL, TRUE);
799                 }
800                 else {
801                     lstInvalidateUnderItem (hwnd, pData, delete);
802                     if (delete <= pData->itemTop) {
803                         pData->itemTop --;
804                         if (pData->itemTop < 0)
805                             pData->itemTop = 0;
806                     }
807                 }
808
809                 if (pData->itemHilighted >= pData->itemCount) {
810                     pData->itemHilighted = pData->itemCount - 1;
811                     if (pData->itemHilighted < 0)
812                         pData->itemHilighted = 0;
813                 }
814
815                 if (pData->itemHilighted < pData->itemTop)
816                     pData->itemHilighted = pData->itemTop;
817                 if (pData->itemHilighted > ITEM_BOTTOM (pData))
818                     pData->itemHilighted = ITEM_BOTTOM (pData);
819              
820                 lstSetVScrollInfo (hwnd, pData, TRUE);
821             }
822         }
823         break;
824
825         case LB_FINDSTRING:
826             if( *(char*)lParam == '\0' )
827                 return LB_ERR;
828                 
829             pData = (PLISTBOXDATA)pCtrl->userdata;
830             return lstFindItem(pData, (int)wParam, (char*)lParam, FALSE);
831
832         case LB_FINDSTRINGEXACT:
833             if( *(char*)lParam == '\0' )
834                 return LB_ERR;
835
836             pData = (PLISTBOXDATA)pCtrl->userdata;
837             return lstFindItem(pData, (int)wParam, (char*)lParam, TRUE);
838     
839         case LB_SETTOPINDEX:
840         {
841             int newTop = (int) wParam;
842             
843             pData = (PLISTBOXDATA)pCtrl->userdata;
844
845             if (newTop <0)
846                 newTop = 0;
847             else if (newTop > pData->itemCount - pData->itemVisibles)
848                 newTop = pData->itemCount - pData->itemVisibles;
849                 
850             if (pData->itemTop != newTop) {
851                 pData->itemTop = newTop;
852
853                 if (pData->itemHilighted < pData->itemTop)
854                     pData->itemHilighted = pData->itemTop;
855                 if (pData->itemHilighted > ITEM_BOTTOM (pData))
856                     pData->itemHilighted = ITEM_BOTTOM (pData);
857
858                 lstSetVScrollInfo (hwnd, pData, TRUE);
859
860                 InvalidateRect (hwnd, NULL, TRUE);
861             }
862         }
863         break;
864     
865         case LB_SETCURSEL:
866         case LB_SETCARETINDEX:
867         {
868             int new = (int)wParam;
869             int old, newTop;
870             
871             pData = (PLISTBOXDATA)pCtrl->userdata;
872             if (new < 0 || new > pData->itemCount - 1)
873                 return LB_ERR;
874
875             old = pData->itemHilighted;
876             if (new >= 0 && new != old) {
877                 if (pData->itemCount - new >= pData->itemVisibles)
878                     newTop = new;
879                 else
880                     newTop = max (pData->itemCount - pData->itemVisibles, 0);
881
882                 pData->itemTop = newTop;
883                 pData->itemHilighted = new;
884                 lstSetVScrollInfo (hwnd, pData, TRUE);
885             }
886
887             if (!(dwStyle & LBS_MULTIPLESEL))
888                 lstSelectItem (dwStyle, pData, new);
889             InvalidateRect (hwnd, NULL, TRUE);
890
891             return old;
892         }
893         break;
894     
895         case LB_GETCOUNT:
896             pData = (PLISTBOXDATA)pCtrl->userdata;
897             return pData->itemCount;
898         break;
899     
900         case LB_GETCURSEL:
901         {
902             PLISTBOXITEM plbi;
903             int index = 0;
904             
905             pData = (PLISTBOXDATA)pCtrl->userdata;
906             if (dwStyle & LBS_MULTIPLESEL)
907                 return pData->itemHilighted;
908
909             plbi = pData->head;
910             while (plbi) {
911                 if (plbi->dwFlags & LBIF_SELECTED)
912                     return index;
913
914                 index ++;
915                 plbi = plbi->next;
916            }
917            
918            return LB_ERR;
919         }
920         break;
921     
922         case LB_GETSELCOUNT:
923         {
924             int nSel;
925             PLISTBOXITEM plbi;
926             
927             pData = (PLISTBOXDATA)pCtrl->userdata;
928
929             nSel = 0;
930             plbi = pData->head;
931             while (plbi) {
932                 if (plbi->dwFlags & LBIF_SELECTED)
933                     nSel ++;
934                 plbi = plbi->next;
935             }
936             
937             return nSel;
938         }
939         break;
940     
941         case LB_GETTOPINDEX:
942             pData = (PLISTBOXDATA)pCtrl->userdata;
943             return pData->itemTop;
944         break;
945     
946         case LB_GETCARETINDEX:
947             pData = (PLISTBOXDATA)pCtrl->userdata;
948             return pData->itemHilighted;
949         break;
950
951         case LB_GETTEXTLEN:
952         {
953             PLISTBOXITEM plbi;
954
955             pData = (PLISTBOXDATA)pCtrl->userdata;
956             plbi = lstGetItem (pData, (int)wParam);
957             if (plbi)
958                 return strlen (plbi->key);
959             else
960                 return LB_ERR;
961         }
962         break;
963         
964         case LB_GETTEXT:
965         {
966             PLISTBOXITEM plbi;
967
968             pData = (PLISTBOXDATA)pCtrl->userdata;
969             plbi = lstGetItem (pData, (int)wParam);
970             if (plbi)
971                 strcpy ((char*)lParam, plbi->key);
972             else
973                 return LB_ERR;
974         }
975         break;
976
977         case LB_SETTEXT:
978         {
979             PLISTBOXITEM plbi;
980             char* newStr;
981
982             pData = (PLISTBOXDATA)pCtrl->userdata;
983             plbi = lstGetItem (pData, (int)wParam);
984             if (plbi) {
985                 newStr = FixStrAlloc (strlen ((char*)lParam));
986                 if (newStr) {
987                     FreeFixStr (plbi->key);
988                     plbi->key = newStr;
989                     strcpy (plbi->key, (char*)lParam);
990                     lstInvalidateItem (hwnd, pData, (int)wParam, TRUE);
991                 }
992                 else
993                     return LB_ERR;
994             }
995             else
996                 return LB_ERR;
997         }
998         break;
999     
1000         case LB_GETITEMDATA:
1001         {
1002             PLISTBOXITEM plbi;
1003             PLISTBOXITEMINFO plbii;
1004
1005             pData = (PLISTBOXDATA)pCtrl->userdata;
1006             if (!(plbi = lstGetItem (pData, (int)wParam)))
1007                 return LB_ERR;
1008
1009             if (!(dwStyle & LBS_CHECKBOX || dwStyle & LBS_USEICON)) {
1010                 return plbi->dwData;
1011             }
1012             
1013             plbii = (PLISTBOXITEMINFO)lParam;
1014             if (!plbii)
1015                 return LB_ERR;
1016
1017             if (plbi->dwFlags & LBIF_CHECKED)
1018                 plbii->cmFlag = CMFLAG_CHECKED;
1019             else if (plbi->dwFlags & LBIF_PARTCHECKED)
1020                 plbii->cmFlag = CMFLAG_PARTCHECKED;
1021             else
1022                 plbii->cmFlag = CMFLAG_BLANK;
1023             plbii->hIcon = (HICON)plbi->dwData;
1024
1025             return LB_OKAY;
1026         }
1027         break;
1028     
1029         case LB_SETITEMDATA:
1030         {
1031             PLISTBOXITEM plbi;
1032             PLISTBOXITEMINFO plbii;
1033
1034             pData = (PLISTBOXDATA)pCtrl->userdata;
1035             if (!(plbi = lstGetItem (pData, (int)wParam)))
1036                 return LB_ERR;
1037
1038             if (!(dwStyle & LBS_CHECKBOX || dwStyle & LBS_USEICON)) {
1039                 plbi->dwData = (DWORD)lParam;
1040                 return LB_OKAY;
1041             }
1042
1043             plbii = (PLISTBOXITEMINFO)lParam;
1044             if (!plbii)
1045                 return LB_ERR;
1046
1047             plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
1048             switch (plbii->cmFlag) {
1049                 case CMFLAG_CHECKED:
1050                     plbi->dwFlags |= LBIF_CHECKED;
1051                 break;
1052                 case CMFLAG_PARTCHECKED:
1053                     plbi->dwFlags |= LBIF_PARTCHECKED;
1054                 break;
1055             }
1056                 
1057             if (dwStyle & LBS_USEICON)
1058                 plbi->dwData = (DWORD)plbii->hIcon;
1059             else
1060                 plbi->dwData = 0;
1061             
1062             lstInvalidateItem (hwnd, pData, (int)wParam, TRUE);
1063
1064             return LB_OKAY;
1065         }
1066         break;
1067         
1068         case LB_GETITEMADDDATA:
1069         {
1070             PLISTBOXITEM plbi;
1071
1072             pData = (PLISTBOXDATA)pCtrl->userdata;
1073             if (!(plbi = lstGetItem (pData, (int)wParam)))
1074                 return LB_ERR;
1075
1076             return plbi->dwAddData;
1077         }
1078         break;
1079     
1080         case LB_SETITEMADDDATA:
1081         {
1082             PLISTBOXITEM plbi;
1083
1084             pData = (PLISTBOXDATA)pCtrl->userdata;
1085             if (!(plbi = lstGetItem (pData, (int)wParam)))
1086                 return LB_ERR;
1087
1088             plbi->dwAddData = (DWORD)lParam;
1089
1090             return LB_OKAY;
1091         }
1092         break;
1093         
1094         case LB_GETCHECKMARK:
1095         {
1096             PLISTBOXITEM plbi;
1097
1098             if (!(dwStyle & LBS_CHECKBOX))
1099                 return LB_ERR;
1100
1101             pData = (PLISTBOXDATA)pCtrl->userdata;
1102             if (!(plbi = lstGetItem (pData, (int)wParam)))
1103                 return LB_ERR;
1104
1105             if (plbi->dwFlags & LBIF_CHECKED)
1106                 return CMFLAG_CHECKED;
1107
1108             if (plbi->dwFlags & LBIF_PARTCHECKED)
1109                 return CMFLAG_PARTCHECKED;
1110
1111             return CMFLAG_BLANK;
1112         }
1113         break;
1114
1115         case LB_SETCHECKMARK:
1116         {
1117             PLISTBOXITEM plbi;
1118
1119             if (!(dwStyle & LBS_CHECKBOX))
1120                 return LB_ERR;
1121
1122             pData = (PLISTBOXDATA)pCtrl->userdata;
1123             if (!(plbi = lstGetItem (pData, (int)wParam)))
1124                 return LB_ERR;
1125
1126             plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
1127             switch (lParam) {
1128                 case CMFLAG_CHECKED:
1129                     plbi->dwFlags |= LBIF_CHECKED;
1130                 break;
1131                 case CMFLAG_PARTCHECKED:
1132                     plbi->dwFlags |= LBIF_PARTCHECKED;
1133                 break;
1134             }
1135                 
1136             lstInvalidateItem (hwnd, pData, (int)wParam, TRUE);
1137
1138             return LB_OKAY;
1139         }
1140         break;
1141
1142         case LB_GETSELITEMS:
1143         {
1144             int  nItem;
1145             int  nSel = 0;
1146             int  index = 0;
1147             int* pInt;
1148             PLISTBOXITEM plbi;
1149
1150             nItem = (int)wParam;
1151             pInt  = (int*)lParam;
1152             
1153             pData = (PLISTBOXDATA)pCtrl->userdata;
1154             plbi = pData->head;
1155             while (plbi) {
1156
1157                 if (plbi->dwFlags & LBIF_SELECTED) {
1158                     if (pInt) {
1159                         if (nSel < nItem)
1160                             *(pInt + nSel) = index;
1161                         else 
1162                             return nItem;
1163                     }
1164                     nSel ++;
1165                 }
1166                 
1167                 plbi = plbi->next;
1168                 index ++;
1169             }
1170             
1171             return nSel;
1172         }
1173         break;
1174     
1175         case LB_GETSEL:
1176         {
1177             PLISTBOXITEM plbi;
1178
1179             pData = (PLISTBOXDATA)pCtrl->userdata;
1180             plbi = lstGetItem (pData, (int)wParam);
1181             if (plbi)
1182                 return plbi->dwFlags & LBIF_SELECTED;
1183             else
1184                 return LB_ERR;
1185         }
1186         break;
1187
1188         case LB_SETSEL:
1189         {
1190             PLISTBOXITEM plbi;
1191
1192             pData = (PLISTBOXDATA)pCtrl->userdata;
1193             plbi = lstGetItem (pData, (int)lParam);
1194             if (plbi) {
1195                 pData->dwFlags &= ~LBF_NOTHINGSELECTED;
1196                 if (wParam == -1)
1197                     plbi->dwFlags ^= LBIF_SELECTED;
1198                 else if (wParam == 0)
1199                     plbi->dwFlags &= ~LBIF_SELECTED;
1200                 else
1201                     plbi->dwFlags |= LBIF_SELECTED;
1202
1203                 lstInvalidateItem (hwnd, pData, (int)lParam, FALSE);
1204             }
1205             else
1206                 return LB_ERR;
1207         }
1208         break;
1209     
1210         case LB_GETITEMHEIGHT:
1211             pData = (PLISTBOXDATA)pCtrl->userdata;
1212             return pData->itemHeight;
1213         break;
1214     
1215         case LB_SETITEMHEIGHT:
1216             pData = (PLISTBOXDATA)pCtrl->userdata;
1217             if (pData->itemHeight != LOWORD (lParam)) {
1218                 RECT rcClient;
1219                 
1220                 pData->itemHeight = LOWORD (lParam);
1221                 GetClientRect (hwnd, &rcClient);
1222                 lstCalcParams (&rcClient, pData);
1223                 
1224                 lstSetVScrollInfo (hwnd, pData, TRUE);
1225                 InvalidateRect (hwnd, NULL, TRUE);
1226             }
1227         break;
1228
1229         case WM_SETFOCUS:
1230         {
1231             pData = (PLISTBOXDATA)pCtrl->userdata;
1232
1233             if (pData->dwFlags & LBF_FOCUS)
1234                 break;
1235                 
1236             pData->dwFlags |= LBF_FOCUS;
1237             InvalidateRect(hwnd, NULL, TRUE);
1238
1239             NotifyParent (hwnd, pCtrl->id, LBN_SETFOCUS);
1240         }
1241         break;
1242         
1243         case WM_KILLFOCUS:
1244         {
1245             pData = (PLISTBOXDATA)pCtrl->userdata;
1246
1247             pData->dwFlags &= ~LBF_FOCUS;
1248             InvalidateRect(hwnd, NULL, TRUE);
1249
1250             NotifyParent (hwnd, pCtrl->id, LBN_KILLFOCUS);
1251         }
1252         break;
1253
1254         case WM_GETDLGCODE:
1255             return DLGC_WANTARROWS | DLGC_WANTCHARS;
1256
1257         case WM_GETTEXTLENGTH:
1258         case WM_GETTEXT:
1259         case WM_SETTEXT:
1260             return -1;
1261 #if 0            
1262         case WM_SETFONT:
1263         break;
1264         
1265         case WM_GETFONT:
1266         break;
1267 #endif        
1268         case WM_NCCALCSIZE:
1269         {
1270                 LPNCCALCSIZE_PARAMS lpnc;
1271
1272                 /* calculate client rect from passed window rect in rgrc[0]*/
1273                 lpnc = (LPNCCALCSIZE_PARAMS)lParam;
1274                 if(GetWindowLong(hwnd, GWL_STYLE) & WS_BORDER)
1275                         InflateRect(&lpnc->rgrc[0], -2, -2);
1276         }
1277                 break;
1278
1279         case WM_NCPAINT:
1280         {
1281             RECT rc;
1282
1283             hdc = wParam? (HDC)wParam: GetWindowDC (hwnd);
1284             GetWindowRect(hwnd, &rc);
1285
1286             if (dwStyle & WS_BORDER)
1287                 Draw3dInset(hdc, rc.left, rc.top,
1288                         rc.right-rc.left, rc.bottom-rc.top);
1289
1290             if (!wParam)
1291                 ReleaseDC (hwnd, hdc);
1292         }
1293             break;
1294
1295         case WM_PAINT:
1296         {
1297             RECT rc;
1298             PAINTSTRUCT ps;
1299             
1300             hdc = BeginPaint (hwnd,&ps);
1301             pData = (PLISTBOXDATA)pCtrl->userdata;
1302
1303             /*
1304              * If this is the first paint and there's nothing
1305              * selected, then auto select the topmost displayed item.
1306              */
1307             if (pData->dwFlags & LBF_NOTHINGSELECTED) {
1308                     lstSelectItem (hwnd->style, pData, pData->itemTop);
1309                     pData->dwFlags &= ~LBF_NOTHINGSELECTED;
1310             }
1311             GetClientRect (hwnd, &rc);
1312             lstOnDrawSListBoxItems (hdc, dwStyle, pData, rc.right-rc.left);
1313             lstDrawFocusRect (hdc, pData, &rc);
1314
1315             EndPaint (hwnd, &ps);
1316         }
1317         break;
1318     
1319         case WM_LBUTTONDBLCLK:
1320             if (dwStyle & LBS_NOTIFY)
1321                 NotifyParent (hwnd, pCtrl->id, LBN_DBLCLK);
1322         break;
1323     
1324         case WM_LBUTTONDOWN:
1325         {
1326             int oldSel, mouseX, mouseY, hit;
1327             RECT rcInv;
1328
1329             pData = (PLISTBOXDATA)pCtrl->userdata;
1330             if (pData->itemCount == 0)
1331                 break;
1332
1333             mouseX = LOWORD (lParam);
1334             mouseY = HIWORD (lParam);
1335             hit = mouseY / pData->itemHeight;
1336             hit += pData->itemTop;
1337             
1338             if (hit >= pData->itemCount)
1339                 break;
1340
1341             GetClientRect (hwnd, &rcInv);
1342             oldSel = lstSelectItem (dwStyle, pData, hit);
1343             if ((dwStyle & LBS_NOTIFY) && (oldSel != hit))
1344                 NotifyParent (hwnd, pCtrl->id, LBN_SELCHANGE);
1345             if (oldSel >= 0) {
1346                 if (oldSel >= pData->itemTop 
1347                         && (oldSel <= pData->itemTop + pData->itemVisibles)) {
1348                     lstGetItemsRect (pData, oldSel, oldSel, &rcInv);
1349                     InvalidateRect (hwnd, &rcInv, TRUE);
1350                 }
1351             }
1352
1353             lstGetItemsRect (pData, hit, hit, &rcInv);
1354             InvalidateRect (hwnd, &rcInv, TRUE);
1355
1356             if (pData->itemHilighted != hit) 
1357             {
1358                 hdc = GetDC(hwnd); /* hdc = GetClientDC (hwnd); */
1359
1360                 lstDrawFocusRect (hdc, pData, &rcInv);
1361                 ReleaseDC (hwnd,hdc);
1362             }
1363             pData->itemHilighted = hit;
1364
1365             if (dwStyle & LBS_CHECKBOX) {
1366                 if (mouseX > 0 && mouseX < LST_WIDTH_CHECKMARK) {
1367                     NotifyParent (hwnd, pCtrl->id, LBN_CLICKCHECKMARK);
1368                     
1369                     if (dwStyle & LBS_AUTOCHECK) {
1370                         PLISTBOXITEM plbi;
1371
1372                         plbi = lstGetItem (pData, hit);
1373
1374                         switch (plbi->dwFlags & LBIF_CHECKMARKMASK) {
1375                         case LBIF_CHECKED:
1376                             plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
1377                             break;
1378                         default:
1379                             plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
1380                             plbi->dwFlags |= LBIF_CHECKED;
1381                             break;
1382                         }
1383                 
1384                         lstInvalidateItem (hwnd, pData, hit, TRUE);
1385                     }
1386                 }
1387             }
1388             
1389             lstSetVScrollInfo (hwnd, pData, TRUE);
1390         }
1391         break;
1392     
1393         case WM_LBUTTONUP:
1394         break;
1395     
1396         case WM_MOUSEMOVE:
1397         break;
1398
1399         case WM_KEYDOWN:
1400         {
1401             int oldSel, newSel, newTop;
1402             RECT rcInv;
1403
1404             pData = (PLISTBOXDATA)pCtrl->userdata;
1405             newTop = pData->itemTop;
1406             newSel = pData->itemHilighted;
1407             switch (LOWORD (wParam))
1408             {
1409                 case VK_HOME:   /* SCANCODE_HOME: */
1410                     newSel = 0;
1411                     newTop = 0;
1412                 break;
1413                 
1414                 case VK_END:    /* SCANCODE_END: */
1415                     newSel = pData->itemCount - 1;
1416                     if (pData->itemCount > pData->itemVisibles)
1417                         newTop = pData->itemCount - pData->itemVisibles;
1418                     else
1419                         newTop = 0;
1420                 break;
1421                 
1422                 case VK_DOWN:   /* SCANCODE_CURSORBLOCKDOWN: */
1423                     newSel ++;
1424                     if (newSel >= pData->itemCount)
1425                         return 0;
1426                     if (newSel > ITEM_BOTTOM (pData))
1427                         newTop ++;
1428                 break;
1429                 
1430                 case VK_UP:     /* SCANCODE_CURSORBLOCKUP: */
1431                     newSel --;
1432                     if (newSel < 0)
1433                         return 0;
1434                     if (newSel < pData->itemTop)
1435                         newTop --;
1436                 break;
1437                 
1438                 case VK_NEXT:   /* SCANCODE_PAGEDOWN: */
1439                     newSel += pData->itemVisibles;
1440                     if (newSel >= pData->itemCount)
1441                         newSel = pData->itemCount - 1;
1442                         
1443                     if (pData->itemCount - newSel >= pData->itemVisibles)
1444                         newTop = newSel;
1445                     else
1446                         newTop = max (pData->itemCount-pData->itemVisibles, 0);
1447                 break;
1448
1449                 case VK_PRIOR:  /* SCANCODE_PAGEUP: */
1450                     newSel -= pData->itemVisibles;
1451                     if (newSel < 0)
1452                         newSel = 0;
1453                         
1454                     newTop -= pData->itemVisibles;
1455                     if (newTop < 0)
1456                         newTop = 0;
1457                 break;
1458                 
1459                 default:
1460                 return 0;
1461             }
1462
1463             GetClientRect (hwnd, &rcInv);
1464             if (pData->itemHilighted != newSel) {
1465                 if (pData->itemTop != newTop) {
1466                     pData->itemTop = newTop;
1467                     pData->itemHilighted = newSel;
1468                     if (!(dwStyle & LBS_MULTIPLESEL)) {
1469                         oldSel = lstSelectItem (dwStyle, pData, newSel);
1470                         if ((dwStyle & LBS_NOTIFY) && (oldSel != newSel))
1471                             NotifyParent (hwnd, pCtrl->id, LBN_SELCHANGE);
1472                     }
1473                     InvalidateRect (hwnd, NULL, TRUE);
1474                 }
1475                 else {
1476                     if (!(dwStyle & LBS_MULTIPLESEL)) {
1477                         oldSel = lstSelectItem (dwStyle, pData, newSel);
1478                         if ((dwStyle & LBS_NOTIFY) && (oldSel != newSel))
1479                             NotifyParent (hwnd, pCtrl->id, LBN_SELCHANGE);
1480                         if (oldSel >= 0) {
1481                             if (oldSel >= pData->itemTop 
1482                                     && oldSel <= (ITEM_BOTTOM (pData) + 1)) {
1483                                 lstGetItemsRect (pData, oldSel, oldSel, &rcInv);
1484                                 InvalidateRect (hwnd, &rcInv, TRUE);
1485                             }
1486                         }
1487                         
1488                         if (newSel < newTop) {
1489                             pData->itemHilighted = newSel;
1490                             break;
1491                         }
1492                             
1493                         lstGetItemsRect (pData, pData->itemHilighted,
1494                                                 pData->itemHilighted, &rcInv);
1495
1496                         hdc = GetDC(hwnd); /* hdc = GetClientDC (hwnd); */
1497
1498                         lstDrawFocusRect (hdc, pData, &rcInv);
1499                         ReleaseDC (hwnd,hdc);
1500                         
1501                         pData->itemHilighted = newSel;
1502                         lstGetItemsRect (pData, newSel, newSel, &rcInv);
1503                         InvalidateRect (hwnd, &rcInv, TRUE);
1504                     }
1505                     else 
1506                     {
1507                         hdc = GetDC(hwnd); /* hdc = GetClientDC (hwnd); */
1508
1509                         lstDrawFocusRect (hdc, pData, &rcInv);
1510                         pData->itemHilighted = newSel;
1511                         GetClientRect (hwnd, &rcInv);
1512                         lstDrawFocusRect (hdc, pData, &rcInv);
1513                         ReleaseDC (hwnd,hdc);
1514                     }
1515                 }
1516                 lstSetVScrollInfo (hwnd, pData, TRUE);
1517             }
1518         }
1519         break;
1520
1521         case WM_CHAR:
1522         {
1523             char head [2];
1524             int index;
1525             int newTop;
1526             
1527             head [0] = (char) (wParam);
1528             head [1] = '\0';
1529
1530             pData = (PLISTBOXDATA)pCtrl->userdata;
1531
1532             if (head[0] == ' ') {
1533                 if (dwStyle & LBS_MULTIPLESEL) {
1534                     RECT rcInv;
1535                     
1536                     GetClientRect (hwnd, &rcInv);
1537                     lstSelectItem (dwStyle, pData, pData->itemHilighted);
1538                     lstGetItemsRect (pData, 
1539                             pData->itemHilighted, 
1540                             pData->itemHilighted,
1541                             &rcInv);
1542                     InvalidateRect (hwnd, &rcInv, TRUE);
1543                 }
1544                 else if (dwStyle & LBS_CHECKBOX) {
1545                     NotifyParent (hwnd, pCtrl->id, LBN_CLICKCHECKMARK);
1546                     
1547                     if (dwStyle & LBS_AUTOCHECK) {
1548                         PLISTBOXITEM plbi;
1549
1550                         plbi = lstGetItem (pData, pData->itemHilighted);
1551
1552                         switch (plbi->dwFlags & LBIF_CHECKMARKMASK) {
1553                         case LBIF_CHECKED:
1554                             plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
1555                             break;
1556                         default:
1557                             plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
1558                             plbi->dwFlags |= LBIF_CHECKED;
1559                             break;
1560                         }
1561                 
1562                         lstInvalidateItem (hwnd, pData, 
1563                                 pData->itemHilighted, TRUE);
1564                     }
1565                 }
1566                 break;
1567             }
1568
1569             index = lstFindItem (pData, pData->itemHilighted + 1, head, FALSE);
1570             if (index < 0) {
1571                 index = lstFindItem (pData, 0, head, FALSE);
1572             }
1573
1574             if (index >= 0) {
1575                 if (pData->itemCount - index >= pData->itemVisibles)
1576                     newTop = index;
1577                 else
1578                     newTop = max (pData->itemCount - pData->itemVisibles, 0);
1579
1580                 pData->itemTop = newTop;
1581                 pData->itemHilighted = index;
1582                 if (!(dwStyle & LBS_MULTIPLESEL))
1583                     lstSelectItem (dwStyle, pData, index);
1584                 InvalidateRect (hwnd, NULL, TRUE);
1585
1586                 lstSetVScrollInfo (hwnd, pData, TRUE);
1587             }
1588         }
1589         break;
1590  
1591         case WM_VSCROLL:
1592         {
1593             int newTop;
1594             int scrollHeight = 0;
1595
1596             pData = (PLISTBOXDATA)pCtrl->userdata;
1597             newTop = pData->itemTop;
1598             switch(wParam)
1599             {
1600                 case SB_LINEDOWN:
1601
1602 #if 0   /* test itemVisibles */
1603                     printf("itemVisibles:%d\n",pData->itemVisibles);
1604                     printf("SB_LINEDOWN:(%d:%d)\n",
1605                         ITEM_BOTTOM (pData),(pData->itemCount - 1 )); 
1606 #endif
1607                     if (ITEM_BOTTOM (pData) < (pData->itemCount - 1 )) 
1608                     {
1609                         newTop ++;
1610                         scrollHeight = -pData->itemHeight;      /* for ScrollWindow() */
1611                     }
1612                 break;
1613                 
1614                 case SB_LINEUP:
1615                     if (pData->itemTop > 0) 
1616                     {
1617                         newTop --;
1618                         scrollHeight = pData->itemHeight;
1619                     }
1620                 break;
1621                 
1622                 case SB_PAGEDOWN:
1623                     if ((pData->itemTop + (pData->itemVisibles << 1)) <=
1624                             pData->itemCount)
1625                         newTop += pData->itemVisibles;
1626                     else
1627                         newTop = pData->itemCount - pData->itemVisibles;
1628
1629                     if (newTop < 0)
1630                         return 0;
1631
1632                     scrollHeight = -(newTop - pData->itemTop)
1633                                     *pData->itemHeight;
1634                 break;
1635
1636                 case SB_PAGEUP:
1637                     if (pData->itemTop >= pData->itemVisibles)
1638                         newTop -= pData->itemVisibles;
1639                     else
1640                         newTop = 0;
1641
1642                     scrollHeight = (pData->itemTop - newTop)*pData->itemHeight;
1643                 break;
1644
1645                 case SB_THUMBTRACK:
1646                     newTop = (int)lParam;
1647                     scrollHeight = (pData->itemTop - newTop)*pData->itemHeight;
1648                 break;
1649             }
1650             
1651             if (scrollHeight) 
1652             {
1653                 pData->itemTop = newTop;
1654 #if 0   /* !!: fix: no scroll */
1655                 ScrollWindow (hwnd, 0, scrollHeight, NULL, NULL);
1656 #endif
1657                 SendMessage (hwnd, WM_PAINT, 0, 0);
1658
1659                 lstSetVScrollInfo (hwnd, pData, TRUE);
1660
1661                 return 0;
1662             }
1663         }
1664         break;
1665
1666         case WM_HSCROLL:
1667             pData = (PLISTBOXDATA)pCtrl->userdata;
1668             switch (wParam)
1669             {
1670                 case SB_LINERIGHT:
1671                 break;
1672                 
1673                 case SB_LINELEFT:
1674                 break;
1675                 
1676                 case SB_PAGELEFT:
1677                 break;
1678                 
1679                 case SB_PAGERIGHT:
1680                 break;
1681             }
1682         break;
1683
1684         default:
1685                 return DefWindowProc (hwnd, message, wParam, lParam);
1686     }
1687     return 0;
1688 }