1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-11-01 05:10:50 +01:00
MLEM/MLEM.Ui/UiSystem.cs

196 lines
6.7 KiB
C#
Raw Normal View History

2019-08-09 18:26:28 +02:00
using System;
using System.Collections.Generic;
2019-08-28 18:27:17 +02:00
using System.Linq;
2019-08-09 18:26:28 +02:00
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
2019-08-09 18:26:28 +02:00
using MLEM.Extensions;
2019-08-09 19:28:48 +02:00
using MLEM.Font;
using MLEM.Input;
using MLEM.Textures;
2019-08-09 18:26:28 +02:00
using MLEM.Ui.Elements;
2019-08-10 21:37:10 +02:00
using MLEM.Ui.Style;
2019-08-09 18:26:28 +02:00
namespace MLEM.Ui {
public class UiSystem {
2019-08-10 18:41:56 +02:00
public readonly GraphicsDevice GraphicsDevice;
public Rectangle Viewport { get; private set; }
2019-08-09 18:26:28 +02:00
private readonly List<RootElement> rootElements = new List<RootElement>();
public bool AutoScaleWithScreen;
public Point AutoScaleReferenceSize;
private float globalScale = 1;
2019-08-09 23:43:50 +02:00
public float GlobalScale {
get {
if (!this.AutoScaleWithScreen)
return this.globalScale;
return Math.Min(this.Viewport.Width / (float) this.AutoScaleReferenceSize.X, this.Viewport.Height / (float) this.AutoScaleReferenceSize.Y) * this.globalScale;
}
2019-08-09 23:43:50 +02:00
set {
this.globalScale = value;
foreach (var root in this.rootElements)
root.Element.ForceUpdateArea();
}
}
2019-08-10 21:37:10 +02:00
private UiStyle style;
public UiStyle Style {
get => this.style;
set {
this.style = value;
foreach (var root in this.rootElements) {
2019-08-28 18:58:05 +02:00
root.Element.Propagate(e => e.System = this);
2019-08-12 14:44:42 +02:00
root.Element.SetAreaDirty();
2019-08-10 21:37:10 +02:00
}
}
}
2019-08-10 13:42:18 +02:00
public float DrawAlpha = 1;
2019-08-09 23:43:50 +02:00
public BlendState BlendState;
public SamplerState SamplerState = SamplerState.PointClamp;
2019-08-28 18:27:17 +02:00
public UiControls Controls;
public Element.DrawCallback OnElementDrawn;
public Element.DrawCallback OnSelectedElementDrawn;
2019-08-10 21:37:10 +02:00
public UiSystem(GameWindow window, GraphicsDevice device, UiStyle style, InputHandler inputHandler = null) {
2019-08-28 18:27:17 +02:00
this.Controls = new UiControls(this, inputHandler);
2019-08-10 18:41:56 +02:00
this.GraphicsDevice = device;
2019-08-10 21:37:10 +02:00
this.style = style;
this.Viewport = device.Viewport.Bounds;
this.AutoScaleReferenceSize = this.Viewport.Size;
2019-08-09 19:28:48 +02:00
2019-08-09 18:26:28 +02:00
window.ClientSizeChanged += (sender, args) => {
this.Viewport = device.Viewport.Bounds;
2019-08-09 18:26:28 +02:00
foreach (var root in this.rootElements)
root.Element.ForceUpdateArea();
};
2019-08-30 19:05:27 +02:00
if (InputHandler.TextInputSupported) {
AddToTextInput(window, (key, character) => {
foreach (var root in this.rootElements)
root.Element.Propagate(e => e.OnTextInput?.Invoke(e, key, character));
});
}
this.OnSelectedElementDrawn = (element, time, batch, alpha, offset) => {
if (!this.Controls.SelectedLastElementWithMouse && element.SelectionIndicator != null) {
batch.Draw(element.SelectionIndicator, element.DisplayArea.OffsetCopy(offset), Color.White * alpha);
}
};
2019-08-09 18:26:28 +02:00
}
2019-08-30 19:05:27 +02:00
private static void AddToTextInput(GameWindow window, Action<Keys, char> func) {
window.TextInput += (sender, args) => func(args.Key, args.Character);
}
2019-08-09 18:26:28 +02:00
public void Update(GameTime time) {
2019-08-28 18:27:17 +02:00
this.Controls.Update();
2019-08-10 18:41:56 +02:00
2019-08-09 18:26:28 +02:00
foreach (var root in this.rootElements)
root.Element.Update(time);
}
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);
}
}
public void Draw(GameTime time, SpriteBatch batch) {
2019-08-09 19:39:51 +02:00
foreach (var root in this.rootElements) {
if (root.Element.IsHidden)
continue;
batch.Begin(SpriteSortMode.Deferred, this.BlendState, this.SamplerState);
root.Element.Draw(time, batch, this.DrawAlpha * root.Element.DrawAlpha, Point.Zero);
batch.End();
2019-08-09 19:39:51 +02:00
}
2019-08-09 18:26:28 +02:00
}
public RootElement Add(string name, Element element) {
var root = new RootElement(name, element, this);
return !this.Add(root) ? null : root;
}
2019-08-09 18:26:28 +02:00
internal bool Add(RootElement root, int index = -1) {
if (this.IndexOf(root.Name) >= 0)
return false;
if (index < 0 || index > this.rootElements.Count)
index = this.rootElements.Count;
this.rootElements.Insert(index, root);
2019-08-28 18:58:05 +02:00
root.Element.Propagate(e => {
e.Root = root;
e.System = this;
});
return true;
2019-08-09 18:26:28 +02:00
}
public void Remove(string name) {
var root = this.Get(name);
if (root == null)
2019-08-09 18:26:28 +02:00
return;
this.rootElements.Remove(root);
2019-08-28 18:58:05 +02:00
root.Element.Propagate(e => {
e.Root = null;
e.System = null;
});
2019-08-09 18:26:28 +02:00
}
public RootElement Get(string name) {
2019-08-09 18:26:28 +02:00
var index = this.IndexOf(name);
return index < 0 ? null : this.rootElements[index];
2019-08-09 18:26:28 +02:00
}
private int IndexOf(string name) {
return this.rootElements.FindIndex(element => element.Name == name);
}
2019-08-28 18:27:17 +02:00
public IEnumerable<RootElement> GetRootElements() {
for (var i = this.rootElements.Count - 1; i >= 0; i--)
yield return this.rootElements[i];
2019-08-28 18:58:05 +02:00
}
internal void Propagate(Action<Element> action) {
foreach (var root in this.rootElements)
root.Element.Propagate(action);
}
2019-08-09 18:26:28 +02:00
}
public class RootElement {
2019-08-09 18:26:28 +02:00
public readonly string Name;
public readonly Element Element;
public readonly UiSystem System;
private float scale = 1;
public float Scale {
get => this.scale;
set {
if (this.scale == value)
return;
this.scale = value;
this.Element.ForceUpdateArea();
}
}
public float ActualScale => this.System.GlobalScale * this.Scale;
2019-08-28 18:27:17 +02:00
public bool CanSelectContent = true;
2019-08-09 18:26:28 +02:00
public RootElement(string name, Element element, UiSystem system) {
2019-08-09 18:26:28 +02:00
this.Name = name;
this.Element = element;
this.System = system;
2019-08-09 18:26:28 +02:00
}
public void MoveToFront() {
this.System.Remove(this.Name);
this.System.Add(this);
}
public void MoveToBack() {
this.System.Remove(this.Name);
this.System.Add(this, 0);
}
2019-08-09 18:26:28 +02:00
}
}