mirror of
https://github.com/VincentWei/MiniGUI.git
synced 2026-09-30 06:23:22 +08:00
2214 lines
60 KiB
C
2214 lines
60 KiB
C
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IMPORTANT NOTICE
|
|
//
|
|
// The following open source license statement does not apply to any
|
|
// entity in the Exception List published by FMSoft.
|
|
//
|
|
// For more information, please visit:
|
|
//
|
|
// https://www.fmsoft.cn/exception-list
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/*
|
|
* This file is part of MiniGUI, a mature cross-platform windowing
|
|
* and Graphics User Interface (GUI) support system for embedded systems
|
|
* and smart IoT devices.
|
|
*
|
|
* Copyright (C) 2002~2018, Beijing FMSoft Technologies Co., Ltd.
|
|
* Copyright (C) 1998~2002, WEI Yongming
|
|
*
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Or,
|
|
*
|
|
* As this program is a library, any link to this program must follow
|
|
* GNU General Public License version 3 (GPLv3). If you cannot accept
|
|
* GPLv3, you need to be licensed from FMSoft.
|
|
*
|
|
* If you have got a commercial license of this program, please use it
|
|
* under the terms and conditions of the commercial license.
|
|
*
|
|
* For more information about the commercial license, please refer to
|
|
* <http://www.minigui.com/blog/minigui-licensing-policy/>.
|
|
*/
|
|
/*
|
|
** listview.c: the ListView control
|
|
**
|
|
** Create date: 2004/04/24
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "common.h"
|
|
|
|
#ifdef _MGCTRL_LISTVIEW
|
|
#include "minigui.h"
|
|
#include "gdi.h"
|
|
#include "window.h"
|
|
#include "control.h"
|
|
|
|
#include "cliprect.h"
|
|
#include "internals.h"
|
|
#include "ctrlclass.h"
|
|
#include "ctrl/listview.h"
|
|
#include "text.h"
|
|
#include "scrolled.h"
|
|
#include "scrollview_impl.h"
|
|
#include "listview_impl.h"
|
|
|
|
extern int scrollview_get_item_rect (HWND hWnd, HITEM hsvi, RECT *rcItem, BOOL bConv);
|
|
|
|
static int lvRemoveAllItem (HWND hWnd, PLVDATA plvdata);
|
|
|
|
/* treeview defines */
|
|
|
|
#define TV_BORDER 2
|
|
#define TV_BOXHALFHEIGHT 4
|
|
#define TV_BOXGAP 3
|
|
#define TV_ICONGAP 3
|
|
#define TV_IDENT 5
|
|
|
|
|
|
#define LV_BE_VALID_COL(nPosition) (nPosition < plvdata->nCols && nPosition >= 0)
|
|
|
|
#define LV_GET_HDR_RECT(p1, rect) \
|
|
rect.left = p1->x + 1; \
|
|
rect.right = p1->x + p1->width - 1; \
|
|
rect.top = LV_HDR_TOP; \
|
|
rect.bottom = plvdata->nHeadHeight;
|
|
|
|
/* Get 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_H_OUTWND(plvdata, rcClient) \
|
|
( plvdata->nHeadWidth - 2 > rcClient.right - rcClient.left)
|
|
|
|
#define LV_GET_ITEM(hsvi) (PITEMDATA)scrollview_get_item_adddata(hsvi)
|
|
|
|
#define ISFOLD(pi) (pi->dwFlags & LVIF_FOLD)
|
|
/*
|
|
* header operations
|
|
*/
|
|
|
|
GET_ENTRY_BY_INDEX(lvGetHdrByCol, LSTHDR, list)
|
|
|
|
#define GET_SUBITEM_X(nCols) ((lvGetHdrByCol(&plvdata->hdrqueue, nCols))->x)
|
|
#define GET_SUBITEM_W(nCols) ((lvGetHdrByCol(&plvdata->hdrqueue, nCols))->width)
|
|
|
|
#define LV_GET_SUBITEM_RECT(rcItem, nCols, rcSub) \
|
|
rcSub.top = rcItem->top; \
|
|
rcSub.bottom = rcItem->bottom; \
|
|
rcSub.left = rcItem->left + GET_SUBITEM_X(nCols); \
|
|
rcSub.right = rcSub.left + GET_SUBITEM_W(nCols);
|
|
|
|
/*
|
|
* gets the previous nCols items width
|
|
*/
|
|
static int
|
|
lvGetFrontSubItemsWidth (int nCols, PLVDATA plvdata)
|
|
{
|
|
PLSTHDR p1;
|
|
|
|
p1 = lvGetHdrByCol(&plvdata->hdrqueue, nCols-1);
|
|
if (p1)
|
|
return p1->x + p1->width;
|
|
return 0;
|
|
}
|
|
|
|
static PITEMDATA lvGetItemByRow (PLVDATA plvdata, int nRows)
|
|
{
|
|
HSVITEM hsvi;
|
|
|
|
hsvi = scrollview_get_item_by_index (&plvdata->svdata, nRows);
|
|
return LV_GET_ITEM(hsvi);
|
|
}
|
|
|
|
/* creates a new header */
|
|
static PLSTHDR
|
|
lvHdrNew (PLVCOLUMN pcol, PLVDATA plvdata, int *col)
|
|
{
|
|
PLSTHDR p1;
|
|
int nCols = pcol->nCols;
|
|
|
|
if (!LV_BE_VALID_COL(nCols)) {
|
|
nCols = plvdata->nCols;
|
|
*col = nCols;
|
|
}
|
|
|
|
if ( !(p1 = (PLSTHDR) malloc(sizeof(LSTHDR))) )
|
|
return NULL;
|
|
|
|
p1->sort = NOTSORTED;
|
|
p1->pfnCmp = pcol->pfnCompare;
|
|
p1->Image = pcol->image;
|
|
p1->flags = pcol->colFlags;
|
|
|
|
if (pcol->pszHeadText != NULL)
|
|
{
|
|
p1->pTitle = (char *) malloc (strlen (pcol->pszHeadText) + 1);
|
|
strcpy (p1->pTitle, pcol->pszHeadText);
|
|
}
|
|
else
|
|
p1->pTitle = NULL;
|
|
|
|
p1->x = lvGetFrontSubItemsWidth (nCols, plvdata);
|
|
if (pcol->width <= 0)
|
|
p1->width = LV_COLW_DEF;
|
|
else if (pcol->width < COLWIDTHMIN)
|
|
p1->width = COLWIDTHMIN;
|
|
else
|
|
p1->width = pcol->width;
|
|
|
|
list_add_by_index (&p1->list, &plvdata->hdrqueue, nCols);
|
|
|
|
return p1;
|
|
}
|
|
|
|
|
|
//free a header
|
|
static void lvHdrDel (PLSTHDR pLstHdr)
|
|
{
|
|
if (pLstHdr != NULL)
|
|
{
|
|
list_del (&pLstHdr->list);
|
|
if (pLstHdr->pTitle != NULL)
|
|
free (pLstHdr->pTitle);
|
|
free (pLstHdr);
|
|
}
|
|
}
|
|
|
|
static void lvHdrDestroy (PLVDATA plvdata)
|
|
{
|
|
PLSTHDR hdr;
|
|
|
|
while (!list_empty(&plvdata->hdrqueue)) {
|
|
hdr = list_entry (plvdata->hdrqueue.next, LSTHDR, list);
|
|
lvHdrDel (hdr);
|
|
}
|
|
}
|
|
|
|
static BOOL
|
|
lvBeInHeadBorder (int mouseX, int mouseY, PLSTHDR p1, PLVDATA plvdata)
|
|
{
|
|
if ( (mouseX >= (p1->x + p1->width - 1))
|
|
&& (mouseX <= (p1->x + p1->width))
|
|
&& (mouseY >= 0) && (mouseY <= plvdata->nHeadHeight) )
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
static int
|
|
lvInWhichHeadBorder (int mouseX, int mouseY, PLSTHDR *pRet, PLVDATA plvdata)
|
|
{
|
|
int nPos = 0;
|
|
PLSTHDR p1 = NULL;
|
|
list_t *me;
|
|
BOOL bGet = FALSE;
|
|
|
|
scrolled_window_to_visible (plvscr, &mouseX, NULL);
|
|
scrolled_visible_to_content (plvscr, &mouseX, NULL);
|
|
|
|
list_for_each (me, &plvdata->hdrqueue) {
|
|
p1 = list_entry (me, LSTHDR, list);
|
|
if (lvBeInHeadBorder(mouseX, mouseY, p1, plvdata)) {
|
|
bGet = TRUE;
|
|
break;
|
|
}
|
|
nPos ++;
|
|
}
|
|
|
|
if (pRet)
|
|
*pRet = bGet ? p1 : NULL;
|
|
|
|
return bGet ? nPos : -1;
|
|
}
|
|
|
|
static int
|
|
isInListViewHead (int mouseX, int mouseY, PLSTHDR * pRet, PLVDATA plvdata)
|
|
{
|
|
int nPosition = 0;
|
|
PLSTHDR p1 = NULL;
|
|
list_t *me;
|
|
RECT rect;
|
|
|
|
scrolled_window_to_visible (plvscr, &mouseX, NULL);
|
|
scrolled_visible_to_content (plvscr, &mouseX, NULL);
|
|
|
|
list_for_each (me, &plvdata->hdrqueue) {
|
|
p1 = list_entry (me, LSTHDR, list);
|
|
LV_GET_HDR_RECT(p1, rect);
|
|
if (PtInRect (&rect, mouseX, mouseY))
|
|
break;
|
|
|
|
nPosition++;
|
|
}
|
|
|
|
//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
|
|
, POINT *pt)
|
|
{
|
|
int ret;
|
|
HSVITEM hsvi = 0;
|
|
|
|
scrolled_window_to_visible (plvscr, &mouseX, &mouseY);
|
|
scrolled_visible_to_content (plvscr, &mouseX, &mouseY);
|
|
|
|
ret = scrollview_is_in_item (&plvdata->svdata, mouseY, &hsvi, NULL);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if (pRet && hsvi) {
|
|
*pRet = LV_GET_ITEM(hsvi);
|
|
}
|
|
|
|
if (pt) {
|
|
pt->x = mouseX;
|
|
pt->y = mouseY;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
GET_ENTRY_BY_INDEX(lvGetSubItemByCol, SUBITEMDATA, list)
|
|
|
|
/*
|
|
* 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 lvDrawFold (HWND hWnd, HDC hdc, RECT *rc_text, PITEMDATA pItem)
|
|
{
|
|
RECT rcFold;
|
|
WINDOWINFO *wnd_info;
|
|
DWORD fg_color;
|
|
|
|
if (!scrollview_is_item_hilight(hWnd, (HSVITEM)pItem->addData))
|
|
fg_color = GetWindowElementAttr (hWnd, WE_FGC_MENU);
|
|
else
|
|
fg_color = GetWindowElementAttr (hWnd, WE_FGC_HIGHLIGHT_ITEM);
|
|
|
|
wnd_info = (WINDOWINFO*)GetWindowInfo (hWnd);
|
|
if (wnd_info == NULL)
|
|
return ;
|
|
|
|
rcFold.left = rc_text->left-1;
|
|
rcFold.right = rcFold.left + 10;
|
|
rcFold.top = rc_text->top + 6;
|
|
rcFold.bottom = rcFold.top + 10;
|
|
|
|
if (ISFOLD(pItem))
|
|
wnd_info->we_rdr->draw_fold (hWnd, hdc, &rcFold, fg_color,
|
|
LFRDR_TREE_CHILD | LFRDR_TREE_FOLD, pItem->child_nr);
|
|
else
|
|
wnd_info->we_rdr->draw_fold (hWnd, hdc, &rcFold, fg_color,
|
|
LFRDR_TREE_CHILD , pItem->child_nr);
|
|
}
|
|
|
|
static void alvDrawSubItem (HWND hWnd, PLVDATA plvdata,
|
|
HDC hdc, PITEMDATA pItem, RECT *rcItem, int nCols)
|
|
{
|
|
RECT rect, rect_text;
|
|
PSUBITEMDATA psub;
|
|
PLSTHDR ph;
|
|
UINT text_format;
|
|
int nItemHeight;
|
|
DWORD bg_color, fg_color;
|
|
gal_pixel bc, fc;
|
|
#ifdef __TARGET_MSTUDIO__
|
|
int index;
|
|
#endif
|
|
|
|
if ( !(psub = lvGetSubItemByCol(&pItem->subqueue, nCols)) )
|
|
return;
|
|
|
|
SetBkMode (hdc, BM_TRANSPARENT);
|
|
|
|
ph = lvGetHdrByCol (&plvdata->hdrqueue, nCols);
|
|
LV_GET_SUBITEM_RECT(rcItem, nCols, rect);
|
|
|
|
#ifdef __TARGET_MSTUDIO__
|
|
index = scrollview_get_item_index(hWnd, (HSVITEM)pItem->addData);
|
|
#endif
|
|
|
|
if (!scrollview_is_item_hilight(hWnd, (HSVITEM)pItem->addData)) {
|
|
|
|
/* NUV
|
|
fg_color = GetWindowElementAttr (hWnd, WE_FGC_WINDOW);
|
|
fc = RGBA2Pixel (hdc, GetRValue(fg_color), GetGValue(fg_color),
|
|
GetBValue(fg_color), GetAValue(fg_color));
|
|
*/
|
|
SetTextColor (hdc, psub->nTextColor);
|
|
|
|
#ifdef __TARGET_MSTUDIO__
|
|
// for mStudio only
|
|
bg_color = GetWindowElementAttr (hWnd, WE_LFFLAT_TAB_NRMLCLR);
|
|
if (bg_color != -1 && index % 2 == 1) {
|
|
SetBrushColor (hdc, DWORD2Pixel (hdc, bg_color));
|
|
FillBox (hdc, rect.left, rect.top, RECTW(rect), RECTH(rect));
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
bg_color = GetWindowElementAttr (hWnd, WE_BGC_HIGHLIGHT_ITEM);
|
|
bc = RGBA2Pixel (hdc, GetRValue(bg_color), GetGValue(bg_color),
|
|
GetBValue(bg_color), GetAValue(bg_color));
|
|
|
|
fg_color = GetWindowElementAttr (hWnd, WE_FGC_HIGHLIGHT_ITEM);
|
|
fc = RGBA2Pixel (hdc, GetRValue(fg_color), GetGValue(fg_color),
|
|
GetBValue(fg_color), GetAValue(fg_color));
|
|
|
|
SetBrushColor (hdc, bc);
|
|
SetTextColor (hdc, fc);
|
|
FillBox (hdc, rect.left, rect.top, RECTW(rect), RECTH(rect));
|
|
}
|
|
|
|
if (GetWindowStyle(hWnd) & LVS_WITHGRID) {
|
|
SetPenColor(hdc, PIXEL_darkgray);
|
|
Rectangle (hdc, rect.left, rect.top, rect.right, rect.bottom);
|
|
}
|
|
|
|
|
|
LV_GET_SUBITEM_TEXTRECT(rect, rect_text);
|
|
|
|
if (nCols == 0) {
|
|
rect_text.left += pItem->depth * INDENT;
|
|
if (pItem->child) {
|
|
lvDrawFold (hWnd, hdc, &rect_text, pItem);
|
|
rect_text.left += INDENT;
|
|
}
|
|
}
|
|
|
|
nItemHeight = scrollview_get_item_height((HSVITEM)pItem->addData);
|
|
if (psub->Image) {
|
|
int width, height;
|
|
if (psub->dwFlags & LVIF_BITMAP) {
|
|
PBITMAP bmp = (PBITMAP)psub->Image;
|
|
height = (bmp->bmHeight < nItemHeight)? bmp->bmHeight : nItemHeight;
|
|
rect.top += (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 < nItemHeight) ? height : nItemHeight;
|
|
rect.top += (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);
|
|
}
|
|
|
|
|
|
static void lvDrawItem (HWND hWnd, HSVITEM hsvi, HDC hdc, RECT *rcDraw)
|
|
{
|
|
int i = 0;
|
|
PLVDATA plvdata;
|
|
PITEMDATA pi = NULL;
|
|
list_t *me;
|
|
|
|
plvdata = (PLVDATA) GetWindowAdditionalData2 (hWnd);
|
|
pi = LV_GET_ITEM(hsvi);
|
|
|
|
list_for_each (me, &pi->subqueue) {
|
|
alvDrawSubItem (hWnd, plvdata, hdc, pi, rcDraw, i);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
static void lvDrawHeaderCustom (HWND hWnd, HDC hdc)
|
|
{
|
|
PLVDATA plvdata;
|
|
PLSTHDR p1 = NULL;
|
|
RECT rcClient, rcHdr, rcItem;
|
|
list_t *me;
|
|
int i = 0;
|
|
|
|
plvdata = (PLVDATA) GetWindowAdditionalData2 (hWnd);
|
|
GetClientRect (hWnd, &rcClient);
|
|
rcHdr = rcClient;
|
|
rcHdr.top = LV_HDR_TOP;
|
|
rcHdr.bottom = LV_HDR_TOP + LV_HDR_HEIGHT;
|
|
rcItem = rcHdr;
|
|
|
|
/* drawing header background */
|
|
plvdata->pfn_draw_hdr_bk (hWnd, 0, hdc, &rcHdr);
|
|
|
|
/* drawing header items */
|
|
list_for_each (me, &plvdata->hdrqueue) {
|
|
p1 = list_entry (me, LSTHDR, list);
|
|
rcItem.left = p1->x;
|
|
rcItem.right = p1->x + p1->width;
|
|
scrolled_content_to_window (&(plvdata->svdata.scrdata), &rcItem.left, NULL);
|
|
scrolled_content_to_window (&(plvdata->svdata.scrdata), &rcItem.right, NULL);
|
|
plvdata->pfn_draw_hdr_item (hWnd, i, hdc, &rcItem);
|
|
i ++;
|
|
}
|
|
}
|
|
|
|
/*Draws listview header*/
|
|
static void lvDrawHeader (HWND hWnd, HDC hdc)
|
|
{
|
|
PLSTHDR p1 = NULL;
|
|
PLVDATA plvdata;
|
|
RECT rcClient, rcButton;
|
|
UINT format;
|
|
list_t *me;
|
|
int item_w = 0;
|
|
WINDOWINFO *wnd_info;
|
|
DWORD fg_color;
|
|
gal_pixel fc;
|
|
|
|
wnd_info = (WINDOWINFO*)GetWindowInfo (hWnd);
|
|
if (wnd_info == NULL)
|
|
return ;
|
|
|
|
|
|
plvdata = (PLVDATA) GetWindowAdditionalData2 (hWnd);
|
|
GetClientRect (hWnd, &rcClient);
|
|
|
|
/* not used vars
|
|
DWORD flags = DF_3DBOX_NORMAL;
|
|
if (LVSTATUS(hWnd) & LVST_HEADCLICK && LVSTATUS(hWnd) & LVST_INHEAD)
|
|
flags = DF_3DBOX_PRESSED;
|
|
*/
|
|
|
|
SetBkMode (hdc, BM_TRANSPARENT);
|
|
|
|
list_for_each (me, &plvdata->hdrqueue) {
|
|
p1 = list_entry (me, LSTHDR, list);
|
|
|
|
rcButton.left = p1->x;
|
|
rcButton.top = LV_HDR_TOP;
|
|
rcButton.right = p1->x + p1->width;
|
|
rcButton.bottom = LV_HDR_TOP + LV_HDR_HEIGHT;
|
|
|
|
scrolled_content_to_window (&(plvdata->svdata.scrdata), &rcButton.left, NULL);
|
|
scrolled_content_to_window (&(plvdata->svdata.scrdata), &rcButton.right, NULL);
|
|
|
|
fg_color = GetWindowElementAttr (hWnd, WE_MAINC_THREED_BODY);
|
|
wnd_info->we_rdr->draw_header (hWnd, hdc, &rcButton, fg_color);
|
|
|
|
item_w += p1->width;
|
|
|
|
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;
|
|
|
|
fg_color = GetWindowElementAttr (hWnd, WE_FGC_WINDOW);
|
|
fc = RGBA2Pixel (hdc, GetRValue(fg_color), GetGValue(fg_color),
|
|
GetBValue(fg_color), GetAValue(fg_color));
|
|
SetTextColor (hdc, fc);
|
|
|
|
sDrawText (hdc, p1->x - plvscr->nContX + 2, LV_HDR_TOP,
|
|
p1->width - 4, LV_HDR_HEIGHT, p1->pTitle, format);
|
|
}
|
|
|
|
/*draws the right most unused header*/
|
|
rcButton.left = item_w - plvscr->nContX + 1;
|
|
rcButton.top = LV_HDR_TOP;
|
|
rcButton.right = rcClient.right + 2;
|
|
rcButton.bottom = LV_HDR_TOP + LV_HDR_HEIGHT;
|
|
fg_color = GetWindowElementAttr (hWnd, WE_MAINC_THREED_BODY);
|
|
wnd_info->we_rdr->draw_header (hWnd, hdc, &rcButton, fg_color);
|
|
}
|
|
|
|
static inline void lv_draw_header (HWND hWnd, HDC hdc)
|
|
{
|
|
PLVDATA plvdata;
|
|
plvdata = (PLVDATA) GetWindowAdditionalData2 (hWnd);
|
|
|
|
if (plvdata->pfn_draw_hdr_bk && plvdata->pfn_draw_hdr_item) {
|
|
lvDrawHeaderCustom (hWnd, hdc);
|
|
}
|
|
else {
|
|
lvDrawHeader (hWnd, hdc);
|
|
}
|
|
}
|
|
|
|
static inline void lvOnDraw (HWND hWnd, HDC hdc)
|
|
{
|
|
PLVDATA plvdata;
|
|
plvdata = (PLVDATA) GetWindowAdditionalData2 (hWnd);
|
|
|
|
if (plvdata->nHeadHeight != 0) {
|
|
lv_draw_header (hWnd, hdc);
|
|
}
|
|
}
|
|
|
|
static int lvGetItemIndent (PLVDATA plvdata, PITEMDATA pitem)
|
|
{
|
|
PITEMDATA pp;
|
|
int indent = -INDENT;
|
|
|
|
if (!pitem)
|
|
return -1;
|
|
|
|
pp = pitem->parent;
|
|
while (pp) {
|
|
indent += INDENT;
|
|
pp = pp->parent;
|
|
}
|
|
|
|
return indent;
|
|
}
|
|
|
|
static int lvFoldItem (HWND hWnd, PLVDATA plvdata, PITEMDATA pitem, BOOL bFold)
|
|
{
|
|
int i;
|
|
HSVITEM hsvi;
|
|
int newh;
|
|
|
|
if (!pitem)
|
|
return -1;
|
|
|
|
hsvi = (HSVITEM)pitem->addData;
|
|
|
|
if (bFold && !(ISFOLD(pitem))) {
|
|
pitem->dwFlags |= LVIF_FOLD;
|
|
}
|
|
else if (!bFold && (ISFOLD(pitem))) {
|
|
pitem->dwFlags &= ~LVIF_FOLD;
|
|
}
|
|
else
|
|
return -1;
|
|
|
|
scrollview_freeze (hWnd, &plvdata->svdata, TRUE);
|
|
for (i = 0; i < pitem->child_nr; i++) {
|
|
PITEMDATA pi;
|
|
|
|
hsvi = scrollview_get_next_item (&plvdata->svdata, hsvi);
|
|
pi = LV_GET_ITEM(hsvi);
|
|
|
|
newh = bFold ? 0 : pi->itemh;
|
|
scrollview_set_item_height (hWnd, hsvi, newh);
|
|
|
|
if (!bFold && ISFOLD(pi) && pi->child_nr > 0) {
|
|
int j;
|
|
i += pi->child_nr;
|
|
for (j=0; j<pi->child_nr; j++) {
|
|
hsvi = scrollview_get_next_item (&plvdata->svdata, hsvi);
|
|
}
|
|
}
|
|
}
|
|
scrollview_freeze (hWnd, &plvdata->svdata, FALSE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static PSUBITEMDATA subitemNew (const char *pszInfoText)
|
|
{
|
|
PSUBITEMDATA p1;
|
|
|
|
p1 = (PSUBITEMDATA) malloc (sizeof (SUBITEMDATA));
|
|
|
|
if (pszInfoText)
|
|
{
|
|
p1->pszInfo = (char *) malloc (strlen (pszInfoText) + 1);
|
|
strcpy (p1->pszInfo, pszInfoText);
|
|
}
|
|
else
|
|
p1->pszInfo = NULL;
|
|
|
|
p1->nTextColor = PIXEL_black;
|
|
p1->Image = 0;
|
|
p1->dwFlags = 0;
|
|
|
|
return p1;
|
|
}
|
|
|
|
static void subitemFree (PSUBITEMDATA pSubItemData)
|
|
{
|
|
if (pSubItemData)
|
|
{
|
|
if (pSubItemData->pszInfo)
|
|
free (pSubItemData->pszInfo);
|
|
free (pSubItemData);
|
|
}
|
|
}
|
|
|
|
static void
|
|
lvAddSubitem (PLVDATA plvdata, int nCols)
|
|
{
|
|
PSUBITEMDATA pnew;
|
|
PITEMDATA p1;
|
|
HSVITEM hsvi;
|
|
|
|
hsvi = scrollview_get_next_item (&plvdata->svdata, 0);
|
|
p1 = LV_GET_ITEM(hsvi);
|
|
while (p1)
|
|
{
|
|
pnew = subitemNew (NULL);
|
|
list_add_by_index (&pnew->list, &p1->subqueue, nCols);
|
|
hsvi = scrollview_get_next_item(&plvdata->svdata, (HSVITEM)p1->addData);
|
|
p1 = LV_GET_ITEM(hsvi);
|
|
}
|
|
}
|
|
|
|
static void
|
|
lvDelSubitem (PLVDATA plvdata, int nCols)
|
|
{
|
|
HSVITEM hsvi;
|
|
PITEMDATA p1;
|
|
PSUBITEMDATA pdel;
|
|
|
|
hsvi = scrollview_get_next_item (&plvdata->svdata, 0);
|
|
p1 = LV_GET_ITEM(hsvi);
|
|
while (p1)
|
|
{
|
|
if ( !(pdel = lvGetSubItemByCol (&p1->subqueue, nCols)) )
|
|
break;
|
|
list_del (&pdel->list);
|
|
subitemFree(pdel);
|
|
hsvi = scrollview_get_next_item(&plvdata->svdata, (HSVITEM)p1->addData);
|
|
p1 = LV_GET_ITEM(hsvi);
|
|
}
|
|
}
|
|
|
|
/* offset the tail subitems from nCols */
|
|
static int sAddOffsetToTailSubItem (int nCols, int offset, PLVDATA plvdata)
|
|
{
|
|
PLSTHDR p;
|
|
list_t *me, *prev;
|
|
|
|
if ( !(p = lvGetHdrByCol (&plvdata->hdrqueue, nCols)) )
|
|
return -1;
|
|
|
|
prev = p->list.prev;
|
|
|
|
list_for_each_ex (me, &plvdata->hdrqueue, prev) {
|
|
p = list_entry (me, LSTHDR, list);
|
|
p->x += offset;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int lvSetContWidth (HWND hWnd, PLVDATA plvdata, int new_w)
|
|
{
|
|
int old_w, width;
|
|
|
|
old_w = plvscr->nContWidth;
|
|
width = scrolled_set_cont_width (hWnd, plvscr, new_w);
|
|
if (width != old_w)
|
|
InvalidateRect (hWnd, NULL, TRUE);
|
|
|
|
return width;
|
|
}
|
|
|
|
static BOOL
|
|
lvAddColumnToList (HWND hWnd, PLVDATA plvdata, PLVCOLUMN pcol)
|
|
{
|
|
PLSTHDR p1 = NULL;
|
|
int nCols = pcol->nCols;
|
|
|
|
if ( !(p1 = lvHdrNew (pcol, plvdata, &nCols)) )
|
|
return FALSE;
|
|
|
|
lvAddSubitem (plvdata, nCols);
|
|
sAddOffsetToTailSubItem (nCols+1, p1->width, plvdata);
|
|
plvdata->nHeadWidth += p1->width;
|
|
lvSetContWidth (hWnd, plvdata, plvdata->nHeadWidth);
|
|
plvdata->nCols ++;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//FIXME
|
|
static int sModifyHeadText (int nCols, const char *pszHeadText, PLVDATA plvdata)
|
|
{
|
|
PLSTHDR p1 = NULL;
|
|
|
|
p1 = lvGetHdrByCol(&plvdata->hdrqueue, nCols);
|
|
if (!p1 || !pszHeadText)
|
|
return -1;
|
|
|
|
if (p1->pTitle != NULL)
|
|
free (p1->pTitle);
|
|
|
|
p1->pTitle = (char *) malloc (strlen (pszHeadText) + 1);
|
|
strcpy (p1->pTitle, pszHeadText);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static PSUBITEMDATA
|
|
lvGetSubItemEx (PITEMDATA pitem, int nSubItem, PLVDATA plvdata)
|
|
{
|
|
if (!pitem)
|
|
return NULL;
|
|
return lvGetSubItemByCol(&pitem->subqueue, nSubItem);
|
|
}
|
|
|
|
/* Fills the content of a subitem */
|
|
static int
|
|
lvFillSubItem (PITEMDATA pi, int subItem, const char *pszText, PLVDATA plvdata)
|
|
{
|
|
PSUBITEMDATA p1;
|
|
|
|
if (!pi)
|
|
return -1;
|
|
|
|
if ( !(p1 = lvGetSubItemEx (pi, subItem, plvdata)) )
|
|
return -1;
|
|
|
|
if (pszText == NULL)
|
|
return -1;
|
|
|
|
if (p1->pszInfo != NULL)
|
|
free (p1->pszInfo);
|
|
p1->pszInfo = (char *) malloc (strlen (pszText) + 1);
|
|
strcpy (p1->pszInfo, pszText);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Set the text color of the subitem */
|
|
static int
|
|
lvSetSubItemTextColor (PITEMDATA pitem, int subItem, int color, PLVDATA plvdata)
|
|
{
|
|
PSUBITEMDATA p1;
|
|
|
|
if (!pitem)
|
|
return -1;
|
|
|
|
if ( !(p1 = lvGetSubItemEx (pitem, subItem, plvdata)) )
|
|
return -1;
|
|
|
|
p1->nTextColor = color;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
lvSetSubItem (PLVDATA plvdata, PITEMDATA pi, PLVSUBITEM pinfo)
|
|
{
|
|
PSUBITEMDATA p1;
|
|
|
|
if (!pinfo)
|
|
return -1;
|
|
|
|
if (!pi)
|
|
pi = lvGetItemByRow (plvdata, pinfo->nItem);
|
|
if (!pi)
|
|
return -1;
|
|
|
|
if ( !(p1 = lvGetSubItemEx (pi, pinfo->subItem, plvdata)) )
|
|
return -1;
|
|
|
|
if (p1->pszInfo != NULL)
|
|
free (p1->pszInfo);
|
|
|
|
if (pinfo->pszText) {
|
|
p1->pszInfo = (char *) malloc (strlen (pinfo->pszText) + 1);
|
|
strcpy (p1->pszInfo, pinfo->pszText);
|
|
}
|
|
else {
|
|
p1->pszInfo = malloc (1);
|
|
p1->pszInfo [0] = 0;
|
|
}
|
|
|
|
p1->nTextColor = pinfo->nTextColor;
|
|
if (pinfo->flags & LVFLAG_BITMAP)
|
|
p1->dwFlags |= LVIF_BITMAP;
|
|
if (pinfo->flags & LVFLAG_ICON)
|
|
p1->dwFlags |= LVIF_ICON;
|
|
p1->Image = pinfo->image;
|
|
|
|
scrollview_refresh_item (&plvdata->svdata, (HSVITEM)pi->addData);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
lvRemoveColumn (HWND hWnd, PLVDATA plvdata, int nCols)
|
|
{
|
|
int offset;
|
|
PLSTHDR pdel;
|
|
|
|
if (!LV_BE_VALID_COL(nCols))
|
|
return -1;
|
|
|
|
offset = -(GET_SUBITEM_W(nCols));
|
|
sAddOffsetToTailSubItem (nCols+1, offset, plvdata);
|
|
|
|
pdel = lvGetHdrByCol(&plvdata->hdrqueue, nCols);
|
|
lvHdrDel (pdel);
|
|
lvDelSubitem (plvdata, nCols);
|
|
|
|
plvdata->nCols --;
|
|
plvdata->nHeadWidth += offset;
|
|
lvSetContWidth (hWnd, plvdata, plvdata->nHeadWidth);
|
|
|
|
if (plvdata->nCols == 0) {
|
|
lvRemoveAllItem (hWnd, plvdata);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int lvAddTree (PLVDATA plvdata, PITEMDATA pp, PITEMDATA pi, int nItem)
|
|
{
|
|
if (!pp || !pi)
|
|
return -1;
|
|
|
|
if (!pp->child)
|
|
pp->child = pi;
|
|
|
|
if (nItem == 0) {
|
|
pp->child = pi;
|
|
}
|
|
|
|
while (pp) {
|
|
pp->child_nr += pi->child_nr + 1;
|
|
pp = pp->parent;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static PITEMDATA lvGetPrevSib (PLVDATA plvdata, PITEMDATA pi)
|
|
{
|
|
PITEMDATA pp, prev;
|
|
if (!pi)
|
|
return NULL;
|
|
|
|
pp = pi->parent;
|
|
prev = pp->child;
|
|
|
|
while (prev && prev->next != pi) {
|
|
prev = prev->next;
|
|
}
|
|
|
|
return prev;
|
|
}
|
|
|
|
static int lvDelTree (PLVDATA plvdata, PITEMDATA pi)
|
|
{
|
|
PITEMDATA pp, prev;
|
|
|
|
if (!pi)
|
|
return -1;
|
|
|
|
if ( !(pp = pi->parent))
|
|
return -1;
|
|
|
|
if ( (prev = lvGetPrevSib(plvdata, pi)) ) {
|
|
prev->next = pi->next;
|
|
}
|
|
else {
|
|
pp->child = pp->next;
|
|
}
|
|
|
|
while (pp) {
|
|
pp->child_nr -= pi->child_nr+1;
|
|
pp = pp->parent;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static PITEMDATA lvGetLastChild (PLVDATA plvdata, PITEMDATA pitem)
|
|
{
|
|
PITEMDATA pi;
|
|
|
|
if (!pitem)
|
|
return NULL;
|
|
|
|
if ( !(pi = pitem->child) )
|
|
return pitem;
|
|
|
|
while (pi->next) {
|
|
pi= pi->next;
|
|
}
|
|
|
|
return lvGetLastChild (plvdata, pi);
|
|
}
|
|
|
|
static int lvGetSibItems (PLVDATA plvdata, PITEMDATA parent, int nItem,
|
|
PITEMDATA *pprev, PITEMDATA *pnext)
|
|
{
|
|
PITEMDATA pi = NULL;
|
|
int i = 0;
|
|
|
|
if (!parent || nItem < 0)
|
|
return -1;
|
|
|
|
pi = parent->child;
|
|
if (nItem == 0 && pi) {
|
|
return 0;
|
|
}
|
|
while (pi && i < nItem-1) {
|
|
pi = pi->next;
|
|
i++;
|
|
}
|
|
|
|
if (pprev) {
|
|
*pprev = pi;
|
|
}
|
|
if (pnext) {
|
|
*pnext = pi ? pi->next : NULL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void lvInitRootItem (PLVDATA plvdata)
|
|
{
|
|
plvroot->dwFlags = 0;
|
|
plvroot->depth = -1;
|
|
plvroot->next = NULL;
|
|
plvroot->child = NULL;
|
|
plvroot->parent = NULL;
|
|
plvroot->child_nr = 0;
|
|
plvroot->itemData = 0;
|
|
plvroot->addData = 0;
|
|
}
|
|
|
|
static PITEMDATA itemNew (int nCols)
|
|
{
|
|
PSUBITEMDATA psub = NULL;
|
|
PITEMDATA pi = NULL;
|
|
int i;
|
|
|
|
if (nCols <= 0)
|
|
return NULL;
|
|
|
|
pi = (PITEMDATA) malloc (sizeof (ITEMDATA));
|
|
|
|
INIT_LIST_HEAD (&pi->subqueue);
|
|
for (i = 0; i < nCols; i++)
|
|
{
|
|
psub = subitemNew (NULL);
|
|
list_add_tail (&psub->list, &pi->subqueue);
|
|
}
|
|
|
|
return pi;
|
|
}
|
|
|
|
static int itemDelete (HWND hWnd, PLVDATA plvdata, PITEMDATA pItem)
|
|
{
|
|
PSUBITEMDATA psub = NULL;
|
|
list_t *me, *n;
|
|
|
|
if (!pItem)
|
|
return -1;
|
|
list_for_each_safe (me, n, &pItem->subqueue) {
|
|
psub = list_entry (me, SUBITEMDATA, list);
|
|
subitemFree (psub);
|
|
}
|
|
free (pItem);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sRemoveItemFromList (HWND hWnd, PLVDATA plvdata, PITEMDATA pi)
|
|
{
|
|
if (!pi)
|
|
return -1;
|
|
lvDelTree (plvdata, pi);
|
|
scrollview_del_item (hWnd, &plvdata->svdata, 0, (HSVITEM)pi->addData);
|
|
return 0;
|
|
}
|
|
|
|
static int lvRemoveAllItem (HWND hWnd, PLVDATA plvdata)
|
|
{
|
|
int cont_width;
|
|
|
|
cont_width = plvscr->nContWidth;
|
|
|
|
scrollview_reset_content (hWnd, &plvdata->svdata);
|
|
lvInitRootItem (plvdata);
|
|
lvSetContWidth (hWnd, plvdata, cont_width);
|
|
return 0;
|
|
}
|
|
|
|
static void lvDelItem (HWND hWnd, HSVITEM hsvi)
|
|
{
|
|
PITEMDATA pi = LV_GET_ITEM(hsvi);
|
|
PLVDATA plvdata = (PLVDATA)GetWindowAdditionalData2(hWnd);
|
|
itemDelete (hWnd, plvdata, pi);
|
|
}
|
|
|
|
static void lvSetColumnWidth (HWND hWnd, PLVDATA plvdata, int nCols, int width)
|
|
{
|
|
int offset;
|
|
PLSTHDR ph = lvGetHdrByCol (&plvdata->hdrqueue, nCols);
|
|
|
|
if (!ph) return;
|
|
|
|
if (width < COLWIDTHMIN)
|
|
width = COLWIDTHMIN;
|
|
|
|
offset = width - ph->width;
|
|
ph->width = width;
|
|
sAddOffsetToTailSubItem (nCols+1, offset, plvdata);
|
|
plvdata->nHeadWidth += offset;
|
|
}
|
|
|
|
static void lvBorderDrag (HWND hWnd, int x, int y)
|
|
{
|
|
PLVDATA plvdata;
|
|
PLSTHDR pDrag;
|
|
int mouseX = x, mouseY = y;
|
|
RECT rect;
|
|
int offset;
|
|
HDC hdc;
|
|
|
|
plvdata = (PLVDATA) GetWindowAdditionalData2 (hWnd);
|
|
pDrag = lvGetHdrByCol (&plvdata->hdrqueue, plvdata->nItemDraged);
|
|
|
|
GetClientRect (hWnd, &rect);
|
|
ScreenToClient (hWnd, &mouseX, &mouseY);
|
|
|
|
/*the column width should not less than the min value*/
|
|
if ((pDrag->x - plvscr->nContX + COLWIDTHMIN) > mouseX - 1)
|
|
return;
|
|
|
|
offset = mouseX - (pDrag->x + pDrag->width - plvscr->nContX);
|
|
lvSetColumnWidth (hWnd, plvdata, plvdata->nItemDraged, pDrag->width+offset);
|
|
|
|
rect.bottom = rect.top + plvdata->nHeadHeight+1;
|
|
/*FIXME
|
|
*InvalidateRect(hWnd, &rect, TRUE);
|
|
*/
|
|
hdc = GetClientDC(hWnd);
|
|
lv_draw_header (hWnd, hdc);
|
|
ReleaseDC (hdc);
|
|
}
|
|
|
|
static void lvToggleSortStatus (PLSTHDR p1)
|
|
{
|
|
switch (p1->sort)
|
|
{
|
|
case NOTSORTED:
|
|
p1->sort = LOSORTED;
|
|
break;
|
|
case HISORTED:
|
|
p1->sort = LOSORTED;
|
|
break;
|
|
case LOSORTED:
|
|
p1->sort = HISORTED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static PITEMDATA lvFindItem (PLVDATA plvdata, PITEMDATA p1, PLVFINDINFO pFindInfo)
|
|
{
|
|
HSVITEM hsvi;
|
|
int j = 0, total_nr;
|
|
BOOL by_index;
|
|
|
|
if (!pFindInfo)
|
|
return NULL;
|
|
|
|
if (!p1) {
|
|
by_index = TRUE;
|
|
p1 = lvGetItemByRow (plvdata, pFindInfo->iStart);
|
|
if (!p1);
|
|
p1 = plvroot->child;
|
|
total_nr = 1; //large than j
|
|
}
|
|
else {
|
|
by_index = FALSE;
|
|
total_nr = p1->child_nr;
|
|
}
|
|
|
|
while (p1 && j < total_nr)
|
|
{
|
|
if (pFindInfo->flags & LVFF_ADDDATA) {
|
|
if (pFindInfo->addData == p1->itemData)
|
|
return p1;
|
|
}
|
|
else if (pFindInfo->flags & LVFF_TEXT) {
|
|
PSUBITEMDATA p2;
|
|
list_t *me;
|
|
int i = 0;
|
|
|
|
list_for_each (me, &p1->subqueue) {
|
|
p2 = list_entry (me, SUBITEMDATA, list);
|
|
if (plvdata->str_cmp (p2->pszInfo, pFindInfo->pszInfo[i],
|
|
(size_t)-1) != 0)
|
|
break;
|
|
if (i >= pFindInfo->nCols)
|
|
return p1;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (!by_index)
|
|
j++;
|
|
hsvi = scrollview_get_next_item(&plvdata->svdata, (HSVITEM)p1->addData);
|
|
p1 = LV_GET_ITEM(hsvi);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* The default comparision function for compare two items */
|
|
static int
|
|
lvDefCompare (HSVITEM hsvi1, HSVITEM hsvi2, int ncol, PLVDATA plvdata)
|
|
{
|
|
PITEMDATA p1, p2;
|
|
PSUBITEMDATA psub1, psub2;
|
|
|
|
p1 = LV_GET_ITEM(hsvi1);
|
|
p2 = LV_GET_ITEM(hsvi2);
|
|
psub1 = lvGetSubItemByCol (&p1->subqueue, ncol);
|
|
psub2 = lvGetSubItemByCol (&p2->subqueue, ncol);
|
|
|
|
if (psub1 == NULL || psub2 == NULL)
|
|
return -1;
|
|
|
|
if(psub1->pszInfo == NULL)
|
|
{
|
|
return (psub2->pszInfo != NULL)?-1:0;
|
|
}
|
|
else if(psub2->pszInfo == NULL)
|
|
{
|
|
return (psub1->pszInfo != NULL)?1:0;
|
|
}
|
|
|
|
if (plvdata->str_cmp)
|
|
return plvdata->str_cmp (psub1->pszInfo, psub2->pszInfo, (size_t)-1);
|
|
else
|
|
return strcasecmp (psub1->pszInfo, psub2->pszInfo);
|
|
}
|
|
|
|
static int lv_cmp_fn (MgList *mglst, HSVITEM hsvi1, HSVITEM hsvi2)
|
|
{
|
|
HWND hWnd = mglst->hLst;
|
|
PLVDATA plvdata;
|
|
int ret;
|
|
LVSORTDATA sortdata;
|
|
|
|
plvdata = (PLVDATA)GetWindowAdditionalData2 (hWnd);
|
|
if (plvdata->pfn_sort) {
|
|
sortdata.ncol = 0;
|
|
sortdata.losorted = 0;
|
|
sortdata.hLV = hWnd;
|
|
ret = plvdata->pfn_sort ( (HLVITEM)LV_GET_ITEM(hsvi1),
|
|
(HLVITEM)LV_GET_ITEM(hsvi2), &sortdata );
|
|
if (ret == 0)
|
|
ret = lvDefCompare (hsvi1, hsvi2, 1, plvdata);
|
|
}
|
|
else {
|
|
ret = lvDefCompare (hsvi1, hsvi2, plvdata->cur_col, plvdata);
|
|
}
|
|
|
|
if ( (plvdata->col_sort == LOSORTED && ret < 0) ||
|
|
(plvdata->col_sort == HISORTED && ret > 0) )
|
|
return -1;
|
|
return 1;
|
|
}
|
|
|
|
/* sorting items using a comparision function */
|
|
static int
|
|
lvSortItem (PFNLVCOMPARE pfn_user, int nCols, SORTTYPE sort, PLVDATA plvdata)
|
|
{
|
|
PLSTHDR ph;
|
|
PFNLVCOMPARE pcmp;
|
|
|
|
/* If pfn_user is not NULL, use it as comparision function; otherwise,
|
|
* use the one associated with nCols column.
|
|
*/
|
|
if (pfn_user)
|
|
pcmp = pfn_user;
|
|
else {
|
|
if ( !(ph = lvGetHdrByCol (&plvdata->hdrqueue, nCols)) )
|
|
return -1;
|
|
pcmp = ph->pfnCmp;
|
|
}
|
|
|
|
plvdata->pfn_sort = pcmp;
|
|
plvdata->col_sort = sort;
|
|
plvdata->cur_col = nCols;
|
|
scrollview_sort_items (&plvdata->svdata, (void*)lv_cmp_fn, MG_CMP_TYPE_EX);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void setup_color (HWND hWnd, PLVDATA plvdata)
|
|
{
|
|
int color;
|
|
|
|
color = (GetFocusChild (GetParent(hWnd)) == hWnd) ?
|
|
WE_BGC_SELECTED_ITEM : WE_BGC_SELECTED_LOSTFOCUS;
|
|
plvdata->bkc_selected = GetWindowElementPixelEx (hWnd, HDC_INVALID, color);
|
|
}
|
|
|
|
static SVITEMOPS listview_iops =
|
|
{
|
|
NULL, lvDelItem, lvDrawItem
|
|
};
|
|
|
|
static int listview_init (HWND hWnd, PLVDATA plvdata)
|
|
{
|
|
RECT rc;
|
|
|
|
if (!plvdata)
|
|
return -1;
|
|
|
|
scrollview_init (hWnd, &plvdata->svdata);
|
|
#ifdef __TARGET_MSTUDIO__
|
|
plvdata->svdata.scrdata.sbPolicy = SB_POLICY_ALWAYS;
|
|
#endif
|
|
|
|
rc.left = LV_LEFTMARGIN;
|
|
rc.right = LV_RIGHTMARGIN;
|
|
rc.bottom = LV_BOTTOMMARGIN;
|
|
rc.top = LV_HDRH_DEF(hWnd) + LV_TOPMARGIN;
|
|
scrolled_set_margins (plvscr, &rc);
|
|
|
|
plvdata->nHeadHeight = LV_HDRH_DEF(hWnd);
|
|
plvdata->nHeadWidth = 0;
|
|
setup_color (hWnd, plvdata);
|
|
|
|
plvdata->nCols = 0;
|
|
//plvdata->nRows = 0;
|
|
|
|
plvdata->nColCurSel = -1;
|
|
|
|
plvdata->nItemDraged = -1;
|
|
plvdata->pHdrClicked = NULL;
|
|
LVSTATUS(hWnd) = LVST_NORMAL;
|
|
|
|
INIT_LIST_HEAD(&plvdata->hdrqueue);
|
|
plvdata->hWnd = hWnd;
|
|
plvdata->str_cmp = strncmp;
|
|
plvdata->pfn_draw_hdr_bk = NULL;
|
|
plvdata->pfn_draw_hdr_item = NULL;
|
|
|
|
scrollview_set_itemops (&plvdata->svdata, (SVITEMOPS*)&listview_iops);
|
|
|
|
lvInitRootItem (plvdata);
|
|
|
|
SetWindowAdditionalData2 (hWnd, (DWORD) plvdata);
|
|
return 0;
|
|
}
|
|
|
|
/*Destroies all the internal datas*/
|
|
static void listview_destroy (HWND hWnd, PLVDATA plvdata)
|
|
{
|
|
scrollview_destroy (&plvdata->svdata);
|
|
lvHdrDestroy (plvdata);
|
|
}
|
|
|
|
#define RETURN_DIRECT return DefaultControlProc(hWnd, message, wParam, lParam)
|
|
|
|
static LRESULT ListViewCtrlProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PLVDATA plvdata = NULL;
|
|
|
|
if (message != MSG_CREATE)
|
|
plvdata = (PLVDATA) GetWindowAdditionalData2 (hWnd);
|
|
|
|
switch (message)
|
|
{
|
|
|
|
case MSG_CREATE:
|
|
{
|
|
if (!(plvdata = (PLVDATA) malloc (sizeof (LVDATA))))
|
|
return -1;
|
|
listview_init (hWnd, plvdata);
|
|
RETURN_DIRECT;
|
|
}
|
|
|
|
case MSG_DESTROY:
|
|
{
|
|
listview_destroy (hWnd, plvdata);
|
|
free (plvdata);
|
|
RETURN_DIRECT;
|
|
}
|
|
|
|
case MSG_SETCURSOR:
|
|
{
|
|
int mouseX = LOSWORD (lParam);
|
|
int mouseY = HISWORD (lParam);
|
|
|
|
if ((LVSTATUS(hWnd) & LVST_BDDRAG) ||
|
|
(lvInWhichHeadBorder (mouseX, mouseY, NULL, plvdata) >= 0)) {
|
|
SetCursor (GetSystemCursor (IDC_SPLIT_VERT));
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MSG_PAINT:
|
|
{
|
|
#if 0
|
|
HDC hdc = BeginPaint (hWnd);
|
|
lvOnDraw (hWnd, hdc);
|
|
EndPaint (hWnd, hdc);
|
|
break;
|
|
#else
|
|
|
|
#define plstscr (&plvdata->svdata.scrdata)
|
|
|
|
HDC hdc = BeginPaint (hWnd);
|
|
RECT rcDraw, rcVis;
|
|
|
|
lvOnDraw (hWnd, hdc);
|
|
|
|
scrolled_get_visible_rect (plstscr, &rcVis);
|
|
ClipRectIntersect (hdc, &rcVis);
|
|
scrolled_get_content_rect (plstscr, &rcDraw);
|
|
scrolled_visible_to_window (plstscr, &rcDraw.left, &rcDraw.top);
|
|
scrolled_visible_to_window (plstscr, &rcDraw.right, &rcDraw.bottom);
|
|
|
|
scrollview_draw (hWnd, hdc, &plvdata->svdata);
|
|
|
|
EndPaint (hWnd, hdc);
|
|
return 0;
|
|
#endif
|
|
}
|
|
case MSG_SETFOCUS:
|
|
case MSG_KILLFOCUS:
|
|
{
|
|
HSVITEM hsvi;
|
|
|
|
setup_color (hWnd, plvdata);
|
|
hsvi = scrollview_get_hilighted_item(&plvdata->svdata);
|
|
if (!hsvi)
|
|
break;
|
|
scrollview_refresh_item (&plvdata->svdata, hsvi);
|
|
break;
|
|
}
|
|
|
|
case MSG_GETDLGCODE:
|
|
return DLGC_WANTARROWS | DLGC_WANTCHARS;
|
|
|
|
case MSG_LBUTTONDBLCLK:
|
|
{
|
|
int mouseX = LOSWORD (lParam);
|
|
int mouseY = HISWORD (lParam);
|
|
PITEMDATA pi = NULL;
|
|
int nCols;
|
|
PLSTHDR p1;
|
|
|
|
// double clicks on the header
|
|
if ( (nCols = isInListViewHead (mouseX, mouseY, &p1, plvdata)) > 0 )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (isInLVItem (mouseX, mouseY, &pi, plvdata, NULL) >= 0) {
|
|
NotifyParent (hWnd, GetDlgCtrlID(hWnd), LVN_ITEMDBCLK);
|
|
if (pi->child) {
|
|
BOOL bfold;
|
|
bfold = (ISFOLD(pi)) ? FALSE : TRUE;
|
|
lvFoldItem (hWnd, plvdata, pi, bfold);
|
|
NotifyParentEx (hWnd, GetDlgCtrlID(hWnd),
|
|
bfold ? LVN_FOLDED : LVN_UNFOLDED, (DWORD)pi);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case MSG_MOUSEMOVE:
|
|
{
|
|
int mouseX = LOSWORD (lParam);
|
|
int mouseY = HISWORD (lParam);
|
|
|
|
/*in head clicked status*/
|
|
if (LVSTATUS(hWnd) & LVST_HEADCLICK) {
|
|
RECT rc;
|
|
PLSTHDR p1;
|
|
|
|
if (GetCapture() != hWnd)
|
|
break;
|
|
|
|
ScreenToClient (hWnd, &mouseX, &mouseY);
|
|
|
|
p1 = plvdata->pHdrClicked;
|
|
LV_GET_HDR_RECT(p1, rc);
|
|
|
|
if (PtInRect(&rc, mouseX, mouseY)) {
|
|
if (!(LVSTATUS(hWnd) & LVST_INHEAD)) {
|
|
LVSTATUS(hWnd) |= LVST_INHEAD;
|
|
InvalidateRect (hWnd, &rc, TRUE);
|
|
}
|
|
}
|
|
else if (LVSTATUS(hWnd) & LVST_INHEAD) {
|
|
rc.left -= 1;
|
|
rc.right += 1;
|
|
LVSTATUS(hWnd) &= ~LVST_INHEAD;
|
|
InvalidateRect (hWnd, &rc, TRUE);
|
|
}
|
|
}
|
|
/*in border dragged status*/
|
|
else if (LVSTATUS(hWnd) & LVST_BDDRAG)
|
|
lvBorderDrag (hWnd, mouseX, mouseY);
|
|
|
|
break;
|
|
}
|
|
|
|
case MSG_LBUTTONDOWN:
|
|
{
|
|
int mouseX = LOSWORD (lParam);
|
|
int mouseY = HISWORD (lParam);
|
|
int nCols = -1, nRows;
|
|
POINT pt;
|
|
|
|
RECT rect, rcClient;
|
|
PLSTHDR p1;
|
|
PITEMDATA pi = NULL;
|
|
|
|
GetClientRect (hWnd, &rcClient);
|
|
|
|
if (GetCapture() == hWnd)
|
|
break;
|
|
|
|
SetCapture (hWnd);
|
|
LVSTATUS(hWnd) |= LVST_CAPTURED;
|
|
|
|
if (plvdata->nHeadHeight > 0)
|
|
nCols = isInListViewHead (mouseX, mouseY, &p1, plvdata);
|
|
|
|
if (nCols >= 0) {
|
|
/* clicks on the header*/
|
|
LVSTATUS(hWnd) |= LVST_HEADCLICK;
|
|
LVSTATUS(hWnd) |= LVST_INHEAD;
|
|
plvdata->pHdrClicked = p1;
|
|
|
|
SetRect (&rect, p1->x - plvscr->nContX, LV_HDR_TOP,
|
|
p1->x - plvscr->nContX+ p1->width,
|
|
LV_HDR_TOP + LV_HDR_HEIGHT);
|
|
InvalidateRect (hWnd, &rect, TRUE);
|
|
}
|
|
else {
|
|
nCols = lvInWhichHeadBorder (mouseX, mouseY, &p1, plvdata);
|
|
if (plvdata->nHeadHeight > 0 && nCols >= 0) {
|
|
LVSTATUS(hWnd) |= LVST_BDDRAG;
|
|
plvdata->nItemDraged = nCols;
|
|
}
|
|
else if ((nRows = isInLVItem (mouseX, mouseY, &pi, plvdata,
|
|
&pt)) >= 0)
|
|
{
|
|
int indent;
|
|
//FIXME
|
|
if ( !(GetWindowStyle(hWnd) & LVS_UPNOTIFY) ) {
|
|
/*NotifyParent (hWnd, GetDlgCtrlID(hWnd), LVN_SELCHANGE);*/
|
|
}
|
|
else {
|
|
LVSTATUS(hWnd) |= LVST_ITEMDRAG;
|
|
}
|
|
indent = lvGetItemIndent (plvdata, pi);
|
|
if (pi->child && pt.x > indent && pt.x < indent + 9
|
|
/*bmp_fold->bmWidth*/ + 4)
|
|
{
|
|
BOOL bfold;
|
|
bfold = (ISFOLD(pi)) ? FALSE : TRUE;
|
|
/* select highlight item first.*/
|
|
ScrollViewCtrlProc (hWnd, message, wParam, lParam);
|
|
lvFoldItem (hWnd, plvdata, pi, bfold);
|
|
NotifyParentEx (hWnd, GetDlgCtrlID(hWnd),
|
|
bfold ? LVN_FOLDED : LVN_UNFOLDED, (DWORD)pi);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case MSG_LBUTTONUP:
|
|
{
|
|
PLSTHDR p1;
|
|
int nCols;
|
|
int mouseX = LOSWORD (lParam);
|
|
int mouseY = HISWORD (lParam);
|
|
|
|
if (GetCapture() != hWnd)
|
|
break;
|
|
|
|
if (LVSTATUS(hWnd) & LVST_CAPTURED) {
|
|
LVSTATUS(hWnd) &= ~LVST_CAPTURED;
|
|
ReleaseCapture ();
|
|
ScreenToClient (hWnd, &mouseX, &mouseY);
|
|
}
|
|
else
|
|
break;
|
|
|
|
if (LVSTATUS(hWnd) & LVST_HEADCLICK)
|
|
{
|
|
LVSTATUS(hWnd) &= ~LVST_HEADCLICK;
|
|
LVSTATUS(hWnd) &= ~LVST_INHEAD;
|
|
|
|
nCols = isInListViewHead (mouseX, mouseY, NULL, plvdata);
|
|
if (nCols < 0)
|
|
break;
|
|
p1 = lvGetHdrByCol (&plvdata->hdrqueue, nCols);
|
|
if (!p1 || p1 != plvdata->pHdrClicked)
|
|
break;
|
|
|
|
lvToggleSortStatus(p1);
|
|
if ( !(GetWindowStyle(hWnd)&LVS_TREEVIEW) )
|
|
lvSortItem (NULL, nCols, p1->sort, plvdata);
|
|
//FIXME
|
|
InvalidateRect (hWnd, NULL, TRUE);
|
|
}
|
|
else if (LVSTATUS(hWnd) & LVST_BDDRAG)
|
|
{
|
|
LVSTATUS(hWnd) &= ~LVST_BDDRAG;
|
|
lvSetContWidth (hWnd, plvdata, plvdata->nHeadWidth);
|
|
}
|
|
else if (LVSTATUS(hWnd) & LVST_ITEMDRAG && GetWindowStyle(hWnd)
|
|
& LVS_UPNOTIFY) {
|
|
// NUV HSVITEM hsvi;
|
|
// NUV int idx;
|
|
|
|
// NUV idx = isInLVItem (mouseX, mouseY, NULL, plvdata, NULL);
|
|
// NUV hsvi = scrollview_get_item_by_index (&plvdata->svdata, idx);
|
|
NotifyParent (hWnd, GetDlgCtrlID(hWnd), LVN_CLICKED);
|
|
|
|
/* LVS_UPNOTIFY only affects LVN_CLICKED
|
|
if (hsvi && hsvi != scrollview_get_hilighted_item
|
|
(&plvdata->svdata)) {
|
|
if ( GetWindowStyle(hWnd) & LVS_UPNOTIFY ) {
|
|
NotifyParent (hWnd, GetDlgCtrlID(hWnd), LVN_SELCHANGE);
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case MSG_RBUTTONUP:
|
|
case MSG_RBUTTONDOWN:
|
|
{
|
|
int mouseX = LOSWORD (lParam);
|
|
int mouseY = HISWORD (lParam);
|
|
int nCols, nRows;
|
|
RECT rcClient;
|
|
PLSTHDR p1;
|
|
LVNM_NORMAL lvnm;
|
|
|
|
lvnm.wParam = wParam;
|
|
lvnm.lParam = lParam;
|
|
|
|
GetClientRect (hWnd, &rcClient);
|
|
|
|
/* clicks on the header*/
|
|
if ((nCols = isInListViewHead (mouseX, mouseY, &p1, plvdata)) > 0)
|
|
{
|
|
if (message == MSG_RBUTTONDOWN)
|
|
NotifyParentEx (hWnd, GetDlgCtrlID(hWnd), LVN_HEADRDOWN,
|
|
(DWORD)&lvnm);
|
|
else
|
|
NotifyParentEx (hWnd, GetDlgCtrlID(hWnd), LVN_HEADRUP,
|
|
(DWORD)&lvnm);
|
|
}
|
|
/* clicks on an item*/
|
|
else if ((nRows = isInLVItem (mouseX, mouseY, NULL, plvdata,
|
|
NULL)) >= 0)
|
|
{
|
|
if (message == MSG_RBUTTONDOWN)
|
|
/*NotifyParent (hWnd, GetDlgCtrlID(hWnd), LVN_SELCHANGE);*/
|
|
NotifyParentEx (hWnd, GetDlgCtrlID(hWnd), LVN_ITEMRDOWN
|
|
, (DWORD)&lvnm);
|
|
else
|
|
NotifyParentEx (hWnd, GetDlgCtrlID(hWnd), LVN_ITEMRUP
|
|
, (DWORD)&lvnm);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MSG_KEYDOWN:
|
|
{
|
|
LVNM_NORMAL lvnm;
|
|
|
|
lvnm.wParam = wParam;
|
|
lvnm.lParam = lParam;
|
|
NotifyParentEx (hWnd, GetDlgCtrlID(hWnd), LVN_KEYDOWN, (DWORD)&lvnm);
|
|
break;
|
|
}
|
|
|
|
case MSG_HSCROLL:
|
|
{
|
|
RECT rc;
|
|
|
|
GetClientRect (hWnd, &rc);
|
|
rc.bottom = rc.top + plvdata->nHeadHeight + 1;
|
|
InvalidateRect (hWnd, &rc, TRUE);
|
|
break;
|
|
}
|
|
|
|
case LVM_ADDCOLUMN:
|
|
{
|
|
PLVCOLUMN p1;
|
|
|
|
if ( !(p1 = (PLVCOLUMN)lParam) )
|
|
return LV_ERR;
|
|
|
|
if (!lvAddColumnToList (hWnd, plvdata, p1))
|
|
return LV_ERR;
|
|
|
|
return LV_OKAY;
|
|
}
|
|
|
|
case LVM_ADDITEM:
|
|
{
|
|
PLVITEM p1;
|
|
SVITEMINFO svii;
|
|
PITEMDATA parent = (PITEMDATA)wParam;
|
|
PITEMDATA pnew, pprev = NULL, pnext = NULL, ptmp;
|
|
HSVITEM hsvi;
|
|
//FIXME
|
|
int nItem = 0;
|
|
|
|
if ( !(p1 = (PLVITEM) lParam) )
|
|
return -1;
|
|
if ( !(pnew = itemNew (plvdata->nCols)) )
|
|
return -1;
|
|
|
|
if (!parent)
|
|
parent = plvroot;
|
|
else {
|
|
IncludeWindowStyle (hWnd, LVS_TREEVIEW);
|
|
}
|
|
|
|
lvGetSibItems (plvdata, parent, p1->nItem, &pprev, &pnext);
|
|
|
|
if (p1->nItemHeight > 0)
|
|
pnew->itemh = p1->nItemHeight;
|
|
else
|
|
pnew->itemh = LV_ITEMH_DEF(hWnd);
|
|
|
|
pnew->parent = parent;
|
|
pnew->child = NULL;
|
|
pnew->depth = parent->depth + 1;
|
|
pnew->next = pnext;
|
|
pnew->child_nr = 0;
|
|
pnew->dwFlags = p1->dwFlags;
|
|
pnew->itemData = p1->itemData;
|
|
|
|
if (pprev)
|
|
pprev->next = pnew;
|
|
lvAddTree (plvdata, parent, pnew, p1->nItem);
|
|
|
|
if (ISFOLD(parent)) {
|
|
svii.nItemHeight = 0;
|
|
}
|
|
else {
|
|
svii.nItemHeight = pnew->itemh;
|
|
}
|
|
|
|
svii.nItem = p1->nItem;
|
|
svii.addData = (DWORD)pnew;
|
|
|
|
if (pnext) {
|
|
hsvi = (HSVITEM)pnext->addData;
|
|
pnew->addData = (DWORD) scrollview_add_item_ex (hWnd,
|
|
&plvdata->svdata, 0, hsvi, &svii, &nItem);
|
|
}
|
|
else if (pprev) {
|
|
ptmp = lvGetLastChild (plvdata, pprev);
|
|
hsvi = (HICON)ptmp->addData;
|
|
pnew->addData = (DWORD) scrollview_add_item (hWnd,
|
|
&plvdata->svdata, hsvi, &svii, &nItem);
|
|
}
|
|
else {
|
|
hsvi = (HICON)parent->addData;
|
|
pnew->addData = (DWORD) scrollview_add_item (hWnd,
|
|
&plvdata->svdata, hsvi, &svii, &nItem);
|
|
}
|
|
|
|
return (LRESULT)pnew;
|
|
}
|
|
|
|
case LVM_GETITEM:
|
|
{
|
|
PLVITEM p1;
|
|
PITEMDATA pitem;
|
|
|
|
p1 = (PLVITEM) lParam;
|
|
pitem = (PITEMDATA)wParam;
|
|
|
|
if (!p1)
|
|
return LV_ERR;
|
|
|
|
if (!pitem)
|
|
pitem = lvGetItemByRow (plvdata, p1->nItem);
|
|
if (!pitem)
|
|
return LV_ERR;
|
|
|
|
p1->itemData = pitem->itemData;
|
|
p1->nItemHeight = scrollview_get_item_height ((HSVITEM)pitem->addData);
|
|
p1->dwFlags = pitem->dwFlags;
|
|
|
|
return LV_OKAY;
|
|
}
|
|
case LVM_GETITEMCOUNT:
|
|
{
|
|
return scrollview_get_item_count(&plvdata->svdata);
|
|
}
|
|
case LVM_GETSELECTEDITEM:
|
|
{
|
|
HSVITEM hsvi;
|
|
PITEMDATA pi;
|
|
|
|
hsvi = scrollview_get_hilighted_item (&plvdata->svdata);
|
|
pi = LV_GET_ITEM (hsvi);
|
|
return (LRESULT)pi;
|
|
}
|
|
|
|
case LVM_GETRELATEDITEM:
|
|
{
|
|
PITEMDATA pi = (PITEMDATA)lParam;
|
|
|
|
if (!pi)
|
|
return 0;
|
|
|
|
if (wParam == LVIR_PARENT) {
|
|
return (LRESULT)pi->parent;
|
|
}
|
|
else if (wParam == LVIR_FIRSTCHILD) {
|
|
return (LRESULT)pi->child;
|
|
}
|
|
else if (wParam == LVIR_NEXTSIBLING) {
|
|
return (LRESULT)pi->next;
|
|
}
|
|
else if (wParam == LVIR_PREVSIBLING) {
|
|
return (LRESULT)lvGetPrevSib(plvdata, pi);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case LVM_GETCOLUMN:
|
|
{
|
|
int col = (int)wParam;
|
|
PLVCOLUMN pcol = (PLVCOLUMN)lParam;
|
|
PLSTHDR ph = lvGetHdrByCol(&plvdata->hdrqueue, col);
|
|
|
|
if (!ph)
|
|
return -1;
|
|
|
|
pcol->width = ph->width;
|
|
strncpy (pcol->pszHeadText, ph->pTitle, pcol->nTextMax);
|
|
pcol->pszHeadText[pcol->nTextMax] = 0;
|
|
pcol->image = ph->Image;
|
|
pcol->pfnCompare = ph->pfnCmp;
|
|
pcol->colFlags = ph->flags;
|
|
|
|
return 0;
|
|
}
|
|
case LVM_GETCOLUMNWIDTH:
|
|
{
|
|
int col = (int)wParam;
|
|
PLSTHDR ph = lvGetHdrByCol(&plvdata->hdrqueue, col);
|
|
if (ph)
|
|
return ph->width;
|
|
else
|
|
return -1;
|
|
}
|
|
case LVM_GETCOLUMNCOUNT:
|
|
{
|
|
return plvdata->nCols;
|
|
}
|
|
|
|
case LVM_FILLSUBITEM:
|
|
case LVM_SETSUBITEM:
|
|
{
|
|
PLVSUBITEM p1;
|
|
PITEMDATA pi = (PITEMDATA)wParam;
|
|
|
|
if ( !(p1 = (PLVSUBITEM)lParam) )
|
|
return LV_ERR;
|
|
|
|
if ( (lvSetSubItem(plvdata, pi, p1)) < 0 )
|
|
return LV_ERR;
|
|
|
|
return LV_OKAY;
|
|
}
|
|
|
|
case LVM_GETSUBITEMLEN:
|
|
{
|
|
PLVSUBITEM p1;
|
|
PSUBITEMDATA p2;
|
|
PITEMDATA pi = (PITEMDATA)wParam;
|
|
|
|
if ( !(p1 = (PLVSUBITEM) lParam) )
|
|
return -1;
|
|
|
|
if (!pi)
|
|
pi = lvGetItemByRow (plvdata, p1->nItem);
|
|
if (!pi)
|
|
return -1;
|
|
p2 = lvGetSubItemEx (pi, p1->subItem, plvdata);
|
|
|
|
if (!p2 || !p2->pszInfo)
|
|
return LV_ERR;
|
|
|
|
return strlen (p2->pszInfo);
|
|
}
|
|
case LVM_GETSUBITEMTEXT:
|
|
{
|
|
PLVSUBITEM p1;
|
|
PSUBITEMDATA p2;
|
|
PITEMDATA pi = (PITEMDATA)wParam;
|
|
|
|
if ( !(p1 = (PLVSUBITEM) lParam) )
|
|
return -1;
|
|
|
|
if (!pi)
|
|
pi = lvGetItemByRow (plvdata, p1->nItem);
|
|
if (!pi)
|
|
return -1;
|
|
p2 = lvGetSubItemEx (pi, p1->subItem, plvdata);
|
|
|
|
if (!p2 || !p2->pszInfo)
|
|
return LV_ERR;
|
|
|
|
strcpy (p1->pszText, p2->pszInfo);
|
|
|
|
return 0;
|
|
}
|
|
case LVM_MODIFYHEAD:
|
|
{
|
|
PLVCOLUMN p1 = (PLVCOLUMN) lParam;
|
|
if (!p1)
|
|
return LV_ERR;
|
|
if (sModifyHeadText (p1->nCols, p1->pszHeadText, plvdata) >= 0) {
|
|
RECT rc;
|
|
GetClientRect (hWnd, &rc);
|
|
rc.bottom = rc.top + plvdata->nHeadHeight;
|
|
InvalidateRect (hWnd, &rc, TRUE);
|
|
return LV_OKAY;
|
|
}
|
|
return LV_ERR;
|
|
}
|
|
case LVM_SETCOLUMN:
|
|
{
|
|
PLVCOLUMN p1 = (PLVCOLUMN) lParam;
|
|
PLSTHDR ph;
|
|
|
|
if (!p1)
|
|
return LV_ERR;
|
|
if ( !(ph = lvGetHdrByCol (&plvdata->hdrqueue, p1->nCols)) )
|
|
return LV_ERR;
|
|
|
|
sModifyHeadText (p1->nCols, p1->pszHeadText, plvdata);
|
|
lvSetColumnWidth (hWnd, plvdata, p1->nCols, p1->width);
|
|
lvSetContWidth (hWnd, plvdata, plvdata->nHeadWidth);
|
|
ph->Image = p1->image;
|
|
ph->flags = p1->colFlags;
|
|
|
|
return LV_OKAY;
|
|
}
|
|
case LVM_FINDITEM:
|
|
{
|
|
return (LRESULT)lvFindItem(plvdata, (PITEMDATA)wParam, (PLVFINDINFO)lParam);
|
|
}
|
|
case LVM_DELITEM:
|
|
{
|
|
PITEMDATA pitem = (PITEMDATA)lParam;
|
|
if (!pitem)
|
|
return LV_ERR;
|
|
if (sRemoveItemFromList (hWnd, plvdata, pitem))
|
|
return LV_ERR;
|
|
return LV_OKAY;
|
|
}
|
|
case LVM_DELALLITEM:
|
|
{
|
|
lvRemoveAllItem (hWnd, plvdata);
|
|
return LV_OKAY;
|
|
}
|
|
|
|
//TODO
|
|
case LVM_CLEARSUBITEM:
|
|
break;
|
|
|
|
case LVM_DELCOLUMN:
|
|
{
|
|
if (lvRemoveColumn (hWnd, plvdata, (int)wParam))
|
|
return LV_ERR;
|
|
return LV_OKAY;
|
|
}
|
|
|
|
//TODO, multi select
|
|
case LVM_SELECTITEM:
|
|
{
|
|
PITEMDATA pitem = (PITEMDATA)lParam;
|
|
if (!pitem)
|
|
pitem = lvGetItemByRow (plvdata, wParam);
|
|
if (!pitem)
|
|
return -1;
|
|
scrollview_hilight_item (&plvdata->svdata, (HSVITEM)pitem->addData);
|
|
return 0;
|
|
}
|
|
case LVM_SHOWITEM:
|
|
{
|
|
PITEMDATA pitem = (PITEMDATA)lParam;
|
|
if (!pitem)
|
|
pitem = lvGetItemByRow (plvdata, wParam);
|
|
if (!pitem)
|
|
return -1;
|
|
scrollview_make_item_visible (&plvdata->svdata,
|
|
(HSVITEM)pitem->addData);
|
|
return 0;
|
|
}
|
|
case LVM_CHOOSEITEM:
|
|
{
|
|
PITEMDATA pitem = (PITEMDATA)lParam;
|
|
if (!pitem)
|
|
pitem = lvGetItemByRow (plvdata, wParam);
|
|
if (!pitem)
|
|
return -1;
|
|
scrollview_hilight_item (&plvdata->svdata, (HSVITEM)pitem->addData);
|
|
scrollview_make_item_visible (&plvdata->svdata,
|
|
(HSVITEM)pitem->addData);
|
|
return 0;
|
|
}
|
|
case LVM_FOLDITEM:
|
|
{
|
|
PITEMDATA pitem = (PITEMDATA)lParam;
|
|
if (!pitem)
|
|
return -1;
|
|
lvFoldItem (hWnd, plvdata, pitem, wParam);
|
|
return 0;
|
|
}
|
|
|
|
case LVM_GETITEMADDDATA:
|
|
{
|
|
PITEMDATA pitem = (PITEMDATA)lParam;
|
|
|
|
if (!pitem)
|
|
pitem = lvGetItemByRow (plvdata, (int)wParam);
|
|
|
|
if (pitem)
|
|
return pitem->itemData;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
case LVM_SETITEMADDDATA:
|
|
{
|
|
PITEMDATA pitem = (PITEMDATA)wParam;
|
|
|
|
if (pitem) {
|
|
pitem->itemData = (DWORD)lParam;
|
|
return LV_OKAY;
|
|
}
|
|
else
|
|
return LV_ERR;
|
|
}
|
|
|
|
case LVM_SETSUBITEMCOLOR:
|
|
{
|
|
PLVSUBITEM p1;
|
|
PITEMDATA pitem;
|
|
|
|
p1 = (PLVSUBITEM) lParam;
|
|
pitem = (PITEMDATA) wParam;
|
|
|
|
if (!pitem)
|
|
pitem = lvGetItemByRow(plvdata, p1->nItem);
|
|
|
|
lvSetSubItemTextColor(pitem, p1->subItem, p1->nTextColor, plvdata);
|
|
scrollview_refresh_item (&plvdata->svdata, (HSVITEM)pitem->addData);
|
|
return 0;
|
|
}
|
|
|
|
case LVM_SETSUBITEMTEXT:
|
|
{
|
|
PLVSUBITEM p1;
|
|
HSVITEM hsvi;
|
|
PITEMDATA pitem;
|
|
|
|
p1 = (PLVSUBITEM) lParam;
|
|
pitem = (PITEMDATA) wParam;
|
|
|
|
if (!pitem)
|
|
pitem = lvGetItemByRow(plvdata, p1->nItem);
|
|
if (!pitem)
|
|
return LV_ERR;
|
|
if (lvFillSubItem(pitem, p1->subItem, p1->pszText, plvdata) < 0)
|
|
return LV_ERR;
|
|
|
|
hsvi = (HSVITEM)pitem->addData;
|
|
/*FIXME& TODO
|
|
* scrollview_refresh_item_rect
|
|
* */
|
|
scrollview_refresh_item (&plvdata->svdata, hsvi);
|
|
return LV_OKAY;
|
|
}
|
|
|
|
case LVM_SETSTRCMPFUNC:
|
|
if (lParam) {
|
|
plvdata->str_cmp = (STRCMP)lParam;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
|
|
case LVM_SETITEMHEIGHT:
|
|
{
|
|
PITEMDATA pi = (PITEMDATA)wParam;
|
|
int new_h = (int)lParam;
|
|
|
|
if (!pi)
|
|
return FALSE;
|
|
|
|
pi->itemh = new_h;
|
|
scrollview_set_item_height (hWnd, (HSVITEM)pi->addData, new_h);
|
|
return TRUE;
|
|
}
|
|
|
|
case LVM_SETHEADHEIGHT:
|
|
{
|
|
int height = (int)wParam;
|
|
RECT rc;
|
|
|
|
if (height < 0)
|
|
height = 0;
|
|
plvdata->nHeadHeight = height;
|
|
|
|
rc.left = LV_LEFTMARGIN;
|
|
rc.right = LV_RIGHTMARGIN;
|
|
rc.bottom = LV_BOTTOMMARGIN;
|
|
rc.top = plvdata->nHeadHeight + LV_TOPMARGIN;
|
|
scrolled_set_margins (plvscr, &rc);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
case LVM_COLSORT:
|
|
{
|
|
int nCols = (int)wParam;
|
|
|
|
if (GetWindowStyle(hWnd) & LVS_TREEVIEW)
|
|
return LV_ERR;
|
|
|
|
if (lvSortItem (NULL, nCols, LOSORTED, plvdata) == 0) {
|
|
return LV_OKAY;
|
|
}
|
|
return LV_ERR;
|
|
}
|
|
|
|
case LVM_SORTITEMS:
|
|
{
|
|
PFNLVCOMPARE pfn = (PFNLVCOMPARE)lParam;
|
|
|
|
if (GetWindowStyle(hWnd) & LVS_TREEVIEW)
|
|
return LV_ERR;
|
|
|
|
if (lvSortItem (pfn, 0, LOSORTED, plvdata) == 0) {
|
|
return LV_OKAY;
|
|
}
|
|
return LV_ERR;
|
|
}
|
|
|
|
case LVM_SETCUSTOMDRAW:
|
|
{
|
|
LVCUSTOMDRAWFUNCS *pnewFuncs = (LVCUSTOMDRAWFUNCS *)lParam;
|
|
if (pnewFuncs) {
|
|
plvdata->pfn_draw_hdr_bk = pnewFuncs->pfnDrawHdrBk;
|
|
plvdata->pfn_draw_hdr_item = pnewFuncs->pfnDrawHdrItem;
|
|
}
|
|
return 0;
|
|
}
|
|
case LVM_GETSELECTEDITEMRECT:
|
|
{
|
|
HSVITEM hsvi;
|
|
RECT *prt = (RECT*) lParam;
|
|
if(prt == NULL)
|
|
return FALSE;
|
|
hsvi = scrollview_get_hilighted_item(&plvdata->svdata);
|
|
if (!hsvi)
|
|
return FALSE;
|
|
return scrollview_get_item_rect(hWnd, (HITEM)hsvi, prt, TRUE);
|
|
/*{
|
|
prt->top += plvdata->nHeadHeight;
|
|
prt->bottom += plvdata->nHeadHeight;
|
|
return TRUE;
|
|
}*/
|
|
return FALSE;
|
|
}
|
|
|
|
} /* end switch */
|
|
|
|
return ScrollViewCtrlProc (hWnd, message, wParam, lParam);
|
|
}
|
|
|
|
|
|
BOOL RegisterListViewControl (void)
|
|
{
|
|
WNDCLASS WndClass;
|
|
|
|
WndClass.spClassName = CTRL_LISTVIEW;
|
|
WndClass.dwStyle = WS_NONE;
|
|
WndClass.dwExStyle = WS_EX_NONE;
|
|
WndClass.hCursor = GetSystemCursor (0);
|
|
#ifdef _MGSCHEMA_COMPOSITING
|
|
WndClass.dwBkColor = GetWindowElementAttr (HWND_NULL, WE_BGC_WINDOW);
|
|
#else
|
|
WndClass.iBkColor =
|
|
GetWindowElementPixelEx (HWND_NULL, HDC_SCREEN, WE_BGC_WINDOW);
|
|
#endif
|
|
WndClass.WinProc = ListViewCtrlProc;
|
|
|
|
return AddNewControlClass (&WndClass) == ERR_OK;
|
|
}
|
|
|
|
#endif /* _MGCTRL_LISTVIEW */
|