summaryrefslogtreecommitdiff
path: root/source/ui/elements
diff options
context:
space:
mode:
Diffstat (limited to 'source/ui/elements')
-rw-r--r--source/ui/elements/Button.cs173
-rw-r--r--source/ui/elements/Clickable.cs21
-rw-r--r--source/ui/elements/Container.cs91
-rw-r--r--source/ui/elements/Element.cs53
-rw-r--r--source/ui/elements/IClickable.cs9
-rw-r--r--source/ui/elements/IContainer.cs12
-rw-r--r--source/ui/elements/IElement.cs52
-rw-r--r--source/ui/elements/Image.cs59
-rw-r--r--source/ui/elements/Label.cs62
-rw-r--r--source/ui/elements/game/CraftingRecipeSlot.cs173
-rw-r--r--source/ui/elements/game/CraftingWindow.cs62
-rw-r--r--source/ui/elements/game/InventorySlot.cs191
-rw-r--r--source/ui/elements/game/InventoryWindow.cs56
-rw-r--r--source/ui/elements/game/PauseMenu.cs74
-rw-r--r--source/ui/elements/game/controls/ControlTips.cs51
-rw-r--r--source/ui/elements/game/tooltips/CraftingTooltipDisplay.cs97
-rw-r--r--source/ui/elements/game/tooltips/ItemDisplay.cs21
-rw-r--r--source/ui/elements/game/tooltips/ItemTooltipDisplay.cs62
-rw-r--r--source/ui/elements/game/tooltips/TooltipDisplay.cs8
19 files changed, 1327 insertions, 0 deletions
diff --git a/source/ui/elements/Button.cs b/source/ui/elements/Button.cs
new file mode 100644
index 0000000..81a6aed
--- /dev/null
+++ b/source/ui/elements/Button.cs
@@ -0,0 +1,173 @@
+using Celesteia.UI.Properties;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using MonoGame.Extended.Input;
+using MonoGame.Extended.TextureAtlases;
+
+namespace Celesteia.UI.Elements {
+ public class Button : Clickable {
+ public Button(Rect rect) {
+ SetRect(rect);
+ }
+
+ public Button SetNewRect(Rect rect) {
+ SetRect(rect);
+ return this;
+ }
+
+ public Button SetPivotPoint(Vector2 pivot) {
+ SetPivot(pivot);
+ return this;
+ }
+
+ // TEXT PROPERTIES
+
+ private TextProperties _text;
+
+ public Button SetTextProperties(TextProperties text) {
+ _text = text;
+ return this;
+ }
+
+ public Button SetText(string text) {
+ _text.SetText(text);
+ return this;
+ }
+
+ // COLOR PROPERTIES
+
+ private ButtonColorGroup _colorGroup = new ButtonColorGroup(Color.White);
+ private Color ButtonColor = Color.White;
+ private bool ButtonEnabled = true;
+
+ public Button SetColorGroup(ButtonColorGroup colorGroup) {
+ _colorGroup = colorGroup;
+ return this;
+ }
+
+ public Button SetButtonEnabled(bool enabled) {
+ ButtonEnabled = enabled;
+ return this;
+ }
+
+ // CLICKING PROPERTIES
+
+ private ClickEvent _onMouseDown = null;
+ private ClickEvent _onMouseUp = null;
+
+ public Button SetOnMouseDown(ClickEvent func) {
+ _onMouseDown = func;
+ return this;
+ }
+
+ public Button SetOnMouseUp(ClickEvent func) {
+ _onMouseUp = func;
+ return this;
+ }
+
+ public override void OnMouseDown(MouseButton button, Point position) {
+ base.OnMouseDown(button, position);
+ _onMouseDown?.Invoke(button, position);
+ }
+
+ public override void OnMouseUp(MouseButton button, Point position) {
+ base.OnMouseUp(button, position);
+ _onMouseUp?.Invoke(button, position);
+ }
+
+ // DRAWING PROPERTIES
+
+ private Texture2D _texture;
+ private TextureAtlas _patches;
+ private int _patchSize;
+
+ public Button SetTexture(Texture2D texture) {
+ _texture = texture;
+ return this;
+ }
+
+ public Button MakePatches(int size) {
+ if (_texture != null) {
+ _patchSize = size;
+ _patches = TextureAtlas.Create("buttonPatches", _texture, _patchSize, _patchSize);
+ }
+ return this;
+ }
+
+ // https://gamedev.stackexchange.com/a/118255
+ private float _colorAmount = 0.0f;
+ private bool _prevMouseOver = false;
+ private bool _prevClicked = false;
+ public override void Update(GameTime gameTime, out bool clickedAnything) {
+ clickedAnything = false;
+ if (ButtonColor == GetTargetColor()) return;
+
+ if (_prevMouseOver != GetMouseOver() || _prevClicked != GetClicked()) _colorAmount = 0.0f;
+
+ _colorAmount += (float)gameTime.ElapsedGameTime.TotalSeconds / 0.5f;
+
+ if (_colorAmount > 1.0f)
+ _colorAmount = 0.0f;
+
+ ButtonColor = Color.Lerp(ButtonColor, GetTargetColor(), _colorAmount);
+
+ _prevMouseOver = GetMouseOver();
+ _prevClicked = GetClicked();
+ }
+
+ Rectangle rectangle;
+ public override void Draw(SpriteBatch spriteBatch)
+ {
+ rectangle = GetRectangle();
+
+ // Draw the button's texture.
+ if (_patches != null) ImageUtilities.DrawPatched(spriteBatch, rectangle, _patches, _patchSize, ButtonColor);
+ else spriteBatch.Draw(GetTexture(spriteBatch), rectangle, null, ButtonColor);
+
+ TextUtilities.DrawAlignedText(spriteBatch, rectangle, _text);
+ }
+
+ public Texture2D GetTexture(SpriteBatch spriteBatch) {
+ if (_texture == null) {
+ _texture = new Texture2D(spriteBatch.GraphicsDevice, 1, 1);
+ _texture.SetData(new[] { Color.Gray });
+ }
+
+ return _texture;
+ }
+
+ private Color GetTargetColor() {
+ return ButtonEnabled ? (GetMouseOver() ? (GetClicked() ? _colorGroup.Active : _colorGroup.Hover) : _colorGroup.Normal) : _colorGroup.Disabled;
+ }
+
+ public Button Clone() {
+ return new Button(GetRect())
+ .SetPivotPoint(GetPivot())
+ .SetOnMouseDown(_onMouseDown)
+ .SetOnMouseUp(_onMouseUp)
+ .SetTexture(_texture)
+ .MakePatches(_patchSize)
+ .SetTextProperties(_text)
+ .SetColorGroup(_colorGroup);
+ }
+ }
+
+ public struct ButtonColorGroup {
+ public Color Normal;
+ public Color Disabled;
+ public Color Hover;
+ public Color Active;
+
+ public ButtonColorGroup(Color normal, Color disabled, Color hover, Color active) {
+ Normal = normal;
+ Disabled = disabled;
+ Hover = hover;
+ Active = active;
+ }
+
+ public ButtonColorGroup(Color normal, Color disabled, Color hover) : this (normal, disabled, hover, normal) {}
+
+ public ButtonColorGroup(Color normal, Color disabled) : this (normal, disabled, normal, normal) {}
+ public ButtonColorGroup(Color normal) : this (normal, normal, normal, normal) {}
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/Clickable.cs b/source/ui/elements/Clickable.cs
new file mode 100644
index 0000000..01436a3
--- /dev/null
+++ b/source/ui/elements/Clickable.cs
@@ -0,0 +1,21 @@
+using Microsoft.Xna.Framework;
+using MonoGame.Extended.Input;
+
+namespace Celesteia.UI.Elements {
+ public class Clickable : Element, IClickable
+ {
+ private bool _clicked;
+
+ public override void OnMouseOut() {
+ _clicked = false;
+ base.OnMouseOut();
+ }
+ public virtual void OnMouseDown(MouseButton button, Point position) => _clicked = true;
+ public virtual void OnMouseUp(MouseButton button, Point position) => _clicked = false;
+
+ public bool GetClicked() => _clicked;
+ }
+
+ public delegate void HoverEvent();
+ public delegate void ClickEvent(MouseButton button, Point position);
+} \ No newline at end of file
diff --git a/source/ui/elements/Container.cs b/source/ui/elements/Container.cs
new file mode 100644
index 0000000..9080999
--- /dev/null
+++ b/source/ui/elements/Container.cs
@@ -0,0 +1,91 @@
+using System.Collections.Generic;
+using Celesteia.Game.Input;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using MonoGame.Extended.Input;
+
+namespace Celesteia.UI.Elements {
+ public class Container : Element, IContainer
+ {
+ private List<IElement> Children;
+
+ public Container(Rect rect) {
+ SetRect(rect);
+ Children = new List<IElement>();
+ }
+
+ public void AddChild(IElement element) {
+ Children.Add(element);
+ element.SetParent(this);
+ }
+
+ public List<IElement> GetChildren() => Children;
+
+ public override void Draw(SpriteBatch spriteBatch)
+ {
+ Children.ForEach(element => { if (element.GetEnabled()) element.Draw(spriteBatch); });
+ }
+
+ private Point _mousePosition;
+
+ public override void Update(GameTime gameTime, out bool clickedAnything)
+ {
+ clickedAnything = false;
+ if (!UIReferences.GUIEnabled) return;
+
+ foreach (IElement element in Children) {
+ element.Update(gameTime, out clickedAnything);
+ }
+
+ _mousePosition = MouseHelper.Position;
+
+ if (MouseHelper.Pressed(MouseButton.Left)) clickedAnything = ResolveMouseDown(MouseButton.Left);
+ else if (MouseHelper.Pressed(MouseButton.Right)) clickedAnything = ResolveMouseDown(MouseButton.Right);
+
+ if (MouseHelper.Released(MouseButton.Left)) clickedAnything = ResolveMouseUp(MouseButton.Left);
+ else if (MouseHelper.Released(MouseButton.Right)) clickedAnything = ResolveMouseUp(MouseButton.Right);
+
+ ResolveMouseOver();
+ }
+
+ public bool ResolveMouseDown(MouseButton button) {
+ bool clicked = false;
+ Children.FindAll(x => x is Clickable).ForEach(element => {
+ if (!element.GetEnabled()) return;
+ Clickable clickable = element as Clickable;
+
+ if (clicked = clickable.GetRectangle().Contains(_mousePosition))
+ clickable.OnMouseDown(button, _mousePosition);
+ });
+ return clicked;
+ }
+
+ public bool ResolveMouseUp(MouseButton button) {
+ bool clicked = false;
+ Children.FindAll(x => x is Clickable).ForEach(element => {
+ if (!element.GetEnabled()) return;
+ Clickable clickable = element as Clickable;
+
+ if (clickable.GetRectangle().Contains(_mousePosition)) {
+ clicked = true;
+ clickable.OnMouseUp(button, _mousePosition);
+ }
+ });
+ return clicked;
+ }
+
+ public void ResolveMouseOver() {
+ Children.ForEach(element => {
+ if (!element.GetEnabled()) return;
+ bool over = element.GetRectangle().Contains(_mousePosition);
+ if (over && !element.GetMouseOver()) {
+ element.OnMouseIn();
+ } else if (!over && element.GetMouseOver()) element.OnMouseOut();
+ });
+ }
+
+ public void Dispose() {
+ Children.Clear();
+ }
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/Element.cs b/source/ui/elements/Element.cs
new file mode 100644
index 0000000..b95a693
--- /dev/null
+++ b/source/ui/elements/Element.cs
@@ -0,0 +1,53 @@
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Celesteia.UI.Elements {
+ public class Element : IElement
+ {
+ private bool _enabled = true;
+ private Rect _rect;
+ private bool _isMouseOver;
+ private IContainer _parent;
+ private Vector2 _pivot;
+
+ public virtual bool GetEnabled() => _enabled && (_parent == null || _parent.GetEnabled());
+ public virtual IContainer GetParent() => _parent;
+ public virtual Vector2 GetPivot() => _pivot;
+ public virtual Rect GetRect() => _rect;
+ public virtual void MoveTo(Point point) {
+ _rect.SetX(AbsoluteUnit.WithValue(point.X));
+ _rect.SetY(AbsoluteUnit.WithValue(point.Y));
+ }
+
+ // Get element rectangle with pivot.
+ public virtual Rectangle GetRectangle() {
+ Rectangle r = GetRect().ResolveRectangle();
+
+ if (GetParent() != null) {
+ r.X += GetParent().GetRectangle().X;
+ r.Y += GetParent().GetRectangle().Y;
+ }
+
+ r.X -= (int)MathF.Round(_pivot.X * r.Width);
+ r.Y -= (int)MathF.Round(_pivot.Y * r.Height);
+
+ return r;
+ }
+
+ // Interface setters.
+ public virtual bool SetEnabled(bool value) => _enabled = value;
+ public virtual void SetParent(IContainer container) => _parent = container;
+ public virtual void SetPivot(Vector2 pivot) => _pivot = pivot;
+ public virtual void SetRect(Rect rect) => _rect = rect;
+
+ // Mouse functions
+ public virtual void OnMouseIn() => _isMouseOver = true;
+ public virtual void OnMouseOut() => _isMouseOver = false;
+ public virtual bool GetMouseOver() => _isMouseOver;
+
+ // Engine functions.
+ public virtual void Update(GameTime gameTime, out bool clickedAnything) { clickedAnything = false; }
+ public virtual void Draw(SpriteBatch spriteBatch) { }
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/IClickable.cs b/source/ui/elements/IClickable.cs
new file mode 100644
index 0000000..19c2848
--- /dev/null
+++ b/source/ui/elements/IClickable.cs
@@ -0,0 +1,9 @@
+using Microsoft.Xna.Framework;
+using MonoGame.Extended.Input;
+
+namespace Celesteia.UI.Elements {
+ public interface IClickable : IElement {
+ void OnMouseDown(MouseButton button, Point position);
+ void OnMouseUp(MouseButton button, Point position);
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/IContainer.cs b/source/ui/elements/IContainer.cs
new file mode 100644
index 0000000..0d3550c
--- /dev/null
+++ b/source/ui/elements/IContainer.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+
+namespace Celesteia.UI.Elements {
+ public interface IContainer : IElement, IDisposable {
+ // Get the element's children.
+ List<IElement> GetChildren();
+
+ // Add to the element's children.
+ void AddChild(IElement element);
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/IElement.cs b/source/ui/elements/IElement.cs
new file mode 100644
index 0000000..094d7b7
--- /dev/null
+++ b/source/ui/elements/IElement.cs
@@ -0,0 +1,52 @@
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Celesteia.UI.Elements {
+ public interface IElement {
+ // Is the element enabled?
+ bool GetEnabled();
+
+ // Set whether the element is enabled.
+ bool SetEnabled(bool value);
+
+ // Get the containing rect of the element.
+ Rect GetRect();
+
+ // Set the containing rect of the element.
+ void SetRect(Rect rect);
+
+ // Move to a point.
+ void MoveTo(Point point);
+
+ // Get the rectangle with a pivot point.
+ Rectangle GetRectangle();
+
+ // Gets the pivot point of the element;
+ Vector2 GetPivot();
+
+ // Sets the pivot point of the element;
+ void SetPivot(Vector2 pivot);
+
+ // Called when the mouse position is within the element's containing rect.
+ void OnMouseIn();
+
+ // Called when the mouse position is within the element's containing rect.
+ void OnMouseOut();
+
+ // Get if the element has the mouse over it.
+ bool GetMouseOver();
+
+ // Update the element.
+ void Update(GameTime gameTime, out bool clickedAnything);
+
+ // Draw the element.
+ void Draw(SpriteBatch spriteBatch);
+
+ // Get the element's parent.
+ IContainer GetParent();
+
+ // Set the element's parent.
+ void SetParent(IContainer container);
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/Image.cs b/source/ui/elements/Image.cs
new file mode 100644
index 0000000..de661e8
--- /dev/null
+++ b/source/ui/elements/Image.cs
@@ -0,0 +1,59 @@
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using MonoGame.Extended.TextureAtlases;
+
+namespace Celesteia.UI.Elements {
+ public class Image : Element {
+ private Texture2D _texture;
+ public Color _color;
+
+ public Image(Rect rect) {
+ SetRect(rect);
+ }
+
+ public Image SetTexture(Texture2D texture) {
+ _texture = texture;
+ return this;
+ }
+
+ public Image SetColor(Color color) {
+ _color = color;
+ return this;
+ }
+
+ public Image SetPivotPoint(Vector2 pivot) {
+ SetPivot(pivot);
+ return this;
+ }
+
+ private TextureAtlas _patches;
+ private int _patchSize;
+ public Image MakePatches(int size) {
+ if (_texture != null) {
+ _patchSize = size;
+ _patches = TextureAtlas.Create("patches", _texture, _patchSize, _patchSize);
+ }
+ return this;
+ }
+
+ public override void Draw(SpriteBatch spriteBatch)
+ {
+ if (_patches != null) ImageUtilities.DrawPatched(spriteBatch, GetRectangle(), _patches, _patchSize, _color);
+ else spriteBatch.Draw(GetTexture(spriteBatch), GetRectangle(), null, _color);
+ }
+
+ public Texture2D GetTexture(SpriteBatch spriteBatch)
+ {
+ if (_texture == null) {
+ // Make a new texture.
+ _texture = new Texture2D(spriteBatch.GraphicsDevice, 1, 1);
+
+ // Set the default texture to one gray pixel.
+ _texture.SetData(new[] { Color.Gray });
+ }
+
+ return _texture;
+ }
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/Label.cs b/source/ui/elements/Label.cs
new file mode 100644
index 0000000..c875791
--- /dev/null
+++ b/source/ui/elements/Label.cs
@@ -0,0 +1,62 @@
+using Celesteia.UI.Properties;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Celesteia.UI.Elements {
+ public class Label : Element {
+ private Texture2D _background;
+ private TextProperties _text;
+
+ public Label(Rect rect) {
+ SetRect(rect);
+ }
+
+ public Label SetNewRect(Rect rect) {
+ SetRect(rect);
+ return this;
+ }
+
+ public Label SetPivotPoint(Vector2 pivot) {
+ SetPivot(pivot);
+ return this;
+ }
+
+ public Label SetBackground(Texture2D background) {
+ SetTexture(background);
+ return this;
+ }
+
+ public Label SetText(string text) {
+ _text.SetText(text);
+ return this;
+ }
+
+ public Label SetColor(Color color) {
+ _text.SetColor(color);
+ return this;
+ }
+
+ public Label SetTextProperties(TextProperties text) {
+ _text = text;
+ return this;
+ }
+
+ public override void Draw(SpriteBatch spriteBatch)
+ {
+ // Draw the label's background, if present.
+ if (_background != null) spriteBatch.Draw(GetTexture(), GetRectangle(), null, Color.White);
+
+ TextUtilities.DrawAlignedText(spriteBatch, GetRectangle(), _text);
+ }
+
+ public Texture2D GetTexture() => _background;
+ public void SetTexture(Texture2D background) => _background = background;
+
+ public Label Clone() {
+ return new Label(GetRect())
+ .SetPivotPoint(GetPivot())
+ .SetBackground(GetTexture())
+ .SetTextProperties(_text);
+ }
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/game/CraftingRecipeSlot.cs b/source/ui/elements/game/CraftingRecipeSlot.cs
new file mode 100644
index 0000000..72101d8
--- /dev/null
+++ b/source/ui/elements/game/CraftingRecipeSlot.cs
@@ -0,0 +1,173 @@
+using System;
+using Celesteia.Game.Components.Items;
+using Celesteia.Resources.Types;
+using Celesteia.UI.Properties;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using MonoGame.Extended.Input;
+using MonoGame.Extended.TextureAtlases;
+
+namespace Celesteia.UI.Elements.Game {
+ public class CraftingRecipeSlot : Clickable {
+ public const float SLOT_SIZE = 64f;
+ public const float SLOT_SPACING = 16f;
+
+ public Inventory referenceInv;
+
+ public CraftingRecipeSlot(Rect rect) {
+ SetRect(rect);
+ }
+
+ public CraftingRecipeSlot SetNewRect(Rect rect) {
+ SetRect(rect);
+ return this;
+ }
+
+ // RECIPE REFERENCE PROPERTIES
+ private Recipe _recipe;
+ public CraftingRecipeSlot SetRecipe(Recipe recipe) {
+ _recipe = recipe;
+ return this;
+ }
+
+ // DRAWING PROPERTIES
+
+ private Texture2D _texture;
+ private TextureAtlas _patches;
+ private int _patchSize;
+
+ public CraftingRecipeSlot SetTexture(Texture2D texture) {
+ _texture = texture;
+ return this;
+ }
+
+ public CraftingRecipeSlot SetPatches(TextureAtlas patches, int size) {
+ if (_texture != null) {
+ _patchSize = size;
+ _patches = patches;
+ }
+ return this;
+ }
+
+ // TEXT PROPERTIES
+
+ private TextProperties _text;
+
+ public CraftingRecipeSlot SetTextProperties(TextProperties text) {
+ _text = text;
+ return this;
+ }
+
+ public CraftingRecipeSlot SetText(string text) {
+ _text.SetText(text);
+ return this;
+ }
+
+ // CLICKING PROPERTIES
+
+ private ClickEvent _onMouseDown = null;
+ private ClickEvent _onMouseUp = null;
+ public delegate void CraftHoverEvent(Recipe recipe);
+ private CraftHoverEvent _onMouseIn = null;
+ private HoverEvent _onMouseOut = null;
+
+ public CraftingRecipeSlot SetOnMouseDown(ClickEvent func) {
+ _onMouseDown = func;
+ return this;
+ }
+
+ public CraftingRecipeSlot SetOnMouseUp(ClickEvent func) {
+ _onMouseUp = func;
+ return this;
+ }
+
+ public CraftingRecipeSlot SetOnMouseIn(CraftHoverEvent func) {
+ _onMouseIn = func;
+ return this;
+ }
+
+ public CraftingRecipeSlot SetOnMouseOut(HoverEvent func) {
+ _onMouseOut = func;
+ return this;
+ }
+
+ public override void OnMouseDown(MouseButton button, Point position) {
+ base.OnMouseDown(button, position);
+ _onMouseDown?.Invoke(button, position);
+ }
+
+ public override void OnMouseUp(MouseButton button, Point position) {
+ base.OnMouseUp(button, position);
+ _onMouseUp?.Invoke(button, position);
+ }
+
+ public override void OnMouseIn() {
+ base.OnMouseIn();
+ if (_recipe != null) _onMouseIn?.Invoke(_recipe);
+ }
+
+ public override void OnMouseOut() {
+ base.OnMouseOut();
+ _onMouseOut?.Invoke();
+ }
+
+ private Rectangle GetScaledTriangle(Rectangle r, float scale) {
+ int newWidth = (int)Math.Round(r.Width * scale);
+ int newHeight = (int)Math.Round(r.Height * scale);
+ return new Rectangle(
+ (int)Math.Round(r.X + ((r.Width - newWidth) / 2f)),
+ (int)Math.Round(r.Y + ((r.Height - newHeight) / 2f)),
+ newWidth,
+ newHeight
+ );
+ }
+
+ Color color;
+ public override void Update(GameTime gameTime, out bool clickedAnything) {
+ base.Update(gameTime, out clickedAnything);
+
+ if (!this.GetEnabled()) return;
+ color = _recipe.Craftable(referenceInv) ? Color.White : Color.Gray;
+ }
+
+ Rectangle rectangle;
+ Rectangle itemRectangle;
+ Rectangle textRectangle;
+ public override void Draw(SpriteBatch spriteBatch)
+ {
+ if (_recipe == null) return;
+
+ rectangle = GetRectangle();
+ itemRectangle = GetScaledTriangle(rectangle, .6f);
+ textRectangle = GetScaledTriangle(rectangle, .4f);
+
+ // Draw the slot's texture.
+ if (_patches != null) ImageUtilities.DrawPatched(spriteBatch, rectangle, _patches, _patchSize, color);
+ else spriteBatch.Draw(GetTexture(spriteBatch), rectangle, null, color);
+
+ spriteBatch.Draw(_recipe.Result.GetItemType().Sprite, itemRectangle, color);
+ TextUtilities.DrawAlignedText(spriteBatch, textRectangle, _text.GetFont(), _recipe.Result.Amount + "", _text.GetColor(), _text.GetAlignment(), _text.GetFontSize());
+ }
+
+ public Texture2D GetTexture(SpriteBatch spriteBatch) {
+ if (_texture == null) {
+ _texture = new Texture2D(spriteBatch.GraphicsDevice, 1, 1);
+ _texture.SetData(new[] { Color.Gray });
+ }
+
+ return _texture;
+ }
+
+ public CraftingRecipeSlot Clone() {
+ return new CraftingRecipeSlot(GetRect())
+ .SetRecipe(_recipe)
+ .SetOnMouseDown(_onMouseDown)
+ .SetOnMouseUp(_onMouseUp)
+ .SetOnMouseIn(_onMouseIn)
+ .SetOnMouseOut(_onMouseOut)
+ .SetTextProperties(_text)
+ .SetTexture(_texture)
+ .SetPatches(_patches, _patchSize);
+ }
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/game/CraftingWindow.cs b/source/ui/elements/game/CraftingWindow.cs
new file mode 100644
index 0000000..e5bcc71
--- /dev/null
+++ b/source/ui/elements/game/CraftingWindow.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using Celesteia.Game.Components.Items;
+using Celesteia.GUIs.Game;
+using Celesteia.Resources;
+using Celesteia.Resources.Management;
+using Celesteia.Resources.Types;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Celesteia.UI.Elements.Game {
+ public class CraftingWindow : Container {
+ private Inventory _referenceInventory;
+ private Image background;
+ private GameGUI _gameGui;
+
+ public CraftingWindow(GameGUI gameGui, Rect rect, Texture2D backgroundImage, Inventory inventory, CraftingRecipeSlot template) : base(rect) {
+ _gameGui = gameGui;
+
+ _referenceInventory = inventory;
+
+ background = new Image(Rect.RelativeFull(rect)).SetTexture(backgroundImage).MakePatches(4).SetColor(Color.White);
+ AddChild(background);
+
+ AddRecipes(27, template);
+ }
+
+ int columns = 9;
+ private void AddRecipes(int amountPerPage, CraftingRecipeSlot template) {
+ int rows = (int)Math.Ceiling(amountPerPage / (double)columns);
+
+ float o = CraftingRecipeSlot.SLOT_SPACING;
+ int index = 0;
+ int i = 0;
+ for (int row = 0; row < rows; row++)
+ for (int column = 0; column < columns; column++) {
+ if (i >= ResourceManager.Recipes.Recipes.Count) break;
+
+ int slotNumber = i;
+ Recipe recipe = ResourceManager.Recipes.Recipes[index];
+ CraftingRecipeSlot slot = template.Clone()
+ .SetNewRect(template.GetRect()
+ .SetX(AbsoluteUnit.WithValue(column * CraftingRecipeSlot.SLOT_SIZE + (column * CraftingRecipeSlot.SLOT_SPACING) + o))
+ .SetY(AbsoluteUnit.WithValue(row * CraftingRecipeSlot.SLOT_SIZE + (row * CraftingRecipeSlot.SLOT_SPACING) + o))
+ )
+ .SetRecipe(recipe)
+ .SetOnMouseUp((button, point) => {
+ if (button == MonoGame.Extended.Input.MouseButton.Left) {
+ recipe.Craft(_referenceInventory);
+ }
+ });
+ slot.referenceInv = _referenceInventory;
+ slot.SetPivot(new Vector2(0f, 0f));
+
+ index++;
+ i++;
+
+ AddChild(slot);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/game/InventorySlot.cs b/source/ui/elements/game/InventorySlot.cs
new file mode 100644
index 0000000..01663b4
--- /dev/null
+++ b/source/ui/elements/game/InventorySlot.cs
@@ -0,0 +1,191 @@
+using System;
+using Celesteia.Game.Components.Items;
+using Celesteia.Resources.Types;
+using Celesteia.UI.Properties;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using MonoGame.Extended.Input;
+using MonoGame.Extended.TextureAtlases;
+
+namespace Celesteia.UI.Elements.Game {
+ public class InventorySlot : Clickable {
+ public const float SLOT_SIZE = 64f;
+ public const float SLOT_SPACING = 16f;
+
+ public InventorySlot(Rect rect) {
+ SetRect(rect);
+ }
+
+ public InventorySlot SetNewRect(Rect rect) {
+ SetRect(rect);
+ return this;
+ }
+
+ // SELECTION
+
+ private bool _selected = false;
+ public InventorySlot SetSelected(bool selected) {
+ _selected = selected;
+ return this;
+ }
+
+ public bool GetSelected() {
+ return _selected;
+ }
+
+
+ // INVENTORY REFERENCE PROPERTIES
+
+ private Inventory _inventory;
+ private int _slot;
+
+ public InventorySlot SetReferenceInventory(Inventory inventory) {
+ _inventory = inventory;
+ return this;
+ }
+
+ public InventorySlot SetSlot(int slot) {
+ _slot = slot;
+ return this;
+ }
+
+ // DRAWING PROPERTIES
+
+ private Texture2D _texture;
+ private TextureAtlas _patches;
+ private int _patchSize;
+
+ public InventorySlot SetTexture(Texture2D texture) {
+ _texture = texture;
+ return this;
+ }
+
+ public InventorySlot SetPatches(TextureAtlas patches, int size) {
+ if (_texture != null) {
+ _patchSize = size;
+ _patches = patches;
+ }
+ return this;
+ }
+
+ // TEXT PROPERTIES
+
+ private TextProperties _text;
+
+ public InventorySlot SetTextProperties(TextProperties text) {
+ _text = text;
+ return this;
+ }
+
+ public InventorySlot SetText(string text) {
+ _text.SetText(text);
+ return this;
+ }
+
+ // CLICKING PROPERTIES
+
+ private ClickEvent _onMouseDown = null;
+ private ClickEvent _onMouseUp = null;
+ public delegate void ItemHoverEvent(ItemType type);
+ private ItemHoverEvent _onMouseIn = null;
+ private HoverEvent _onMouseOut = null;
+
+ public InventorySlot SetOnMouseDown(ClickEvent func) {
+ _onMouseDown = func;
+ return this;
+ }
+
+ public InventorySlot SetOnMouseUp(ClickEvent func) {
+ _onMouseUp = func;
+ return this;
+ }
+
+ public InventorySlot SetOnMouseIn(ItemHoverEvent func) {
+ _onMouseIn = func;
+ return this;
+ }
+
+ public InventorySlot SetOnMouseOut(HoverEvent func) {
+ _onMouseOut = func;
+ return this;
+ }
+
+ public override void OnMouseDown(MouseButton button, Point position) {
+ base.OnMouseDown(button, position);
+ _onMouseDown?.Invoke(button, position);
+ }
+
+ public override void OnMouseUp(MouseButton button, Point position) {
+ base.OnMouseUp(button, position);
+ _onMouseUp?.Invoke(button, position);
+ }
+
+ public override void OnMouseIn() {
+ base.OnMouseIn();
+ if (_inventory.GetSlot(_slot) != null) _onMouseIn?.Invoke(_inventory.GetSlot(_slot).Type);
+ }
+
+ public override void OnMouseOut() {
+ base.OnMouseOut();
+ _onMouseOut?.Invoke();
+ }
+
+ private Rectangle GetScaledTriangle(Rectangle r, float scale) {
+ int newWidth = (int)Math.Round(r.Width * scale);
+ int newHeight = (int)Math.Round(r.Height * scale);
+ return new Rectangle(
+ (int)Math.Round(r.X + ((r.Width - newWidth) / 2f)),
+ (int)Math.Round(r.Y + ((r.Height - newHeight) / 2f)),
+ newWidth,
+ newHeight
+ );
+ }
+
+ Rectangle rectangle;
+ Rectangle itemRectangle;
+ Rectangle textRectangle;
+ ItemStack inSlot;
+ Color slightlyTransparent = new Color(255, 255, 255, 100);
+ public override void Draw(SpriteBatch spriteBatch)
+ {
+ if (_inventory == null) return;
+
+ rectangle = GetRectangle();
+ itemRectangle = GetScaledTriangle(rectangle, .6f);
+ textRectangle = GetScaledTriangle(rectangle, .4f);
+
+ // Draw the slot's texture.
+ if (_patches != null) ImageUtilities.DrawPatched(spriteBatch, rectangle, _patches, _patchSize, _selected ? Color.DarkViolet : Color.White);
+ else spriteBatch.Draw(GetTexture(spriteBatch), rectangle, null, Color.White);
+
+ // Draw item if present.
+ inSlot = _inventory.GetSlot(_slot);
+ if (inSlot != null) {
+ spriteBatch.Draw(inSlot.Type.Sprite, itemRectangle, Color.White);
+ if (inSlot.Amount > 1) TextUtilities.DrawAlignedText(spriteBatch, textRectangle, _text.GetFont(), $"{inSlot.Amount}", _text.GetColor(), _text.GetAlignment(), _text.GetFontSize());
+ } else TextUtilities.DrawAlignedText(spriteBatch, rectangle, _text.GetFont(), $"{_slot + 1}", slightlyTransparent, TextAlignment.Center, 24f);
+ }
+
+ public Texture2D GetTexture(SpriteBatch spriteBatch) {
+ if (_texture == null) {
+ _texture = new Texture2D(spriteBatch.GraphicsDevice, 1, 1);
+ _texture.SetData(new[] { Color.Gray });
+ }
+
+ return _texture;
+ }
+
+ public InventorySlot Clone() {
+ return new InventorySlot(GetRect())
+ .SetReferenceInventory(_inventory)
+ .SetOnMouseDown(_onMouseDown)
+ .SetOnMouseUp(_onMouseUp)
+ .SetOnMouseIn(_onMouseIn)
+ .SetOnMouseOut(_onMouseOut)
+ .SetSlot(_slot)
+ .SetTextProperties(_text)
+ .SetTexture(_texture)
+ .SetPatches(_patches, _patchSize);
+ }
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/game/InventoryWindow.cs b/source/ui/elements/game/InventoryWindow.cs
new file mode 100644
index 0000000..c8dba41
--- /dev/null
+++ b/source/ui/elements/game/InventoryWindow.cs
@@ -0,0 +1,56 @@
+using System;
+using Celesteia.Game.Components.Items;
+using Celesteia.GUIs.Game;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Celesteia.UI.Elements.Game {
+ public class InventoryWindow : Container {
+ private Inventory _referenceInventory;
+ private Image background;
+ private GameGUI _gameGui;
+
+ public InventoryWindow(GameGUI gameGui, Rect rect, Texture2D backgroundImage, Inventory inventory, int slots, int offset, InventorySlot template) : base(rect) {
+ _gameGui = gameGui;
+
+ background = new Image(Rect.RelativeFull(rect)).SetTexture(backgroundImage).MakePatches(4).SetColor(Color.White);
+ AddChild(background);
+
+ _referenceInventory = inventory;
+
+ AddSlots(slots, offset, template);
+ }
+
+ int columns = 9;
+ private void AddSlots(int amount, int offset, InventorySlot template) {
+ int rows = (int)Math.Ceiling(amount / (double)columns);
+
+ float o = InventorySlot.SLOT_SPACING;
+ int i = 0;
+ for (int row = 0; row < rows; row++)
+ for (int column = 0; column < 9; column++) {
+ if (i > amount) break;
+
+ int slotNumber = i + offset;
+ InventorySlot slot = template.Clone()
+ .SetNewRect(template.GetRect()
+ .SetX(AbsoluteUnit.WithValue(column * InventorySlot.SLOT_SIZE + (column * InventorySlot.SLOT_SPACING) + o))
+ .SetY(AbsoluteUnit.WithValue(row * InventorySlot.SLOT_SIZE + (row * InventorySlot.SLOT_SPACING) + o))
+ )
+ .SetSlot(slotNumber)
+ .SetOnMouseUp((button, point) => {
+ ItemStack itemInSlot = _referenceInventory.GetSlot(slotNumber);
+ if ((int)_gameGui.State > 0) {
+ _referenceInventory.SetSlot(slotNumber, _gameGui.CursorItem);
+ _gameGui.CursorItem = itemInSlot;
+ }
+ });
+ slot.SetPivot(new Vector2(0f, 0f));
+
+ i++;
+
+ AddChild(slot);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/game/PauseMenu.cs b/source/ui/elements/game/PauseMenu.cs
new file mode 100644
index 0000000..39281ee
--- /dev/null
+++ b/source/ui/elements/game/PauseMenu.cs
@@ -0,0 +1,74 @@
+using Celesteia.Game.Components.Items;
+using Celesteia.GUIs.Game;
+using Celesteia.Resources;
+using Celesteia.Screens;
+using Celesteia.UI.Properties;
+using Microsoft.Xna.Framework;
+
+namespace Celesteia.UI.Elements.Game {
+ public class PauseMenu : Container {
+ private Image background;
+ private IContainer centerMenu;
+ private GameGUI _gameGui;
+
+ private float buttonRow(int number) => number * (buttonHeight + buttonSpacing);
+ private float buttonHeight = 56f;
+ private float buttonSpacing = 10f;
+
+ public PauseMenu(GameGUI gameGui, Rect rect, Button buttonTemplate) : base(rect) {
+ _gameGui = gameGui;
+
+ background = new Image(Rect.RelativeFull(rect)).SetColor(new Color(0, 0, 0, 100));
+ AddChild(background);
+
+ centerMenu = new Container(new Rect(
+ new RelativeUnit(0.5f, GetRect(), RelativeUnit.Orientation.Horizontal),
+ new RelativeUnit(0.5f, GetRect(), RelativeUnit.Orientation.Vertical),
+ AbsoluteUnit.WithValue(350f),
+ AbsoluteUnit.WithValue(2 * (buttonHeight + buttonSpacing) - buttonSpacing)
+ ));
+ AddChild(centerMenu);
+
+ AddButtons(buttonTemplate);
+ }
+
+ private void AddButtons(Button template) {
+ centerMenu.AddChild(new Label(new Rect(
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(buttonRow(-1)),
+ new RelativeUnit(1f, centerMenu.GetRect(), RelativeUnit.Orientation.Horizontal),
+ AbsoluteUnit.WithValue(buttonHeight)
+ ))
+ .SetPivotPoint(new Vector2(0.5f, 0.5f))
+ .SetTextProperties(new TextProperties().SetColor(Color.White).SetFont(ResourceManager.Fonts.GetFontType("Hobo")).SetFontSize(24f).SetTextAlignment(TextAlignment.Center))
+ .SetText("Paused")
+ );
+
+ centerMenu.AddChild(template.Clone()
+ .SetNewRect(new Rect(
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(buttonRow(0)),
+ new RelativeUnit(1f, centerMenu.GetRect(), RelativeUnit.Orientation.Horizontal),
+ AbsoluteUnit.WithValue(buttonHeight)
+ ))
+ .SetText("Back to Game")
+ .SetOnMouseUp((button, point) => {
+ _gameGui.TogglePause();
+ })
+ );
+
+ centerMenu.AddChild(template.Clone()
+ .SetNewRect(new Rect(
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(buttonRow(1)),
+ new RelativeUnit(1f, centerMenu.GetRect(), RelativeUnit.Orientation.Horizontal),
+ AbsoluteUnit.WithValue(buttonHeight)
+ ))
+ .SetText("Return to Title")
+ .SetOnMouseUp((button, point) => {
+ _gameGui.Game.LoadScreen(new MainMenuScreen(_gameGui.Game),new MonoGame.Extended.Screens.Transitions.FadeTransition(_gameGui.Game.GraphicsDevice, Color.Black));
+ })
+ );
+ }
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/game/controls/ControlTips.cs b/source/ui/elements/game/controls/ControlTips.cs
new file mode 100644
index 0000000..904b3cc
--- /dev/null
+++ b/source/ui/elements/game/controls/ControlTips.cs
@@ -0,0 +1,51 @@
+using System.Collections.Generic;
+using Celesteia.Game.Input;
+using Celesteia.Resources;
+using Celesteia.UI.Properties;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+
+namespace Celesteia.UI.Elements.Game.Controls {
+ public class ControlTips : Container {
+ private TextProperties _properties;
+ private Dictionary<Keys, string> _keyboardControls = new Dictionary<Keys, string>();
+ private List<string> _lines = new List<string>();
+ private List<Label> _labels = new List<Label>();
+
+ public ControlTips(Rect rect) : base(rect) {
+ _properties = new TextProperties()
+ .SetColor(Color.White)
+ .SetFont(ResourceManager.Fonts.DEFAULT)
+ .SetFontSize(12f)
+ .SetTextAlignment(TextAlignment.Left);
+ }
+
+ private int lineHeight = 16;
+ private Rect LineRect(int line) => new Rect(
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(line * lineHeight),
+ new RelativeUnit(1f, GetRect(), RelativeUnit.Orientation.Horizontal),
+ AbsoluteUnit.WithValue(lineHeight)
+ );
+
+ private void UpdateLines() {
+ _labels.Clear();
+
+ foreach (Keys keys in _keyboardControls.Keys) _lines.Add($"[{keys}] {_keyboardControls[keys]}");
+
+ for (int i = 0; i < _lines.Count; i++) {
+ Label label = new Label(LineRect(i - (_lines.Count / 2)))
+ .SetTextProperties(_properties)
+ .SetText(_lines[i]);
+ label.SetParent(this);
+ _labels.Add(label);
+ }
+ }
+
+ public override void Draw(SpriteBatch spriteBatch)
+ {
+ foreach (Label l in _labels) l.Draw(spriteBatch);
+ }
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/game/tooltips/CraftingTooltipDisplay.cs b/source/ui/elements/game/tooltips/CraftingTooltipDisplay.cs
new file mode 100644
index 0000000..a7c6e2f
--- /dev/null
+++ b/source/ui/elements/game/tooltips/CraftingTooltipDisplay.cs
@@ -0,0 +1,97 @@
+using Celesteia.Resources.Types;
+using Celesteia.UI.Properties;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Celesteia.UI.Elements.Game.Tooltips {
+ public class CraftingTooltipDisplay : TooltipDisplay
+ {
+ private const float OUTER_SPACING = 16f;
+ private const float INNER_SPACING = 8f;
+ public readonly Container Content;
+ public readonly Label Title;
+ public readonly ItemDisplay Item;
+ public Container Recipe;
+
+ public CraftingTooltipDisplay(Rect rect, Texture2D background) : base(rect) {
+ AddChild(new Image(Rect.RelativeFull(new Rect(
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(256f + (2 * OUTER_SPACING)),
+ AbsoluteUnit.WithValue(64f + (1 * INNER_SPACING) + (2 * OUTER_SPACING))
+ ))).SetTexture(background).MakePatches(4).SetColor(Color.White));
+
+ Content = new Container(new Rect(
+ AbsoluteUnit.WithValue(OUTER_SPACING),
+ AbsoluteUnit.WithValue(OUTER_SPACING),
+ AbsoluteUnit.WithValue(256f),
+ AbsoluteUnit.WithValue(64f + (1 * INNER_SPACING))
+ ));
+
+ Container titleCard = new Container(new Rect(
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(0f),
+ new RelativeUnit(1f, Content.GetRect(), RelativeUnit.Orientation.Horizontal),
+ AbsoluteUnit.WithValue(32f)
+ ));
+ titleCard.AddChild(Item = new ItemDisplay(new Rect(
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(32f),
+ AbsoluteUnit.WithValue(32f)
+ )) {
+ Text = new TextProperties().Standard().SetTextAlignment(TextAlignment.Bottom | TextAlignment.Right)
+ });
+ titleCard.AddChild(Title = new Label(new Rect(
+ AbsoluteUnit.WithValue(72f),
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(150f),
+ AbsoluteUnit.WithValue(32f)
+ )).SetTextProperties(new Properties.TextProperties().Standard().SetTextAlignment(TextAlignment.Left)).SetPivotPoint(new Vector2(0f, 0f)));
+ Content.AddChild(titleCard);
+
+ Recipe = new Container(new Rect(
+ new RelativeUnit(.5f, Content.GetRect(), RelativeUnit.Orientation.Horizontal),
+ AbsoluteUnit.WithValue(32f + INNER_SPACING),
+ new RelativeUnit(1f, Content.GetRect(), RelativeUnit.Orientation.Horizontal),
+ AbsoluteUnit.WithValue(32f)
+ ));
+ Content.AddChild(Recipe);
+
+ AddChild(Content);
+
+ SetEnabled(false);
+ }
+
+ public void SetRecipe(Recipe recipe) {
+ Item.Item = recipe.Result.GetItemType();
+ Title.SetText(recipe.Result.GetItemType().Name);
+
+ if (Recipe != null) Recipe.Dispose();
+ Recipe = new Container(new Rect(
+ new RelativeUnit(0f, Content.GetRect(), RelativeUnit.Orientation.Horizontal),
+ AbsoluteUnit.WithValue(32f + INNER_SPACING),
+ new RelativeUnit(1f, Content.GetRect(), RelativeUnit.Orientation.Horizontal),
+ AbsoluteUnit.WithValue(32f)
+ ));
+ Recipe.SetPivot(new Vector2(0f, 0f));
+
+ for (int i = 0; i < recipe.Ingredients.Count; i++)
+ Recipe.AddChild(new ItemDisplay(new Rect(
+ AbsoluteUnit.WithValue((i * INNER_SPACING) + (i * 32)),
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(32f),
+ AbsoluteUnit.WithValue(32f)
+ )) {
+ Item = recipe.Ingredients[i].GetItemType(),
+ Amount = recipe.Ingredients[i].Amount,
+ Text = new TextProperties().Standard()
+ .SetTextAlignment(TextAlignment.Bottom | TextAlignment.Right)
+ .SetFontSize(12f)
+ .SetText(recipe.Ingredients[i].Amount.ToString())
+ });
+
+ Content.AddChild(Recipe);
+ }
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/game/tooltips/ItemDisplay.cs b/source/ui/elements/game/tooltips/ItemDisplay.cs
new file mode 100644
index 0000000..d3b1524
--- /dev/null
+++ b/source/ui/elements/game/tooltips/ItemDisplay.cs
@@ -0,0 +1,21 @@
+using Celesteia.Resources.Types;
+using Celesteia.UI.Properties;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using MonoGame.Extended.TextureAtlases;
+
+namespace Celesteia.UI.Elements.Game.Tooltips {
+ public class ItemDisplay : Element {
+ public ItemType Item;
+ public int Amount;
+ public TextProperties Text;
+
+ public ItemDisplay(Rect rect) => SetRect(rect);
+
+ public override void Draw(SpriteBatch spriteBatch)
+ {
+ spriteBatch.Draw(Item.Sprite, GetRectangle(), Color.White, null);
+ if (Amount > 1) TextUtilities.DrawAlignedText(spriteBatch, GetRectangle(), Text);
+ }
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/game/tooltips/ItemTooltipDisplay.cs b/source/ui/elements/game/tooltips/ItemTooltipDisplay.cs
new file mode 100644
index 0000000..9b62af4
--- /dev/null
+++ b/source/ui/elements/game/tooltips/ItemTooltipDisplay.cs
@@ -0,0 +1,62 @@
+using Celesteia.Resources.Types;
+using Celesteia.UI.Properties;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace Celesteia.UI.Elements.Game.Tooltips {
+ public class ItemTooltipDisplay : TooltipDisplay
+ {
+ private const float OUTER_SPACING = 16f;
+ private const float INNER_SPACING = 8f;
+ public readonly Container Content;
+ public readonly Label Title;
+ public readonly ItemDisplay Item;
+
+ public ItemTooltipDisplay(Rect rect, Texture2D background) : base(rect) {
+ AddChild(new Image(Rect.RelativeFull(new Rect(
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(256f + (2 * OUTER_SPACING)),
+ AbsoluteUnit.WithValue(32f + (2 * OUTER_SPACING))
+ ))).SetTexture(background).MakePatches(4).SetColor(Color.White));
+
+ Content = new Container(new Rect(
+ AbsoluteUnit.WithValue(OUTER_SPACING),
+ AbsoluteUnit.WithValue(OUTER_SPACING),
+ AbsoluteUnit.WithValue(256f),
+ AbsoluteUnit.WithValue(32f)
+ ));
+
+ Container titleCard = new Container(new Rect(
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(0f),
+ new RelativeUnit(1f, Content.GetRect(), RelativeUnit.Orientation.Horizontal),
+ AbsoluteUnit.WithValue(32f)
+ ));
+ titleCard.AddChild(Item = new ItemDisplay(new Rect(
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(32f),
+ AbsoluteUnit.WithValue(32f)
+ )) {
+ Text = new TextProperties().Standard().SetTextAlignment(TextAlignment.Bottom | TextAlignment.Right)
+ });
+ titleCard.AddChild(Title = new Label(new Rect(
+ AbsoluteUnit.WithValue(72f),
+ AbsoluteUnit.WithValue(0f),
+ AbsoluteUnit.WithValue(150f),
+ AbsoluteUnit.WithValue(32f)
+ )).SetTextProperties(new Properties.TextProperties().Standard().SetTextAlignment(TextAlignment.Left)).SetPivotPoint(new Vector2(0f, 0f)));
+ Content.AddChild(titleCard);
+
+ AddChild(Content);
+
+ SetEnabled(false);
+ }
+
+ public void SetItem(ItemType type) {
+ Item.Item = type;
+ Title.SetText(type.Name);
+ }
+ }
+} \ No newline at end of file
diff --git a/source/ui/elements/game/tooltips/TooltipDisplay.cs b/source/ui/elements/game/tooltips/TooltipDisplay.cs
new file mode 100644
index 0000000..2ff051d
--- /dev/null
+++ b/source/ui/elements/game/tooltips/TooltipDisplay.cs
@@ -0,0 +1,8 @@
+using Microsoft.Xna.Framework;
+
+namespace Celesteia.UI.Elements.Game.Tooltips {
+ public class TooltipDisplay : Container
+ {
+ public TooltipDisplay(Rect rect) : base(rect) {}
+ }
+} \ No newline at end of file