From 008c27026d16c6fe62cb0d09da87e9e068a635cc Mon Sep 17 00:00:00 2001
From: Patrick Simpson
Date: Fri, 30 Jun 2017 14:55:51 +0200
Subject: [PATCH] [KOE-125] Added focused border to tree control
---
.../AcaciaZPushPlugin/Controls/KTree.cs | 140 +++++++++---------
.../Controls/KTreeRenderer.cs | 2 +
.../Controls/KTreeRendererVisualStyles.cs | 24 ++-
.../AcaciaZPushPlugin/Controls/KUIUtil.cs | 5 +
.../SharedFolders/SharedFoldersDialog.cs | 2 +-
5 files changed, 98 insertions(+), 75 deletions(-)
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTree.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTree.cs
index 4debde0..a4b3d1d 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTree.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTree.cs
@@ -1,6 +1,6 @@
/// Project : Kopano OL Extension
///
-/// Copyright 2016 Kopano b.v.
+/// Copyright 2017 Kopano b.v.
///
/// This program is free software: you can redistribute it and/or modify
/// it under the terms of the GNU Affero General Public License, version 3,
@@ -138,6 +138,13 @@ namespace Acacia.Controls
set { _nodeIdent = value; Rerender(); }
}
+ public int BorderThickness
+ {
+ get
+ {
+ return BorderStyle == BorderStyle.FixedSingle ? 1 : 0;
+ }
+ }
#endregion
#region Images
@@ -416,6 +423,8 @@ namespace Acacia.Controls
{
if (newHighlight != _highlightNode || _highlightPart != newPart)
{
+ bool oldFocused = Focused;
+
KTreeNode old = _highlightNode;
if (newHighlight != null && !newHighlight.IsSelectable)
@@ -429,6 +438,10 @@ namespace Acacia.Controls
_highlightPart = newPart;
}
+ // Update the border if required
+ if (oldFocused != Focused)
+ RedrawBorder();
+
// Render old node without highlight
if (old != null)
Rerender(old);
@@ -612,21 +625,6 @@ namespace Acacia.Controls
#endregion
- #region Columns
- // TODO
- /*
- private readonly TreeViewColumnCollection _columns;
-
- [Category("Columns")]
- [Browsable(true)]
- [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
- public TreeViewColumnCollection Columns
- {
- get { return _columns; }
- }*/
-
- #endregion
-
#region Rendering
private KTreeRenderer _renderer;
@@ -864,6 +862,10 @@ namespace Acacia.Controls
e.Graphics.FillRectangle(SystemBrushes.Control,
ClientSize.Width - VerticalScrollBarWidth, ClientSize.Height - HorizontalScrollBarHeight,
VerticalScrollBarWidth, HorizontalScrollBarHeight);
+
+ // The scrollbars sometimes get lost, force a repaint
+ _verticalScrollBar.Refresh();
+ _horizontalScrollBar.Refresh();
}
#endregion
@@ -1081,20 +1083,69 @@ namespace Acacia.Controls
#endregion
- #region Focus
+ #region Border
+
+ public override bool Focused
+ {
+ get
+ {
+ return base.Focused || _highlightNode != null;
+ }
+ }
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
- Invalidate();
+ RedrawBorder();
}
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus(e);
- Invalidate();
+ RedrawBorder();
}
+ protected override void OnEnabledChanged(EventArgs e)
+ {
+ base.OnEnabledChanged(e);
+ RedrawBorder();
+ }
+
+ protected override void WndProc(ref Message m)
+ {
+ if (m.Msg == (int)WM.NCPAINT)
+ {
+ IntPtr hDC = User32.GetWindowDC(m.HWnd);
+ try
+ {
+ using (Graphics g = Graphics.FromHdc(hDC))
+ {
+ _renderer.RenderControlBorder(g, new Rectangle(0, 0, Width, Height));
+ }
+ }
+ finally
+ {
+ User32.ReleaseDC(m.HWnd, hDC);
+ }
+ return;
+ }
+ base.WndProc(ref m);
+ }
+
+ protected override void OnResize(EventArgs e)
+ {
+ base.OnResize(e);
+ RedrawBorder();
+ }
+
+ private void RedrawBorder()
+ {
+ // Force NCPaint update
+ User32.RedrawWindow(this.Handle, IntPtr.Zero, IntPtr.Zero,
+ User32.RedrawWindowFlags.Frame | User32.RedrawWindowFlags.Invalidate);
+ }
+
+
#endregion
#region Winforms Autogenerated
@@ -1111,56 +1162,5 @@ namespace Acacia.Controls
#endregion
- #region Disabled state
-
- protected override void OnEnabledChanged(EventArgs e)
- {
- base.OnEnabledChanged(e);
- RedrawBorder();
- }
-
- protected override void WndProc(ref Message m)
- {
- if (m.Msg == (int)WM.NCPAINT)
- {
- WmNcPaint(ref m);
- return;
- }
- base.WndProc(ref m);
- }
-
- private void WmNcPaint(ref Message m)
- {
- if (BorderStyle == BorderStyle.None)
- return;
-
- IntPtr hDC = User32.GetWindowDC(m.HWnd);
- try
- {
- using (Graphics g = Graphics.FromHdc(hDC))
- {
- _renderer.RenderControlBorder(g, new Rectangle(0, 0, Width, Height));
- }
- }
- finally
- {
- User32.ReleaseDC(m.HWnd, hDC);
- }
- }
-
- protected override void OnResize(EventArgs e)
- {
- base.OnResize(e);
- RedrawBorder();
- }
-
- private void RedrawBorder()
- {
- // Force NCPaint update
- User32.RedrawWindow(this.Handle, IntPtr.Zero, IntPtr.Zero,
- User32.RedrawWindowFlags.Frame | User32.RedrawWindowFlags.Invalidate /*| User32.RedrawWindowFlags.UpdateNow*/);
- }
-
- #endregion
}
}
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRenderer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRenderer.cs
index 436cfbc..21c274c 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRenderer.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRenderer.cs
@@ -117,6 +117,8 @@ namespace Acacia.Controls
Rectangle containerRect = dims.NodeRect;
containerRect.X = _clientRect.X;
containerRect.Width = Math.Max(_totalRect.Width, _clientRect.Width);
+ // Overlap the rectangle with the control border, to prevent duplicate lines
+ containerRect = containerRect.Expand(new Padding(_tree.BorderThickness));
// Selection background
RenderNodeOutline(graphics, node, _tree.FullRowSelect ? containerRect : dims.NodeRect, highlight);
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRendererVisualStyles.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRendererVisualStyles.cs
index 0769696..8a325f5 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRendererVisualStyles.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KTreeRendererVisualStyles.cs
@@ -66,6 +66,11 @@ namespace Acacia.Controls
private readonly VisualStyleRenderer _treeViewGlyphHotClosed = new VisualStyleRenderer(TREEVIEW, 4, 1);
private readonly VisualStyleRenderer _treeViewGlyphHotOpened = new VisualStyleRenderer(TREEVIEW, 4, 2);
+ // We use the combo box styles for the outline
+ private readonly VisualStyleRenderer _treeViewBorderNormal = new VisualStyleRenderer("COMBOBOX", 4, 1);
+ private readonly VisualStyleRenderer _treeViewBorderFocus = new VisualStyleRenderer("COMBOBOX", 4, 2);
+ private readonly VisualStyleRenderer _treeViewBorderDisabled = new VisualStyleRenderer("COMBOBOX", 4, 4);
+
private Size? _glyphSize;
protected override Size GetExpanderSize(Graphics graphics, KTreeNode node)
@@ -124,8 +129,10 @@ namespace Acacia.Controls
protected override void RenderNodeOutline(Graphics graphics, KTreeNode node, Rectangle rect, KTreeNodeMeasurements.Part? highlight)
{
// Draw one pixel too far, to overlap top and bottom borders for a continuous selection
-
Rectangle highlightRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height + 1);
+ // If full-row selecting, compensate for shifted rectangle.
+ if (_tree.FullRowSelect)
+ highlightRect.Height -= 2 * _tree.BorderThickness;
if (_tree.ActiveNode == node && _tree.Focused)
{
if (node.IsSelected)
@@ -148,11 +155,20 @@ namespace Acacia.Controls
public override void RenderControlBorder(Graphics graphics, Rectangle rect)
{
- Color color = (_tree.Enabled ? _treeViewItemNormal : _treeViewItemDisabled).GetColor(ColorProperty.BorderColor);
- using (Pen pen = new Pen(_tree.Enabled ? Color.Black : SystemColors.GrayText))
+ VisualStyleRenderer style;
+ if (_tree.Enabled)
{
- graphics.DrawRectangle(pen, new Rectangle(rect.X, rect.Y, rect.Width - 1, rect.Height - 1));
+ if (_tree.Focused)
+ style = _treeViewBorderFocus;
+ else
+ style = _treeViewBorderNormal;
}
+ else
+ {
+ style = _treeViewBorderDisabled;
+ }
+
+ style.DrawBackground(graphics, rect, graphics.ClipBounds.ToRectangle());
}
}
}
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUIUtil.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUIUtil.cs
index 07ad8be..8b980d2 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUIUtil.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUIUtil.cs
@@ -131,6 +131,11 @@ namespace Acacia.Controls
return new Point(_this.Left, _this.Top);
}
+ public static Rectangle ToRectangle(this RectangleF _this)
+ {
+ return new Rectangle((int)_this.X, (int)_this.Y, (int)_this.Width, (int)_this.Height);
+ }
+
#endregion
}
}
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs
index bbf8edf..9f7e722 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs
@@ -1,4 +1,4 @@
-/// Copyright 2016 Kopano b.v.
+/// Copyright 2017 Kopano b.v.
///
/// This program is free software: you can redistribute it and/or modify
/// it under the terms of the GNU Affero General Public License, version 3,