📄 listview.c
字号:
/*** $Id: listview.c,v 1.76.8.1 2004/04/30 01:21:48 snig Exp $**** listview.c: the ListView control**** Copyright (C) 2003 Feynman Software.** ** 2003/05/17: Rewritten by Zhong Shuyi.**** Create date: 2001/12/03**** Original authors: Shu Ming, Amokaqi, chenjm, kevin.*//*** This program is free software; you can redistribute it and/or modify** it under the terms of the GNU General Public License as published by** the Free Software Foundation; either version 2 of the License, or** (at your option) any later version.**** This program 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 General Public License for more details.**** You should have received a copy of the GNU General Public License** along with this program; if not, write to the Free Software** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*//*** Modify records:**** Who When Where For What Status**-----------------------------------------------------------------------------** amokaqi 2002/9/26 add CURSORBLOCKDOWN and UP finish** amokaqi 2002/10/8 add KILLFOCUS and SETFOCUS finish** amokaqi 2002/10/8 add GETDLGCODE for dialog finish** chenjm 2002/10/24 add LVM_SELECTITEM and LVM_SHOWITEM finish** kevin 2003/01/03 modify KILLFOCUS and SETFOCUS finish** snig 2003/05/06 add SB_PAGELEFT, SB_PAGERIGHT finish** SB_PAGEUP and SB_PAGEDOWN;** snig 2003/05/13 code cleanup, rewrite ... finish**** snig 2003/05/15 entirely new listview interfaces done**-----------------------------------------------------------------------------**** TODO:*/#include <stdio.h>#include <stdlib.h>#include <string.h>#ifdef __MINIGUI_LIB__#include "common.h"#include "minigui.h"#include "gdi.h"#include "window.h"#include "control.h"#else#include <minigui/common.h>#include <minigui/minigui.h>#include <minigui/gdi.h>#include <minigui/window.h>#include <minigui/control.h>#endif#ifdef _EXT_CTRL_LISTVIEW#include "mgext.h"#include "listview.h"/********************** internals functions declaration **********************/static int itemDelete (PITEMDATA pHead);#define sGetItemFromList(nSeq, plvdata) lvGetItemByRow(plvdata, nSeq)inline static int sGetFrontSubItemsWidth (int end, PLVDATA plvdata);static int sGetSubItemWidth (int nCols, PLVDATA plvdata);static int sAddOffsetToTailSubItem (int nCols, int offset, PLVDATA plvdata);static int sGetItemWidth (PLVDATA plvdata);static PITEMDATA lvGetItemByRow (PLVDATA plvdata, int nRows);static int lstSetVScrollInfo (PLVDATA plvdata);static int lstSetHScrollInfo (PLVDATA plvdata);static PSUBITEMDATA lvGetSubItemByCol (PITEMDATA pItem, int nCols);static PLSTHDR lvGetHdrByCol (PLVDATA plvdata, int nCols);/* ========================================================================= * size and position operation section of the listview control. ========================================================================= */#define LV_HDR_HEIGHT (plvdata->nHeadHeight)#define LV_ITEM_Y(nRows) ((nRows-1) * plvdata->nItemHeight)#define LV_ITEM_YY(nRows) ( LV_ITEM_Y(nRows) - plvdata->nOriginalY )#define LV_ITEM_YYH(nRows) ( LV_ITEM_YY(nRows) + plvdata->nHeadHeight)#define sGetSubItemX(nCols) ((lvGetHdrByCol(plvdata, nCols))->x)/* Gets the rect of an item */#define LV_GET_ITEM_RECT(nRow, rect) \ GetClientRect(plvdata->hWnd, &rect); \ rect.top = LV_ITEM_YYH(nRow); \ rect.bottom = rect.top + plvdata->nItemHeight;/* Gets the rect of a subitem */#define LV_GET_SUBITEM_RECT(nRows, nCols, rect) \ LV_GET_ITEM_RECT(nRows, rect); \ rect.left = sGetSubItemX(nCols) - plvdata->nOriginalX; \ rect.right = rect.left + sGetSubItemWidth(nCols, plvdata); /* Gets the text rect of a subitem */#define LV_GET_SUBITEM_TEXTRECT(rect, textrect) \ textrect.left = rect.left + 2; \ textrect.top = rect.top + 2; \ textrect.right = rect.right - 2; \ textrect.bottom = rect.bottom - 2;#define LV_GET_HDR_RECT(p1, rect) \ rect.left = p1->x - plvdata->nOriginalX + 1; \ rect.right = p1->x + p1->width - plvdata->nOriginalX - 1; \ rect.top = LV_HDR_TOP; \ rect.bottom = plvdata->nHeadHeight;#if 0#define LV_GET_BD_RECT(p1, rect) \ rect.left = p1->x + p1->width - plvdata->nOriginalX - 1; \ rect.right = p1->x + p1->width - plvdata->nOriginalX + 1; \ rect.top = 0; \ rect.bottom = plvdata->nHeadHeight;/* Gets the rect of a column */#define LV_GET_COL_RECT(nCols, rect) \ GetClientRect(plvdata->hWnd, &rect); \ rect.left = sGetSubItemX (nCols) - plvdata->nOriginalX; \ rect.right = rect.left + sGetSubItemWidth (nCols, plvdata);#endif#define LV_BE_VALID_COL(nPosition) (nPosition <= plvdata->nCols && nPosition >= 1)#define LV_BE_VALID_ROW(nPosition) (nPosition <= plvdata->nRows && nPosition >= 1)#define LV_H_OUTWND(plvdata, rcClient) \ ( sGetItemWidth (plvdata) - 2 > rcClient.right - rcClient.left)inline static BOOL lvBeInHeadBorder (int mouseX, int mouseY, PLSTHDR p1, PLVDATA plvdata){ /* RECT rect; LV_GET_BD_RECT(p1, rect); if (PtInRect (&rect, mouseX, mouseY)) */ if ( (mouseX >= (p1->x + p1->width - plvdata->nOriginalX - 1)) && (mouseX <= (p1->x + p1->width - plvdata->nOriginalX)) && (mouseY >= 0) && (mouseY <= plvdata->nHeadHeight) ) return TRUE; return FALSE;}static int lvInWhichHeadBorder (int mouseX, int mouseY, PLSTHDR * pRet, PLVDATA plvdata){ int nPosition = 0; PLSTHDR p1 = plvdata->pLstHead; while (p1 != NULL) { nPosition++; if (lvBeInHeadBorder(mouseX, mouseY, p1, plvdata)) break; p1 = p1->pNext; } if (!p1) { if (pRet) *pRet = NULL; return -1; } if (pRet) *pRet = p1; return nPosition;}static int isInListViewHead (int mouseX, int mouseY, PLSTHDR * pRet, PLVDATA plvdata){ int nPosition = 0; PLSTHDR p1 = plvdata->pLstHead; RECT rect; while (p1) { nPosition++; LV_GET_HDR_RECT(p1, rect); if (PtInRect (&rect, mouseX, mouseY)) break; p1 = p1->pNext; } //not in head if (!p1 || (nPosition > plvdata->nCols) || (nPosition == 0)) { if (pRet) *pRet = NULL; return -1; } //in head if (pRet) *pRet = p1; return nPosition;}static int isInLVItem (int mouseX, int mouseY, PITEMDATA * pRet, PLVDATA plvdata){ int ret, j; PITEMDATA p1; if ((mouseY < plvdata->nHeadHeight)) return -1; ret = (mouseY + plvdata->nOriginalY - plvdata->nHeadHeight) / plvdata->nItemHeight; ret++; *pRet = NULL; p1 = plvdata->pItemHead; j = 0; while ((p1 != NULL) && (j < ret)) { *pRet = p1; p1 = p1->pNext; j++; } if (ret > j) return -1; return ret;}/* ========================================================================= * Drawing section of the listview control. ========================================================================= */static void sDrawText (HDC hdc, int x, int y, int width, int height, const char *pszText, UINT format){ RECT rect; //SIZE size; if (pszText != NULL) { SetRect (&rect, x+2, y+2, x+width, y+height); DrawText (hdc, pszText, -1, &rect, format); }}static void lvDrawSubItem (HDC hdc, int nRows, int nCols, PLVDATA plvdata){ RECT rect, rect_text; PITEMDATA pItem; PSUBITEMDATA psub; PLSTHDR ph; UINT text_format; if ( !(pItem = lvGetItemByRow(plvdata, nRows)) ) return; if ( !(psub = lvGetSubItemByCol(pItem, nCols)) ) return; ph = lvGetHdrByCol (plvdata, nCols); LV_GET_SUBITEM_RECT(nRows, nCols, rect); if (!pItem->bSelected) { SetBrushColor (hdc, GetWindowBkColor(plvdata->hWnd)); SetBkColor (hdc, GetWindowBkColor(plvdata->hWnd)); SetTextColor (hdc, psub->nTextColor); } else { SetBkColor (hdc, plvdata->bkc_selected); SetBrushColor (hdc, plvdata->bkc_selected); SetTextColor (hdc, PIXEL_lightwhite); } FillBox (hdc, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top); LV_GET_SUBITEM_TEXTRECT(rect, rect_text); if (psub->Image) { int width, height; if (psub->dwFlags & LVIF_BITMAP) { PBITMAP bmp = (PBITMAP)psub->Image; height = (bmp->bmHeight < plvdata->nItemHeight)? bmp->bmHeight : plvdata->nItemHeight; rect.top += (plvdata->nItemHeight - height) / 2; rect.left += 2; FillBoxWithBitmap (hdc, rect.left, rect.top, 0, height, bmp); rect_text.left = rect.left + bmp->bmWidth + 2; } else if (psub->dwFlags & LVIF_ICON) { GetIconSize ((HICON)psub->Image, &width, &height); height = (height < plvdata->nItemHeight) ? height : plvdata->nItemHeight; rect.top += (plvdata->nItemHeight - height) / 2; rect.left += 2; DrawIcon (hdc, rect.left, rect.top, 0, height, (HICON)psub->Image); rect_text.left = rect.left + width + 2; } } if (!psub->pszInfo) return; if (ph->flags & LVCF_RIGHTALIGN) text_format = DT_SINGLELINE | DT_RIGHT | DT_VCENTER; else if (ph->flags & LVCF_CENTERALIGN) text_format = DT_SINGLELINE | DT_CENTER | DT_VCENTER; else text_format = DT_SINGLELINE | DT_LEFT | DT_VCENTER; DrawText (hdc, psub->pszInfo, -1, &rect_text, text_format);}//Draws listview headerstatic void lvDrawHeader (HWND hwnd, HDC hdc){ PLSTHDR p1 = NULL; PLVDATA plvdata; RECT rcClient; BOOL up = TRUE; UINT format; GetClientRect (hwnd, &rcClient); plvdata = (PLVDATA) GetWindowAdditionalData2 (hwnd); p1 = plvdata->pLstHead; if (LVSTATUS(hwnd) & LVST_HEADCLICK && LVSTATUS(hwnd) & LVST_INHEAD) up = FALSE; SetBkColor (hdc, PIXEL_lightgray); SetBrushColor (hdc, PIXEL_lightgray); FillBox (hdc, rcClient.left, rcClient.top, rcClient.right - rcClient.left, plvdata->nHeadHeight); SetTextColor (hdc, PIXEL_black); while (p1) {#ifdef _FLAT_WINDOW_STYLE DrawFlatControlFrameEx (hdc, p1->x - plvdata->nOriginalX-1, LV_HDR_TOP - plvdata->nOriginalY-1, p1->x - plvdata->nOriginalX + p1->width, LV_HDR_TOP + LV_HDR_HEIGHT, PIXEL_lightgray, 0, up);#else Draw3DControlFrame (hdc, p1->x - plvdata->nOriginalX + 1, LV_HDR_TOP, p1->x - plvdata->nOriginalX + p1->width - 1, LV_HDR_TOP + LV_HDR_HEIGHT, PIXEL_lightgray, up);#endif if (p1->flags & LVHF_CENTERALIGN) format = DT_SINGLELINE | DT_CENTER | DT_VCENTER; else if (p1->flags & LVHF_RIGHTALIGN) format = DT_SINGLELINE | DT_RIGHT | DT_VCENTER; else format = DT_SINGLELINE | DT_LEFT | DT_VCENTER; sDrawText (hdc, p1->x - plvdata->nOriginalX + 2, LV_HDR_TOP, p1->width - 4, LV_HDR_HEIGHT, p1->pTitle, format); p1 = p1->pNext; } //draws the right most unused header if ( !LV_H_OUTWND(plvdata, rcClient) ) {#ifdef _FLAT_WINDOW_STYLE DrawFlatControlFrameEx (hdc, sGetItemWidth (plvdata)-2, LV_HDR_TOP-1, rcClient.right+2, LV_HDR_TOP + LV_HDR_HEIGHT, PIXEL_lightgray, 0, up);#else Draw3DControlFrame (hdc, sGetItemWidth (plvdata), LV_HDR_TOP, rcClient.right+2, LV_HDR_TOP + LV_HDR_HEIGHT, PIXEL_lightgray, up);#endif }}static void lvDrawItem (HWND hwnd, HDC hdc, int nRows){ int i; RECT rcClient; PLVDATA plvdata; PITEMDATA p3 = NULL; plvdata = (PLVDATA) GetWindowAdditionalData2 (hwnd); p3 = lvGetItemByRow(plvdata, nRows); GetClientRect (hwnd, &rcClient); /* if (p3->bSelected) { SetBrushColor (hdc,plvdata->bkc_selected); } else SetBrushColor (hdc, PIXEL_lightwhite); FillBox (hdc, rcClient.left, (nRows - 1) * plvdata->nItemHeight + plvdata->nHeadHeight, sGetItemWidth(plvdata)-1, plvdata->nItemHeight); */ for (i = 1; i <= plvdata->nCols; i++) { lvDrawSubItem (hdc, nRows, i, plvdata); }}static void lvOnDraw (HWND hwnd, HDC hdc){ int j; RECT rcClient; PLVDATA plvdata; plvdata = (PLVDATA) GetWindowAdditionalData2 (hwnd); GetClientRect (hwnd, &rcClient); SetBkColor (hdc, PIXEL_lightwhite); SetBrushColor (hdc, PIXEL_lightwhite); FillBox (hdc, rcClient.left, rcClient.top, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top); //draws item area for (j = 1; j <= plvdata->nRows; j++) { lvDrawItem (hwnd, hdc, j); } lvDrawHeader (hwnd, hdc);}/************************************* Listview Move/Scroll Action ***********************//* Makes an item to be visible */static voidlvMakeItemVisible (HWND hwnd, PLVDATA plvdata, int nRows){ int scrollHeight = 0; RECT rect; int area_height; if (!LV_BE_VALID_ROW(nRows)) nRows = plvdata->nItemSelected; if (!LV_BE_VALID_ROW(nRows)) return; GetClientRect (hwnd, &rect); area_height = rect.bottom - rect.top - plvdata->nHeadHeight; if ( LV_ITEM_Y(nRows) < plvdata->nOriginalY) { scrollHeight = plvdata->nOriginalY - LV_ITEM_Y(nRows); } else if ( LV_ITEM_Y(nRows+1) - plvdata->nOriginalY > area_height ) { scrollHeight = plvdata->nOriginalY + area_height - LV_ITEM_Y(nRows+1); } if (scrollHeight != 0) { plvdata->nOriginalY -= scrollHeight; lstSetVScrollInfo (plvdata); InvalidateRect(hwnd, NULL, FALSE); }}static void lvVScroll (HWND hwnd, WPARAM wParam, LPARAM lParam){ int scrollHeight = 0; RECT rect; int scrollBoundMax; int scrollBoundMin; int vscroll = 0; PLVDATA plvdata; plvdata = (PLVDATA) GetWindowAdditionalData2 (hwnd); GetClientRect (hwnd, &rect); scrollBoundMax = plvdata->nRows * plvdata->nItemHeight - (rect.bottom - rect.top - plvdata->nHeadHeight); scrollBoundMin = 0; //decides the desired value to scroll if (wParam == SB_LINEUP || wParam == SB_LINEDOWN) vscroll = VSCROLL; else if (wParam == SB_PAGEUP || wParam == SB_PAGEDOWN) vscroll = rect.bottom - rect.top - plvdata->nHeadHeight - plvdata->nItemHeight; //scroll down if ( (wParam == SB_LINEDOWN || wParam == SB_PAGEDOWN) && plvdata->nOriginalY < scrollBoundMax ) { if ((plvdata->nOriginalY + vscroll) > scrollBoundMax) { scrollHeight = plvdata->nOriginalY - scrollBoundMax; plvdata->nOriginalY = scrollBoundMax; } else { plvdata->nOriginalY += vscroll; scrollHeight = -vscroll; } } //scroll up else if ( (wParam == SB_LINEUP || wParam == SB_PAGEUP) && plvdata->nOriginalY > scrollBoundMin ) { if ((plvdata->nOriginalY - vscroll) > scrollBoundMin) { plvdata->nOriginalY -= vscroll; scrollHeight = vscroll; } else { scrollHeight = plvdata->nOriginalY - scrollBoundMin; plvdata->nOriginalY = scrollBoundMin; } } //dragging else if ( wParam == SB_THUMBTRACK ) { int scrollNewPos = (int) lParam; if (((scrollNewPos - plvdata->nOriginalY) < 5) && ((scrollNewPos - plvdata->nOriginalY) > -5) && (scrollNewPos > 5) && ((scrollBoundMax - scrollNewPos) > 5)) return; if ((scrollNewPos < plvdata->nOriginalY) && (scrollNewPos <= VSCROLL)) { scrollHeight = plvdata->nOriginalY - 0; plvdata->nOriginalY = 0; } else { if ((scrollNewPos > plvdata->nOriginalY) && ((scrollBoundMax - scrollNewPos) < VSCROLL)) { scrollHeight = plvdata->nOriginalY - scrollBoundMax; plvdata->nOriginalY = scrollBoundMax; } else { scrollHeight = plvdata->nOriginalY - scrollNewPos; plvdata->nOriginalY = scrollNewPos; } } } if (scrollHeight != 0) { InvalidateRect (hwnd, NULL, FALSE); lstSetVScrollInfo (plvdata); }}static void lvHScroll (HWND hwnd, WPARAM wParam, LPARAM lParam){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -