Skip to content

Commit

Permalink
Recalculate the node position of the TreeView when DrawMode = TreeVie…
Browse files Browse the repository at this point in the history
…wDrawMode.OwnerDrawText
  • Loading branch information
LeafShi1 committed Jan 23, 2025
1 parent a990c47 commit 3841b91
Showing 1 changed file with 68 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2735,6 +2735,13 @@ private unsafe void CustomDraw(ref Message m)
// as background color.
if (_drawMode == TreeViewDrawMode.OwnerDrawText)
{
if (node is { IsEditing: true })
{
nmtvcd->clrText = ColorTranslator.ToWin32(BackColor);
nmtvcd->clrTextBk = ColorTranslator.ToWin32(BackColor);
goto default;
}

nmtvcd->clrText = nmtvcd->clrTextBk;
m.ResultInternal = (LRESULT)(nint)(PInvoke.CDRF_NEWFONT | PInvoke.CDRF_NOTIFYPOSTPAINT);
return;
Expand Down Expand Up @@ -2793,6 +2800,11 @@ private unsafe void CustomDraw(ref Message m)
nmtvcd->clrTextBk = ColorTranslator.ToWin32(riBack);
}

if (node is { IsEditing: true })
{
nmtvcd->clrTextBk = ColorTranslator.ToWin32(BackColor);
}

if (renderinfo is not null && renderinfo.Font is not null)
{
// Mess with the DC directly...
Expand Down Expand Up @@ -2827,8 +2839,30 @@ private unsafe void CustomDraw(ref Message m)
{
Rectangle bounds = node.Bounds;
Size textSize = TextRenderer.MeasureText(node.Text, node.TreeView!.Font);
Point textLoc = new(LocalAppContextSwitches.MoveTreeViewTextLocationOnePixel ? bounds.X : bounds.X - 1, bounds.Y);
bounds = new Rectangle(textLoc, new Size(textSize.Width, bounds.Height));
Point textLocation = new(LocalAppContextSwitches.MoveTreeViewTextLocationOnePixel ? bounds.X : bounds.X - 1, bounds.Y);
bounds = new Rectangle(textLocation, new Size(textSize.Width, bounds.Height));

Rectangle fillRectangle = new Rectangle(textLocation, new(textSize.Width, bounds.Height));
Rectangle focusRectangle = new Rectangle(textLocation, new(textSize.Width, bounds.Height));

if (RightToLeft == RightToLeft.Yes && RightToLeftLayout)
{
// Reverse the X-axis drawing coordinates of the rectangle.
// Offset the text four pixels to the left to ensure that the text is centered on the fill rectangle.
int invertedX = Width - bounds.X - textSize.Width - 4;

// Subtract the scroll bar width when the scroll bar appears.
if (Height <= PreferredHeight)
{
float dpiScale = (float)DeviceDpi / (float)ScaleHelper.InitialSystemDpi;
invertedX -= (int)(SystemInformation.VerticalScrollBarWidth * Math.Round(dpiScale, 2));
}

// To ensure that the right side of the fillRectangle does not
// touch the left edge of the node prefix symbol, 1 pixel is subtracted here.
fillRectangle = new Rectangle(new Point(invertedX - 1, bounds.Y), new(textSize.Width, bounds.Height));
focusRectangle = new Rectangle(new Point(invertedX, bounds.Y), new(textSize.Width, bounds.Height));
}

DrawTreeNodeEventArgs e = new(g, node, bounds, (TreeNodeStates)(nmtvcd->nmcd.uItemState));
OnDrawNode(e);
Expand All @@ -2844,14 +2878,14 @@ private unsafe void CustomDraw(ref Message m)
// Draw the actual node.
if ((curState & TreeNodeStates.Selected) == TreeNodeStates.Selected)
{
g.FillRectangle(SystemBrushes.Highlight, bounds);
ControlPaint.DrawFocusRectangle(g, bounds, color, SystemColors.Highlight);
g.FillRectangle(SystemBrushes.Highlight, fillRectangle);
ControlPaint.DrawFocusRectangle(g, focusRectangle, color, SystemColors.Highlight);
TextRenderer.DrawText(g, node.Text, font, bounds, color, TextFormatFlags.Default);
}
else
{
using var brush = BackColor.GetCachedSolidBrushScope();
g.FillRectangle(brush, bounds);
g.FillRectangle(brush, fillRectangle);

TextRenderer.DrawText(g, node.Text, font, bounds, color, TextFormatFlags.Default);
}
Expand All @@ -2871,6 +2905,35 @@ private unsafe void CustomDraw(ref Message m)
}
}

private int PreferredHeight
{
get
{
int height = 0;
foreach (TreeNode node in Nodes)
{
height += GetNodeHeight(node);
}

return height;
}
}

private int GetNodeHeight(TreeNode node)
{
int height = ItemHeight;

if (node.IsExpanded)
{
foreach (TreeNode childNode in node.Nodes)
{
height += GetNodeHeight(childNode);
}
}

return height;
}

/// <summary>
/// Generates colors for each item. This can be overridden to provide colors on a per state/per node
/// basis, rather than using the ForeColor/BackColor/NodeFont properties on TreeNode.
Expand Down

0 comments on commit 3841b91

Please sign in to comment.