diff --git a/Demos/UiDemo.cs b/Demos/UiDemo.cs index 1e67f5e..ee70b48 100644 --- a/Demos/UiDemo.cs +++ b/Demos/UiDemo.cs @@ -138,9 +138,8 @@ namespace Demos { this.root.AddChild(slider); // Check the WobbleButton method for an explanation of how this button works - var group = this.root.AddChild(new CustomDrawGroup(Anchor.AutoLeft, new Vector2(1, 0))); - group.AddChild(new Button(Anchor.AutoCenter, new Vector2(0.5F, 10), "Wobble Me", "This button wobbles around visually when clicked, but this doesn't affect its actual size and positioning") { - OnPressed = element => CoroutineHandler.Start(WobbleButton(group)), + this.root.AddChild(new Button(Anchor.AutoCenter, new Vector2(0.5F, 10), "Wobble Me", "This button wobbles around visually when clicked, but this doesn't affect its actual size and positioning") { + OnPressed = element => CoroutineHandler.Start(WobbleButton(element)), PositionOffset = new Vector2(0, 1) }); this.root.AddChild(new Button(Anchor.AutoCenter, new Vector2(0.5F, 10), "Transform Ui", "This button causes the entire ui to be transformed (both in positioning, rotation and scale)") { @@ -200,20 +199,20 @@ namespace Demos { // This method is used by the wobbling button (see above) // Note that this particular example makes use of the Coroutine package, which is not required but makes demonstration easier - private static IEnumerator WobbleButton(CustomDrawGroup group) { + private static IEnumerator WobbleButton(Element button) { var counter = 0F; while (counter < 4 * Math.PI) { - // A custom draw group allows the implementation of any sort of custom rendering for all of its child components + // Every element allows the implementation of any sort of custom rendering for itself and all of its child components // This includes simply changing the transform matrix like here, but also applying custom effects and doing // anything else that can be done in the SpriteBatch's Begin call. // Note that changing visual features like this // has no effect on the ui's actual interaction behavior (mouse position interpretation, for example), but it can // be a great way to accomplish feedback animations for buttons and so on. - group.Transform = Matrix.CreateTranslation((float) Math.Sin(counter / 2) * 10 * group.Scale, 0, 0); + button.Transform = Matrix.CreateTranslation((float) Math.Sin(counter / 2) * 10 * button.Scale, 0, 0); counter += 0.1F; yield return new Wait(0.01F); } - group.Transform = Matrix.Identity; + button.Transform = Matrix.Identity; } private static IEnumerator WobbleProgressBar(ProgressBar bar) { diff --git a/MLEM.Ui/Elements/CustomDrawGroup.cs b/MLEM.Ui/Elements/CustomDrawGroup.cs index 43dd6c7..b28e07a 100644 --- a/MLEM.Ui/Elements/CustomDrawGroup.cs +++ b/MLEM.Ui/Elements/CustomDrawGroup.cs @@ -1,42 +1,23 @@ +using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace MLEM.Ui.Elements { /// /// A that can have custom drawing parameters. - /// Custom drawing parameters include a matrix, as well as a custom call. + /// Custom drawing parameters include a matrix, as well as a custom call. /// All of the custom draw group will be drawn with the custom parameters. /// + [Obsolete("CustomDrawGroup mechanics have been moved down to Element, which means custom draw groups are no longer necessary.")] public class CustomDrawGroup : Group { - /// - /// This custom draw group's transform matrix - /// - public Matrix? Transform; - /// - /// A callback for retrieving this group's automatically - /// - public TransformCallback TransformGetter; - private BeginDelegate beginImpl; - private bool isDefaultBegin; - /// - /// The call that this custom draw group should make to to begin drawing. - /// - public BeginDelegate BeginImpl { - get => this.beginImpl; - set { - this.beginImpl = value ?? ((element, time, batch, alpha, blendState, samplerState, matrix) => batch.Begin(SpriteSortMode.Deferred, blendState, samplerState, null, null, null, matrix)); - this.isDefaultBegin = value == null; - } - } - /// /// Creates a new custom draw group with the given settings /// /// The group's anchor /// The group's size - /// The group's - /// The group's + /// The group's + /// The group's /// Whether this group should automatically calculate its height based on its children public CustomDrawGroup(Anchor anchor, Vector2 size, TransformCallback transformGetter = null, BeginDelegate beginImpl = null, bool setHeightBasedOnChildren = true) : base(anchor, size, setHeightBasedOnChildren) { @@ -44,54 +25,11 @@ namespace MLEM.Ui.Elements { this.BeginImpl = beginImpl; } - /// - public override void Draw(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, Matrix matrix) { - var transform = this.Transform ?? this.TransformGetter(this, time, matrix); - var customDraw = !this.isDefaultBegin || transform != Matrix.Identity; - var mat = matrix * transform; - if (customDraw) { - // end the usual draw so that we can begin our own - batch.End(); - this.BeginImpl(this, time, batch, alpha, blendState, samplerState, mat); - } - // draw child components in custom begin call - base.Draw(time, batch, alpha, blendState, samplerState, mat); - if (customDraw) { - // end our draw - batch.End(); - // begin the usual draw again for other elements - batch.Begin(SpriteSortMode.Deferred, blendState, samplerState, null, null, null, matrix); - } - } - - /// - /// Scales this custom draw group's matrix based on the given scale and origin. - /// - /// The scale to use - /// The origin to use for scaling, or null to use this element's center point + /// + [Obsolete("Use ScaleTransform instead")] public void ScaleOrigin(float scale, Vector2? origin = null) { - this.Transform = Matrix.CreateScale(scale, scale, 1) * Matrix.CreateTranslation(new Vector3((1 - scale) * (origin ?? this.DisplayArea.Center), 0)); + this.ScaleTransform(scale, origin); } - /// - /// A delegate method used for - /// - /// The custom draw group - /// The game's time - /// The sprite batch used for drawing - /// This element's draw alpha - /// The blend state used for drawing - /// The sampler state used for drawing - /// The transform matrix used for drawing - public delegate void BeginDelegate(CustomDrawGroup element, GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, Matrix matrix); - - /// - /// A delegate method used for - /// - /// The element whose transform to get - /// The game's time - /// The regular transform matrix - public delegate Matrix TransformCallback(CustomDrawGroup element, GameTime time, Matrix matrix); - } } \ No newline at end of file diff --git a/MLEM.Ui/Elements/Element.cs b/MLEM.Ui/Elements/Element.cs index 645cc08..f6b2e88 100644 --- a/MLEM.Ui/Elements/Element.cs +++ b/MLEM.Ui/Elements/Element.cs @@ -225,6 +225,22 @@ namespace MLEM.Ui.Elements { } } + /// + /// This element's transform matrix. + /// Can easily be scaled using . + /// Note that, when this is non-null, a new call is used for this element. + /// + public Matrix? Transform; + /// + /// A callback for retrieving this element's automatically. + /// + public TransformCallback TransformGetter = (e, time, m) => Matrix.Identity; + /// + /// The call that this element should make to to begin drawing. + /// Note that, when this is non-null, a new call is used for this element. + /// + public BeginDelegate BeginImpl; + /// /// Set this field to false to disallow the element from being selected. /// An unselectable element is skipped by automatic navigation and its callback will never be called. @@ -379,6 +395,8 @@ namespace MLEM.Ui.Elements { this.anchor = anchor; this.size = size; + // force BeginImpl to be reset to the default + this.BeginImpl = null; this.OnMouseEnter += element => this.IsMouseOver = true; this.OnMouseExit += element => this.IsMouseOver = false; this.OnTouchEnter += element => this.IsMouseOver = true; @@ -806,8 +824,42 @@ namespace MLEM.Ui.Elements { } /// - /// Draws this element and all of its - /// Note that, when this is called, has already been called. + /// Draws this element by calling internally. + /// If or is set, a new call is also started. + /// + /// The game's time + /// The sprite batch to use for drawing + /// The alpha to draw this element and its children with + /// The blend state that is used for drawing + /// The sampler state that is used for drawing + /// The transformation matrix that is used for drawing + public void DrawAll(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, Matrix matrix) { + var transform = this.Transform ?? this.TransformGetter(this, time, matrix); + var customDraw = this.BeginImpl != null || transform != Matrix.Identity; + var mat = matrix * transform; + if (customDraw) { + // end the usual draw so that we can begin our own + batch.End(); + // begin our own draw call + if (this.BeginImpl != null) { + this.BeginImpl(this, time, batch, alpha, blendState, samplerState, mat); + } else { + batch.Begin(SpriteSortMode.Deferred, blendState, samplerState, null, null, null, mat); + } + } + // draw content in custom begin call + this.Draw(time, batch, alpha, blendState, samplerState, mat); + if (customDraw) { + // end our draw + batch.End(); + // begin the usual draw again for other elements + batch.Begin(SpriteSortMode.Deferred, blendState, samplerState, null, null, null, matrix); + } + } + + /// + /// Draws this element and all of its children. Override this method to draw the content of custom elements. + /// Note that, when this is called, has already been called with custom etc. applied. /// /// The game's time /// The sprite batch to use for drawing @@ -822,7 +874,7 @@ namespace MLEM.Ui.Elements { foreach (var child in this.GetRelevantChildren()) { if (!child.IsHidden) - child.Draw(time, batch, alpha * child.DrawAlpha, blendState, samplerState, matrix); + child.DrawAll(time, batch, alpha * child.DrawAlpha, blendState, samplerState, matrix); } } @@ -888,6 +940,15 @@ namespace MLEM.Ui.Elements { this.Children.Reverse(index, count ?? this.Children.Count); } + /// + /// Scales this element's matrix based on the given scale and origin. + /// + /// The scale to use + /// The origin to use for scaling, or null to use this element's center point + public void ScaleTransform(float scale, Vector2? origin = null) { + this.Transform = Matrix.CreateScale(scale, scale, 1) * Matrix.CreateTranslation(new Vector3((1 - scale) * (origin ?? this.DisplayArea.Center), 0)); + } + /// /// Initializes this element's instances using the ui system's . /// @@ -949,5 +1010,25 @@ namespace MLEM.Ui.Elements { /// The element that is considered to be the next element by default public delegate Element GamepadNextElementCallback(Direction2 dir, Element usualNext); + /// + /// A delegate method used for + /// + /// The custom draw group + /// The game's time + /// The sprite batch used for drawing + /// This element's draw alpha + /// The blend state used for drawing + /// The sampler state used for drawing + /// The transform matrix used for drawing + public delegate void BeginDelegate(Element element, GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, Matrix matrix); + + /// + /// A delegate method used for + /// + /// The element whose transform to get + /// The game's time + /// The regular transform matrix + public delegate Matrix TransformCallback(Element element, GameTime time, Matrix matrix); + } } \ No newline at end of file diff --git a/MLEM.Ui/UiSystem.cs b/MLEM.Ui/UiSystem.cs index 2754393..2f113a5 100644 --- a/MLEM.Ui/UiSystem.cs +++ b/MLEM.Ui/UiSystem.cs @@ -260,7 +260,7 @@ namespace MLEM.Ui { continue; batch.Begin(SpriteSortMode.Deferred, this.BlendState, this.SamplerState, null, null, null, root.Transform); var alpha = this.DrawAlpha * root.Element.DrawAlpha; - root.Element.Draw(time, batch, alpha, this.BlendState, this.SamplerState, root.Transform); + root.Element.DrawAll(time, batch, alpha, this.BlendState, this.SamplerState, root.Transform); batch.End(); } }