318 lines
8.9 KiB
C#
318 lines
8.9 KiB
C#
namespace Pilz.UI.WinForms;
|
|
|
|
|
|
internal class HighlightPanel : Control
|
|
{
|
|
|
|
private Dictionary<Control, eHighlightColor> _Highlights = null;
|
|
private List<HighlightRegion> _HighlightRegions = [];
|
|
|
|
public HighlightPanel(Dictionary<Control, eHighlightColor> highlights)
|
|
{
|
|
_Highlights = highlights;
|
|
SetStyle(ControlStyles.UserPaint, true);
|
|
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
|
SetStyle(ControlStyles.Opaque, true);
|
|
SetStyle(ControlStyles.ResizeRedraw, true);
|
|
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
|
SetStyle(ControlStyles.Selectable, false);
|
|
}
|
|
|
|
protected override void OnPaint(PaintEventArgs e)
|
|
{
|
|
var g = e.Graphics;
|
|
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
|
|
|
|
foreach (var highlightRegion in _HighlightRegions)
|
|
{
|
|
var colors = GetHighlightColors(highlightRegion.HighlightColor);
|
|
var r = highlightRegion.Bounds;
|
|
var back = highlightRegion.BackColor;
|
|
r.Inflate(1, 1);
|
|
DisplayHelp.FillRectangle(g, r, back);
|
|
r.Inflate(-1, -1);
|
|
DisplayHelp.FillRoundedRectangle(g, r, 2, colors[0]);
|
|
r.Inflate(-2, -2);
|
|
DisplayHelp.DrawRectangle(g, colors[2], r);
|
|
r.Inflate(1, 1);
|
|
DisplayHelp.DrawRoundedRectangle(g, colors[1], r, 2);
|
|
}
|
|
|
|
base.OnPaint(e);
|
|
}
|
|
|
|
private Color[] GetHighlightColors(eHighlightColor color)
|
|
{
|
|
var colors = new Color[3];
|
|
|
|
if (color == eHighlightColor.Blue)
|
|
{
|
|
colors[0] = GetColor(172, 0x6A9CD4);
|
|
colors[1] = GetColor(0x6A9CD4);
|
|
colors[2] = GetColor(0x5D7EA4);
|
|
}
|
|
else if (color == eHighlightColor.Orange)
|
|
{
|
|
colors[0] = GetColor(172, 0xFF9C00);
|
|
colors[1] = GetColor(0xFF9C00);
|
|
colors[2] = GetColor(0xCC6600);
|
|
}
|
|
else if (color == eHighlightColor.Green)
|
|
{
|
|
colors[0] = GetColor(172, 0x71B171);
|
|
colors[1] = GetColor(0x71B171);
|
|
colors[2] = GetColor(0x339933);
|
|
}
|
|
else if (color == eHighlightColor.Custom)
|
|
{
|
|
if (_CustomHighlightColors is null || _CustomHighlightColors.Length < 3)
|
|
{
|
|
colors[0] = Color.Red;
|
|
colors[1] = Color.Red;
|
|
colors[2] = Color.Red;
|
|
}
|
|
else
|
|
{
|
|
colors[0] = _CustomHighlightColors[0];
|
|
colors[1] = _CustomHighlightColors[1];
|
|
colors[2] = _CustomHighlightColors[2];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
colors[0] = GetColor(172, 0xC63030);
|
|
colors[1] = GetColor(0xC63030);
|
|
colors[2] = GetColor(0x990000);
|
|
}
|
|
|
|
return colors;
|
|
}
|
|
|
|
protected override void OnVisibleChanged(EventArgs e)
|
|
{
|
|
if (Visible && !_UpdatingRegion)
|
|
UpdateRegion();
|
|
base.OnVisibleChanged(e);
|
|
}
|
|
|
|
protected override void OnHandleCreated(EventArgs e)
|
|
{
|
|
if (!_RegionInitialized)
|
|
UpdateRegion();
|
|
base.OnHandleCreated(e);
|
|
}
|
|
|
|
private bool _RegionInitialized = false;
|
|
private bool _UpdatingRegion = false;
|
|
|
|
internal void UpdateRegion()
|
|
{
|
|
if (_UpdatingRegion || !IsHandleCreated)
|
|
return;
|
|
|
|
try
|
|
{
|
|
_UpdatingRegion = true;
|
|
Region = null;
|
|
_HighlightRegions.Clear();
|
|
if (_Highlights is null)
|
|
return;
|
|
|
|
if (_Highlights.Count == 0 && _FocusHighlightControl is null)
|
|
{
|
|
Visible = false;
|
|
return;
|
|
}
|
|
|
|
var processFocusControl = true;
|
|
Region region = null;
|
|
|
|
foreach (var item in _Highlights)
|
|
{
|
|
if (item.Value == eHighlightColor.None || !GetIsVisible(item.Key))
|
|
continue;
|
|
if (ReferenceEquals(item.Key, _FocusHighlightControl))
|
|
processFocusControl = false;
|
|
var r = GetControlRect(item.Key);
|
|
if (r.IsEmpty)
|
|
continue;
|
|
r.Inflate(2, 2);
|
|
_HighlightRegions.Add(new HighlightRegion(r, GetBackColor(item.Key.Parent), item.Value));
|
|
|
|
if (region is null)
|
|
region = new Region(r);
|
|
else
|
|
{
|
|
region.Union(r);
|
|
}
|
|
|
|
r.Inflate(-3, -3);
|
|
region.Exclude(r);
|
|
}
|
|
|
|
if (processFocusControl && _FocusHighlightControl is not null && _FocusHighlightControl.Visible)
|
|
{
|
|
var r = GetControlRect(_FocusHighlightControl);
|
|
|
|
if (!r.IsEmpty)
|
|
{
|
|
r.Inflate(2, 2);
|
|
_HighlightRegions.Add(new HighlightRegion(r, GetBackColor(_FocusHighlightControl.Parent), _FocusHighlightColor));
|
|
|
|
if (region is null)
|
|
region = new Region(r);
|
|
else
|
|
{
|
|
region.Union(r);
|
|
}
|
|
|
|
r.Inflate(-3, -3);
|
|
region.Exclude(r);
|
|
}
|
|
}
|
|
|
|
Region = region;
|
|
|
|
if (region is null)
|
|
Visible = false;
|
|
else if (!Visible)
|
|
{
|
|
Visible = true;
|
|
BringToFront();
|
|
}
|
|
|
|
Invalidate();
|
|
}
|
|
finally
|
|
{
|
|
_UpdatingRegion = false;
|
|
_RegionInitialized = true;
|
|
}
|
|
}
|
|
|
|
private static Color GetColor(int rgb)
|
|
{
|
|
if (rgb == -1)
|
|
return Color.Empty;
|
|
else
|
|
{
|
|
return Color.FromArgb((rgb & 0xFF0000) >> 16, (rgb & 0xFF00) >> 8, rgb & 0xFF);
|
|
}
|
|
}
|
|
|
|
private static Color GetColor(int alpha, int rgb)
|
|
{
|
|
if (rgb == -1)
|
|
return Color.Empty;
|
|
else
|
|
{
|
|
return Color.FromArgb(alpha, (rgb & 0xFF0000) >> 16, (rgb & 0xFF00) >> 8, rgb & 0xFF);
|
|
}
|
|
}
|
|
|
|
private bool GetIsVisible(Control control)
|
|
{
|
|
if (!control.Visible)
|
|
return false;
|
|
if (control.Parent is null || !control.IsHandleCreated)
|
|
return control.Visible;
|
|
var rect = new Win32.Native.RECT();
|
|
Win32.Native.User32.GetWindowRect(control.Handle, ref rect);
|
|
var pp = control.Parent.PointToClient(new Point(rect.Left + 3, rect.Top + 3));
|
|
var handle = Win32.Native.User32.ChildWindowFromPointEx(control.Parent.Handle, new Win32.Native.POINT(pp.X, pp.Y), (uint)Win32.Native.WindowFromPointFlags.CWP_SKIPINVISIBLE);
|
|
if (handle == nint.Zero)
|
|
return control.Visible;
|
|
var c = FromHandle(handle);
|
|
|
|
if (c is not null && !ReferenceEquals(c, control) && !ReferenceEquals(c, this) && !ReferenceEquals(c, control.Parent))
|
|
return false;
|
|
|
|
return control.Visible;
|
|
}
|
|
|
|
private Color GetBackColor(Control control)
|
|
{
|
|
var backColor = control.BackColor;
|
|
|
|
if (backColor.IsEmpty || backColor == Color.Transparent)
|
|
backColor = SystemColors.Control;
|
|
else if (backColor.A < 255)
|
|
{
|
|
backColor = Color.FromArgb(255, backColor);
|
|
}
|
|
|
|
return backColor;
|
|
}
|
|
|
|
protected override void OnResize(EventArgs e)
|
|
{
|
|
UpdateRegion();
|
|
base.OnResize(e);
|
|
}
|
|
|
|
private Rectangle GetControlRect(Control c)
|
|
{
|
|
if (!c.IsHandleCreated)
|
|
return Rectangle.Empty;
|
|
var rect = default(Win32.Native.RECT);
|
|
Win32.Native.User32.GetWindowRect(c.Handle, ref rect);
|
|
var p = PointToClient(rect.Location);
|
|
return new Rectangle(p, rect.Size);
|
|
}
|
|
|
|
private struct HighlightRegion
|
|
{
|
|
public Rectangle Bounds;
|
|
public Color BackColor;
|
|
public eHighlightColor HighlightColor;
|
|
|
|
public HighlightRegion(Rectangle bounds, Color backColor, eHighlightColor highlightColor)
|
|
{
|
|
Bounds = bounds;
|
|
BackColor = backColor;
|
|
HighlightColor = highlightColor;
|
|
}
|
|
}
|
|
|
|
private Control _FocusHighlightControl;
|
|
|
|
public Control FocusHighlightControl
|
|
{
|
|
get
|
|
{
|
|
return _FocusHighlightControl;
|
|
}
|
|
set
|
|
{
|
|
_FocusHighlightControl = value;
|
|
}
|
|
}
|
|
|
|
private eHighlightColor _FocusHighlightColor = eHighlightColor.Blue;
|
|
|
|
public eHighlightColor FocusHighlightColor
|
|
{
|
|
get
|
|
{
|
|
return _FocusHighlightColor;
|
|
}
|
|
set
|
|
{
|
|
_FocusHighlightColor = value;
|
|
}
|
|
}
|
|
|
|
private Color[] _CustomHighlightColors = null;
|
|
|
|
public Color[] CustomHighlightColors
|
|
{
|
|
get
|
|
{
|
|
return _CustomHighlightColors;
|
|
}
|
|
set
|
|
{
|
|
_CustomHighlightColors = value;
|
|
}
|
|
}
|
|
} |