Scale TreeViewAdv elements based on DPI

TreeViewAdv assumed a standard 96 DPI display. This commit fixes some
problems on high DPI displays, including some problems mentioned in
OHM issue 830.

- column header height
- checkboxes
- icons
- indentation
This commit is contained in:
David Wilhelm 2017-08-10 12:34:05 -07:00 committed by Michael Möller
parent 1cd85881e8
commit e2099a034d
5 changed files with 73 additions and 10 deletions

View File

@ -46,7 +46,9 @@ namespace Aga.Controls.Tree.NodeControls
public override Size MeasureSize(TreeNodeAdv node, DrawContext context) public override Size MeasureSize(TreeNodeAdv node, DrawContext context)
{ {
return new Size(ImageSize, ImageSize); int scaledX = node.Tree.GetScaledSize(ImageSize, false);
int scaledY = node.Tree.GetScaledSize(ImageSize);
return new Size(scaledX, scaledY);
} }
public override void Draw(TreeNodeAdv node, DrawContext context) public override void Draw(TreeNodeAdv node, DrawContext context)
@ -56,13 +58,15 @@ namespace Aga.Controls.Tree.NodeControls
if (Application.RenderWithVisualStyles) if (Application.RenderWithVisualStyles)
{ {
VisualStyleRenderer renderer; VisualStyleRenderer renderer;
int scaledX = node.Tree.GetScaledSize(ImageSize, false);
int scaledY = node.Tree.GetScaledSize(ImageSize);
if (state == CheckState.Indeterminate) if (state == CheckState.Indeterminate)
renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.MixedNormal); renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.MixedNormal);
else if (state == CheckState.Checked) else if (state == CheckState.Checked)
renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.CheckedNormal); renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.CheckedNormal);
else else
renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.UncheckedNormal); renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.UncheckedNormal);
renderer.DrawBackground(context.Graphics, new Rectangle(bounds.X, bounds.Y, ImageSize, ImageSize)); renderer.DrawBackground(context.Graphics, new Rectangle(bounds.X, bounds.Y, scaledX, scaledY));
} }
else else
{ {

View File

@ -19,9 +19,15 @@ namespace Aga.Controls.Tree.NodeControls
{ {
Image image = GetIcon(node); Image image = GetIcon(node);
if (image != null) if (image != null)
return image.Size; {
int scaledX = node.Tree.GetScaledSize(image.Size.Width, false);
int scaledY = node.Tree.GetScaledSize(image.Size.Height);
return new Size(scaledX, scaledY); ;
}
else else
{
return Size.Empty; return Size.Empty;
}
} }

View File

@ -46,7 +46,9 @@ namespace Aga.Controls.Tree.NodeControls
public override Size MeasureSize(TreeNodeAdv node, DrawContext context) public override Size MeasureSize(TreeNodeAdv node, DrawContext context)
{ {
return new Size(Width, Width); int scaledX = node.Tree.GetScaledSize(Width, false);
int scaledY = node.Tree.GetScaledSize(Width);
return new Size(scaledX, scaledY);
} }
public override void Draw(TreeNodeAdv node, DrawContext context) public override void Draw(TreeNodeAdv node, DrawContext context)
@ -54,7 +56,9 @@ namespace Aga.Controls.Tree.NodeControls
if (node.CanExpand) if (node.CanExpand)
{ {
Rectangle r = context.Bounds; Rectangle r = context.Bounds;
int dy = (int)Math.Round((float)(r.Height - ImageSize) / 2); int scaledX = node.Tree.GetScaledSize(ImageSize, false);
int scaledY = node.Tree.GetScaledSize(ImageSize);
int dy = (int)Math.Round((float)(r.Height - scaledY) / 2);
if (Application.RenderWithVisualStyles) if (Application.RenderWithVisualStyles)
{ {
VisualStyleRenderer renderer; VisualStyleRenderer renderer;
@ -62,7 +66,7 @@ namespace Aga.Controls.Tree.NodeControls
renderer = OpenedRenderer; renderer = OpenedRenderer;
else else
renderer = ClosedRenderer; renderer = ClosedRenderer;
renderer.DrawBackground(context.Graphics, new Rectangle(r.X, r.Y + dy, ImageSize, ImageSize)); renderer.DrawBackground(context.Graphics, new Rectangle(r.X, r.Y + dy, scaledX, scaledY));
} }
else else
{ {

View File

@ -259,8 +259,9 @@ namespace Aga.Controls.Tree
while (curNode != _root && curNode != null) while (curNode != _root && curNode != null)
{ {
int level = curNode.Level; int level = curNode.Level;
int x = (level - 1) * _indent + NodePlusMinus.ImageSize / 2 + LeftMargin; int scaledIndent = node.Tree.GetScaledSize(_indent, false);
int width = NodePlusMinus.Width - NodePlusMinus.ImageSize / 2; int x = (level - 1) * scaledIndent + NodePlusMinus.ImageSize / 2 + LeftMargin;
int width = node.Tree.GetScaledSize(NodePlusMinus.Width - NodePlusMinus.ImageSize / 2, false);
int y = rowRect.Y; int y = rowRect.Y;
int y2 = y + rowRect.Height; int y2 = y + rowRect.Height;

View File

@ -42,6 +42,11 @@ namespace Aga.Controls.Tree
private List<TreeNodeAdv> _expandingNodes = new List<TreeNodeAdv>(); private List<TreeNodeAdv> _expandingNodes = new List<TreeNodeAdv>();
private AbortableThreadPool _threadPool = new AbortableThreadPool(); private AbortableThreadPool _threadPool = new AbortableThreadPool();
private float dpiX;
private float dpiY;
private float dpiXscale = 1;
private float dpiYscale = 1;
#region Public Events #region Public Events
[Category("Action")] [Category("Action")]
@ -204,6 +209,7 @@ namespace Aga.Controls.Tree
public TreeViewAdv() public TreeViewAdv()
{ {
InitializeComponent(); InitializeComponent();
SetDPI();
SetStyle(ControlStyles.AllPaintingInWmPaint SetStyle(ControlStyles.AllPaintingInWmPaint
| ControlStyles.UserPaint | ControlStyles.UserPaint
| ControlStyles.OptimizedDoubleBuffer | ControlStyles.OptimizedDoubleBuffer
@ -216,6 +222,7 @@ namespace Aga.Controls.Tree
_columnHeaderHeight = 20; _columnHeaderHeight = 20;
else else
_columnHeaderHeight = 17; _columnHeaderHeight = 17;
_columnHeaderHeight = GetScaledSize(_columnHeaderHeight);
//BorderStyle = BorderStyle.Fixed3D; //BorderStyle = BorderStyle.Fixed3D;
_hScrollBar.Height = SystemInformation.HorizontalScrollBarHeight; _hScrollBar.Height = SystemInformation.HorizontalScrollBarHeight;
@ -245,6 +252,46 @@ namespace Aga.Controls.Tree
ExpandingIcon.IconChanged += ExpandingIconChanged; ExpandingIcon.IconChanged += ExpandingIconChanged;
} }
public void SetDPI()
{
// https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266(v=vs.85).aspx
const int _default_dpi = 96;
Graphics g = this.CreateGraphics();
try
{
this.dpiX = g.DpiX;
this.dpiY = g.DpiY;
}
finally
{
g.Dispose();
}
if (dpiX > 0)
{
this.dpiXscale = dpiX / _default_dpi;
}
if (dpiY > 0)
{
this.dpiYscale = dpiY / _default_dpi;
}
}
public int GetScaledSize(int size, bool useY = true)
{
int scaledsize = size;
if (useY && this.dpiYscale > 1)
{
scaledsize = (int)(this.dpiYscale * size);
}
else if (this.dpiXscale > 1)
{
scaledsize = (int)(this.dpiXscale * size);
}
return scaledsize;
}
void ExpandingIconChanged(object sender, EventArgs e) void ExpandingIconChanged(object sender, EventArgs e)
{ {
if (IsHandleCreated && !IsDisposed) if (IsHandleCreated && !IsDisposed)
@ -543,11 +590,12 @@ namespace Aga.Controls.Tree
if (node == null) if (node == null)
yield break; yield break;
int scaledIndent = node.Tree.GetScaledSize(_indent, false);
int y = rowRect.Y; int y = rowRect.Y;
int x = (node.Level - 1) * _indent + LeftMargin; int x = (node.Level - 1) * scaledIndent + LeftMargin;
int width = 0; int width = 0;
if (node.Row == 0 && ShiftFirstNode) if (node.Row == 0 && ShiftFirstNode)
x -= _indent; x -= scaledIndent;
Rectangle rect = Rectangle.Empty; Rectangle rect = Rectangle.Empty;
if (ShowPlusMinus) if (ShowPlusMinus)