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