using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; namespace Pilz.UI.WinForms; internal class HighlightPanel : Control { private Dictionary _Highlights = null; private List _HighlightRegions = new List(); public HighlightPanel(Dictionary 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; } } }