Implement Control ownership and nice to have interfaces.
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.ComponentModel;
|
||||||
using Dashboard.Drawing;
|
using Dashboard.Drawing;
|
||||||
using Dashboard.Events;
|
using Dashboard.Events;
|
||||||
using Dashboard.Layout;
|
using Dashboard.Layout;
|
||||||
@@ -8,21 +10,21 @@ using Dashboard.Pal;
|
|||||||
|
|
||||||
namespace Dashboard.Controls
|
namespace Dashboard.Controls
|
||||||
{
|
{
|
||||||
public class Container : Control, IList<Control>, ILayoutContainer
|
public class Container : Control, IList<Control>, ILayoutContainer, INotifyCollectionChanged
|
||||||
{
|
{
|
||||||
private readonly List<Control> _controls = new List<Control>();
|
private readonly List<Control> _controls = new List<Control>();
|
||||||
|
|
||||||
|
public ContainerLayoutInfo ContainerLayout { get; } = new ContainerLayoutInfo();
|
||||||
|
|
||||||
public int Count => _controls.Count;
|
public int Count => _controls.Count;
|
||||||
|
|
||||||
public bool IsReadOnly => false;
|
public bool IsReadOnly => false;
|
||||||
|
|
||||||
public ContainerLayoutInfo ContainerLayout { get; } = new ContainerLayoutInfo();
|
|
||||||
|
|
||||||
ILayoutItem IReadOnlyList<ILayoutItem>.this[int index] => _controls[index];
|
ILayoutItem IReadOnlyList<ILayoutItem>.this[int index] => _controls[index];
|
||||||
|
|
||||||
public event EventHandler<ContainerChildAddedEventArgs>? ChildAdded;
|
public event EventHandler<ContainerChildAddedEventArgs>? ChildAdded;
|
||||||
public event EventHandler<ContainerChildRemovedEventArgs>? ChildRemoved;
|
public event EventHandler<ContainerChildRemovedEventArgs>? ChildRemoved;
|
||||||
|
public event NotifyCollectionChangedEventHandler? CollectionChanged;
|
||||||
|
|
||||||
public Control this[int index]
|
public Control this[int index]
|
||||||
{
|
{
|
||||||
@@ -30,6 +32,11 @@ namespace Dashboard.Controls
|
|||||||
set => _controls[index] = value;
|
set => _controls[index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Container()
|
||||||
|
{
|
||||||
|
ContainerLayout.PropertyChanged += OnContainerLayoutChanged;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void ValidateLayout()
|
protected override void ValidateLayout()
|
||||||
{
|
{
|
||||||
if (!IsLayoutEnabled || IsLayoutValid)
|
if (!IsLayoutEnabled || IsLayoutValid)
|
||||||
@@ -82,16 +89,17 @@ namespace Dashboard.Controls
|
|||||||
SetParent(this, item);
|
SetParent(this, item);
|
||||||
|
|
||||||
_controls.Add(item);
|
_controls.Add(item);
|
||||||
ChildAdded?.Invoke(this, new ContainerChildAddedEventArgs(this, item));
|
OnChildAdded(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
foreach (Control control in this)
|
foreach (Control control in this)
|
||||||
{
|
{
|
||||||
ChildRemoved?.Invoke(this, new ContainerChildRemovedEventArgs(this, control));
|
OnChildRemoved(control, false);
|
||||||
}
|
}
|
||||||
_controls.Clear();
|
_controls.Clear();
|
||||||
|
OnCollectionChanged(NotifyCollectionChangedAction.Reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Contains(Control item)
|
public bool Contains(Control item)
|
||||||
@@ -109,7 +117,7 @@ namespace Dashboard.Controls
|
|||||||
if (!_controls.Remove(item))
|
if (!_controls.Remove(item))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ChildRemoved?.Invoke(this, new ContainerChildRemovedEventArgs(this, item));
|
OnChildRemoved(item);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,17 +131,64 @@ namespace Dashboard.Controls
|
|||||||
SetParent(this, item);
|
SetParent(this, item);
|
||||||
|
|
||||||
_controls.Insert(index, item);
|
_controls.Insert(index, item);
|
||||||
ChildAdded?.Invoke(this, new ContainerChildAddedEventArgs(this, item));
|
OnChildAdded(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveAt(int index)
|
public void RemoveAt(int index)
|
||||||
{
|
{
|
||||||
Control child = _controls[index];
|
Control child = _controls[index];
|
||||||
_controls.RemoveAt(index);
|
_controls.RemoveAt(index);
|
||||||
ChildRemoved?.Invoke(this, new ContainerChildRemovedEventArgs(this, child));
|
OnChildRemoved(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnOwnerChanged(Form value)
|
||||||
|
{
|
||||||
|
base.OnOwnerChanged(value);
|
||||||
|
|
||||||
|
foreach (Control control in this)
|
||||||
|
{
|
||||||
|
SetOwner(control, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
base.Dispose(disposing);
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
ContainerLayout.PropertyChanged -= OnContainerLayoutChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnChildAdded(Control item)
|
||||||
|
{
|
||||||
|
SetOwner(item, Owner ?? null);
|
||||||
|
ChildAdded?.Invoke(this, new ContainerChildAddedEventArgs(this, item));
|
||||||
|
|
||||||
|
OnCollectionChanged(NotifyCollectionChangedAction.Add);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnChildRemoved(Control control, bool notifyCollectionChanged = true)
|
||||||
|
{
|
||||||
|
SetOwner(control, null!);
|
||||||
|
ChildRemoved?.Invoke(this, new ContainerChildRemovedEventArgs(this, control));
|
||||||
|
|
||||||
|
if (notifyCollectionChanged)
|
||||||
|
OnCollectionChanged(NotifyCollectionChangedAction.Remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnCollectionChanged(NotifyCollectionChangedAction action)
|
||||||
|
{
|
||||||
|
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(action));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnContainerLayoutChanged(object? sender, PropertyChangedEventArgs ea)
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(ContainerLayout));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ContainerChildAddedEventArgs(Container parent, Control child) : EventArgs
|
public class ContainerChildAddedEventArgs(Container parent, Control child) : EventArgs
|
||||||
|
|||||||
@@ -13,27 +13,33 @@ namespace Dashboard.Controls
|
|||||||
{
|
{
|
||||||
public class Control : IEventListener, ILayoutItem, IDisposable
|
public class Control : IEventListener, ILayoutItem, IDisposable
|
||||||
{
|
{
|
||||||
private Form? _owner = null;
|
public string? Id
|
||||||
|
{
|
||||||
public string? Id { get; set; }
|
get;
|
||||||
|
set => SetField(ref field, value);
|
||||||
|
}
|
||||||
|
|
||||||
public Form Owner
|
public Form Owner
|
||||||
{
|
{
|
||||||
get => _owner ?? throw NoOwnerException;
|
get ;
|
||||||
protected set
|
protected set
|
||||||
{
|
{
|
||||||
_owner = value;
|
|
||||||
OnOwnerChanged(value);
|
OnOwnerChanged(value);
|
||||||
|
SetField(ref field, value);
|
||||||
}
|
}
|
||||||
}
|
} = null!;
|
||||||
|
|
||||||
public Control? Parent { get; private set; } = null;
|
public Control? Parent
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set => SetField(ref field, value);
|
||||||
|
} = null;
|
||||||
public bool Disposed { get; private set; }
|
public bool Disposed { get; private set; }
|
||||||
public virtual Box2d ClientArea => Layout.ComputedBox;
|
public virtual Box2d ClientArea => Layout.ComputedBox;
|
||||||
public bool IsFocused => _owner?.FocusedControl == this;
|
public bool IsFocused => Owner?.FocusedControl == this;
|
||||||
|
|
||||||
public Brush Background { get; set; } = new SolidColorBrush(Color.Transparent);
|
public Brush Background { get; set => SetField(ref field, value); } = new SolidColorBrush(Color.Transparent);
|
||||||
public Brush BorderBrush { get; set; } = new SolidColorBrush(Color.Black);
|
public Brush BorderBrush { get; set => SetField(ref field, value); } = new SolidColorBrush(Color.Black);
|
||||||
|
|
||||||
public LayoutInfo Layout { get; } = new LayoutInfo();
|
public LayoutInfo Layout { get; } = new LayoutInfo();
|
||||||
public bool IsLayoutEnabled { get; private set; } = true;
|
public bool IsLayoutEnabled { get; private set; } = true;
|
||||||
@@ -49,6 +55,11 @@ namespace Dashboard.Controls
|
|||||||
public event EventHandler? Disposing;
|
public event EventHandler? Disposing;
|
||||||
public event EventHandler? Resized;
|
public event EventHandler? Resized;
|
||||||
|
|
||||||
|
public Control()
|
||||||
|
{
|
||||||
|
Layout.PropertyChanged += LayoutChanged;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual Vector2 CalculateIntrinsicSize()
|
public virtual Vector2 CalculateIntrinsicSize()
|
||||||
{
|
{
|
||||||
return Vector2.Zero;
|
return Vector2.Zero;
|
||||||
@@ -74,7 +85,9 @@ namespace Dashboard.Controls
|
|||||||
{
|
{
|
||||||
if (Disposed)
|
if (Disposed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Disposed = true;
|
Disposed = true;
|
||||||
|
Layout.PropertyChanged -= LayoutChanged;
|
||||||
|
|
||||||
Dispose(disposing);
|
Dispose(disposing);
|
||||||
|
|
||||||
@@ -134,23 +147,13 @@ namespace Dashboard.Controls
|
|||||||
FocusLost?.Invoke(sender, EventArgs.Empty);
|
FocusLost?.Invoke(sender, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void InvokeFocusGained(Form form, Control control)
|
|
||||||
{
|
|
||||||
control.OnFocusGained(form);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void InvokeFocusLost(Form form, Control control)
|
|
||||||
{
|
|
||||||
control.OnFocusLost(form);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnResize()
|
protected virtual void OnResize()
|
||||||
{
|
{
|
||||||
Resized?.Invoke(this, EventArgs.Empty);
|
Resized?.Invoke(this, EventArgs.Empty);
|
||||||
InvalidateLayout();
|
InvalidateLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnOwnerChanged(Form value)
|
protected virtual void OnOwnerChanged(Form value)
|
||||||
{
|
{
|
||||||
OwnerChanged?.Invoke(this, EventArgs.Empty);
|
OwnerChanged?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
@@ -188,6 +191,26 @@ namespace Dashboard.Controls
|
|||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void LayoutChanged(object? sender, PropertyChangedEventArgs ea)
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(Layout));
|
||||||
|
}
|
||||||
|
|
||||||
protected static Exception NoOwnerException => new Exception("No form owns this control");
|
protected static Exception NoOwnerException => new Exception("No form owns this control");
|
||||||
|
|
||||||
|
internal static void InvokeFocusGained(Form form, Control control)
|
||||||
|
{
|
||||||
|
control.OnFocusGained(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void InvokeFocusLost(Form form, Control control)
|
||||||
|
{
|
||||||
|
control.OnFocusLost(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
private protected static void SetOwner(Control item, Form owner)
|
||||||
|
{
|
||||||
|
item.Owner = owner;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-17
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Numerics;
|
|
||||||
using Dashboard.Drawing;
|
using Dashboard.Drawing;
|
||||||
using Dashboard.Events;
|
using Dashboard.Events;
|
||||||
using Dashboard.Pal;
|
using Dashboard.Pal;
|
||||||
@@ -10,20 +9,18 @@ namespace Dashboard.Controls
|
|||||||
{
|
{
|
||||||
public class Form : Container, IForm
|
public class Form : Container, IForm
|
||||||
{
|
{
|
||||||
private string? _title = "Untitled Form";
|
|
||||||
public IWindow Window { get; }
|
public IWindow Window { get; }
|
||||||
|
|
||||||
public Image? WindowIcon { get; set; }
|
public Image? WindowIcon { get; set; }
|
||||||
|
|
||||||
public string? Title
|
public string Title
|
||||||
{
|
{
|
||||||
get => _title;
|
get;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_title = value;
|
field = value;
|
||||||
Window.Title = _title ?? "";
|
Window.Title = field ?? "";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} = "Untitled Form";
|
||||||
public Control? FocusedControl { get; private set; } = null;
|
public Control? FocusedControl { get; private set; } = null;
|
||||||
|
|
||||||
public override Box2d ClientArea
|
public override Box2d ClientArea
|
||||||
@@ -37,19 +34,11 @@ namespace Dashboard.Controls
|
|||||||
{
|
{
|
||||||
Window = window;
|
Window = window;
|
||||||
Window.Form = this;
|
Window.Form = this;
|
||||||
Window.Title = _title;
|
Window.Title = Title;
|
||||||
Window.EventRaised += WindowEventRaised;
|
Window.EventRaised += WindowEventRaised;
|
||||||
Background = new SolidColorBrush(Color.SlateGray);
|
Background = new SolidColorBrush(Color.SlateGray);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WindowEventRaised(object? sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (e is ResizeEventArgs)
|
|
||||||
{
|
|
||||||
InvalidateLayout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Focus(Control control)
|
public void Focus(Control control)
|
||||||
{
|
{
|
||||||
if (FocusedControl != null)
|
if (FocusedControl != null)
|
||||||
@@ -108,5 +97,20 @@ namespace Dashboard.Controls
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnChildAdded(Control item)
|
||||||
|
{
|
||||||
|
base.OnChildAdded(item);
|
||||||
|
|
||||||
|
SetOwner(item, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WindowEventRaised(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (e is ResizeEventArgs)
|
||||||
|
{
|
||||||
|
InvalidateLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user