⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 treeview.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Treeview control
 *
 * Copyright 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de>
 * Copyright 1998,1999 Alex Priem <alexp@sci.kun.nl>
 * Copyright 1999 Sylvain St-Germain
 * Copyright 2002 CodeWeavers, Aric Stewart
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 * NOTES
 *
 * Note that TREEVIEW_INFO * and HTREEITEM are the same thing.
 *
 * Note2: All items always! have valid (allocated) pszText field.
 *      If item's text == LPSTR_TEXTCALLBACKA we allocate buffer
 *      of size TEXT_CALLBACK_SIZE in DoSetItem.
 *      We use callbackMask to keep track of fields to be updated.
 *
 * TODO:
 *   missing notifications: NM_SETCURSOR, TVN_GETINFOTIP, TVN_KEYDOWN,
 *      TVN_SETDISPINFO, TVN_SINGLEEXPAND
 *
 *   missing styles: TVS_FULLROWSELECT, TVS_INFOTIP, TVS_RTLREADING,
 *
 *   missing item styles: TVIS_CUT, TVIS_EXPANDPARTIAL
 *
 *   Make the insertion mark look right.
 *   Scroll (instead of repaint) as much as possible.
 */

#include "config.h"
#include "wine/port.h"

#include <assert.h>
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>

#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "commctrl.h"
#include "comctl32.h"
#include "uxtheme.h"
#include "tmschema.h"
#include "wine/unicode.h"
#include "wine/debug.h"

/* internal structures */

typedef struct _TREEITEM    /* HTREEITEM is a _TREEINFO *. */
{
  UINT      callbackMask;
  UINT      state;
  UINT      stateMask;
  LPWSTR    pszText;
  int       cchTextMax;
  int       iImage;
  int       iSelectedImage;
  int       cChildren;
  LPARAM    lParam;
  int       iIntegral;      /* item height multiplier (1 is normal) */
  int       iLevel;         /* indentation level:0=root level */
  HTREEITEM parent;         /* handle to parent or 0 if at root */
  HTREEITEM firstChild;     /* handle to first child or 0 if no child */
  HTREEITEM lastChild;
  HTREEITEM prevSibling;    /* handle to prev item in list, 0 if first */
  HTREEITEM nextSibling;    /* handle to next item in list, 0 if last */
  RECT      rect;
  LONG      linesOffset;
  LONG      stateOffset;
  LONG      imageOffset;
  LONG      textOffset;
  LONG      textWidth;      /* horizontal text extent for pszText */
  LONG      visibleOrder;   /* visible ordering, 0 is first visible item */
} TREEVIEW_ITEM;


typedef struct tagTREEVIEW_INFO
{
  HWND          hwnd;
  HWND          hwndNotify;     /* Owner window to send notifications to */
  DWORD         dwStyle;
  HTREEITEM     root;
  UINT          uInternalStatus;
  INT           Timer;
  UINT          uNumItems;      /* number of valid TREEVIEW_ITEMs */
  INT           cdmode;         /* last custom draw setting */
  UINT          uScrollTime;	/* max. time for scrolling in milliseconds */
  BOOL          bRedraw;        /* if FALSE we validate but don't redraw in TREEVIEW_Paint() */

  UINT          uItemHeight;    /* item height */
  BOOL          bHeightSet;

  LONG          clientWidth;    /* width of control window */
  LONG          clientHeight;   /* height of control window */

  LONG          treeWidth;      /* width of visible tree items */
  LONG          treeHeight;     /* height of visible tree items */

  UINT          uIndent;        /* indentation in pixels */
  HTREEITEM     selectedItem;   /* handle to selected item or 0 if none */
  HTREEITEM     hotItem;        /* handle currently under cursor, 0 if none */
  HTREEITEM	focusedItem;    /* item that was under the cursor when WM_LBUTTONDOWN was received */

  HTREEITEM     firstVisible;   /* handle to first visible item */
  LONG          maxVisibleOrder;
  HTREEITEM     dropItem;       /* handle to item selected by drag cursor */
  HTREEITEM     insertMarkItem; /* item after which insertion mark is placed */
  BOOL          insertBeforeorAfter; /* flag used by TVM_SETINSERTMARK */
  HIMAGELIST    dragList;       /* Bitmap of dragged item */
  LONG          scrollX;
  COLORREF      clrBk;
  COLORREF      clrText;
  COLORREF      clrLine;
  COLORREF      clrInsertMark;
  HFONT         hFont;
  HFONT         hDefaultFont;
  HFONT         hBoldFont;
  HFONT         hUnderlineFont;
  HCURSOR       hcurHand;
  HWND          hwndToolTip;

  HWND          hwndEdit;
  WNDPROC       wpEditOrig;     /* orig window proc for subclassing edit */
  BOOL          bIgnoreEditKillFocus;
  BOOL          bLabelChanged;

  BOOL          bNtfUnicode;    /* TRUE if should send NOTIFY with W */
  HIMAGELIST    himlNormal;
  int           normalImageHeight;
  int           normalImageWidth;
  HIMAGELIST    himlState;
  int           stateImageHeight;
  int           stateImageWidth;
  HDPA          items;

  DWORD lastKeyPressTimestamp; /* Added */
  WPARAM charCode; /* Added */
  INT nSearchParamLength; /* Added */
  WCHAR szSearchParam[ MAX_PATH ]; /* Added */
} TREEVIEW_INFO;


