1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-12-24 01:09:23 +01:00

added the ability to transform the entire ui

This commit is contained in:
Ellpeck 2019-09-02 19:55:26 +02:00
parent 64eefedac0
commit 0dff0e275d
7 changed files with 41 additions and 19 deletions

View file

@ -139,12 +139,21 @@ namespace Demos {
root.AddChild(new Paragraph(Anchor.AutoLeft, 1, paragraph => "Slider is at " + (slider.CurrentValue * 100).Floor() + "%") {PositionOffset = new Vector2(0, 1)});
root.AddChild(slider);
// This button uses a coroutine from my Coroutine NuGet package (which is included with MLEM.Startup)
// but the important thing it does is change its visual scale and offset (check the method below for more info)
root.AddChild(new Button(Anchor.AutoCenter, new Vector2(0.5F, 10), "Wobble", "This button wobbles around visually when clicked, but this doesn't affect its actual size and positioning") {
// Check the WobbleButton method for an explanation of how this button works
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(this.WobbleButton(element)),
PositionOffset = new Vector2(0, 1)
});
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). As this is an easily pulled off operation, it can be used for animations and other gimmicks.") {
OnPressed = element => {
if (element.Root.Transform == Matrix.Identity) {
element.Root.Transform = Matrix.CreateScale(0.75F) * Matrix.CreateRotationZ(0.25F) * Matrix.CreateTranslation(50, -10, 0);
} else {
element.Root.Transform = Matrix.Identity;
}
},
PositionOffset = new Vector2(0, 1)
});
root.AddChild(new VerticalSpace(3));
root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "There are also some additional \"components\" which are created as combinations of other components. You can find all of them in the ElementHelper class. Here are some examples:"));
@ -183,7 +192,7 @@ namespace Demos {
}
// This method is used by the wobbling button (see above)
// Note that this particular example makes use of the Coroutine package
// Note that this particular example makes use of the Coroutine package, which is not required but makes demonstration easier
private IEnumerator<Wait> WobbleButton(Element button) {
var counter = 0F;
while (counter < 4 * Math.PI) {

View file

@ -436,10 +436,10 @@ namespace MLEM.Ui.Elements {
this.System.OnSelectedElementDrawn?.Invoke(this, time, batch, alpha, offset);
}
public virtual void DrawEarly(GameTime time, SpriteBatch batch, float alpha, BlendState blendState = null, SamplerState samplerState = null) {
public virtual void DrawEarly(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, Matrix matrix) {
foreach (var child in this.SortedChildren) {
if (!child.IsHidden)
child.DrawEarly(time, batch, alpha * child.DrawAlpha, blendState, samplerState);
child.DrawEarly(time, batch, alpha * child.DrawAlpha, blendState, samplerState, matrix);
}
}

View file

@ -103,11 +103,12 @@ namespace MLEM.Ui.Elements {
}
}
public override void DrawEarly(GameTime time, SpriteBatch batch, float alpha, BlendState blendState = null, SamplerState samplerState = null) {
public override void DrawEarly(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, Matrix matrix) {
if (this.scrollOverflow && this.renderTarget != null) {
// draw children onto the render target
batch.GraphicsDevice.SetRenderTarget(this.renderTarget);
batch.GraphicsDevice.Clear(Color.Transparent);
// we don't apply the matrix here because it's already applied when drawing the render target
batch.Begin(SpriteSortMode.Deferred, blendState, samplerState);
// offset children by the render target's location
var area = this.GetRenderTargetArea();
@ -115,7 +116,7 @@ namespace MLEM.Ui.Elements {
batch.End();
batch.GraphicsDevice.SetRenderTarget(null);
}
base.DrawEarly(time, batch, alpha, blendState, samplerState);
base.DrawEarly(time, batch, alpha, blendState, samplerState, matrix);
}
public override Element GetElementUnderPos(Point position) {

View file

@ -67,7 +67,7 @@ namespace MLEM.Ui.Elements {
this.isMouseHeld = false;
}
if (this.isMouseHeld)
this.ScrollToPos(this.Input.MousePosition);
this.ScrollToPos(this.Input.MousePosition.Transform(this.Root.InvTransform));
if (!this.Horizontal && moused != null && (moused == this.Parent || moused.GetParentTree().Contains(this.Parent))) {
var scroll = this.Input.LastScrollWheel - this.Input.ScrollWheel;
if (scroll != 0)
@ -79,7 +79,7 @@ namespace MLEM.Ui.Elements {
// are we dragging on top of the panel?
if (this.Input.GetGesture(GestureType.VerticalDrag, out var drag)) {
// if the element under the drag's start position is on top of the panel, start dragging
var touched = this.Parent.GetElementUnderPos(drag.Position.ToPoint());
var touched = this.Parent.GetElementUnderPos(drag.Position.ToPoint().Transform(this.Root.InvTransform));
if (touched != null && touched != this)
this.isDragging = true;
@ -95,14 +95,15 @@ namespace MLEM.Ui.Elements {
this.isTouchHeld = false;
} else {
foreach (var loc in this.Input.TouchState) {
var pos = Vector2.Transform(loc.Position, this.Root.InvTransform);
// if we just started touching and are on top of the scroller, then we should start scrolling
if (this.DisplayArea.Contains(loc.Position) && !loc.TryGetPreviousLocation(out _)) {
if (this.DisplayArea.Contains(pos) && !loc.TryGetPreviousLocation(out _)) {
this.isTouchHeld = true;
break;
}
// scroll no matter if we're on the scroller right now
if (this.isTouchHeld)
this.ScrollToPos(loc.Position.ToPoint());
this.ScrollToPos(pos.ToPoint());
}
}
}

View file

@ -3,6 +3,7 @@ using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using MLEM.Extensions;
using MLEM.Input;
using MLEM.Ui.Elements;
@ -40,7 +41,7 @@ namespace MLEM.Ui {
this.MousedElement = mousedNow;
this.system.ApplyToAll(e => e.OnMousedElementChanged?.Invoke(e, mousedNow));
}
if (this.Input.IsMouseButtonPressed(MouseButton.Left)) {
var selectedNow = mousedNow != null && mousedNow.CanBeSelected ? mousedNow : null;
this.SelectElement(selectedNow, true);
@ -50,7 +51,7 @@ namespace MLEM.Ui {
if (mousedNow != null)
mousedNow.OnSecondaryPressed?.Invoke(mousedNow);
}
// KEYBOARD INPUT
else if (this.Input.IsKeyPressed(Keys.Enter) || this.Input.IsKeyPressed(Keys.Space)) {
if (this.SelectedElement != null) {
@ -66,7 +67,7 @@ namespace MLEM.Ui {
// tab or shift-tab to next or previous element
this.SelectElement(this.GetNextElement(this.Input.IsModifierKeyDown(ModifierKey.Shift)), false);
}
// TOUCH INPUT
else if (this.Input.GetGesture(GestureType.Tap, out var tap)) {
var tapped = this.GetElementUnderPos(tap.Position.ToPoint());
@ -94,9 +95,10 @@ namespace MLEM.Ui {
this.system.ApplyToAll(e => e.OnSelectedElementChanged?.Invoke(e, element));
}
public Element GetElementUnderPos(Point position) {
public Element GetElementUnderPos(Point position, bool transform = true) {
foreach (var root in this.system.GetRootElements()) {
var moused = root.Element.GetElementUnderPos(position);
var pos = transform ? position.Transform(root.InvTransform) : position;
var moused = root.Element.GetElementUnderPos(pos);
if (moused != null)
return moused;
}

View file

@ -91,7 +91,7 @@ namespace MLEM.Ui {
public void DrawEarly(GameTime time, SpriteBatch batch) {
foreach (var root in this.rootElements) {
if (!root.Element.IsHidden)
root.Element.DrawEarly(time, batch, this.DrawAlpha * root.Element.DrawAlpha, this.BlendState, this.SamplerState);
root.Element.DrawEarly(time, batch, this.DrawAlpha * root.Element.DrawAlpha, this.BlendState, this.SamplerState, root.Transform);
}
}
@ -99,7 +99,7 @@ namespace MLEM.Ui {
foreach (var root in this.rootElements) {
if (root.Element.IsHidden)
continue;
batch.Begin(SpriteSortMode.Deferred, this.BlendState, this.SamplerState);
batch.Begin(SpriteSortMode.Deferred, this.BlendState, this.SamplerState, null, null, null, root.Transform);
root.Element.Draw(time, batch, this.DrawAlpha * root.Element.DrawAlpha, Point.Zero);
batch.End();
}
@ -173,6 +173,9 @@ namespace MLEM.Ui {
public float ActualScale => this.System.GlobalScale * this.Scale;
public bool CanSelectContent = true;
public Matrix Transform = Matrix.Identity;
public Matrix InvTransform => Matrix.Invert(this.Transform);
public RootElement(string name, Element element, UiSystem system) {
this.Name = name;
this.Element = element;

View file

@ -32,6 +32,12 @@ namespace MLEM.Extensions {
return new Point((point.X / f).Floor(), (point.Y / f).Floor());
}
public static Point Transform(this Point position, Matrix matrix) {
return new Point(
(position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M41).Floor(),
(position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M42).Floor());
}
public static Rectangle OffsetCopy(this Rectangle rect, Point offset) {
rect.X += offset.X;
rect.Y += offset.Y;