mirror of
https://gitlab.acidiclight.dev/sociallydistant/sociallydistant.git
synced 2025-01-22 09:31:47 -05:00
Add support for Image widgets
This commit is contained in:
parent
d028164cda
commit
4a62f661ed
6 changed files with 215 additions and 36 deletions
|
@ -63,10 +63,10 @@ public class GeometryHelper : IFontStashRenderer2
|
|||
{
|
||||
var mesh = GetMeshBuilder(texture);
|
||||
|
||||
int tl = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Top), color);
|
||||
int tr = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Top), color);
|
||||
int bl = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Bottom), color);
|
||||
int br = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Bottom), color);
|
||||
int tl = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Top), color, new Vector2(0, 0));
|
||||
int tr = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Top), color new Vector2(1, 0));
|
||||
int bl = mesh.AddVertex(new Vector2(rectangle.Left, rectangle.Bottom), color new Vector2(0, 1));
|
||||
int br = mesh.AddVertex(new Vector2(rectangle.Right, rectangle.Bottom), color new Vector2(1, 1));
|
||||
|
||||
mesh.AddQuad(tl, tr, bl, br);
|
||||
}
|
||||
|
|
33
src/AcidicGUI/Widgets/Image.cs
Normal file
33
src/AcidicGUI/Widgets/Image.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using AcidicGUI.Rendering;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace AcidicGUI.Widgets;
|
||||
|
||||
public sealed class Image : Widget
|
||||
{
|
||||
private Texture2D? texture;
|
||||
|
||||
public Texture2D? Texture
|
||||
{
|
||||
get => texture;
|
||||
set
|
||||
{
|
||||
texture = value;
|
||||
InvalidateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
protected override Vector2 GetContentSize(Vector2 availableSize)
|
||||
{
|
||||
if (texture == null)
|
||||
return Vector2.Zero;
|
||||
|
||||
return new Vector2(texture.Width, texture.Height);
|
||||
}
|
||||
|
||||
protected override void RebuildGeometry(GeometryHelper geometry)
|
||||
{
|
||||
geometry.AddQuad(ContentArea, Color.Wheat, texture);
|
||||
}
|
||||
}
|
|
@ -51,6 +51,8 @@ public sealed class InputField :
|
|||
{
|
||||
Children.Add(display);
|
||||
ClippingMode = ClippingMode.Clip;
|
||||
|
||||
display.ShowMarkup = true;
|
||||
}
|
||||
|
||||
protected override Vector2 GetContentSize(Vector2 availableSize)
|
||||
|
|
|
@ -74,7 +74,7 @@ public sealed class ScrollView :
|
|||
}
|
||||
|
||||
// Make sure we adjust the scroll page offset in case we've lost some inner height.
|
||||
pageOffset = Math.Clamp(pageOffset, 0, innerSize - availableSpace.Height);
|
||||
pageOffset = Math.Clamp(pageOffset, 0, Math.Max(innerSize - availableSpace.Height, 0));
|
||||
|
||||
// Pass 2: Layout updates
|
||||
foreach (Widget child in Children)
|
||||
|
|
|
@ -18,8 +18,20 @@ public class TextWidget : Widget
|
|||
private string text = string.Empty;
|
||||
private bool useMarkup = true;
|
||||
private bool wordWrapping = false;
|
||||
private bool showMarkup;
|
||||
private TextAlignment textAlignment;
|
||||
|
||||
public bool ShowMarkup
|
||||
{
|
||||
get => showMarkup;
|
||||
set
|
||||
{
|
||||
showMarkup = value;
|
||||
RebuildText();
|
||||
InvalidateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public TextAlignment TextAlignment
|
||||
{
|
||||
get => textAlignment;
|
||||
|
@ -145,12 +157,12 @@ public class TextWidget : Widget
|
|||
{
|
||||
foreach (TextElement element in textElements)
|
||||
{
|
||||
var fontInstance = (element.FontOverride ?? font).GetFont(this);
|
||||
var fontInstance = (element.MarkupData.FontOverride ?? font).GetFont(this);
|
||||
|
||||
// TODO: Color from a property or the Visual Style.
|
||||
var color = (element.ColorOverride ?? Color.White);
|
||||
var color = (element.MarkupData.ColorOverride ?? Color.White);
|
||||
|
||||
if (element.MeasuredSize.HasValue && element.Highlight.A > 0)
|
||||
if (element.MeasuredSize.HasValue && element.MarkupData.Highlight.A > 0)
|
||||
{
|
||||
var highlightRect = new LayoutRect(
|
||||
element.Position.X,
|
||||
|
@ -159,10 +171,42 @@ public class TextWidget : Widget
|
|||
element.MeasuredSize.Value.Y
|
||||
);
|
||||
|
||||
geometry.AddQuad(highlightRect, element.Highlight);
|
||||
geometry.AddQuad(highlightRect, element.MarkupData.Highlight);
|
||||
}
|
||||
|
||||
fontInstance.Draw(geometry, element.Position, color, element.Text);
|
||||
|
||||
var strikeLine = 1;
|
||||
var underLine = 2;
|
||||
|
||||
if (element.MarkupData.Underline)
|
||||
{
|
||||
geometry.AddQuad(new LayoutRect(
|
||||
element.Position.X,
|
||||
element.Position.Y + element.MeasuredSize!.Value.Y - underLine,
|
||||
element.MeasuredSize.Value.X,
|
||||
underLine
|
||||
), color);
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(element.MarkupData.Link))
|
||||
{
|
||||
geometry.AddQuad(new LayoutRect(
|
||||
element.Position.X,
|
||||
element.Position.Y + element.MeasuredSize!.Value.Y - strikeLine,
|
||||
element.MeasuredSize.Value.X,
|
||||
strikeLine
|
||||
), color);
|
||||
}
|
||||
|
||||
if (element.MarkupData.Strikethrough)
|
||||
{
|
||||
geometry.AddQuad(new LayoutRect(
|
||||
element.Position.X,
|
||||
element.Position.Y + ((element.MeasuredSize!.Value.Y - underLine)/2),
|
||||
element.MeasuredSize.Value.X,
|
||||
strikeLine
|
||||
), color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,7 +221,7 @@ public class TextWidget : Widget
|
|||
{
|
||||
if (i == textElements.Count-1)
|
||||
{
|
||||
textElements[i].MeasuredSize = (textElements[i].FontOverride ?? font).GetFont(this)
|
||||
textElements[i].MeasuredSize = (textElements[i].MarkupData.FontOverride ?? font).GetFont(this)
|
||||
.Measure(textElements[i].Text.TrimEnd());
|
||||
}
|
||||
|
||||
|
@ -190,7 +234,7 @@ public class TextWidget : Widget
|
|||
if (i > 0)
|
||||
{
|
||||
offset.X -= textElements[i - 1].MeasuredSize!.Value.X;
|
||||
textElements[i - 1].MeasuredSize = (textElements[i - 1].FontOverride ?? font).GetFont(this)
|
||||
textElements[i - 1].MeasuredSize = (textElements[i - 1].MarkupData.FontOverride ?? font).GetFont(this)
|
||||
.Measure(textElements[i - 1].Text.TrimEnd());
|
||||
offset.X += textElements[i - 1].MeasuredSize!.Value.X;
|
||||
}
|
||||
|
@ -215,6 +259,35 @@ public class TextWidget : Widget
|
|||
return lines.ToArray();
|
||||
}
|
||||
|
||||
public bool TryFindLink(Vector2 position, out string? linkId)
|
||||
{
|
||||
linkId = null;
|
||||
|
||||
foreach (TextElement element in textElements)
|
||||
{
|
||||
if (element.MeasuredSize == null)
|
||||
continue;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(element.MarkupData.Link))
|
||||
continue;
|
||||
|
||||
LayoutRect rect = new LayoutRect(
|
||||
element.Position.X,
|
||||
element.Position.Y,
|
||||
element.MeasuredSize.Value.X,
|
||||
element.MeasuredSize.Value.Y
|
||||
);
|
||||
|
||||
if (!rect.Contains(position))
|
||||
continue;
|
||||
|
||||
linkId = element.MarkupData.Link;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool ParseMarkup(ReadOnlySpan<char> chars, int start, ref MarkupData markupData)
|
||||
{
|
||||
if (start < 0)
|
||||
|
@ -266,7 +339,7 @@ public class TextWidget : Widget
|
|||
{
|
||||
if (ColorHelpers.ParseColor(afterEquals, out Color color))
|
||||
{
|
||||
markupData.ForegroundOverride = color;
|
||||
markupData.ColorOverride = color;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -274,14 +347,14 @@ public class TextWidget : Widget
|
|||
}
|
||||
case "/color":
|
||||
{
|
||||
markupData.ForegroundOverride = null;
|
||||
markupData.ColorOverride = null;
|
||||
return true;
|
||||
}
|
||||
case "highlight":
|
||||
{
|
||||
if (ColorHelpers.ParseColor(afterEquals, out Color color))
|
||||
{
|
||||
markupData.BackgroundColor = color;
|
||||
markupData.Highlight = color;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -289,10 +362,50 @@ public class TextWidget : Widget
|
|||
}
|
||||
case "/highlight":
|
||||
{
|
||||
markupData.BackgroundColor = Color.Transparent;
|
||||
markupData.Highlight = Color.Transparent;
|
||||
return true;
|
||||
}
|
||||
|
||||
case "b":
|
||||
markupData.Bold = true;
|
||||
return true;
|
||||
case "/b":
|
||||
markupData.Bold = false;
|
||||
return true;
|
||||
case "i":
|
||||
markupData.Italic = true;
|
||||
return true;
|
||||
case "/i":
|
||||
markupData.Italic = false;
|
||||
return true;
|
||||
case "u":
|
||||
markupData.Underline = true;
|
||||
return true;
|
||||
case "/u":
|
||||
markupData.Underline = false;
|
||||
return true;
|
||||
case "s":
|
||||
markupData.Strikethrough = true;
|
||||
return true;
|
||||
case "/s":
|
||||
markupData.Strikethrough = false;
|
||||
return true;
|
||||
case "selected":
|
||||
markupData.Selected = true;
|
||||
return true;
|
||||
case "/selected":
|
||||
markupData.Selected = false;
|
||||
return true;
|
||||
case "link":
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(afterEquals))
|
||||
return false;
|
||||
|
||||
markupData.Link = afterEquals;
|
||||
return true;
|
||||
}
|
||||
case "/link":
|
||||
markupData.Link = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -323,9 +436,9 @@ public class TextWidget : Widget
|
|||
Text = stringBuilder.ToString().TrimEnd(),
|
||||
SourceStart = sourceStart,
|
||||
SourceEnd = i,
|
||||
ColorOverride = markupData.ForegroundOverride,
|
||||
Highlight = markupData.BackgroundColor
|
||||
MarkupData = markupData
|
||||
});
|
||||
markupData.Length = 0;
|
||||
sourceStart = i;
|
||||
}
|
||||
|
||||
|
@ -348,15 +461,30 @@ public class TextWidget : Widget
|
|||
Text = stringBuilder.ToString(),
|
||||
SourceStart = sourceStart,
|
||||
SourceEnd = i,
|
||||
ColorOverride = markupData.ForegroundOverride,
|
||||
Highlight = markupData.BackgroundColor
|
||||
MarkupData = markupData
|
||||
});
|
||||
|
||||
int markupLength = newMarkupData.Length;
|
||||
|
||||
if (showMarkup)
|
||||
{
|
||||
textElements.Add(new TextElement
|
||||
{
|
||||
Text = chars.Slice(i, newMarkupData.Length).ToString(),
|
||||
SourceStart = i,
|
||||
SourceEnd = i + newMarkupData.Length,
|
||||
MarkupData = markupData
|
||||
});
|
||||
|
||||
newMarkupData.Length = 0;
|
||||
}
|
||||
|
||||
markupData = newMarkupData;
|
||||
|
||||
stringBuilder.Length = 0;
|
||||
sourceStart = i;
|
||||
i += markupData.Length-1;
|
||||
|
||||
i += markupLength - 1;
|
||||
break;
|
||||
}
|
||||
case '\r':
|
||||
|
@ -368,10 +496,11 @@ public class TextWidget : Widget
|
|||
Text = stringBuilder.ToString().TrimEnd(),
|
||||
SourceStart = sourceStart,
|
||||
SourceEnd = i,
|
||||
ColorOverride = markupData.ForegroundOverride,
|
||||
Highlight = markupData.BackgroundColor
|
||||
MarkupData = markupData
|
||||
});
|
||||
|
||||
markupData.Length = 0;
|
||||
|
||||
stringBuilder.Length = 0;
|
||||
sourceStart = i;
|
||||
|
||||
|
@ -381,8 +510,7 @@ public class TextWidget : Widget
|
|||
IsNewLine = true,
|
||||
SourceStart = sourceStart,
|
||||
SourceEnd = i + 1,
|
||||
ColorOverride = markupData.ForegroundOverride,
|
||||
Highlight = markupData.BackgroundColor
|
||||
MarkupData = markupData
|
||||
});
|
||||
|
||||
sourceStart = i + 1;
|
||||
|
@ -399,10 +527,10 @@ public class TextWidget : Widget
|
|||
Text = stringBuilder.ToString(),
|
||||
SourceStart = sourceStart,
|
||||
SourceEnd = i + 1,
|
||||
ColorOverride = markupData.ForegroundOverride,
|
||||
Highlight = markupData.BackgroundColor
|
||||
MarkupData = markupData
|
||||
});
|
||||
|
||||
markupData.Length = 0;
|
||||
sourceStart = i + 1;
|
||||
stringBuilder.Length = 0;
|
||||
}
|
||||
|
@ -517,7 +645,7 @@ public class TextWidget : Widget
|
|||
if (textElements[i].MeasuredSize != null)
|
||||
continue;
|
||||
|
||||
var fontInstance = (textElements[i].FontOverride ?? font).GetFont(this);
|
||||
var fontInstance = (textElements[i].MarkupData.FontOverride ?? font).GetFont(this);
|
||||
|
||||
textElements[i].MeasuredSize = fontInstance.Measure(textElements[i].Text);
|
||||
}
|
||||
|
@ -536,7 +664,7 @@ public class TextWidget : Widget
|
|||
|
||||
if (i == textElements.Count - 1 || characterIndex <= element.SourceEnd)
|
||||
{
|
||||
var fontInstance = (element.FontOverride ?? font).GetFont(this);
|
||||
var fontInstance = (element.MarkupData.FontOverride ?? font).GetFont(this);
|
||||
|
||||
if (characterIndex == element.SourceStart)
|
||||
{
|
||||
|
@ -584,20 +712,25 @@ public class TextWidget : Widget
|
|||
private struct MarkupData
|
||||
{
|
||||
public int Length;
|
||||
public Color BackgroundColor;
|
||||
public Color? ForegroundOverride;
|
||||
public Color? ColorOverride;
|
||||
public Color Highlight;
|
||||
public FontInfo? FontOverride;
|
||||
public bool Bold;
|
||||
public bool Italic;
|
||||
public bool Underline;
|
||||
public bool Strikethrough;
|
||||
public bool Selected;
|
||||
public string? Link;
|
||||
}
|
||||
|
||||
private class TextElement
|
||||
{
|
||||
public string Text;
|
||||
public Color? ColorOverride;
|
||||
public Color Highlight;
|
||||
public FontInfo? FontOverride;
|
||||
public Vector2 Position;
|
||||
public Vector2? MeasuredSize;
|
||||
public bool IsNewLine;
|
||||
public int SourceStart;
|
||||
public int SourceEnd;
|
||||
public MarkupData MarkupData;
|
||||
}
|
||||
}
|
|
@ -263,11 +263,18 @@ internal sealed class SociallyDistantGame :
|
|||
Log.Logger = new LoggerConfiguration()
|
||||
.WriteTo.Console()
|
||||
.CreateLogger();
|
||||
|
||||
using var game = new SociallyDistantGame();
|
||||
|
||||
AppDomain.CurrentDomain.UnhandledException += Fuck;
|
||||
|
||||
void Fuck(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
Log.Error("Fuck. Game just crashed.");
|
||||
Log.Fatal(e.ExceptionObject.ToString() ?? "Unknown exception details.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using var game = new SociallyDistantGame();
|
||||
game.Run();
|
||||
}
|
||||
finally
|
||||
|
@ -354,6 +361,10 @@ internal sealed class SociallyDistantGame :
|
|||
|
||||
private void OnGameSettingsChanged(ISettingsManager settings)
|
||||
{
|
||||
// Not yet.
|
||||
if (GraphicsDevice == null)
|
||||
return;
|
||||
|
||||
var graphicsSettings = new GraphicsSettings(settings);
|
||||
var parameters = GraphicsDevice.PresentationParameters;
|
||||
|
||||
|
|
Loading…
Reference in a new issue