2 * Copyright (C) 1999, 2000, Wei Yongming.
3 * Portions Copyright (c) 2000 Greg Haerr <greg@censoft.com>
5 * Listbox for Microwindows win32 api.
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.
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.
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,
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.
32 ** Although there was a version by Zhao Jianghua, this version of
33 ** LISTBOX control is written by Wei Yongming from scratch.
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
54 ** 1. Multiple columns support.
60 #define MWINCLUDECOLORS
62 #include "wintools.h" /* Draw3dBox */
63 #include "device.h" /* GdGetTextSize */
65 #define FixStrAlloc(n) malloc((n)+1)
66 #define FreeFixStr(p) free(p)
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
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;
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;
92 #define DEF_LB_BUFFER_LEN 5
94 #define LBF_FOCUS 0x0001
95 #define LBF_NOTHINGSELECTED 0x0002
97 typedef struct _LISTBOXDATA {
98 DWORD dwFlags; /* listbox flags */
100 int itemCount; /* items count */
101 int itemTop; /* start display item */
102 int itemVisibles; /* number of visible items */
104 int itemHilighted; /* current hilighted item */
105 int itemHeight; /* item height */
107 LISTBOXITEM* head; /* items linked list head */
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;
115 void ListboxControlCleanup ();
116 static LRESULT CALLBACK
117 ListboxCtrlProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
119 #define ITEM_BOTTOM(x) (x->itemTop + x->itemVisibles - 1)
121 #define LST_WIDTH_CHECKMARK 11
122 #define LST_HEIGHT_CHECKMARK 11
123 #define LST_INTER_BMPTEXT 2
125 int WINAPI MwRegisterListboxControl(HINSTANCE hInstance)
129 static BITMAP sg_bmpCheckMark;
130 if (!LoadSystemBitmap (&sg_bmpCheckMark, "checkmark")) {
131 fprintf (stderr, "Load ListBox Check Mark Bitmap failure!\n");
135 wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_GLOBALCLASS;
136 wc.lpfnWndProc = (WNDPROC)ListboxCtrlProc;
139 wc.hInstance = hInstance;
141 wc.hCursor = 0; /*LoadCursor(NULL, IDC_ARROW);*/
142 wc.hbrBackground= GetStockObject(WHITE_BRUSH);
143 wc.lpszMenuName = NULL;
144 wc.lpszClassName= "LISTBOX";
146 return RegisterClass(&wc);
149 void ListboxControlCleanup ()
152 UnloadBitmap (&sg_bmpCheckMark);
156 static LRESULT NotifyParent (HWND hwnd, int id, int code)
158 return SendMessage (GetParent (hwnd), WM_COMMAND,
159 (WPARAM) MAKELONG (id, code), (LPARAM)hwnd);
162 static BOOL lstInitListBoxData (HWND hwnd,LISTBOXDATA* pData, int len)
168 memset (pData, 0, sizeof (LISTBOXDATA));
170 pData->itemHeight = GetSysCharHeight ();
173 #if MWCLIENT /* nanox client */
174 GrSetGCFont(hdc->gc,hdc->font->fontid);
175 GrGetGCTextSize(hdc->gc,"X",1,
176 MWTF_ASCII,&xw,&xh,&xb);
178 GdSetFont(hdc->font->pfont);
179 GdGetTextSize(hdc->font->pfont,"X",1,
180 &xw,&xh,&xb,MWTF_ASCII);
183 pData->itemHeight=xh + 1;
185 pData->itemHilighted = 0;
186 pData->dwFlags = LBF_NOTHINGSELECTED;
188 /* init item buffer. */
189 if (!(pData->buffStart = malloc (len * sizeof (LISTBOXITEM))))
192 pData->buffLen = len;
193 pData->buffEnd = pData->buffStart + len;
194 pData->freeList = pData->buffStart;
196 plbi = pData->freeList;
197 for (i = 0; i < len - 1; i++) {
198 plbi->next = plbi + 1;
206 static void lstListBoxCleanUp (LISTBOXDATA* pData)
213 FreeFixStr (plbi->key);
215 if (plbi < pData->buffStart || plbi > pData->buffEnd)
221 free (pData->buffStart);
224 static void lstResetListBoxContent (PLISTBOXDATA pData)
227 PLISTBOXITEM plbi, next;
229 pData->itemCount = 0;
231 pData->itemHilighted = 0;
233 pData->itemVisibles = 0;
238 FreeFixStr (plbi->key);
240 if (plbi < pData->buffStart || plbi > pData->buffEnd)
247 pData->freeList = pData->buffStart;
249 plbi = pData->freeList;
250 for (i = 0; i < pData->buffLen - 1; i++) {
251 plbi->next = plbi + 1;
257 static PLISTBOXITEM lstAllocItem (PLISTBOXDATA pData)
261 if (pData->freeList) {
262 plbi = pData->freeList;
263 pData->freeList = plbi->next;
266 plbi = (PLISTBOXITEM) malloc (sizeof (LISTBOXITEM));
271 static void lstFreeItem (PLISTBOXDATA pData, PLISTBOXITEM plbi)
273 if (plbi < pData->buffStart || plbi > pData->buffEnd)
276 plbi->next = pData->freeList;
277 pData->freeList = plbi;
281 static int lstAddNewItem (DWORD dwStyle,
282 PLISTBOXDATA pData, PLISTBOXITEM newItem, int pos)
285 PLISTBOXITEM insPosItem = NULL;
288 newItem->next = NULL;
291 else if (dwStyle & LBS_SORT) {
294 if (strcmp (newItem->key, plbi->key) < 0) {
300 if (strcmp (newItem->key, plbi->next->key) <= 0)
334 plbi = insPosItem->next;
335 insPosItem->next = newItem;
336 newItem->next = plbi;
342 pData->head = newItem;
343 newItem->next = plbi;
350 static PLISTBOXITEM lstRemoveItem (PLISTBOXDATA pData, int* pos)
353 PLISTBOXITEM plbi, prev;
367 if (plbi == pData->head) {
368 pData->head = pData->head->next;
373 prev->next = plbi->next;
378 else if (*pos == 0) {
380 pData->head = plbi->next;
396 if (plbi == pData->head) {
397 pData->head = pData->head->next;
402 prev->next = plbi->next;
411 static void lstGetItemsRect (PLISTBOXDATA pData, int start, int end, RECT* prc)
416 prc->top = (start - pData->itemTop)*pData->itemHeight;
419 prc->bottom = (end - pData->itemTop + 1)*pData->itemHeight;
423 static void lstInvalidateItem (HWND hwnd, PLISTBOXDATA pData, int pos,BOOL fEBk)
427 if (pos < pData->itemTop || pos > (pData->itemTop + pData->itemVisibles))
430 GetClientRect (hwnd, &rcInv);
431 rcInv.top = (pos - pData->itemTop)*pData->itemHeight;
432 rcInv.bottom = rcInv.top + pData->itemHeight;
434 InvalidateRect (hwnd, &rcInv, fEBk);
437 static BOOL lstInvalidateUnderItem (HWND hwnd, PLISTBOXDATA pData, int pos)
441 if (pos > (pData->itemTop + pData->itemVisibles))
444 if (pos <= pData->itemTop) {
445 InvalidateRect (hwnd, NULL, TRUE);
449 GetClientRect (hwnd, &rcInv);
451 lstGetItemsRect (pData, pos, -1, &rcInv);
453 if (rcInv.top < rcInv.bottom)
454 InvalidateRect (hwnd, &rcInv, TRUE);
459 static PLISTBOXITEM lstGetItem (PLISTBOXDATA pData, int pos)
465 for (i=0; i < pos && plbi; i++)
471 static int lstFindItem (PLISTBOXDATA pData, int start, char* key, BOOL bExact)
474 int keylen = strlen (key);
476 if (start >= (pData->itemCount - 1))
479 plbi = lstGetItem (pData, start);
483 if (bExact && (keylen != strlen (plbi->key))) {
489 if (strncasecmp (key, plbi->key, keylen) == 0)
499 static void lstOnDrawSListBoxItems (HDC hdc, DWORD dwStyle,
500 PLISTBOXDATA pData, int width)
509 plbi = lstGetItem (pData, pData->itemTop);
511 for (i = 0; plbi && i < (pData->itemVisibles + 1); i++) {
513 if (plbi->dwFlags & LBIF_SELECTED) {
514 SetBkColor (hdc, bk = BLUE);
515 SetTextColor (hdc, WHITE);
518 SetBkColor (hdc, bk = WHITE);
519 SetTextColor (hdc, BLACK);
524 rc.bottom = y + pData->itemHeight;
525 FastFillRect(hdc, &rc, bk);
527 if (dwStyle & LBS_CHECKBOX) {
528 x = LST_INTER_BMPTEXT;
529 if (plbi->dwFlags & LBIF_CHECKED)
531 else if (plbi->dwFlags & LBIF_PARTCHECKED)
532 offset = LST_WIDTH_CHECKMARK << 1;
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,
543 x += LST_WIDTH_CHECKMARK + LST_INTER_BMPTEXT;
545 #if 0 /* fix: no icon */
546 if (dwStyle & LBS_USEICON && plbi->dwData) {
548 x, y, pData->itemHeight, pData->itemHeight,
549 (HICON) plbi->dwData);
550 x += pData->itemHeight + LST_INTER_BMPTEXT;
554 /* jmt: should be SYSTEM_FIXED_FONT because of minigui's GetSysCharXXX() */
556 SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
558 SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
559 TextOut (hdc, x+2, y, plbi->key,-1);
561 y += pData->itemHeight;
566 static int lstSelectItem (DWORD dwStyle, PLISTBOXDATA pData, int newSel)
568 PLISTBOXITEM plbi, newItem;
571 newItem = lstGetItem (pData, newSel);
572 #if 1 /* jmt: fixed if no item added */
573 if (!newItem) return -1;
577 fprintf (stderr, "ASSERT failed: return value of lstGetItem"
578 " in lstSelectItem.\n");
581 if (dwStyle & LBS_MULTIPLESEL) {
582 newItem->dwFlags ^= LBIF_SELECTED;
589 if (plbi->dwFlags & LBIF_SELECTED) {
590 if (index != newSel) {
591 plbi->dwFlags &= ~LBIF_SELECTED;
592 newItem->dwFlags |= LBIF_SELECTED;
602 newItem->dwFlags |= LBIF_SELECTED;
606 static void lstDrawFocusRect (HDC hdc, PLISTBOXDATA pData, RECT* rc)
608 HGDIOBJ oldbrush,oldpen;
610 if (pData->itemHilighted < pData->itemTop
611 || pData->itemHilighted > (pData->itemTop + pData->itemVisibles))
614 if (pData->dwFlags & LBF_FOCUS) {
615 lstGetItemsRect (pData, pData->itemHilighted, pData->itemHilighted, rc);
617 InflateRect (rc, -1, -1);
619 FocusRect (hdc, rc->left - 1, rc->top, rc->right, rc->bottom);
621 oldbrush=SelectObject(hdc, GetStockObject(NULL_BRUSH));
622 oldpen=SelectObject(hdc, CreatePen(PS_SOLID, 1,
623 GetSysColor(COLOR_BTNHIGHLIGHT)));
625 GdSetMode(MWMODE_XOR);
627 Rectangle (hdc, rc->left, rc->top, rc->right, rc->bottom);
629 GdSetMode(MWMODE_SET);
631 SelectObject(hdc,oldbrush);
632 DeleteObject(SelectObject(hdc,oldpen));
637 static void lstCalcParams (const RECT* rcClient, PLISTBOXDATA pData)
639 #define RECTHP(prc) (prc->bottom - prc->top)
640 pData->itemVisibles = (RECTHP (rcClient)) / pData->itemHeight;
642 #if 1 /* test calculation of itemVisibles */
643 if( ((RECTHP (rcClient)) % pData->itemHeight) )
644 pData->itemVisibles++;
648 extern BOOL SetScrollPos (HWND hWnd, int iSBar, int iNewPos);
649 extern BOOL EnableScrollBar (HWND hWnd, int iSBar, BOOL bEnable);
651 static void lstSetVScrollInfo (HWND hwnd, PLISTBOXDATA pData, BOOL fRedraw)
655 if (pData->itemVisibles >= pData->itemCount)
657 SetScrollPos (hwnd, SB_VERT, 0);
658 EnableScrollBar (hwnd, SB_VERT, FALSE);
662 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
663 si.nMax = pData->itemCount - 1;
665 si.nPage = min (pData->itemVisibles, (pData->itemCount - pData->itemTop));
666 si.nPos = pData->itemTop;
668 SetScrollInfo (hwnd, SB_VERT, &si, fRedraw);
669 EnableScrollBar (hwnd, SB_VERT, TRUE);
673 ListboxCtrlProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
681 dwStyle = pCtrl->style;
686 pData = (LISTBOXDATA*) malloc (sizeof(LISTBOXDATA));
690 pCtrl->userdata = (DWORD)pData;
691 if (!lstInitListBoxData (hwnd, pData, DEF_LB_BUFFER_LEN)) {
701 pData = (PLISTBOXDATA)pCtrl->userdata;
702 GetClientRect(hwnd, &rc);
703 lstCalcParams (&rc, pData);
708 pData = (PLISTBOXDATA)pCtrl->userdata;
709 lstListBoxCleanUp (pData);
713 case LB_RESETCONTENT:
714 pData = (PLISTBOXDATA)pCtrl->userdata;
715 lstResetListBoxContent (pData);
716 InvalidateRect (hwnd, NULL, TRUE);
720 case LB_INSERTSTRING:
723 PLISTBOXITEMINFO plbii = NULL;
724 PLISTBOXITEM newItem;
727 if (dwStyle & LBS_CHECKBOX || dwStyle & LBS_USEICON) {
728 plbii = (PLISTBOXITEMINFO)lParam;
732 string = plbii->string;
735 string = (char*)lParam;
736 if (string == NULL || string [0] == '\0')
740 pData = (PLISTBOXDATA)pCtrl->userdata;
741 newItem = lstAllocItem (pData);
743 NotifyParent (hwnd, pCtrl->id, LBN_ERRSPACE);
747 newItem->key = FixStrAlloc (strlen (string));
748 strcpy (newItem->key, string);
749 newItem->dwFlags = LBIF_NORMAL;
751 switch (plbii->cmFlag) {
753 newItem->dwFlags |= LBIF_CHECKED;
755 case CMFLAG_PARTCHECKED:
756 newItem->dwFlags |= LBIF_PARTCHECKED;
760 if (dwStyle & LBS_USEICON)
761 newItem->dwData = (DWORD)plbii->hIcon;
763 newItem->dwData = 0L;
765 newItem->dwAddData = 0L;
767 if (message == LB_ADDSTRING)
768 pos = lstAddNewItem (dwStyle, pData, newItem, -1);
770 pos = lstAddNewItem (dwStyle, pData, newItem, (int)wParam);
772 lstInvalidateUnderItem (hwnd, pData, pos);
774 lstSetVScrollInfo (hwnd, pData, TRUE);
780 case LB_DELETESTRING:
782 PLISTBOXITEM removed;
785 delete = (int)wParam;
787 pData = (PLISTBOXDATA)pCtrl->userdata;
788 removed = lstRemoveItem (pData, &delete);
790 FreeFixStr (removed->key);
791 lstFreeItem (pData, removed);
795 if (pData->itemTop != 0
796 && pData->itemCount <= pData->itemVisibles) {
798 InvalidateRect (hwnd, NULL, TRUE);
801 lstInvalidateUnderItem (hwnd, pData, delete);
802 if (delete <= pData->itemTop) {
804 if (pData->itemTop < 0)
809 if (pData->itemHilighted >= pData->itemCount) {
810 pData->itemHilighted = pData->itemCount - 1;
811 if (pData->itemHilighted < 0)
812 pData->itemHilighted = 0;
815 if (pData->itemHilighted < pData->itemTop)
816 pData->itemHilighted = pData->itemTop;
817 if (pData->itemHilighted > ITEM_BOTTOM (pData))
818 pData->itemHilighted = ITEM_BOTTOM (pData);
820 lstSetVScrollInfo (hwnd, pData, TRUE);
826 if( *(char*)lParam == '\0' )
829 pData = (PLISTBOXDATA)pCtrl->userdata;
830 return lstFindItem(pData, (int)wParam, (char*)lParam, FALSE);
832 case LB_FINDSTRINGEXACT:
833 if( *(char*)lParam == '\0' )
836 pData = (PLISTBOXDATA)pCtrl->userdata;
837 return lstFindItem(pData, (int)wParam, (char*)lParam, TRUE);
841 int newTop = (int) wParam;
843 pData = (PLISTBOXDATA)pCtrl->userdata;
847 else if (newTop > pData->itemCount - pData->itemVisibles)
848 newTop = pData->itemCount - pData->itemVisibles;
850 if (pData->itemTop != newTop) {
851 pData->itemTop = newTop;
853 if (pData->itemHilighted < pData->itemTop)
854 pData->itemHilighted = pData->itemTop;
855 if (pData->itemHilighted > ITEM_BOTTOM (pData))
856 pData->itemHilighted = ITEM_BOTTOM (pData);
858 lstSetVScrollInfo (hwnd, pData, TRUE);
860 InvalidateRect (hwnd, NULL, TRUE);
866 case LB_SETCARETINDEX:
868 int new = (int)wParam;
871 pData = (PLISTBOXDATA)pCtrl->userdata;
872 if (new < 0 || new > pData->itemCount - 1)
875 old = pData->itemHilighted;
876 if (new >= 0 && new != old) {
877 if (pData->itemCount - new >= pData->itemVisibles)
880 newTop = max (pData->itemCount - pData->itemVisibles, 0);
882 pData->itemTop = newTop;
883 pData->itemHilighted = new;
884 lstSetVScrollInfo (hwnd, pData, TRUE);
887 if (!(dwStyle & LBS_MULTIPLESEL))
888 lstSelectItem (dwStyle, pData, new);
889 InvalidateRect (hwnd, NULL, TRUE);
896 pData = (PLISTBOXDATA)pCtrl->userdata;
897 return pData->itemCount;
905 pData = (PLISTBOXDATA)pCtrl->userdata;
906 if (dwStyle & LBS_MULTIPLESEL)
907 return pData->itemHilighted;
911 if (plbi->dwFlags & LBIF_SELECTED)
927 pData = (PLISTBOXDATA)pCtrl->userdata;
932 if (plbi->dwFlags & LBIF_SELECTED)
942 pData = (PLISTBOXDATA)pCtrl->userdata;
943 return pData->itemTop;
946 case LB_GETCARETINDEX:
947 pData = (PLISTBOXDATA)pCtrl->userdata;
948 return pData->itemHilighted;
955 pData = (PLISTBOXDATA)pCtrl->userdata;
956 plbi = lstGetItem (pData, (int)wParam);
958 return strlen (plbi->key);
968 pData = (PLISTBOXDATA)pCtrl->userdata;
969 plbi = lstGetItem (pData, (int)wParam);
971 strcpy ((char*)lParam, plbi->key);
982 pData = (PLISTBOXDATA)pCtrl->userdata;
983 plbi = lstGetItem (pData, (int)wParam);
985 newStr = FixStrAlloc (strlen ((char*)lParam));
987 FreeFixStr (plbi->key);
989 strcpy (plbi->key, (char*)lParam);
990 lstInvalidateItem (hwnd, pData, (int)wParam, TRUE);
1000 case LB_GETITEMDATA:
1003 PLISTBOXITEMINFO plbii;
1005 pData = (PLISTBOXDATA)pCtrl->userdata;
1006 if (!(plbi = lstGetItem (pData, (int)wParam)))
1009 if (!(dwStyle & LBS_CHECKBOX || dwStyle & LBS_USEICON)) {
1010 return plbi->dwData;
1013 plbii = (PLISTBOXITEMINFO)lParam;
1017 if (plbi->dwFlags & LBIF_CHECKED)
1018 plbii->cmFlag = CMFLAG_CHECKED;
1019 else if (plbi->dwFlags & LBIF_PARTCHECKED)
1020 plbii->cmFlag = CMFLAG_PARTCHECKED;
1022 plbii->cmFlag = CMFLAG_BLANK;
1023 plbii->hIcon = (HICON)plbi->dwData;
1029 case LB_SETITEMDATA:
1032 PLISTBOXITEMINFO plbii;
1034 pData = (PLISTBOXDATA)pCtrl->userdata;
1035 if (!(plbi = lstGetItem (pData, (int)wParam)))
1038 if (!(dwStyle & LBS_CHECKBOX || dwStyle & LBS_USEICON)) {
1039 plbi->dwData = (DWORD)lParam;
1043 plbii = (PLISTBOXITEMINFO)lParam;
1047 plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
1048 switch (plbii->cmFlag) {
1049 case CMFLAG_CHECKED:
1050 plbi->dwFlags |= LBIF_CHECKED;
1052 case CMFLAG_PARTCHECKED:
1053 plbi->dwFlags |= LBIF_PARTCHECKED;
1057 if (dwStyle & LBS_USEICON)
1058 plbi->dwData = (DWORD)plbii->hIcon;
1062 lstInvalidateItem (hwnd, pData, (int)wParam, TRUE);
1068 case LB_GETITEMADDDATA:
1072 pData = (PLISTBOXDATA)pCtrl->userdata;
1073 if (!(plbi = lstGetItem (pData, (int)wParam)))
1076 return plbi->dwAddData;
1080 case LB_SETITEMADDDATA:
1084 pData = (PLISTBOXDATA)pCtrl->userdata;
1085 if (!(plbi = lstGetItem (pData, (int)wParam)))
1088 plbi->dwAddData = (DWORD)lParam;
1094 case LB_GETCHECKMARK:
1098 if (!(dwStyle & LBS_CHECKBOX))
1101 pData = (PLISTBOXDATA)pCtrl->userdata;
1102 if (!(plbi = lstGetItem (pData, (int)wParam)))
1105 if (plbi->dwFlags & LBIF_CHECKED)
1106 return CMFLAG_CHECKED;
1108 if (plbi->dwFlags & LBIF_PARTCHECKED)
1109 return CMFLAG_PARTCHECKED;
1111 return CMFLAG_BLANK;
1115 case LB_SETCHECKMARK:
1119 if (!(dwStyle & LBS_CHECKBOX))
1122 pData = (PLISTBOXDATA)pCtrl->userdata;
1123 if (!(plbi = lstGetItem (pData, (int)wParam)))
1126 plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
1128 case CMFLAG_CHECKED:
1129 plbi->dwFlags |= LBIF_CHECKED;
1131 case CMFLAG_PARTCHECKED:
1132 plbi->dwFlags |= LBIF_PARTCHECKED;
1136 lstInvalidateItem (hwnd, pData, (int)wParam, TRUE);
1142 case LB_GETSELITEMS:
1150 nItem = (int)wParam;
1151 pInt = (int*)lParam;
1153 pData = (PLISTBOXDATA)pCtrl->userdata;
1157 if (plbi->dwFlags & LBIF_SELECTED) {
1160 *(pInt + nSel) = index;
1179 pData = (PLISTBOXDATA)pCtrl->userdata;
1180 plbi = lstGetItem (pData, (int)wParam);
1182 return plbi->dwFlags & LBIF_SELECTED;
1192 pData = (PLISTBOXDATA)pCtrl->userdata;
1193 plbi = lstGetItem (pData, (int)lParam);
1195 pData->dwFlags &= ~LBF_NOTHINGSELECTED;
1197 plbi->dwFlags ^= LBIF_SELECTED;
1198 else if (wParam == 0)
1199 plbi->dwFlags &= ~LBIF_SELECTED;
1201 plbi->dwFlags |= LBIF_SELECTED;
1203 lstInvalidateItem (hwnd, pData, (int)lParam, FALSE);
1210 case LB_GETITEMHEIGHT:
1211 pData = (PLISTBOXDATA)pCtrl->userdata;
1212 return pData->itemHeight;
1215 case LB_SETITEMHEIGHT:
1216 pData = (PLISTBOXDATA)pCtrl->userdata;
1217 if (pData->itemHeight != LOWORD (lParam)) {
1220 pData->itemHeight = LOWORD (lParam);
1221 GetClientRect (hwnd, &rcClient);
1222 lstCalcParams (&rcClient, pData);
1224 lstSetVScrollInfo (hwnd, pData, TRUE);
1225 InvalidateRect (hwnd, NULL, TRUE);
1231 pData = (PLISTBOXDATA)pCtrl->userdata;
1233 if (pData->dwFlags & LBF_FOCUS)
1236 pData->dwFlags |= LBF_FOCUS;
1237 InvalidateRect(hwnd, NULL, TRUE);
1239 NotifyParent (hwnd, pCtrl->id, LBN_SETFOCUS);
1245 pData = (PLISTBOXDATA)pCtrl->userdata;
1247 pData->dwFlags &= ~LBF_FOCUS;
1248 InvalidateRect(hwnd, NULL, TRUE);
1250 NotifyParent (hwnd, pCtrl->id, LBN_KILLFOCUS);
1255 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1257 case WM_GETTEXTLENGTH:
1270 LPNCCALCSIZE_PARAMS lpnc;
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);
1283 hdc = wParam? (HDC)wParam: GetWindowDC (hwnd);
1284 GetWindowRect(hwnd, &rc);
1286 if (dwStyle & WS_BORDER)
1287 Draw3dInset(hdc, rc.left, rc.top,
1288 rc.right-rc.left, rc.bottom-rc.top);
1291 ReleaseDC (hwnd, hdc);
1300 hdc = BeginPaint (hwnd,&ps);
1301 pData = (PLISTBOXDATA)pCtrl->userdata;
1304 * If this is the first paint and there's nothing
1305 * selected, then auto select the topmost displayed item.
1307 if (pData->dwFlags & LBF_NOTHINGSELECTED) {
1308 lstSelectItem (hwnd->style, pData, pData->itemTop);
1309 pData->dwFlags &= ~LBF_NOTHINGSELECTED;
1311 GetClientRect (hwnd, &rc);
1312 lstOnDrawSListBoxItems (hdc, dwStyle, pData, rc.right-rc.left);
1313 lstDrawFocusRect (hdc, pData, &rc);
1315 EndPaint (hwnd, &ps);
1319 case WM_LBUTTONDBLCLK:
1320 if (dwStyle & LBS_NOTIFY)
1321 NotifyParent (hwnd, pCtrl->id, LBN_DBLCLK);
1324 case WM_LBUTTONDOWN:
1326 int oldSel, mouseX, mouseY, hit;
1329 pData = (PLISTBOXDATA)pCtrl->userdata;
1330 if (pData->itemCount == 0)
1333 mouseX = LOWORD (lParam);
1334 mouseY = HIWORD (lParam);
1335 hit = mouseY / pData->itemHeight;
1336 hit += pData->itemTop;
1338 if (hit >= pData->itemCount)
1341 GetClientRect (hwnd, &rcInv);
1342 oldSel = lstSelectItem (dwStyle, pData, hit);
1343 if ((dwStyle & LBS_NOTIFY) && (oldSel != hit))
1344 NotifyParent (hwnd, pCtrl->id, LBN_SELCHANGE);
1346 if (oldSel >= pData->itemTop
1347 && (oldSel <= pData->itemTop + pData->itemVisibles)) {
1348 lstGetItemsRect (pData, oldSel, oldSel, &rcInv);
1349 InvalidateRect (hwnd, &rcInv, TRUE);
1353 lstGetItemsRect (pData, hit, hit, &rcInv);
1354 InvalidateRect (hwnd, &rcInv, TRUE);
1356 if (pData->itemHilighted != hit)
1358 hdc = GetDC(hwnd); /* hdc = GetClientDC (hwnd); */
1360 lstDrawFocusRect (hdc, pData, &rcInv);
1361 ReleaseDC (hwnd,hdc);
1363 pData->itemHilighted = hit;
1365 if (dwStyle & LBS_CHECKBOX) {
1366 if (mouseX > 0 && mouseX < LST_WIDTH_CHECKMARK) {
1367 NotifyParent (hwnd, pCtrl->id, LBN_CLICKCHECKMARK);
1369 if (dwStyle & LBS_AUTOCHECK) {
1372 plbi = lstGetItem (pData, hit);
1374 switch (plbi->dwFlags & LBIF_CHECKMARKMASK) {
1376 plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
1379 plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
1380 plbi->dwFlags |= LBIF_CHECKED;
1384 lstInvalidateItem (hwnd, pData, hit, TRUE);
1389 lstSetVScrollInfo (hwnd, pData, TRUE);
1401 int oldSel, newSel, newTop;
1404 pData = (PLISTBOXDATA)pCtrl->userdata;
1405 newTop = pData->itemTop;
1406 newSel = pData->itemHilighted;
1407 switch (LOWORD (wParam))
1409 case VK_HOME: /* SCANCODE_HOME: */
1414 case VK_END: /* SCANCODE_END: */
1415 newSel = pData->itemCount - 1;
1416 if (pData->itemCount > pData->itemVisibles)
1417 newTop = pData->itemCount - pData->itemVisibles;
1422 case VK_DOWN: /* SCANCODE_CURSORBLOCKDOWN: */
1424 if (newSel >= pData->itemCount)
1426 if (newSel > ITEM_BOTTOM (pData))
1430 case VK_UP: /* SCANCODE_CURSORBLOCKUP: */
1434 if (newSel < pData->itemTop)
1438 case VK_NEXT: /* SCANCODE_PAGEDOWN: */
1439 newSel += pData->itemVisibles;
1440 if (newSel >= pData->itemCount)
1441 newSel = pData->itemCount - 1;
1443 if (pData->itemCount - newSel >= pData->itemVisibles)
1446 newTop = max (pData->itemCount-pData->itemVisibles, 0);
1449 case VK_PRIOR: /* SCANCODE_PAGEUP: */
1450 newSel -= pData->itemVisibles;
1454 newTop -= pData->itemVisibles;
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);
1473 InvalidateRect (hwnd, NULL, TRUE);
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);
1481 if (oldSel >= pData->itemTop
1482 && oldSel <= (ITEM_BOTTOM (pData) + 1)) {
1483 lstGetItemsRect (pData, oldSel, oldSel, &rcInv);
1484 InvalidateRect (hwnd, &rcInv, TRUE);
1488 if (newSel < newTop) {
1489 pData->itemHilighted = newSel;
1493 lstGetItemsRect (pData, pData->itemHilighted,
1494 pData->itemHilighted, &rcInv);
1496 hdc = GetDC(hwnd); /* hdc = GetClientDC (hwnd); */
1498 lstDrawFocusRect (hdc, pData, &rcInv);
1499 ReleaseDC (hwnd,hdc);
1501 pData->itemHilighted = newSel;
1502 lstGetItemsRect (pData, newSel, newSel, &rcInv);
1503 InvalidateRect (hwnd, &rcInv, TRUE);
1507 hdc = GetDC(hwnd); /* hdc = GetClientDC (hwnd); */
1509 lstDrawFocusRect (hdc, pData, &rcInv);
1510 pData->itemHilighted = newSel;
1511 GetClientRect (hwnd, &rcInv);
1512 lstDrawFocusRect (hdc, pData, &rcInv);
1513 ReleaseDC (hwnd,hdc);
1516 lstSetVScrollInfo (hwnd, pData, TRUE);
1527 head [0] = (char) (wParam);
1530 pData = (PLISTBOXDATA)pCtrl->userdata;
1532 if (head[0] == ' ') {
1533 if (dwStyle & LBS_MULTIPLESEL) {
1536 GetClientRect (hwnd, &rcInv);
1537 lstSelectItem (dwStyle, pData, pData->itemHilighted);
1538 lstGetItemsRect (pData,
1539 pData->itemHilighted,
1540 pData->itemHilighted,
1542 InvalidateRect (hwnd, &rcInv, TRUE);
1544 else if (dwStyle & LBS_CHECKBOX) {
1545 NotifyParent (hwnd, pCtrl->id, LBN_CLICKCHECKMARK);
1547 if (dwStyle & LBS_AUTOCHECK) {
1550 plbi = lstGetItem (pData, pData->itemHilighted);
1552 switch (plbi->dwFlags & LBIF_CHECKMARKMASK) {
1554 plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
1557 plbi->dwFlags &= ~LBIF_CHECKMARKMASK;
1558 plbi->dwFlags |= LBIF_CHECKED;
1562 lstInvalidateItem (hwnd, pData,
1563 pData->itemHilighted, TRUE);
1569 index = lstFindItem (pData, pData->itemHilighted + 1, head, FALSE);
1571 index = lstFindItem (pData, 0, head, FALSE);
1575 if (pData->itemCount - index >= pData->itemVisibles)
1578 newTop = max (pData->itemCount - pData->itemVisibles, 0);
1580 pData->itemTop = newTop;
1581 pData->itemHilighted = index;
1582 if (!(dwStyle & LBS_MULTIPLESEL))
1583 lstSelectItem (dwStyle, pData, index);
1584 InvalidateRect (hwnd, NULL, TRUE);
1586 lstSetVScrollInfo (hwnd, pData, TRUE);
1594 int scrollHeight = 0;
1596 pData = (PLISTBOXDATA)pCtrl->userdata;
1597 newTop = pData->itemTop;
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 ));
1607 if (ITEM_BOTTOM (pData) < (pData->itemCount - 1 ))
1610 scrollHeight = -pData->itemHeight; /* for ScrollWindow() */
1615 if (pData->itemTop > 0)
1618 scrollHeight = pData->itemHeight;
1623 if ((pData->itemTop + (pData->itemVisibles << 1)) <=
1625 newTop += pData->itemVisibles;
1627 newTop = pData->itemCount - pData->itemVisibles;
1632 scrollHeight = -(newTop - pData->itemTop)
1637 if (pData->itemTop >= pData->itemVisibles)
1638 newTop -= pData->itemVisibles;
1642 scrollHeight = (pData->itemTop - newTop)*pData->itemHeight;
1646 newTop = (int)lParam;
1647 scrollHeight = (pData->itemTop - newTop)*pData->itemHeight;
1653 pData->itemTop = newTop;
1654 #if 0 /* !!: fix: no scroll */
1655 ScrollWindow (hwnd, 0, scrollHeight, NULL, NULL);
1657 SendMessage (hwnd, WM_PAINT, 0, 0);
1659 lstSetVScrollInfo (hwnd, pData, TRUE);
1667 pData = (PLISTBOXDATA)pCtrl->userdata;
1685 return DefWindowProc (hwnd, message, wParam, lParam);