/******** Defines that TREEVIEW_ProcessLetterKeys uses ****************/
#define KEY_DELAY       450

/* bitflags for infoPtr->uInternalStatus */

#define TV_HSCROLL 	0x01    /* treeview too large to fit in window */
#define TV_VSCROLL 	0x02	/* (horizontal/vertical) */
#define TV_LDRAG		0x04	/* Lbutton pushed to start drag */
#define TV_LDRAGGING	0x08	/* Lbutton pushed, mouse moved. */
#define TV_RDRAG		0x10	/* dito Rbutton */
#define TV_RDRAGGING	0x20

/* bitflags for infoPtr->timer */

#define TV_EDIT_TIMER    2
#define TV_EDIT_TIMER_SET 2


VOID TREEVIEW_Register (VOID);
VOID TREEVIEW_Unregister (VOID);


WINE_DEFAULT_DEBUG_CHANNEL(treeview);


#define TEXT_CALLBACK_SIZE 260

#define TREEVIEW_LEFT_MARGIN 8

#define MINIMUM_INDENT 19

#define CALLBACK_MASK_ALL (TVIF_TEXT|TVIF_CHILDREN|TVIF_IMAGE|TVIF_SELECTEDIMAGE)

#define STATEIMAGEINDEX(x) (((x) >> 12) & 0x0f)
#define OVERLAYIMAGEINDEX(x) (((x) >> 8) & 0x0f)
#define ISVISIBLE(x)         ((x)->visibleOrder >= 0)


static const WCHAR themeClass[] = { 'T','r','e','e','v','i','e','w',0 };


typedef VOID (*TREEVIEW_ItemEnumFunc)(TREEVIEW_INFO *, TREEVIEW_ITEM *,LPVOID);


static VOID TREEVIEW_Invalidate(TREEVIEW_INFO *, TREEVIEW_ITEM *);

static LRESULT TREEVIEW_DoSelectItem(TREEVIEW_INFO *, INT, HTREEITEM, INT);
static VOID TREEVIEW_SetFirstVisible(TREEVIEW_INFO *, TREEVIEW_ITEM *, BOOL);
static LRESULT TREEVIEW_EnsureVisible(TREEVIEW_INFO *, HTREEITEM, BOOL);
static LRESULT TREEVIEW_RButtonUp(TREEVIEW_INFO *, LPPOINT);
static LRESULT TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel);
static VOID TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr);
static LRESULT TREEVIEW_HScroll(TREEVIEW_INFO *, WPARAM);
static INT TREEVIEW_NotifyFormat (TREEVIEW_INFO *infoPtr, HWND wParam, UINT lParam);


/* Random Utilities *****************************************************/

#ifndef NDEBUG
static inline void
TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr)
{
    (void)infoPtr;
}
#else
/* The definition is at the end of the file. */
static void TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr);
#endif

/* Returns the treeview private data if hwnd is a treeview.
 * Otherwise returns an undefined value. */
static TREEVIEW_INFO *
TREEVIEW_GetInfoPtr(HWND hwnd)
{
    return (TREEVIEW_INFO *)GetWindowLongPtrW(hwnd, 0);
}

/* Don't call this. Nothing wants an item index. */
static inline int
TREEVIEW_GetItemIndex(TREEVIEW_INFO *infoPtr, HTREEITEM handle)
{
    assert(infoPtr != NULL);

    return DPA_GetPtrIndex(infoPtr->items, handle);
}

/* Checks if item has changed and needs to be redrawn */
static inline BOOL item_changed (TREEVIEW_ITEM *tiOld, TREEVIEW_ITEM *tiNew, LPTVITEMEXW tvChange)
{
    /* Number of children has changed */
    if ((tvChange->mask & TVIF_CHILDREN) && (tiOld->cChildren != tiNew->cChildren))
	return TRUE;

    /* Image has changed and it's not a callback */
    if ((tvChange->mask & TVIF_IMAGE) && (tiOld->iImage != tiNew->iImage) &&
	tiNew->iImage != I_IMAGECALLBACK)
	return TRUE;

    /* Selected image has changed and it's not a callback */
    if ((tvChange->mask & TVIF_SELECTEDIMAGE) && (tiOld->iSelectedImage != tiNew->iSelectedImage) &&
	tiNew->iSelectedImage != I_IMAGECALLBACK)
	return TRUE;

    /* Text has changed and it's not a callback */
    if ((tvChange->mask & TVIF_TEXT) && (tiOld->pszText != tiNew->pszText) &&
	tiNew->pszText != LPSTR_TEXTCALLBACKW)
	return TRUE;

    /* Indent has changed */
    if ((tvChange->mask & TVIF_INTEGRAL) && (tiOld->iIntegral != tiNew->iIntegral))
	return TRUE;

    /* Item state has changed */
    if ((tvChange->mask & TVIF_STATE) && ((tiOld->state ^ tiNew->state) & tvChange->stateMask ))
	return TRUE;

    return FALSE;
}

/***************************************************************************
 * This method checks that handle is an item for this tree.
 */
static BOOL
TREEVIEW_ValidItem(TREEVIEW_INFO *infoPtr, HTREEITEM handle)
{
    if (TREEVIEW_GetItemIndex(infoPtr, handle) == -1)
    {
	TRACE("invalid item %p\n", handle);
	return FALSE;
    }
    else
	return TRUE;
}

static HFONT
TREEVIEW_CreateBoldFont(HFONT hOrigFont)
{
    LOGFONTW font;

    GetObjectW(hOrigFont, sizeof(font), &font);
    font.lfWeight = FW_BOLD;
    return CreateFontIndirectW(&font);
}

static HFONT
TREEVIEW_CreateUnderlineFont(HFONT hOrigFont)
{
    LOGFONTW font;

    GetObjectW(hOrigFont, sizeof(font), &font);
    font.lfUnderline = TRUE;
    return CreateFontIndirectW(&font);
}

static inline HFONT
TREEVIEW_FontForItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
{
    if ((infoPtr->dwStyle & TVS_TRACKSELECT) && (item == infoPtr->hotItem))
        return infoPtr->hUnderlineFont;
    if (item->state & TVIS_BOLD)
        return infoPtr->hBoldFont;
    return infoPtr->hFont;
}

/* for trace/debugging purposes only */
static const char *
TREEVIEW_ItemName(TREEVIEW_ITEM *item)
{
    if (item == NULL) return "<null item>";
    if (item->pszText == LPSTR_TEXTCALLBACKW) return "<callback>";
    if (item->pszText == NULL) return "<null>";
    return debugstr_w(item->pszText);
}

/* An item is not a child of itself. */
static BOOL
TREEVIEW_IsChildOf(TREEVIEW_ITEM *parent, TREEVIEW_ITEM *child)
{
    do
    {
	child = child->parent;
	if (child == parent) return TRUE;
    } while (child != NULL);

    return FALSE;
}


/* Tree Traversal *******************************************************/

/***************************************************************************
 * This method returns the last expanded sibling or child child item
 * of a tree node
 */
static TREEVIEW_ITEM *
TREEVIEW_GetLastListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem)
{
    if (!wineItem)
       return NULL;

    while (wineItem->lastChild)
    {
       if (wineItem->state & TVIS_EXPANDED)
          wineItem = wineItem->lastChild;
       else
          break;
    }

    if (wineItem == infoPtr->root)
        return NULL;

    return wineItem;
}

/***************************************************************************
 * This method returns the previous non-hidden item in the list not
 * considering the tree hierarchy.
 */
static TREEVIEW_ITEM *
TREEVIEW_GetPrevListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *tvItem)
{
    if (tvItem->prevSibling)
    {
	/* This item has a prevSibling, get the last item in the sibling's tree. */
	TREEVIEW_ITEM *upItem = tvItem->prevSibling;

	if ((upItem->state & TVIS_EXPANDED) && upItem->lastChild != NULL)
	    return TREEVIEW_GetLastListItem(infoPtr, upItem->lastChild);
	else
	    return upItem;
    }
    else
    {
	/* this item does not have a prevSibling, get the parent */
	return (tvItem->parent != infoPtr->root) ? tvItem->parent : NULL;
    }
}


/***************************************************************************
 * This method returns the next physical item in the treeview not
 * considering the tree hierarchy.
 */
static TREEVIEW_ITEM *
TREEVIEW_GetNextListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *tvItem)
{
    assert(tvItem != NULL);

    /*
     * If this item has children and is expanded, return the first child
     */
    if ((tvItem->state & TVIS_EXPANDED) && tvItem->firstChild != NULL)
    {
	return tvItem->firstChild;
    }


    /*
     * try to get the sibling
     */
    if (tvItem->nextSibling)
	return tvItem->nextSibling;

    /*
     * Otherwise, get the parent's sibling.
     */
    while (tvItem->parent)
    {
	tvItem = tvItem->parent;

	if (tvItem->nextSibling)
	    return tvItem->nextSibling;
    }

    return NULL;
}

/***************************************************************************
 * This method returns the nth item starting at the given item.  It returns
 * the last item (or first) we we run out of items.
 *
 * Will scroll backward if count is <0.
 *             forward if count is >0.
 */
static TREEVIEW_ITEM *
TREEVIEW_GetListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
		     LONG count)
{
    TREEVIEW_ITEM *(*next_item)(TREEVIEW_INFO *, TREEVIEW_ITEM *);
    TREEVIEW_ITEM *previousItem;

    assert(wineItem != NULL);

    if (count > 0)
    {
	next_item = TREEVIEW_GetNextListItem;
    }
    else if (count < 0)
    {
	count = -count;
	next_item = TREEVIEW_GetPrevListItem;
    }
    else
	return wineItem;

    do
    {
	previousItem = wineItem;
	wineItem = next_item(infoPtr, wineItem);

    } while (--count && wineItem != NULL);


    return wineItem ? wineItem : previousItem;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -