📄 treeview.c
字号:
while (kill != NULL)
{
TREEVIEW_ITEM *next = kill->nextSibling;
TREEVIEW_RemoveItem(infoPtr, kill);
kill = next;
}
assert(parentItem->cChildren <= 0); /* I_CHILDRENCALLBACK or 0 */
assert(parentItem->firstChild == NULL);
assert(parentItem->lastChild == NULL);
}
static void
TREEVIEW_UnlinkItem(TREEVIEW_ITEM *item)
{
TREEVIEW_ITEM *parentItem = item->parent;
assert(item != NULL);
assert(item->parent != NULL); /* i.e. it must not be the root */
if (parentItem->firstChild == item)
parentItem->firstChild = item->nextSibling;
if (parentItem->lastChild == item)
parentItem->lastChild = item->prevSibling;
if (parentItem->firstChild == NULL && parentItem->lastChild == NULL
&& parentItem->cChildren > 0)
parentItem->cChildren = 0;
if (item->prevSibling)
item->prevSibling->nextSibling = item->nextSibling;
if (item->nextSibling)
item->nextSibling->prevSibling = item->prevSibling;
}
static void
TREEVIEW_RemoveItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem)
{
TRACE("%p, (%s)\n", wineItem, TREEVIEW_ItemName(wineItem));
TREEVIEW_SendTreeviewNotify(infoPtr, TVN_DELETEITEMW, TVC_UNKNOWN,
TVIF_HANDLE | TVIF_PARAM, wineItem, 0);
if (wineItem->firstChild)
TREEVIEW_RemoveAllChildren(infoPtr, wineItem);
TREEVIEW_UnlinkItem(wineItem);
infoPtr->uNumItems--;
if (wineItem->pszText && wineItem->pszText != LPSTR_TEXTCALLBACKW)
Free(wineItem->pszText);
TREEVIEW_FreeItem(infoPtr, wineItem);
}
/* Empty out the tree. */
static void
TREEVIEW_RemoveTree(TREEVIEW_INFO *infoPtr)
{
TREEVIEW_RemoveAllChildren(infoPtr, infoPtr->root);
assert(infoPtr->uNumItems == 0); /* root isn't counted in uNumItems */
}
static LRESULT
TREEVIEW_DeleteItem(TREEVIEW_INFO *infoPtr, HTREEITEM wineItem)
{
TREEVIEW_ITEM *newSelection = NULL;
TREEVIEW_ITEM *newFirstVisible = NULL;
TREEVIEW_ITEM *parent, *prev = NULL;
BOOL visible = FALSE;
if (wineItem == TVI_ROOT)
{
TRACE("TVI_ROOT\n");
parent = infoPtr->root;
newSelection = NULL;
visible = TRUE;
TREEVIEW_RemoveTree(infoPtr);
}
else
{
if (!TREEVIEW_ValidItem(infoPtr, wineItem))
return FALSE;
TRACE("%p (%s)\n", wineItem, TREEVIEW_ItemName(wineItem));
parent = wineItem->parent;
if (ISVISIBLE(wineItem))
{
prev = TREEVIEW_GetPrevListItem(infoPtr, wineItem);
visible = TRUE;
}
if (infoPtr->selectedItem != NULL
&& (wineItem == infoPtr->selectedItem
|| TREEVIEW_IsChildOf(wineItem, infoPtr->selectedItem)))
{
if (wineItem->nextSibling)
newSelection = wineItem->nextSibling;
else if (wineItem->parent != infoPtr->root)
newSelection = wineItem->parent;
else
newSelection = wineItem->prevSibling;
TRACE("newSelection = %p\n", newSelection);
}
if (infoPtr->firstVisible == wineItem)
{
if (wineItem->nextSibling)
newFirstVisible = wineItem->nextSibling;
else if (wineItem->prevSibling)
newFirstVisible = wineItem->prevSibling;
else if (wineItem->parent != infoPtr->root)
newFirstVisible = wineItem->parent;
TREEVIEW_SetFirstVisible(infoPtr, NULL, TRUE);
}
else
newFirstVisible = infoPtr->firstVisible;
TREEVIEW_RemoveItem(infoPtr, wineItem);
}
/* Don't change if somebody else already has (infoPtr->selectedItem is cleared by FreeItem). */
if (!infoPtr->selectedItem && newSelection)
{
if (TREEVIEW_ValidItem(infoPtr, newSelection))
TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, newSelection, TVC_UNKNOWN);
}
/* Validate insertMark dropItem.
* hotItem ??? - used for comparison only.
*/
if (!TREEVIEW_ValidItem(infoPtr, infoPtr->insertMarkItem))
infoPtr->insertMarkItem = 0;
if (!TREEVIEW_ValidItem(infoPtr, infoPtr->dropItem))
infoPtr->dropItem = 0;
if (!TREEVIEW_ValidItem(infoPtr, newFirstVisible))
newFirstVisible = infoPtr->root->firstChild;
TREEVIEW_VerifyTree(infoPtr);
if (visible)
{
TREEVIEW_SetFirstVisible(infoPtr, newFirstVisible, TRUE);
TREEVIEW_RecalculateVisibleOrder(infoPtr, prev);
TREEVIEW_UpdateScrollBars(infoPtr);
TREEVIEW_Invalidate(infoPtr, NULL);
}
else if (ISVISIBLE(parent) && !TREEVIEW_HasChildren(infoPtr, parent))
{
/* parent lost '+/-' - update it */
TREEVIEW_Invalidate(infoPtr, parent);
}
return TRUE;
}
/* Get/Set Messages *********************************************************/
static LRESULT
TREEVIEW_SetRedraw(TREEVIEW_INFO* infoPtr, WPARAM wParam, LPARAM lParam)
{
if(wParam)
infoPtr->bRedraw = TRUE;
else
infoPtr->bRedraw = FALSE;
return 0;
}
static LRESULT
TREEVIEW_GetIndent(TREEVIEW_INFO *infoPtr)
{
TRACE("\n");
return infoPtr->uIndent;
}
static LRESULT
TREEVIEW_SetIndent(TREEVIEW_INFO *infoPtr, UINT newIndent)
{
TRACE("\n");
if (newIndent < MINIMUM_INDENT)
newIndent = MINIMUM_INDENT;
if (infoPtr->uIndent != newIndent)
{
infoPtr->uIndent = newIndent;
TREEVIEW_UpdateSubTree(infoPtr, infoPtr->root);
TREEVIEW_UpdateScrollBars(infoPtr);
TREEVIEW_Invalidate(infoPtr, NULL);
}
return 0;
}
static LRESULT
TREEVIEW_GetToolTips(TREEVIEW_INFO *infoPtr)
{
TRACE("\n");
return (LRESULT)infoPtr->hwndToolTip;
}
static LRESULT
TREEVIEW_SetToolTips(TREEVIEW_INFO *infoPtr, HWND hwndTT)
{
HWND prevToolTip;
TRACE("\n");
prevToolTip = infoPtr->hwndToolTip;
infoPtr->hwndToolTip = hwndTT;
return (LRESULT)prevToolTip;
}
static LRESULT
TREEVIEW_SetUnicodeFormat(TREEVIEW_INFO *infoPtr, BOOL fUnicode)
{
BOOL rc = infoPtr->bNtfUnicode;
infoPtr->bNtfUnicode = fUnicode;
return rc;
}
static LRESULT
TREEVIEW_GetUnicodeFormat(TREEVIEW_INFO *infoPtr)
{
return infoPtr->bNtfUnicode;
}
static LRESULT
TREEVIEW_GetScrollTime(TREEVIEW_INFO *infoPtr)
{
return infoPtr->uScrollTime;
}
static LRESULT
TREEVIEW_SetScrollTime(TREEVIEW_INFO *infoPtr, UINT uScrollTime)
{
UINT uOldScrollTime = infoPtr->uScrollTime;
infoPtr->uScrollTime = min(uScrollTime, 100);
return uOldScrollTime;
}
static LRESULT
TREEVIEW_GetImageList(TREEVIEW_INFO *infoPtr, WPARAM wParam)
{
TRACE("\n");
switch (wParam)
{
case (WPARAM)TVSIL_NORMAL:
return (LRESULT)infoPtr->himlNormal;
case (WPARAM)TVSIL_STATE:
return (LRESULT)infoPtr->himlState;
default:
return 0;
}
}
#define TVHEIGHT_MIN 16
#define TVHEIGHT_FONT_ADJUST 3 /* 2 for focus border + 1 for margin some apps assume */
/* Compute the natural height for items. */
static UINT
TREEVIEW_NaturalHeight(TREEVIEW_INFO *infoPtr)
{
TEXTMETRICW tm;
HDC hdc = GetDC(0);
HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
UINT height;
/* Height is the maximum of:
* 16 (a hack because our fonts are tiny), and
* The text height + border & margin, and
* The size of the normal image list
*/
GetTextMetricsW(hdc, &tm);
SelectObject(hdc, hOldFont);
ReleaseDC(0, hdc);
height = TVHEIGHT_MIN;
if (height < tm.tmHeight + tm.tmExternalLeading + TVHEIGHT_FONT_ADJUST)
height = tm.tmHeight + tm.tmExternalLeading + TVHEIGHT_FONT_ADJUST;
if (height < infoPtr->normalImageHeight)
height = infoPtr->normalImageHeight;
return height;
}
static LRESULT
TREEVIEW_SetImageList(TREEVIEW_INFO *infoPtr, WPARAM wParam, HIMAGELIST himlNew)
{
HIMAGELIST himlOld = 0;
int oldWidth = infoPtr->normalImageWidth;
int oldHeight = infoPtr->normalImageHeight;
TRACE("%x,%p\n", wParam, himlNew);
switch (wParam)
{
case (WPARAM)TVSIL_NORMAL:
himlOld = infoPtr->himlNormal;
infoPtr->himlNormal = himlNew;
if (himlNew != NULL)
ImageList_GetIconSize(himlNew, &infoPtr->normalImageWidth,
&infoPtr->normalImageHeight);
else
{
infoPtr->normalImageWidth = 0;
infoPtr->normalImageHeight = 0;
}
break;
case (WPARAM)TVSIL_STATE:
himlOld = infoPtr->himlState;
infoPtr->himlState = himlNew;
if (himlNew != NULL)
ImageList_GetIconSize(himlNew, &infoPtr->stateImageWidth,
&infoPtr->stateImageHeight);
else
{
infoPtr->stateImageWidth = 0;
infoPtr->stateImageHeight = 0;
}
break;
}
if (oldWidth != infoPtr->normalImageWidth ||
oldHeight != infoPtr->normalImageHeight)
{
BOOL bRecalcVisible = FALSE;
if (oldHeight != infoPtr->normalImageHeight &&
!infoPtr->bHeightSet)
{
infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr);
bRecalcVisible = TRUE;
}
if (infoPtr->normalImageWidth > MINIMUM_INDENT &&
infoPtr->normalImageWidth != infoPtr->uIndent)
{
infoPtr->uIndent = infoPtr->normalImageWidth;
bRecalcVisible = TRUE;
}
if (bRecalcVisible)
TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL);
TREEVIEW_UpdateSubTree(infoPtr, infoPtr->root);
TREEVIEW_UpdateScrollBars(infoPtr);
}
TREEVIEW_Invalidate(infoPtr, NULL);
return (LRESULT)himlOld;
}
static LRESULT
TREEVIEW_SetItemHeight(TREEVIEW_INFO *infoPtr, INT newHeight)
{
INT prevHeight = infoPtr->uItemHeight;
TRACE("%d\n", newHeight);
if (newHeight == -1)
{
infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr);
infoPtr->bHeightSet = FALSE;
}
else
{
infoPtr->uItemHeight = newHeight;
infoPtr->bHeightSet = TRUE;
}
/* Round down, unless we support odd ("non even") heights. */
if (!(infoPtr->dwStyle) & TVS_NONEVENHEIGHT)
infoPtr->uItemHeight &= ~1;
if (infoPtr->uItemHeight != prevHeight)
{
TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL);
TREEVIEW_UpdateScrollBars(infoPtr);
TREEVIEW_Invalidate(infoPtr, NULL);
}
return prevHeight;
}
static LRESULT
TREEVIEW_GetItemHeight(TREEVIEW_INFO *infoPtr)
{
TRACE("\n");
return infoPtr->uItemHeight;
}
static LRESULT
TREEVIEW_GetFont(TREEVIEW_INFO *infoPtr)
{
TRACE("%p\n", infoPtr->hFont);
return (LRESULT)infoPtr->hFont;
}
static INT CALLBACK
TREEVIEW_ResetTextWidth(LPVOID pItem, LPVOID unused)
{
(void)unused;
((TREEVIEW_ITEM *)pItem)->textWidth = 0;
return 1;
}
static LRESULT
TREEVIEW_SetFont(TREEVIEW_INFO *infoPtr, HFONT hFont, BOOL bRedraw)
{
UINT uHeight = infoPtr->uItemHeight;
TRACE("%p %i\n", hFont, bRedraw);
infoPtr->hFont = hFont ? hFont : infoPtr->hDefaultFont;
DeleteObject(infoPtr->hBoldFont);
infoPtr->hBoldFont = TREEVIEW_CreateBoldFont(infoPtr->hFont);
infoPtr->hUnderlineFont = TREEVIEW_CreateUnderlineFont(infoPtr->hFont);
if (!infoPtr->bHeightSet)
infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr);
if (uHeight != infoPtr->uItemHeight)
TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL);
DPA_EnumCallback(infoPtr->items, TREEVIEW_ResetTextWidth, 0);
TREEVIEW_UpdateSubTree(infoPtr, infoPtr->root);
TREEVIEW_UpdateScrollBars(infoPtr);
if (bRedraw)
TREEVIEW_Invalidate(infoPtr, NULL);
return 0;
}
static LRESULT
TREEVIEW_GetLineColor(TREEVIEW_INFO *infoPtr)
{
TRACE("\n");
return (LRESULT)infoPtr->clrLine;
}
static LRESULT
TREEVIEW_SetLineColor(TREEVIEW_INFO *infoPtr, COLORREF color)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -