📄 listbox.c
字号:
/* * Copyright (C) 1999, 2000, Wei Yongming. * Portions Copyright (c) 2000, 2005 Greg Haerr <greg@censoft.com> * * Listbox for Microwindows win32 api. *//*** This library is free software; you can redistribute it and/or** modify it under the terms of the GNU Library General Public** License as published by the Free Software Foundation; either** version 2 of the License, or (at your option) any later version.**** This library is distributed in the hope that it will be useful,** but WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU** Library General Public License for more details.**** You should have received a copy of the GNU Library General Public** License along with this library; if not, write to the Free** Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,** MA 02111-1307, USA*//*** Alternatively, the contents of this file may be used under the terms ** of the Mozilla Public License (the "MPL License") in which case the** provisions of the MPL License are applicable instead of those above.*//* Note:** Although there was a version by Zhao Jianghua, this version of** LISTBOX control is written by Wei Yongming from scratch.**** Modify records:**** Who When Where For What Status**-----------------------------------------------------------------------------** Wei Yongming 1999/10/18 Tsinghua Item Additional Data Finished** Wei Yongming 1999/10/31 Tsinghua Space bar for checkmark Finished** Wei Yongming 1999/10/31 Tsinghua Character match item Finished** Wei Yongming 1999/11/07 Tsinghua Character match item Bug fixing** WEI Yongming 2000/01/20 Tsinghua Thumb dragging Finished** WEI Yongming 2000/02/24 Tsinghua Add MPL License Finished** Kevin Tseng 2000/05/26 gv port to microwin ported** Greg Haerr 2000/06/15 Utah 3d look, bug fixes Finished** Kevin Tseng 2000/06/22 gv port to mw-nanox ported** Kevin Tseng 2000/06/22 gv fixed bug if no item Finished** Kevin Tseng 2000/08/08 gv enable scrollbar(V) porting** Kevin Tseng 2000/08/10 gv enable scrollbar(V) ported** Kevin Tseng 2000/08/10 gv WM_CHAR, WM_KEYDOWN ported** Gabriele Brugnoni 2003/09/16 Italy Implemented WM_SETFONT Finished** Gabriele Brugnoni 2003/09/16 Italy Implemented LBS_USETABSTOPS Finished** Gabriele Brugnoni 2003/09/29 Italy Implemented WS_OWNERDRAW FIX and VAR**** TODO:** 1. Multiple columns support.*/#include <stdio.h>#include <stdlib.h>#include <string.h>#define MWINCLUDECOLORS#include "windows.h"#include "wintern.h"#include "wintools.h" /* Draw3dBox */#include "device.h" /* GdGetTextSize */// WM_SETFONT implementation#define GET_WND_FONT(h) ((HFONT)GetWindowLong(h, 0))#define SET_WND_FONT(h, f) (SetWindowLong(h, 0, (LPARAM)(f)))#define ISOWNERDRAW(dwStyle) ((dwStyle & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) != 0)#define FixStrAlloc(n) malloc((n)+1)#define FreeFixStr(p) free(p)#define LBIF_NORMAL 0x0000L#define LBIF_SELECTED 0x0001L#define LBIF_CHECKED 0x0010L#define LBIF_PARTCHECKED 0x0020L#define LBIF_CHECKMARKMASK 0x00F0L#define CMFLAG_BLANK 0#define CMFLAG_CHECKED 1#define CMFLAG_PARTCHECKED 2typedef struct _LISTBOXITEMINFO{ int insPos; /* insert position */ char *string; /* item string */ int cmFlag; /* check mark flag */ HICON hIcon; /* handle of icon */} LISTBOXITEMINFO, *PLISTBOXITEMINFO;typedef struct _LISTBOXITEM{ char *key; /* item sort key */ DWORD dwFlags; /* item flags */ DWORD dwData; /* item data */ DWORD dwAddData; /* item additional data */ struct _LISTBOXITEM *next; /* next item */} LISTBOXITEM, *PLISTBOXITEM;#define DEF_LB_BUFFER_LEN 5#define LBF_FOCUS 0x0001#define LBF_NOTHINGSELECTED 0x0002#define LBF_FOCUSRECT 0x0004#define LBF_USERMEASURE 0x0008typedef struct _LISTBOXDATA{ DWORD dwFlags; /* listbox flags */ int itemCount; /* items count */ int itemTop; /* start display item */ int itemVisibles; /* number of visible items */ int itemHilighted; /* current hilighted item */ int itemHeight; /* item height */ int hoffset; /* offset for horiz scroll */ int hextent; /* horizontal extent */ int nTabStops; /* count of tabstops */ LPINT pTabStops; /* array of tabstops */ LISTBOXITEM *head; /* items linked list head */ int buffLen; /* buffer length */ LISTBOXITEM *buffStart; /* buffer start */ LISTBOXITEM *buffEnd; /* buffer end */ LISTBOXITEM *freeList; /* free list in buffer */} LISTBOXDATA, *PLISTBOXDATA;void ListboxControlCleanup();static LRESULT CALLBACKListboxCtrlProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);static void lstDrawFocusRect(HWND hwnd, HDC hdc, PLISTBOXDATA pData, BOOL bFocus);static PLISTBOXITEM lstGetItem(PLISTBOXDATA pData, int pos);#define ITEM_BOTTOM(x) (x->itemTop + x->itemVisibles - 1)#define LST_WIDTH_CHECKMARK 11#define LST_HEIGHT_CHECKMARK 11#define LST_INTER_BMPTEXT 2int WINAPIMwRegisterListboxControl(HINSTANCE hInstance){ WNDCLASS wc;#if 0 static BITMAP sg_bmpCheckMark; if (!LoadSystemBitmap(&sg_bmpCheckMark, "checkmark")) { fprintf(stderr, "Load ListBox Check Mark Bitmap failure!\n"); return FALSE; }#endif wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_GLOBALCLASS; wc.lpfnWndProc = (WNDPROC) ListboxCtrlProc; wc.cbClsExtra = 0; wc.cbWndExtra = 4; // WM_SETFONT wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = 0; /*LoadCursor(NULL, IDC_ARROW); */ wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "LISTBOX"; return RegisterClass(&wc);}voidListboxControlCleanup(){#if 0 UnloadBitmap(&sg_bmpCheckMark);#endif}static voidlbFillDrawitemstruct(HWND hwnd, HDC hdc, LPDRAWITEMSTRUCT lpDrw, LPRECT lpRc, UINT action, int id, PLISTBOXITEM plbi){ PLISTBOXDATA pData = (PLISTBOXDATA) hwnd->userdata; if (plbi == NULL) plbi = lstGetItem(pData, id); lpDrw->CtlType = ODT_LISTBOX; lpDrw->CtlID = GetDlgCtrlID(hwnd); lpDrw->itemID = id; lpDrw->itemAction = action; lpDrw->itemState = 0; if (plbi->dwFlags & LBIF_SELECTED) lpDrw->itemState |= ODS_SELECTED; if ((id == pData->itemHilighted) && (hwnd == GetFocus())) lpDrw->itemState |= ODS_FOCUS; if (!IsWindowEnabled(hwnd)) lpDrw->itemState |= ODS_DISABLED; lpDrw->hwndItem = hwnd; lpDrw->hDC = hdc; lpDrw->rcItem = *lpRc; lpDrw->itemData = plbi->dwData;}static BOOLlbAskMeasureItem(HWND hwnd, int id, int *ph){ MEASUREITEMSTRUCT ms; BOOL res; ms.CtlType = ODT_LISTBOX; ms.CtlID = GetDlgCtrlID(hwnd); ms.itemID = id; if (id >= 0) ms.itemData = SendMessage(hwnd, LB_GETITEMDATA, id, 0); res = SendMessage(GetParent(hwnd), WM_MEASUREITEM, ms.CtlType, (LPARAM) & ms); if (res) { *ph = ms.itemHeight; } return res;}static LRESULTNotifyParent(HWND hwnd, int id, int code){ return SendMessage(GetParent(hwnd), WM_COMMAND, (WPARAM) MAKELONG(id, code), (LPARAM) hwnd);}static voidlstCalcHeight(HWND hwnd){ int xw, xh, xb; PLISTBOXDATA pData = (PLISTBOXDATA) hwnd->userdata; BOOL other = FALSE; if (ISOWNERDRAW(GetWindowLong(hwnd, GWL_STYLE))) other = lbAskMeasureItem(hwnd, -1, &pData->itemHeight); if (!other) { HDC hdc = GetDC(hwnd);#if MWCLIENT /* nanox client */ GrSetGCFont(hdc->gc, hdc->font->fontid); GrGetGCTextSize(hdc->gc, "X", 1, MWTF_ASCII, &xw, &xh, &xb);#else SelectObject(hdc, GET_WND_FONT(hwnd)); GdSetFont(hdc->font->pfont); GdGetTextSize(hdc->font->pfont, "X", 1, &xw, &xh, &xb, MWTF_ASCII);#endif ReleaseDC(hwnd, hdc); pData->itemHeight = xh + 1; } else pData->dwFlags |= LBF_USERMEASURE;}static BOOLlstInitListBoxData(HWND hwnd, LISTBOXDATA * pData, int len){ int i; PLISTBOXITEM plbi; RECT rc; GetClientRect(hwnd, &rc); memset(pData, 0, sizeof(LISTBOXDATA)); SET_WND_FONT(hwnd, GetStockObject(SYSTEM_FIXED_FONT)); lstCalcHeight(hwnd); pData->itemHilighted = 0; pData->dwFlags = LBF_NOTHINGSELECTED; pData->hextent = rc.right; pData->hoffset = 0; /* init item buffer. */ if (!(pData->buffStart = malloc(len * sizeof(LISTBOXITEM)))) return FALSE; pData->buffLen = len; pData->buffEnd = pData->buffStart + len; pData->freeList = pData->buffStart; plbi = pData->freeList; for (i = 0; i < len - 1; i++) { plbi->next = plbi + 1; plbi++; } plbi->next = NULL; return TRUE;}static voidlstListBoxCleanUp(LISTBOXDATA * pData){ PLISTBOXITEM plbi; PLISTBOXITEM next; plbi = pData->head; while (plbi) { FreeFixStr(plbi->key); next = plbi->next; if (plbi < pData->buffStart || plbi > pData->buffEnd) free(plbi); plbi = next; } if (pData->pTabStops) { free(pData->pTabStops); pData->pTabStops = NULL; } free(pData->buffStart);}static voidlstResetListBoxContent(PLISTBOXDATA pData){ int i; PLISTBOXITEM plbi, next; pData->itemCount = 0; pData->itemTop = 0; pData->itemHilighted = 0;#if 0 pData->itemVisibles = 0;#endif plbi = pData->head; while (plbi) { FreeFixStr(plbi->key); next = plbi->next; if (plbi < pData->buffStart || plbi > pData->buffEnd) free(plbi); plbi = next; } pData->head = NULL; pData->freeList = pData->buffStart; plbi = pData->freeList; for (i = 0; i < pData->buffLen - 1; i++) { plbi->next = plbi + 1; plbi++; } plbi->next = NULL;}static PLISTBOXITEMlstAllocItem(PLISTBOXDATA pData){ PLISTBOXITEM plbi; if (pData->freeList) { plbi = pData->freeList; pData->freeList = plbi->next; } else plbi = (PLISTBOXITEM) malloc(sizeof(LISTBOXITEM)); return plbi;}static voidlstFreeItem(PLISTBOXDATA pData, PLISTBOXITEM plbi){ if (plbi < pData->buffStart || plbi > pData->buffEnd) free(plbi); else { plbi->next = pData->freeList; pData->freeList = plbi; }}static intlstAddNewItem(DWORD dwStyle, PLISTBOXDATA pData, PLISTBOXITEM newItem, int pos){ PLISTBOXITEM plbi; PLISTBOXITEM insPosItem = NULL; int insPos = 0; newItem->next = NULL; if (!pData->head) insPosItem = NULL; else if (dwStyle & LBS_SORT) { plbi = pData->head; if (strcmp(newItem->key, plbi->key) < 0) { insPosItem = NULL; insPos = 0; } else { while (plbi->next) { if (strcmp(newItem->key, plbi->next->key) <= 0) break; plbi = plbi->next; insPos++; } insPosItem = plbi; } } else { plbi = pData->head; if (pos < 0) { while (plbi->next) { plbi = plbi->next; insPos++; } insPosItem = plbi; } else if (pos > 0) { int index = 0; while (plbi->next) { if (pos == index) break; plbi = plbi->next; index++; insPos++; } insPosItem = plbi; } } if (insPosItem) { plbi = insPosItem->next; insPosItem->next = newItem; newItem->next = plbi; insPos++; } else { plbi = pData->head; pData->head = newItem; newItem->next = plbi; } pData->itemCount++; return insPos;}static PLISTBOXITEMlstRemoveItem(PLISTBOXDATA pData, int *pos){ int index = 0; PLISTBOXITEM plbi, prev; if (!pData->head) return NULL; if (*pos < 0) { prev = pData->head; plbi = pData->head; while (plbi->next) { prev = plbi; plbi = plbi->next; index++; } if (plbi == pData->head) { pData->head = pData->head->next; *pos = 0; return plbi; } else { prev->next = plbi->next; *pos = index; return plbi; } } else if (*pos == 0) { plbi = pData->head; pData->head = plbi->next; return plbi; } else { index = 0; prev = pData->head; plbi = pData->head; while (plbi->next) { if (*pos == index) break; prev = plbi; plbi = plbi->next; index++; } if (plbi == pData->head) { pData->head = pData->head->next; *pos = 0; return plbi; } else { prev->next = plbi->next; *pos = index; return plbi; } } return NULL;}static voidlstGetItemsRect(HWND hwnd, PLISTBOXDATA pData, int start, int end, RECT * prc){ if (start < 0) start = 0; GetClientRect(hwnd, prc); if (!(hwnd->style & LBS_OWNERDRAWVARIABLE) || !(pData->dwFlags & LBF_USERMEASURE)) { prc->top = (start - pData->itemTop) * pData->itemHeight; if (end >= 0) prc->bottom = (end - pData->itemTop + 1) * pData->itemHeight; } else { int i; for (i = pData->itemTop; (i <= end) || (end < 0); i++) { int h; lbAskMeasureItem(hwnd, i, &h); if (i < start) prc->top += h; else if (end < 0) break; if (i == end) prc->bottom = prc->top + h; } }}static voidlstInvalidateItem(HWND hwnd, PLISTBOXDATA pData, int pos, BOOL fEBk){ RECT rcInv; if (pos < pData->itemTop || pos > (pData->itemTop + pData->itemVisibles)) return; lstGetItemsRect(hwnd, pData, pos, pos, &rcInv); InvalidateRect(hwnd, &rcInv, fEBk);}static BOOLlstInvalidateUnderItem(HWND hwnd, PLISTBOXDATA pData, int pos){ RECT rcInv; if (pos > (pData->itemTop + pData->itemVisibles)) return FALSE; if (pos <= pData->itemTop) { InvalidateRect(hwnd, NULL, TRUE); return TRUE; } lstGetItemsRect(hwnd, pData, pos, -1, &rcInv); if (rcInv.top < rcInv.bottom) InvalidateRect(hwnd, &rcInv, FALSE); return TRUE;}static PLISTBOXITEMlstGetItem(PLISTBOXDATA pData, int pos){ int i; PLISTBOXITEM plbi; plbi = pData->head; for (i = 0; i < pos && plbi; i++) plbi = plbi->next; return plbi;}static intlstFindItem(PLISTBOXDATA pData, int start, char *key, BOOL bExact){ PLISTBOXITEM plbi; int keylen = strlen(key); if (start >= (pData->itemCount - 1)) start = 0; plbi = lstGetItem(pData, start); while (plbi) { if (bExact && (keylen != strlen(plbi->key))) { plbi = plbi->next; start++; continue; } if (strncasecmp(key, plbi->key, keylen) == 0) return start; plbi = plbi->next; start++; } return LB_ERR;}static voidlstOnDrawSListBoxItems(HWND hwnd, HDC hdc, DWORD dwStyle, PLISTBOXDATA pData, LPRECT pRcPaint){ PLISTBOXITEM plbi; int i; int x = 0, y = 0; int offset; RECT rc; COLORREF bk; int width; GetClientRect(hwnd, &rc); width = rc.right - rc.left; plbi = lstGetItem(pData, pData->itemTop); SelectObject(hdc, GET_WND_FONT(hwnd)); for (i = 0; plbi && i < (pData->itemVisibles + 1); i++) { POINT centPt; int itemHeight = pData->itemHeight; if ((dwStyle & LBS_OWNERDRAWVARIABLE)) { lbAskMeasureItem(hwnd, pData->itemTop + i, &itemHeight); } rc.left = 0; rc.top = y; rc.right = width; rc.bottom = y + itemHeight; centPt.x = width / 2; centPt.y = y + itemHeight / 2; /* GB: ownerdraw */ if (ISOWNERDRAW(dwStyle) && PtInRect(pRcPaint, centPt)) { DRAWITEMSTRUCT drw; lbFillDrawitemstruct(hwnd, hdc, &drw, &rc, ODA_DRAWENTIRE, pData->itemTop + i, plbi); if (!SendMessage (GetParent(hwnd), WM_DRAWITEM, drw.CtlID, (LPARAM) & drw)) FastFillRect(hdc, &rc, WHITE); if (pData->itemTop + i == pData->itemHilighted) { if ((drw.itemState & ODS_FOCUS)) pData->dwFlags |= LBF_FOCUSRECT; else pData->dwFlags &= ~LBF_FOCUSRECT; } } else /* GB: draw only if in update region... */ if (PtInRect(pRcPaint, centPt)) { if (plbi->dwFlags & LBIF_SELECTED) { SetBkColor(hdc, bk = BLUE); SetTextColor(hdc, WHITE); } else { SetBkColor(hdc, bk = WHITE); SetTextColor(hdc, BLACK); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -