📄 treeview.c
字号:
COLORREF prevColor = infoPtr->clrLine;
TRACE("\n");
infoPtr->clrLine = color;
return (LRESULT)prevColor;
}
static LRESULT
TREEVIEW_GetTextColor(TREEVIEW_INFO *infoPtr)
{
TRACE("\n");
return (LRESULT)infoPtr->clrText;
}
static LRESULT
TREEVIEW_SetTextColor(TREEVIEW_INFO *infoPtr, COLORREF color)
{
COLORREF prevColor = infoPtr->clrText;
TRACE("\n");
infoPtr->clrText = color;
if (infoPtr->clrText != prevColor)
TREEVIEW_Invalidate(infoPtr, NULL);
return (LRESULT)prevColor;
}
static LRESULT
TREEVIEW_GetBkColor(TREEVIEW_INFO *infoPtr)
{
TRACE("\n");
return (LRESULT)infoPtr->clrBk;
}
static LRESULT
TREEVIEW_SetBkColor(TREEVIEW_INFO *infoPtr, COLORREF newColor)
{
COLORREF prevColor = infoPtr->clrBk;
TRACE("\n");
infoPtr->clrBk = newColor;
if (newColor != prevColor)
TREEVIEW_Invalidate(infoPtr, NULL);
return (LRESULT)prevColor;
}
static LRESULT
TREEVIEW_GetInsertMarkColor(TREEVIEW_INFO *infoPtr)
{
TRACE("\n");
return (LRESULT)infoPtr->clrInsertMark;
}
static LRESULT
TREEVIEW_SetInsertMarkColor(TREEVIEW_INFO *infoPtr, COLORREF color)
{
COLORREF prevColor = infoPtr->clrInsertMark;
TRACE("%x\n", color);
infoPtr->clrInsertMark = color;
return (LRESULT)prevColor;
}
static LRESULT
TREEVIEW_SetInsertMark(TREEVIEW_INFO *infoPtr, BOOL wParam, HTREEITEM item)
{
TRACE("%d %p\n", wParam, item);
if (!TREEVIEW_ValidItem(infoPtr, item))
return 0;
infoPtr->insertBeforeorAfter = wParam;
infoPtr->insertMarkItem = item;
TREEVIEW_Invalidate(infoPtr, NULL);
return 1;
}
/************************************************************************
* Some serious braindamage here. lParam is a pointer to both the
* input HTREEITEM and the output RECT.
*/
static LRESULT
TREEVIEW_GetItemRect(TREEVIEW_INFO *infoPtr, BOOL fTextRect, LPRECT lpRect)
{
TREEVIEW_ITEM *wineItem;
const HTREEITEM *pItem = (HTREEITEM *)lpRect;
TRACE("\n");
/*
* validate parameters
*/
if (pItem == NULL)
return FALSE;
wineItem = *pItem;
if (!TREEVIEW_ValidItem(infoPtr, wineItem) || !ISVISIBLE(wineItem))
return FALSE;
/*
* If wParam is TRUE return the text size otherwise return
* the whole item size
*/
if (fTextRect)
{
/* Windows does not send TVN_GETDISPINFO here. */
lpRect->top = wineItem->rect.top;
lpRect->bottom = wineItem->rect.bottom;
lpRect->left = wineItem->textOffset;
lpRect->right = wineItem->textOffset + wineItem->textWidth;
}
else
{
*lpRect = wineItem->rect;
}
TRACE("%s [L:%d R:%d T:%d B:%d]\n", fTextRect ? "text" : "item",
lpRect->left, lpRect->right, lpRect->top, lpRect->bottom);
return TRUE;
}
static inline LRESULT
TREEVIEW_GetVisibleCount(TREEVIEW_INFO *infoPtr)
{
/* Suprise! This does not take integral height into account. */
return infoPtr->clientHeight / infoPtr->uItemHeight;
}
static LRESULT
TREEVIEW_GetItemT(TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW)
{
TREEVIEW_ITEM *wineItem;
wineItem = tvItem->hItem;
if (!TREEVIEW_ValidItem(infoPtr, wineItem))
return FALSE;
TREEVIEW_UpdateDispInfo(infoPtr, wineItem, tvItem->mask);
if (tvItem->mask & TVIF_CHILDREN)
{
if (wineItem->cChildren==I_CHILDRENCALLBACK)
FIXME("I_CHILDRENCALLBACK not supported\n");
tvItem->cChildren = wineItem->cChildren;
}
if (tvItem->mask & TVIF_HANDLE)
tvItem->hItem = wineItem;
if (tvItem->mask & TVIF_IMAGE)
tvItem->iImage = wineItem->iImage;
if (tvItem->mask & TVIF_INTEGRAL)
tvItem->iIntegral = wineItem->iIntegral;
/* undocumented: windows ignores TVIF_PARAM and
* * always sets lParam
*/
tvItem->lParam = wineItem->lParam;
if (tvItem->mask & TVIF_SELECTEDIMAGE)
tvItem->iSelectedImage = wineItem->iSelectedImage;
if (tvItem->mask & TVIF_STATE)
/* Careful here - Windows ignores the stateMask when you get the state
That contradicts the documentation, but makes more common sense, masking
retrieval in this way seems overkill */
tvItem->state = wineItem->state;
if (tvItem->mask & TVIF_TEXT)
{
if (isW)
{
if (wineItem->pszText == LPSTR_TEXTCALLBACKW)
{
tvItem->pszText = LPSTR_TEXTCALLBACKW;
FIXME(" GetItem called with LPSTR_TEXTCALLBACK\n");
}
else
{
lstrcpynW(tvItem->pszText, wineItem->pszText, tvItem->cchTextMax);
}
}
else
{
if (wineItem->pszText == LPSTR_TEXTCALLBACKW)
{
tvItem->pszText = (LPWSTR)LPSTR_TEXTCALLBACKA;
FIXME(" GetItem called with LPSTR_TEXTCALLBACK\n");
}
else
{
WideCharToMultiByte(CP_ACP, 0, wineItem->pszText, -1,
(LPSTR)tvItem->pszText, tvItem->cchTextMax, NULL, NULL);
}
}
}
TRACE("item <%p>, txt %p, img %p, mask %x\n",
wineItem, tvItem->pszText, &tvItem->iImage, tvItem->mask);
return TRUE;
}
/* Beware MSDN Library Visual Studio 6.0. It says -1 on failure, 0 on success,
* which is wrong. */
static LRESULT
TREEVIEW_SetItemT(TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW)
{
TREEVIEW_ITEM *wineItem;
TREEVIEW_ITEM originalItem;
wineItem = tvItem->hItem;
TRACE("item %d,mask %x\n", TREEVIEW_GetItemIndex(infoPtr, wineItem),
tvItem->mask);
if (!TREEVIEW_ValidItem(infoPtr, wineItem))
return FALSE;
/* store the orignal item values */
originalItem = *wineItem;
if (!TREEVIEW_DoSetItemT(infoPtr, wineItem, tvItem, isW))
return FALSE;
/* If the text or TVIS_BOLD was changed, and it is visible, recalculate. */
if ((tvItem->mask & TVIF_TEXT
|| (tvItem->mask & TVIF_STATE && tvItem->stateMask & TVIS_BOLD))
&& ISVISIBLE(wineItem))
{
TREEVIEW_UpdateDispInfo(infoPtr, wineItem, TVIF_TEXT);
TREEVIEW_ComputeTextWidth(infoPtr, wineItem, 0);
}
if (tvItem->mask != 0 && ISVISIBLE(wineItem))
{
/* The refresh updates everything, but we can't wait until then. */
TREEVIEW_ComputeItemInternalMetrics(infoPtr, wineItem);
/* if any of the item's values changed and it's not a callback, redraw the item */
if (item_changed(&originalItem, wineItem, tvItem))
{
if (tvItem->mask & TVIF_INTEGRAL)
{
TREEVIEW_RecalculateVisibleOrder(infoPtr, wineItem);
TREEVIEW_UpdateScrollBars(infoPtr);
TREEVIEW_Invalidate(infoPtr, NULL);
}
else
{
TREEVIEW_UpdateScrollBars(infoPtr);
TREEVIEW_Invalidate(infoPtr, wineItem);
}
}
}
return TRUE;
}
static LRESULT
TREEVIEW_GetItemState(TREEVIEW_INFO *infoPtr, HTREEITEM wineItem, UINT mask)
{
TRACE("\n");
if (!wineItem || !TREEVIEW_ValidItem(infoPtr, wineItem))
return 0;
return (wineItem->state & mask);
}
static LRESULT
TREEVIEW_GetNextItem(TREEVIEW_INFO *infoPtr, UINT which, HTREEITEM wineItem)
{
TREEVIEW_ITEM *retval;
retval = 0;
/* handle all the global data here */
switch (which)
{
case TVGN_CHILD: /* Special case: child of 0 is root */
if (wineItem)
break;
/* fall through */
case TVGN_ROOT:
retval = infoPtr->root->firstChild;
break;
case TVGN_CARET:
retval = infoPtr->selectedItem;
break;
case TVGN_FIRSTVISIBLE:
retval = infoPtr->firstVisible;
break;
case TVGN_DROPHILITE:
retval = infoPtr->dropItem;
break;
case TVGN_LASTVISIBLE:
retval = TREEVIEW_GetLastListItem(infoPtr, infoPtr->root);
break;
}
if (retval)
{
TRACE("flags:%x, returns %p\n", which, retval);
return (LRESULT)retval;
}
if (wineItem == TVI_ROOT) wineItem = infoPtr->root;
if (!TREEVIEW_ValidItem(infoPtr, wineItem))
return FALSE;
switch (which)
{
case TVGN_NEXT:
retval = wineItem->nextSibling;
break;
case TVGN_PREVIOUS:
retval = wineItem->prevSibling;
break;
case TVGN_PARENT:
retval = (wineItem->parent != infoPtr->root) ? wineItem->parent : NULL;
break;
case TVGN_CHILD:
retval = wineItem->firstChild;
break;
case TVGN_NEXTVISIBLE:
retval = TREEVIEW_GetNextListItem(infoPtr, wineItem);
break;
case TVGN_PREVIOUSVISIBLE:
retval = TREEVIEW_GetPrevListItem(infoPtr, wineItem);
break;
default:
TRACE("Unknown msg %x,item %p\n", which, wineItem);
break;
}
TRACE("flags:%x, item %p;returns %p\n", which, wineItem, retval);
return (LRESULT)retval;
}
static LRESULT
TREEVIEW_GetCount(TREEVIEW_INFO *infoPtr)
{
TRACE(" %d\n", infoPtr->uNumItems);
return (LRESULT)infoPtr->uNumItems;
}
static VOID
TREEVIEW_ToggleItemState(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
{
if (infoPtr->dwStyle & TVS_CHECKBOXES)
{
static const unsigned int state_table[] = { 0, 2, 1 };
unsigned int state;
state = STATEIMAGEINDEX(item->state);
TRACE("state:%x\n", state);
item->state &= ~TVIS_STATEIMAGEMASK;
if (state < 3)
state = state_table[state];
item->state |= INDEXTOSTATEIMAGEMASK(state);
TRACE("state:%x\n", state);
TREEVIEW_Invalidate(infoPtr, item);
}
}
/* Painting *************************************************************/
/* Draw the lines and expand button for an item. Also draws one section
* of the line from item's parent to item's parent's next sibling. */
static void
TREEVIEW_DrawItemLines(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *item)
{
LONG centerx, centery;
BOOL lar = ((infoPtr->dwStyle
& (TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS))
> TVS_LINESATROOT);
HBRUSH hbr, hbrOld;
if (!lar && item->iLevel == 0)
return;
hbr = CreateSolidBrush(infoPtr->clrBk);
hbrOld = SelectObject(hdc, hbr);
centerx = (item->linesOffset + item->stateOffset) / 2;
centery = (item->rect.top + item->rect.bottom) / 2;
if (infoPtr->dwStyle & TVS_HASLINES)
{
HPEN hOldPen, hNewPen;
HTREEITEM parent;
LOGBRUSH lb;
/*
* Get a dotted grey pen
*/
lb.lbStyle = BS_SOLID;
lb.lbColor = infoPtr->clrLine;
hNewPen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, NULL);
hOldPen = SelectObject(hdc, hNewPen);
MoveToEx(hdc, item->stateOffset, centery, NULL);
LineTo(hdc, centerx - 1, centery);
if (item->prevSibling || item->parent != infoPtr->root)
{
MoveToEx(hdc, centerx, item->rect.top, NULL);
LineTo(hdc, centerx, centery);
}
if (item->nextSibling)
{
MoveToEx(hdc, centerx, centery, NULL);
LineTo(hdc, centerx, item->rect.bottom + 1);
}
/* Draw the line from our parent to its next sibling. */
parent = item->parent;
while (parent != infoPtr->root)
{
int pcenterx = (parent->linesOffset + parent->stateOffset) / 2;
if (parent->nextSibling
/* skip top-levels unless TVS_LINESATROOT */
&& parent->stateOffset > parent->linesOffset)
{
MoveToEx(hdc, pcenterx, item->rect.top, NULL);
LineTo(hdc, pcenterx, item->rect.bottom + 1);
}
parent = parent->parent;
}
SelectObject(hdc, hOldPen);
DeleteObject(hNewPen);
}
/*
* Display the (+/-) signs
*/
if (infoPtr->dwStyle & TVS_HASBUTTONS)
{
if (item->cChildren)
{
HTHEME theme = GetWindowTheme(infoPtr->hwn
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -