I coded a small sample application that makes its own control structure by drawing in form using .Net C #. Just something simple with this result:

I did IsSelected by recursively disabling all controls and clicking clicks. See Section with window.MouseUp += (sender, arg) => .
The selection can go through the mouse or the Tab key.
The code approach should be portable to other languages โโand online translated to VB.Net.
Corresponding code snippet:
using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using System.Drawing; using System.Threading; using System.Threading.Tasks; namespace CustomGUI { static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Form window = new Form1(); window.BackColor = Color.Gray; Graphics api = window.CreateGraphics(); GUIControl form = new GUIControl(); form.Location = new Point(30,30); form.Size = new Size(200, 300); GUIControl control1 = new GUIControl(); control1.Location = new Point(0, 0); control1.Size = new Size(200, 130); control1.Background = Color.Blue; GUIControl control11 = new GUIControl(); control11.Location = new Point(140, 30); control11.Size = new Size(30, 30); control11.Background = Color.Red; GUIControl control12 = new GUIControl(); control12.Location = new Point(30, 30); control12.Size = new Size(30, 30); control12.Background = Color.Red; control12.BorderColor = Color.Green; control12.BorderWidth = 5; GuiLabel control2 = new GuiLabel(); control2.Location = new Point(10, 200); control2.Size = new Size(180, 30); control2.Background = Color.Green; control2.Text = "Hello World!"; control1.AddChild(control11); control1.AddChild(control12); form.AddChild(control1); form.AddChild(control2); window.MouseUp += (sender, arg) => { // hit test the control where the mouse has landed IGUIContainer control = form.HitTest(arg.Location); if (control != null) { // recursive on all controls foreach (var ct in (new IGUIContainer[] { form }).Traverse(c => c.Controls)) { //deselecting all others if (ct != control) ct.IsSelected = false; } control.IsSelected = !control.IsSelected; } window.Invalidate(); // force paint }; window.KeyUp += (sender, key) => { if (key.KeyCode == Keys.Tab && key.Modifiers == Keys.None) { var selected = (new IGUIContainer[] { form }).Traverse(c => c.Controls).FirstOrDefault(c => c.IsSelected); IGUIContainer parent; if (selected == null) { parent = form; } else { parent = selected; } IGUIContainer control; if (parent.Controls.Count > 0) { control = parent.Controls[0]; } else { control = GUIControl.Next(parent); } if (control == null) control = form; foreach (var ct in (new IGUIContainer[] { form }).Traverse(c => c.Controls)) { if (ct != control) ct.IsSelected = false; } control.IsSelected = true; window.Invalidate(); } }; window.Paint += (sender, args) => { form.Draw(api, new Point(0,0)); }; Application.Run(window); } } }
All necessary classes and interfaces:
IDrawable:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; namespace CustomGUI { public interface IDrawable { Point Location { get; set; } Size Size { get; set; } Rectangle GetRealRect(Point origin); void Draw(Graphics gfxApi, Point origin); } }
IGUIContainer:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; namespace CustomGUI { delegate void SelectionChangedHandler(object sender, bool newIsSelected); interface IGUIContainer : IUIElement { IGUIContainer Parent { get; set; } List<IGUIContainer> Controls { get; } void AddChild(IGUIContainer child); bool IsSelected { get; set; } event SelectionChangedHandler SelectionChanged; IGUIContainer HitTest(Point mouseCoord); } }
UIElement:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using System.Diagnostics; namespace CustomGUI { abstract class UIElement : IUIElement { private Point _location; private Size _size; private Color _background; private Color _foreground; private Color _borderColor; private int _borderWidth; public UIElement() { _foreground = Color.Black; _background = Color.White; _borderColor = Color.Transparent; } public Point Location { get { return _location; } set { _location = value; } } public Size Size { get { return _size; } set { _size = value; } } public virtual void Draw(Graphics drawingApi, Point origin) { Rectangle inside = GetRealRect(origin); Pen borderPen = new Pen(new SolidBrush(_borderColor), _borderWidth); drawingApi.FillRectangle(new SolidBrush(_background), inside); drawingApi.DrawRectangle(borderPen, inside); } public Rectangle ClientRect { get { return new Rectangle(_location, _size); } } public Color Background { get { return _background; } set { _background = value; } } public Color Foreground { get { return _foreground; } set { _foreground = value; } } public Rectangle GetRealRect(Point origin) { int left = ClientRect.Left + origin.X; int top = ClientRect.Top + origin.Y; int width = ClientRect.Width; int height = ClientRect.Height; Debug.WriteLine("GetRealRect " + left + ", " + top + ", " + width + ", " + height); return new Rectangle(left, top, width, height); } public int BorderWidth { get { return _borderWidth; } set { _borderWidth = value; } } public Color BorderColor { get { return _borderColor; } set { _borderColor = value; } } } }
GuiControl:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; namespace CustomGUI { class GUIControl : UIElement, IGUIContainer { private IGUIContainer _parent; private List<IGUIContainer> _controls = new List<IGUIContainer>(); private bool _isSelected; public List<IGUIContainer> Controls { get { return _controls; } } public override void Draw(Graphics api, Point origin) { Point original = origin; base.Draw(api, origin); origin.Offset(this.Location); foreach (var ctrl in Controls) { ctrl.Draw(api, origin); } if (IsSelected) { Pen selection = new Pen(Color.Yellow, 3); selection.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; api.DrawRectangle(selection, GetRealRect(original)); } } public IGUIContainer HitTest(Point coord) { Point newOrigin = coord; newOrigin.Offset(-this.Location.X, -this.Location.Y); foreach (var ctrl in Controls) { IGUIContainer hit = ctrl.HitTest(newOrigin); if (hit != null) { return hit; } } return ClientRect.Contains(coord) ? this : null; } public bool IsSelected { get { return _isSelected; } set { _isSelected = value; if (SelectionChanged != null) { SelectionChanged(this, _isSelected); } } } public event SelectionChangedHandler SelectionChanged; public void AddChild(IGUIContainer child) {
GUILabel:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; namespace CustomGUI { class GuiLabel : GUIControl { public string Text { get; set; } public Font Font { get; set; } public GuiLabel() { Font = new Font(new FontFamily("Tahoma"), 12, FontStyle.Regular); } public override void Draw(System.Drawing.Graphics api, System.Drawing.Point origin) { base.Draw(api, origin); Rectangle controlRect = GetRealRect(origin); SizeF size = api.MeasureString(Text, Font); Point textPosition = new Point(controlRect.Location.X + (int)(controlRect.Width - size.Width) / 2, controlRect.Location.Y + (int)(controlRect.Height - size.Height) / 2); api.DrawString(Text, Font, new SolidBrush(Foreground), textPosition); } } }
Extension (for the Traverse method for smoothing recursion):
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CustomGUI { static class Extensions { public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse) { foreach (T item in source) { yield return item; IEnumerable<T> seqRecurse = fnRecurse(item); if (seqRecurse != null) { foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse)) { yield return itemRecurse; } } } } } }