diff --git a/MLEM.Startup/MlemGame.cs b/MLEM.Startup/MlemGame.cs
index e2f0c7d..3a42e26 100644
--- a/MLEM.Startup/MlemGame.cs
+++ b/MLEM.Startup/MlemGame.cs
@@ -40,15 +40,15 @@ namespace MLEM.Startup {
///
/// An event that is invoked in
///
- public GenericCallback OnLoadContent;
+ public event GenericCallback OnLoadContent;
///
/// An event that is invoked in
///
- public TimeCallback OnUpdate;
+ public event TimeCallback OnUpdate;
///
/// An event that is invoked in
///
- public TimeCallback OnDraw;
+ public event TimeCallback OnDraw;
///
/// Creates a new MlemGame instance with some default settings
diff --git a/MLEM.Ui/Elements/Element.cs b/MLEM.Ui/Elements/Element.cs
index c5ad4b5..a7b6925 100644
--- a/MLEM.Ui/Elements/Element.cs
+++ b/MLEM.Ui/Elements/Element.cs
@@ -15,7 +15,7 @@ namespace MLEM.Ui.Elements {
///
/// This class represents a generic base class for ui elements of a .
///
- public abstract class Element : GenericDataHolder {
+ public abstract class Element : GenericDataHolder, IDisposable {
///
/// A list of all of this element's direct children.
@@ -377,6 +377,11 @@ namespace MLEM.Ui.Elements {
/// Event that is called when a child is removed from this element using
///
public OtherElementCallback OnChildRemoved;
+ ///
+ /// Event that is called when this element's method is called, which also happens in .
+ /// This event is useful for unregistering global event handlers when this object should be destroyed.
+ ///
+ public GenericCallback OnDisposed;
///
/// A style property that contains the selection indicator that is displayed on this element if it is the
@@ -415,6 +420,11 @@ namespace MLEM.Ui.Elements {
this.SetSortedChildrenDirty();
}
+ ///
+ ~Element() {
+ this.Dispose();
+ }
+
///
/// Adds a child to this element.
///
@@ -430,7 +440,7 @@ namespace MLEM.Ui.Elements {
element.AndChildren(e => {
e.Root = this.Root;
e.System = this.System;
- this.Root?.OnElementAdded(e);
+ this.Root?.InvokeOnElementAdded(e);
this.OnChildAdded?.Invoke(this, e);
});
this.SetSortedChildrenDirty();
@@ -451,7 +461,7 @@ namespace MLEM.Ui.Elements {
element.AndChildren(e => {
e.Root = null;
e.System = null;
- this.Root?.OnElementRemoved(e);
+ this.Root?.InvokeOnElementRemoved(e);
this.OnChildRemoved?.Invoke(this, e);
});
this.SetSortedChildrenDirty();
@@ -618,7 +628,7 @@ namespace MLEM.Ui.Elements {
}
this.area = new RectangleF(pos, newSize);
- this.System.OnElementAreaUpdated?.Invoke(this);
+ this.System.InvokeOnElementAreaUpdated(this);
foreach (var child in this.Children)
child.ForceUpdateArea();
@@ -626,7 +636,7 @@ namespace MLEM.Ui.Elements {
if (this.SetWidthBasedOnChildren || this.SetHeightBasedOnChildren) {
Element foundChild = null;
var autoSize = this.UnscrolledArea.Size;
-
+
if (this.SetHeightBasedOnChildren) {
var lowest = this.GetLowestChild(e => !e.IsHidden);
if (lowest != null) {
@@ -638,7 +648,7 @@ namespace MLEM.Ui.Elements {
autoSize.Y = 0;
}
}
-
+
if (this.SetWidthBasedOnChildren) {
var rightmost = this.GetRightmostChild(e => !e.IsHidden);
if (rightmost != null) {
@@ -650,7 +660,7 @@ namespace MLEM.Ui.Elements {
autoSize.X = 0;
}
}
-
+
if (this.TreatSizeAsMinimum)
autoSize = Vector2.Max(autoSize, actualSize);
if (!autoSize.Equals(this.UnscrolledArea.Size, 0.01F)) {
@@ -837,7 +847,7 @@ namespace MLEM.Ui.Elements {
///
/// The game's time
public virtual void Update(GameTime time) {
- this.System.OnElementUpdated?.Invoke(this, time);
+ this.System.InvokeOnElementUpdated(this, time);
foreach (var child in this.GetRelevantChildren())
if (child.System != null)
@@ -888,9 +898,9 @@ namespace MLEM.Ui.Elements {
/// The sampler state that is used for drawing
/// The transformation matrix that is used for drawing
public virtual void Draw(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, Matrix matrix) {
- this.System.OnElementDrawn?.Invoke(this, time, batch, alpha);
+ this.System.InvokeOnElementDrawn(this, time, batch, alpha);
if (this.IsSelected)
- this.System.OnSelectedElementDrawn?.Invoke(this, time, batch, alpha);
+ this.System.InvokeOnSelectedElementDrawn(this, time, batch, alpha);
foreach (var child in this.GetRelevantChildren()) {
if (!child.IsHidden)
@@ -935,6 +945,12 @@ namespace MLEM.Ui.Elements {
return this.CanBeMoused && this.DisplayArea.Contains(position) ? this : null;
}
+ ///
+ public virtual void Dispose() {
+ this.OnDisposed?.Invoke(this);
+ GC.SuppressFinalize(this);
+ }
+
///
/// Performs the specified action on this element and all of its
///
diff --git a/MLEM.Ui/Elements/Panel.cs b/MLEM.Ui/Elements/Panel.cs
index 22ffa96..b6c23ca 100644
--- a/MLEM.Ui/Elements/Panel.cs
+++ b/MLEM.Ui/Elements/Panel.cs
@@ -15,7 +15,7 @@ namespace MLEM.Ui.Elements {
/// Additionally, a panel can be set to on construction, which causes all elements that don't fit into the panel to be hidden until scrolled to using a .
/// As this behavior is accomplished using a , scrolling panels need to have their methods called using .
///
- public class Panel : Element, IDisposable {
+ public class Panel : Element {
///
/// The texture that this panel should have, or null if it should be invisible.
@@ -76,11 +76,6 @@ namespace MLEM.Ui.Elements {
}
}
- ///
- ~Panel() {
- this.Dispose();
- }
-
///
public override void ForceUpdateArea() {
if (this.scrollOverflow) {
@@ -237,12 +232,12 @@ namespace MLEM.Ui.Elements {
}
///
- public void Dispose() {
+ public override void Dispose() {
if (this.renderTarget != null) {
this.renderTarget.Dispose();
this.renderTarget = null;
}
- GC.SuppressFinalize(this);
+ base.Dispose();
}
}
diff --git a/MLEM.Ui/UiControls.cs b/MLEM.Ui/UiControls.cs
index 1b9adf7..9821353 100644
--- a/MLEM.Ui/UiControls.cs
+++ b/MLEM.Ui/UiControls.cs
@@ -151,11 +151,11 @@ namespace MLEM.Ui {
var selectedNow = mousedNow != null && mousedNow.CanBeSelected ? mousedNow : null;
this.SelectElement(this.ActiveRoot, selectedNow);
if (mousedNow != null && mousedNow.CanBePressed)
- this.System.OnElementPressed?.Invoke(mousedNow);
+ this.System.InvokeOnElementPressed(mousedNow);
} else if (this.Input.IsMouseButtonPressed(MouseButton.Right)) {
this.IsAutoNavMode = false;
if (mousedNow != null && mousedNow.CanBePressed)
- this.System.OnElementSecondaryPressed?.Invoke(mousedNow);
+ this.System.InvokeOnElementSecondaryPressed(mousedNow);
}
}
@@ -165,10 +165,10 @@ namespace MLEM.Ui {
if (this.SelectedElement?.Root != null && this.SelectedElement.CanBePressed) {
if (this.Input.IsModifierKeyDown(ModifierKey.Shift)) {
// secondary action on element using space or enter
- this.System.OnElementSecondaryPressed?.Invoke(this.SelectedElement);
+ this.System.InvokeOnElementSecondaryPressed(this.SelectedElement);
} else {
// first action on element using space or enter
- this.System.OnElementPressed?.Invoke(this.SelectedElement);
+ this.System.InvokeOnElementPressed(this.SelectedElement);
}
}
} else if (this.Input.IsKeyPressed(Keys.Tab)) {
@@ -189,13 +189,13 @@ namespace MLEM.Ui {
var tapped = this.GetElementUnderPos(tap.Position);
this.SelectElement(this.ActiveRoot, tapped);
if (tapped != null && tapped.CanBePressed)
- this.System.OnElementPressed?.Invoke(tapped);
+ this.System.InvokeOnElementPressed(tapped);
} else if (this.Input.GetGesture(GestureType.Hold, out var hold)) {
this.IsAutoNavMode = false;
var held = this.GetElementUnderPos(hold.Position);
this.SelectElement(this.ActiveRoot, held);
if (held != null && held.CanBePressed)
- this.System.OnElementSecondaryPressed?.Invoke(held);
+ this.System.InvokeOnElementSecondaryPressed(held);
} else if (this.Input.TouchState.Count <= 0) {
this.SetTouchedElement(null);
} else {
@@ -216,10 +216,10 @@ namespace MLEM.Ui {
if (this.HandleGamepad) {
if (this.GamepadButtons.IsPressed(this.Input, this.GamepadIndex)) {
if (this.SelectedElement?.Root != null && this.SelectedElement.CanBePressed)
- this.System.OnElementPressed?.Invoke(this.SelectedElement);
+ this.System.InvokeOnElementPressed(this.SelectedElement);
} else if (this.SecondaryGamepadButtons.IsPressed(this.Input, this.GamepadIndex)) {
if (this.SelectedElement?.Root != null && this.SelectedElement.CanBePressed)
- this.System.OnElementSecondaryPressed?.Invoke(this.SelectedElement);
+ this.System.InvokeOnElementSecondaryPressed(this.SelectedElement);
} else if (this.DownButtons.IsPressed(this.Input, this.GamepadIndex)) {
this.HandleGamepadNextElement(Direction2.Down);
} else if (this.LeftButtons.IsPressed(this.Input, this.GamepadIndex)) {
@@ -265,14 +265,14 @@ namespace MLEM.Ui {
return;
if (selected != null)
- this.System.OnElementDeselected?.Invoke(selected);
+ this.System.InvokeOnElementDeselected(selected);
if (element != null) {
- this.System.OnElementSelected?.Invoke(element);
+ this.System.InvokeOnElementSelected(element);
this.selectedElements[root.Name] = element;
} else {
this.selectedElements.Remove(root.Name);
}
- this.System.OnSelectedElementChanged?.Invoke(element);
+ this.System.InvokeOnSelectedElementChanged(element);
if (autoNav != null)
this.IsAutoNavMode = autoNav.Value;
@@ -285,11 +285,11 @@ namespace MLEM.Ui {
public void SetMousedElement(Element element) {
if (element != this.MousedElement) {
if (this.MousedElement != null)
- this.System.OnElementMouseExit?.Invoke(this.MousedElement);
+ this.System.InvokeOnElementMouseExit(this.MousedElement);
if (element != null)
- this.System.OnElementMouseEnter?.Invoke(element);
+ this.System.InvokeOnElementMouseEnter(element);
this.MousedElement = element;
- this.System.OnMousedElementChanged?.Invoke(element);
+ this.System.InvokeOnMousedElementChanged(element);
}
}
@@ -300,11 +300,11 @@ namespace MLEM.Ui {
public void SetTouchedElement(Element element) {
if (element != this.TouchedElement) {
if (this.TouchedElement != null)
- this.System.OnElementTouchExit?.Invoke(this.TouchedElement);
+ this.System.InvokeOnElementTouchExit(this.TouchedElement);
if (element != null)
- this.System.OnElementTouchEnter?.Invoke(element);
+ this.System.InvokeOnElementTouchEnter(element);
this.TouchedElement = element;
- this.System.OnTouchedElementChanged?.Invoke(element);
+ this.System.InvokeOnTouchedElementChanged(element);
}
}
diff --git a/MLEM.Ui/UiSystem.cs b/MLEM.Ui/UiSystem.cs
index 6caceaa..764025d 100644
--- a/MLEM.Ui/UiSystem.cs
+++ b/MLEM.Ui/UiSystem.cs
@@ -96,71 +96,71 @@ namespace MLEM.Ui {
///
/// Event that is invoked after an is drawn, but before its children are drawn.
///
- public Element.DrawCallback OnElementDrawn = (e, time, batch, alpha) => e.OnDrawn?.Invoke(e, time, batch, alpha);
+ public event Element.DrawCallback OnElementDrawn;
///
/// Event that is invoked after the for each root element is drawn, but before its children are drawn.
///
- public Element.DrawCallback OnSelectedElementDrawn;
+ public event Element.DrawCallback OnSelectedElementDrawn;
///
/// Event that is invoked when an is updated
///
- public Element.TimeCallback OnElementUpdated = (e, time) => e.OnUpdated?.Invoke(e, time);
+ public event Element.TimeCallback OnElementUpdated;
///
/// Event that is invoked when an is pressed with the primary action key
///
- public Element.GenericCallback OnElementPressed = e => e.OnPressed?.Invoke(e);
+ public event Element.GenericCallback OnElementPressed;
///
/// Event that is invoked when an is pressed with the secondary action key
///
- public Element.GenericCallback OnElementSecondaryPressed = e => e.OnSecondaryPressed?.Invoke(e);
+ public event Element.GenericCallback OnElementSecondaryPressed;
///
/// Event that is invoked when an is newly selected using automatic navigation, or after it has been pressed with the mouse.
///
- public Element.GenericCallback OnElementSelected = e => e.OnSelected?.Invoke(e);
+ public event Element.GenericCallback OnElementSelected;
///
/// Event that is invoked when an is deselected during the selection of a new element.
///
- public Element.GenericCallback OnElementDeselected = e => e.OnDeselected?.Invoke(e);
+ public event Element.GenericCallback OnElementDeselected;
///
/// Event that is invoked when the mouse enters an
///
- public Element.GenericCallback OnElementMouseEnter = e => e.OnMouseEnter?.Invoke(e);
+ public event Element.GenericCallback OnElementMouseEnter;
///
/// Event that is invoked when the mouse exits an
///
- public Element.GenericCallback OnElementMouseExit = e => e.OnMouseExit?.Invoke(e);
+ public event Element.GenericCallback OnElementMouseExit;
///
/// Event that is invoked when an starts being touched
///
- public Element.GenericCallback OnElementTouchEnter = e => e.OnTouchEnter?.Invoke(e);
+ public event Element.GenericCallback OnElementTouchEnter;
///
/// Event that is invoked when an stops being touched
///
- public Element.GenericCallback OnElementTouchExit = e => e.OnTouchExit?.Invoke(e);
+ public event Element.GenericCallback OnElementTouchExit;
///
/// Event that is invoked when an 's display area changes
///
- public Element.GenericCallback OnElementAreaUpdated = e => e.OnAreaUpdated?.Invoke(e);
+ public event Element.GenericCallback OnElementAreaUpdated;
///
/// Event that is invoked when the that the mouse is currently over changes
///
- public Element.GenericCallback OnMousedElementChanged;
+ public event Element.GenericCallback OnMousedElementChanged;
///
/// Event that is invoked when the that is being touched changes
///
- public Element.GenericCallback OnTouchedElementChanged;
+ public event Element.GenericCallback OnTouchedElementChanged;
///
/// Event that is invoked when the selected changes, either through automatic navigation, or by pressing on an element with the mouse
///
- public Element.GenericCallback OnSelectedElementChanged;
+ public event Element.GenericCallback OnSelectedElementChanged;
///
/// Event that is invoked when a new is added to this ui system
///
- public RootCallback OnRootAdded;
+ public event RootCallback OnRootAdded;
///
/// Event that is invoked when a is removed from this ui system
///
- public RootCallback OnRootRemoved;
+ public event RootCallback OnRootRemoved;
///
/// Creates a new ui system with the given settings.
@@ -172,6 +172,17 @@ namespace MLEM.Ui {
public UiSystem(Game game, UiStyle style, InputHandler inputHandler = null, bool automaticViewport = true) : base(game) {
this.Controls = new UiControls(this, inputHandler);
this.style = style;
+ this.OnElementDrawn += (e, time, batch, alpha) => e.OnDrawn?.Invoke(e, time, batch, alpha);
+ this.OnElementUpdated += (e, time) => e.OnUpdated?.Invoke(e, time);
+ this.OnElementPressed += e => e.OnPressed?.Invoke(e);
+ this.OnElementSecondaryPressed += e => e.OnSecondaryPressed?.Invoke(e);
+ this.OnElementSelected += e => e.OnSelected?.Invoke(e);
+ this.OnElementDeselected += e => e.OnDeselected?.Invoke(e);
+ this.OnElementMouseEnter += e => e.OnMouseEnter?.Invoke(e);
+ this.OnElementMouseExit += e => e.OnMouseExit?.Invoke(e);
+ this.OnElementTouchEnter += e => e.OnTouchEnter?.Invoke(e);
+ this.OnElementTouchExit += e => e.OnTouchExit?.Invoke(e);
+ this.OnElementAreaUpdated += e => e.OnAreaUpdated?.Invoke(e);
if (automaticViewport) {
this.Viewport = new Rectangle(Point.Zero, game.Window.ClientBounds.Size);
@@ -264,11 +275,11 @@ namespace MLEM.Ui {
root.Element.AndChildren(e => {
e.Root = root;
e.System = this;
- root.OnElementAdded(e);
+ root.InvokeOnElementAdded(e);
e.SetAreaDirty();
});
this.OnRootAdded?.Invoke(root);
- root.OnAddedToUi?.Invoke(this);
+ root.InvokeOnAddedToUi(this);
this.SortRoots();
return root;
}
@@ -286,11 +297,11 @@ namespace MLEM.Ui {
root.Element.AndChildren(e => {
e.Root = null;
e.System = null;
- root.OnElementRemoved(e);
+ root.InvokeOnElementRemoved(e);
e.SetAreaDirty();
});
this.OnRootRemoved?.Invoke(root);
- root.OnRemovedFromUi?.Invoke(this);
+ root.InvokeOnRemovedFromUi(this);
}
///
@@ -333,6 +344,22 @@ namespace MLEM.Ui {
root.Element.AndChildren(action);
}
+ internal void InvokeOnElementDrawn(Element element, GameTime time, SpriteBatch batch, float alpha) => this.OnElementDrawn?.Invoke(element, time, batch, alpha);
+ internal void InvokeOnSelectedElementDrawn(Element element, GameTime time, SpriteBatch batch, float alpha) => this.OnSelectedElementDrawn?.Invoke(element, time, batch, alpha);
+ internal void InvokeOnElementUpdated(Element element, GameTime time) => this.OnElementUpdated?.Invoke(element, time);
+ internal void InvokeOnElementAreaUpdated(Element element) => this.OnElementAreaUpdated?.Invoke(element);
+ internal void InvokeOnElementPressed(Element element) => this.OnElementPressed?.Invoke(element);
+ internal void InvokeOnElementSecondaryPressed(Element element) => this.OnElementSecondaryPressed?.Invoke(element);
+ internal void InvokeOnElementSelected(Element element) => this.OnElementSelected?.Invoke(element);
+ internal void InvokeOnElementDeselected(Element element) => this.OnElementDeselected?.Invoke(element);
+ internal void InvokeOnSelectedElementChanged(Element element) => this.OnSelectedElementChanged?.Invoke(element);
+ internal void InvokeOnElementMouseExit(Element element) => this.OnElementMouseExit?.Invoke(element);
+ internal void InvokeOnElementMouseEnter(Element element) => this.OnElementMouseEnter?.Invoke(element);
+ internal void InvokeOnMousedElementChanged(Element element) => this.OnMousedElementChanged?.Invoke(element);
+ internal void InvokeOnElementTouchExit(Element element) => this.OnElementTouchExit?.Invoke(element);
+ internal void InvokeOnElementTouchEnter(Element element) => this.OnElementTouchEnter?.Invoke(element);
+ internal void InvokeOnTouchedElementChanged(Element element) => this.OnTouchedElementChanged?.Invoke(element);
+
///
/// A delegate used for callbacks that involve a
///
@@ -346,7 +373,7 @@ namespace MLEM.Ui {
/// Root elements are only used for the element in each element tree that doesn't have a
/// To create a new root element, use
///
- public class RootElement {
+ public class RootElement : GenericDataHolder {
///
/// The name of this root element
@@ -417,19 +444,19 @@ namespace MLEM.Ui {
///
/// Event that is invoked when a is added to this root element or any of its children.
///
- public Element.GenericCallback OnElementAdded;
+ public event Element.GenericCallback OnElementAdded;
///
/// Event that is invoked when a is removed rom this root element of any of its children.
///
- public Element.GenericCallback OnElementRemoved;
+ public event Element.GenericCallback OnElementRemoved;
///
/// Event that is invoked when this gets added to a in
///
- public Action OnAddedToUi;
+ public event Action OnAddedToUi;
///
/// Event that is invoked when this gets removed from a in
///
- public Action OnRemovedFromUi;
+ public event Action OnRemovedFromUi;
internal RootElement(string name, Element element, UiSystem system) {
this.Name = name;
@@ -465,5 +492,10 @@ namespace MLEM.Ui {
this.Transform = Matrix.CreateScale(scale, scale, 1) * Matrix.CreateTranslation(new Vector3((1 - scale) * (origin ?? this.Element.DisplayArea.Center), 0));
}
+ internal void InvokeOnElementAdded(Element element) => this.OnElementAdded?.Invoke(element);
+ internal void InvokeOnElementRemoved(Element element) => this.OnElementRemoved?.Invoke(element);
+ internal void InvokeOnAddedToUi(UiSystem system) => this.OnAddedToUi?.Invoke(system);
+ internal void InvokeOnRemovedFromUi(UiSystem system) => this.OnRemovedFromUi?.Invoke(system);
+
}
}
\ No newline at end of file