mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
UI Scaling Support. (#809)
Not quite perfect, but quite usable. Adds the ability to scale the UI. Scaling is controlled via a cvar, and can be changed at runtime. Fractional scaling is supported. Some controls could be better (SpriteView, TextureRect), but for now it's a good start.
This commit is contained in:
committed by
GitHub
parent
c4fb96b5e8
commit
17ebeac107
@@ -430,8 +430,10 @@ namespace Robust.Client.Console.Commands
|
||||
{
|
||||
var window = new SS14Window(IoCManager.Resolve<IDisplayManager>(), "UITest");
|
||||
window.AddToScreen();
|
||||
var tabContainer = new TabContainer();
|
||||
window.Contents.AddChild(tabContainer);
|
||||
var scroll = new ScrollContainer();
|
||||
window.Contents.AddChild(scroll);
|
||||
tabContainer.AddChild(scroll);
|
||||
scroll.SetAnchorAndMarginPreset(Control.LayoutPreset.Wide);
|
||||
var vBox = new VBoxContainer();
|
||||
scroll.AddChild(vBox);
|
||||
@@ -468,6 +470,25 @@ namespace Robust.Client.Console.Commands
|
||||
rich.SetMessage(message);
|
||||
vBox.AddChild(rich);
|
||||
|
||||
var itemList = new ItemList();
|
||||
tabContainer.AddChild(itemList);
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
itemList.AddItem(i.ToString());
|
||||
}
|
||||
|
||||
var grid = new GridContainer {Columns = 3};
|
||||
tabContainer.AddChild(grid);
|
||||
for (var y = 0; y < 3; y++)
|
||||
for (var x = 0; x < 3; x++)
|
||||
{
|
||||
grid.AddChild(new Button
|
||||
{
|
||||
CustomMinimumSize = (50, 50),
|
||||
Text = $"{x}, {y}"
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,11 +32,11 @@ namespace Robust.Client.GameStates
|
||||
|
||||
private void DrawString(DrawingHandleScreen handle, Font font, Vector2 pos, string str)
|
||||
{
|
||||
var baseLine = new Vector2(pos.X, font.Ascent + pos.Y);
|
||||
var baseLine = new Vector2(pos.X, font.GetAscent(1) + pos.Y);
|
||||
|
||||
foreach (var chr in str)
|
||||
{
|
||||
var advance = font.DrawChar(handle, chr, baseLine, Color.White);
|
||||
var advance = font.DrawChar(handle, chr, baseLine, 1, Color.White);
|
||||
baseLine += new Vector2(advance, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,30 +15,39 @@ namespace Robust.Client.Graphics
|
||||
public abstract class Font
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum amount a glyph goes above the baseline.
|
||||
/// The maximum amount a glyph goes above the baseline, in pixels.
|
||||
/// </summary>
|
||||
public virtual int Ascent => default;
|
||||
public abstract int GetAscent(float scale);
|
||||
|
||||
/// <summary>
|
||||
/// The maximum glyph height of a line of text, not relative to the baseline.
|
||||
/// The maximum glyph height of a line of text in pixels, not relative to the baseline.
|
||||
/// </summary>
|
||||
public virtual int Height => default;
|
||||
public abstract int GetHeight(float scale);
|
||||
|
||||
/// <summary>
|
||||
/// The maximum amount a glyph drops below the baseline.
|
||||
/// The maximum amount a glyph drops below the baseline, in pixels.
|
||||
/// </summary>
|
||||
public virtual int Descent => default;
|
||||
public abstract int GetDescent(float scale);
|
||||
|
||||
/// <summary>
|
||||
/// The distance between the baselines of two consecutive lines.
|
||||
/// The distance between the baselines of two consecutive lines, in pixels.
|
||||
/// Basically, if you encounter a new line, this is how much you need to move down the cursor.
|
||||
/// </summary>
|
||||
public virtual int LineHeight => Height;
|
||||
public abstract int GetLineHeight(float scale);
|
||||
|
||||
/// <summary>
|
||||
/// The distance between the edges of two consecutive lines.
|
||||
/// The distance between the edges of two consecutive lines, in pixels.
|
||||
/// </summary>
|
||||
public int LineSeparation => LineHeight - Height;
|
||||
public int GetLineSeparation(float scale)
|
||||
{
|
||||
return GetLineHeight(scale) - GetHeight(scale);
|
||||
}
|
||||
|
||||
[Obsolete("Use GetAscent")] public int Ascent => GetAscent(1);
|
||||
[Obsolete("Use GetHeight")] public int Height => GetHeight(1);
|
||||
[Obsolete("Use GetDescent")] public int Descent => GetDescent(1);
|
||||
[Obsolete("Use GetLineHeight")] public int LineHeight => GetLineHeight(1);
|
||||
[Obsolete("Use GetLineSeparation")] public int LineSeparation => GetLineSeparation(1);
|
||||
|
||||
// Yes, I am aware that using char is bad.
|
||||
// At the same time the font system is nowhere close to rendering Unicode so...
|
||||
@@ -53,7 +62,14 @@ namespace Robust.Client.Graphics
|
||||
/// <param name="baseline">The baseline from which to draw the character.</param>
|
||||
/// <param name="color">The color of the character to draw.</param>
|
||||
/// <returns>How much to advance the cursor to draw the next character.</returns>
|
||||
public abstract float DrawChar(DrawingHandleScreen handle, char chr, Vector2 baseline, Color color);
|
||||
[Obsolete("Use DrawChar with scale support.")]
|
||||
public float DrawChar(DrawingHandleScreen handle, char chr, Vector2 baseline, Color color)
|
||||
{
|
||||
return DrawChar(handle, chr, baseline, 1, color);
|
||||
}
|
||||
|
||||
public abstract float DrawChar(DrawingHandleScreen handle, char chr, Vector2 baseline, float scale,
|
||||
Color color);
|
||||
|
||||
/// <summary>
|
||||
/// Gets metrics describing the dimensions and positioning of a single glyph in the font.
|
||||
@@ -64,14 +80,26 @@ namespace Robust.Client.Graphics
|
||||
/// otherwise the metrics you asked for.
|
||||
/// </returns>
|
||||
/// <seealso cref="TryGetCharMetrics"/>
|
||||
public abstract CharMetrics? GetCharMetrics(char chr);
|
||||
[Obsolete("Use GetCharMetrics with scale support.")]
|
||||
public CharMetrics? GetCharMetrics(char chr)
|
||||
{
|
||||
return GetCharMetrics(chr, 1);
|
||||
}
|
||||
|
||||
public abstract CharMetrics? GetCharMetrics(char chr, float scale);
|
||||
|
||||
/// <summary>
|
||||
/// Try-pattern version of <see cref="GetCharMetrics"/>.
|
||||
/// </summary>
|
||||
[Obsolete("Use TryGetCharMetrics with scale support.")]
|
||||
public bool TryGetCharMetrics(char chr, out CharMetrics metrics)
|
||||
{
|
||||
var maybe = GetCharMetrics(chr);
|
||||
return TryGetCharMetrics(chr, 1, out metrics);
|
||||
}
|
||||
|
||||
public bool TryGetCharMetrics(char chr, float scale, out CharMetrics metrics)
|
||||
{
|
||||
var maybe = GetCharMetrics(chr, scale);
|
||||
if (maybe.HasValue)
|
||||
{
|
||||
metrics = maybe.Value;
|
||||
@@ -92,26 +120,26 @@ namespace Robust.Client.Graphics
|
||||
|
||||
internal IFontInstanceHandle Handle { get; }
|
||||
|
||||
public override int Ascent => Handle?.Ascent ?? base.Ascent;
|
||||
public override int Descent => Handle?.Descent ?? base.Descent;
|
||||
public override int Height => Handle?.Height ?? base.Height;
|
||||
public override int LineHeight => Handle?.LineHeight ?? base.LineHeight;
|
||||
|
||||
public VectorFont(FontResource res, int size)
|
||||
{
|
||||
Size = size;
|
||||
Handle = IoCManager.Resolve<IFontManagerInternal>().MakeInstance(res.FontFaceHandle, size);
|
||||
}
|
||||
|
||||
public override float DrawChar(DrawingHandleScreen handle, char chr, Vector2 baseline, Color color)
|
||||
public override int GetAscent(float scale) => Handle.GetAscent(scale);
|
||||
public override int GetHeight(float scale) => Handle.GetHeight(scale);
|
||||
public override int GetDescent(float scale) => Handle.GetDescent(scale);
|
||||
public override int GetLineHeight(float scale) => Handle.GetLineHeight(scale);
|
||||
|
||||
public override float DrawChar(DrawingHandleScreen handle, char chr, Vector2 baseline, float scale, Color color)
|
||||
{
|
||||
var metrics = Handle.GetCharMetrics(chr);
|
||||
var metrics = Handle.GetCharMetrics(chr, scale);
|
||||
if (!metrics.HasValue)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var texture = Handle.GetCharTexture(chr);
|
||||
var texture = Handle.GetCharTexture(chr, scale);
|
||||
if (texture == null)
|
||||
{
|
||||
return metrics.Value.Advance;
|
||||
@@ -122,21 +150,26 @@ namespace Robust.Client.Graphics
|
||||
return metrics.Value.Advance;
|
||||
}
|
||||
|
||||
public override CharMetrics? GetCharMetrics(char chr)
|
||||
public override CharMetrics? GetCharMetrics(char chr, float scale)
|
||||
{
|
||||
return Handle.GetCharMetrics(chr);
|
||||
return Handle.GetCharMetrics(chr, scale);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DummyFont : Font
|
||||
{
|
||||
public override float DrawChar(DrawingHandleScreen handle, char chr, Vector2 baseline, Color color)
|
||||
public override int GetAscent(float scale) => default;
|
||||
public override int GetHeight(float scale) => default;
|
||||
public override int GetDescent(float scale) => default;
|
||||
public override int GetLineHeight(float scale) => default;
|
||||
|
||||
public override float DrawChar(DrawingHandleScreen handle, char chr, Vector2 baseline, float scale, Color color)
|
||||
{
|
||||
// Nada, it's a dummy after all.
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override CharMetrics? GetCharMetrics(char chr)
|
||||
public override CharMetrics? GetCharMetrics(char chr, float scale)
|
||||
{
|
||||
// Nada, it's a dummy after all.
|
||||
return null;
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Robust.Client.Graphics
|
||||
{
|
||||
[Dependency] private readonly IConfigurationManager _configuration;
|
||||
|
||||
private uint FontDPI;
|
||||
private uint BaseFontDPI;
|
||||
|
||||
private readonly Library _library;
|
||||
|
||||
@@ -32,12 +32,14 @@ namespace Robust.Client.Graphics
|
||||
|
||||
public IFontFaceHandle Load(ReadOnlySpan<byte> data)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
var face = new Face(_library, data.ToArray(), 0);
|
||||
var handle = new FontFaceHandle(face);
|
||||
return handle;
|
||||
}
|
||||
var face = new Face(_library, data.ToArray(), 0);
|
||||
var handle = new FontFaceHandle(face);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void IFontManagerInternal.Initialize()
|
||||
{
|
||||
BaseFontDPI = (uint) _configuration.GetCVar<int>("display.fontdpi");
|
||||
}
|
||||
|
||||
public IFontInstanceHandle MakeInstance(IFontFaceHandle handle, int size)
|
||||
@@ -48,50 +50,63 @@ namespace Robust.Client.Graphics
|
||||
return instance;
|
||||
}
|
||||
|
||||
var face = fontFaceHandle.Face;
|
||||
var (atlasData, glyphMap, metricsMap) = _generateAtlas(face, size);
|
||||
var ascent = face.Size.Metrics.Ascender.ToInt32();
|
||||
var descent = -face.Size.Metrics.Descender.ToInt32();
|
||||
var height = face.Size.Metrics.Height.ToInt32();
|
||||
var instanceHandle = new FontInstanceHandle(this, atlasData, size, fontFaceHandle.Face, glyphMap, ascent,
|
||||
descent, height, metricsMap);
|
||||
_loadedInstances.Add((fontFaceHandle, size), instanceHandle);
|
||||
return instanceHandle;
|
||||
var glyphMap = _generateGlyphMap(fontFaceHandle.Face);
|
||||
instance = new FontInstanceHandle(this, size, glyphMap, fontFaceHandle);
|
||||
|
||||
_loadedInstances.Add((fontFaceHandle, size), instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
void IFontManagerInternal.Initialize()
|
||||
private ScaledFontData _generateScaledDatum(FontInstanceHandle instance, float scale)
|
||||
{
|
||||
FontDPI = (uint) _configuration.GetCVar<int>("display.fontdpi");
|
||||
var ftFace = instance.FaceHandle.Face;
|
||||
ftFace.SetCharSize(0, instance.Size, 0, (uint) (BaseFontDPI * scale));
|
||||
|
||||
var ascent = ftFace.Size.Metrics.Ascender.ToInt32();
|
||||
var descent = -ftFace.Size.Metrics.Descender.ToInt32();
|
||||
var lineHeight = ftFace.Size.Metrics.Height.ToInt32();
|
||||
|
||||
var (atlas, metricsMap) = _generateAtlas(instance, scale);
|
||||
|
||||
return new ScaledFontData(metricsMap, ascent, descent, ascent + descent, lineHeight, atlas);
|
||||
}
|
||||
|
||||
private (FontTextureAtlas, Dictionary<char, uint> glyphMap, Dictionary<uint, CharMetrics> metricsMap)
|
||||
_generateAtlas(Face face, int size)
|
||||
private (FontTextureAtlas, Dictionary<uint, CharMetrics> metricsMap)
|
||||
_generateAtlas(FontInstanceHandle instance, float scale)
|
||||
{
|
||||
// TODO: This could use a better box packing algorithm.
|
||||
// Right now we treat each glyph bitmap as having the max size among all glyphs.
|
||||
// So we can divide the atlas into equal-size rectangles.
|
||||
// This wastes a lot of space though because there's a lot of tiny glyphs.
|
||||
face.SetCharSize(0, size, 0, FontDPI);
|
||||
|
||||
var face = instance.FaceHandle.Face;
|
||||
|
||||
var maxGlyphSize = Vector2i.Zero;
|
||||
var count = 0;
|
||||
|
||||
// TODO: Render more than extended ASCII, somehow. Does it make sense to just render every glyph in the font?
|
||||
// Render all the extended ASCII characters.
|
||||
const uint startIndex = 32;
|
||||
const uint endIndex = 255;
|
||||
for (var i = startIndex; i <= endIndex; i++)
|
||||
var metricsMap = new Dictionary<uint, CharMetrics>();
|
||||
|
||||
foreach (var glyph in instance.GlyphMap.Values)
|
||||
{
|
||||
var glyphIndex = face.GetCharIndex(i);
|
||||
if (glyphIndex == 0)
|
||||
if (metricsMap.ContainsKey(glyph))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
face.LoadChar(i, LoadFlags.Default, LoadTarget.Normal);
|
||||
face.LoadGlyph(glyph, LoadFlags.Default, LoadTarget.Normal);
|
||||
face.Glyph.RenderGlyph(RenderMode.Normal);
|
||||
|
||||
var glyphMetrics = face.Glyph.Metrics;
|
||||
var metrics = new CharMetrics(glyphMetrics.HorizontalBearingX.ToInt32(),
|
||||
glyphMetrics.HorizontalBearingY.ToInt32(),
|
||||
glyphMetrics.HorizontalAdvance.ToInt32(),
|
||||
glyphMetrics.Width.ToInt32(),
|
||||
glyphMetrics.Height.ToInt32());
|
||||
metricsMap.Add(glyph, metrics);
|
||||
|
||||
maxGlyphSize = Vector2i.ComponentMax(maxGlyphSize,
|
||||
new Vector2i(face.Glyph.Bitmap.Width, face.Glyph.Bitmap.Rows));
|
||||
|
||||
count += 1;
|
||||
}
|
||||
|
||||
@@ -107,33 +122,12 @@ namespace Robust.Client.Graphics
|
||||
(int) Math.Round(atlasEntriesVertical * maxGlyphSize.Y / 4f, MidpointRounding.AwayFromZero) * 4;
|
||||
var atlas = new Image<Alpha8>(atlasDimX, atlasDimY);
|
||||
|
||||
var glyphMap = new Dictionary<char, uint>();
|
||||
var metricsMap = new Dictionary<uint, CharMetrics>();
|
||||
var atlasRegions = new Dictionary<uint, UIBox2>();
|
||||
count = 0;
|
||||
for (var i = startIndex; i <= endIndex; i++)
|
||||
foreach (var glyph in metricsMap.Keys)
|
||||
{
|
||||
var glyphIndex = face.GetCharIndex(i);
|
||||
if (glyphIndex == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
glyphMap.Add((char) i, glyphIndex);
|
||||
if (metricsMap.ContainsKey(glyphIndex))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
|
||||
face.LoadGlyph(glyph, LoadFlags.Default, LoadTarget.Normal);
|
||||
face.Glyph.RenderGlyph(RenderMode.Normal);
|
||||
var glyphMetrics = face.Glyph.Metrics;
|
||||
var metrics = new CharMetrics(glyphMetrics.HorizontalBearingX.ToInt32(),
|
||||
glyphMetrics.HorizontalBearingY.ToInt32(),
|
||||
glyphMetrics.HorizontalAdvance.ToInt32(),
|
||||
glyphMetrics.Width.ToInt32(),
|
||||
glyphMetrics.Height.ToInt32());
|
||||
metricsMap.Add(glyphIndex, metrics);
|
||||
|
||||
var bitmap = face.Glyph.Bitmap;
|
||||
if (bitmap.Pitch == 0)
|
||||
@@ -185,18 +179,19 @@ namespace Robust.Client.Graphics
|
||||
atlas.Mutate(x => x.DrawImage(bitmapImage, new Point(column * maxGlyphSize.X, row * maxGlyphSize.Y),
|
||||
PixelColorBlendingMode.Overlay, 1));
|
||||
count += 1;
|
||||
atlasRegions.Add(glyphIndex, UIBox2i.FromDimensions(offsetX, offsetY, bitmap.Width, bitmap.Rows));
|
||||
atlasRegions.Add(glyph, UIBox2i.FromDimensions(offsetX, offsetY, bitmap.Width, bitmap.Rows));
|
||||
}
|
||||
|
||||
var atlasDictionary = new Dictionary<uint, AtlasTexture>();
|
||||
var texture = Texture.LoadFromImage(atlas, $"font-{face.FamilyName}-{size}");
|
||||
var texture = Texture.LoadFromImage(atlas,
|
||||
$"font-{face.FamilyName}-{instance.Size}-{(uint) (BaseFontDPI * scale)}");
|
||||
|
||||
foreach (var (glyph, region) in atlasRegions)
|
||||
{
|
||||
atlasDictionary.Add(glyph, new AtlasTexture(texture, region));
|
||||
}
|
||||
|
||||
return (new FontTextureAtlas(texture, atlasDictionary), glyphMap, metricsMap);
|
||||
return (new FontTextureAtlas(texture, atlasDictionary), metricsMap);
|
||||
}
|
||||
|
||||
private static Image<Alpha8> MonoBitMapToImage(FTBitmap bitmap)
|
||||
@@ -226,6 +221,27 @@ namespace Robust.Client.Graphics
|
||||
return bitmapImage;
|
||||
}
|
||||
|
||||
private Dictionary<char, uint> _generateGlyphMap(Face face)
|
||||
{
|
||||
var map = new Dictionary<char, uint>();
|
||||
// TODO: Render more than extended ASCII, somehow. Does it make sense to just render every glyph in the font?
|
||||
// Render all the extended ASCII characters.
|
||||
const uint startIndex = 32;
|
||||
const uint endIndex = 255;
|
||||
for (var i = startIndex; i <= endIndex; i++)
|
||||
{
|
||||
var glyphIndex = face.GetCharIndex(i);
|
||||
if (glyphIndex == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
map.Add((char) i, glyphIndex);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private class FontFaceHandle : IFontFaceHandle
|
||||
{
|
||||
public Face Face { get; }
|
||||
@@ -239,42 +255,22 @@ namespace Robust.Client.Graphics
|
||||
[PublicAPI]
|
||||
private class FontInstanceHandle : IFontInstanceHandle
|
||||
{
|
||||
public Face Face { get; }
|
||||
public FontFaceHandle FaceHandle { get; }
|
||||
public int Size { get; }
|
||||
private readonly Dictionary<char, uint> _glyphMap;
|
||||
private readonly Dictionary<uint, CharMetrics> _metricsMap;
|
||||
public int Ascent { get; }
|
||||
public int Descent { get; }
|
||||
public int Height { get; }
|
||||
public int LineHeight { get; }
|
||||
private readonly Dictionary<float, ScaledFontData> _scaledData = new Dictionary<float, ScaledFontData>();
|
||||
public readonly IReadOnlyDictionary<char, uint> GlyphMap;
|
||||
private readonly FontManager _fontManager;
|
||||
|
||||
public FontInstanceHandle(FontManager manager, FontTextureAtlas atlas, int size, Face face,
|
||||
Dictionary<char, uint> glyphMap,
|
||||
int ascent, int descent, int lineHeight, Dictionary<uint, CharMetrics> metricsMap)
|
||||
public FontInstanceHandle(FontManager fontManager, int size, IReadOnlyDictionary<char, uint> glyphMap,
|
||||
FontFaceHandle faceHandle)
|
||||
{
|
||||
_fontManager = manager;
|
||||
Atlas = atlas;
|
||||
_fontManager = fontManager;
|
||||
Size = size;
|
||||
Face = face;
|
||||
_glyphMap = glyphMap;
|
||||
Ascent = ascent;
|
||||
Descent = descent;
|
||||
LineHeight = lineHeight;
|
||||
Height = ascent + descent;
|
||||
_metricsMap = metricsMap;
|
||||
GlyphMap = glyphMap;
|
||||
FaceHandle = faceHandle;
|
||||
}
|
||||
|
||||
public FontTextureAtlas Atlas { get; }
|
||||
|
||||
public Texture GetCharTexture(char chr)
|
||||
{
|
||||
var glyph = _getGlyph(chr);
|
||||
Atlas.AtlasData.TryGetValue(glyph, out var ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public CharMetrics? GetCharMetrics(char chr)
|
||||
public Texture GetCharTexture(char chr, float scale)
|
||||
{
|
||||
var glyph = _getGlyph(chr);
|
||||
if (glyph == 0)
|
||||
@@ -282,19 +278,89 @@ namespace Robust.Client.Graphics
|
||||
return null;
|
||||
}
|
||||
|
||||
_metricsMap.TryGetValue(glyph, out var metrics);
|
||||
return metrics;
|
||||
var scaled = _getScaleDatum(scale);
|
||||
scaled.Atlas.AtlasData.TryGetValue(glyph, out var texture);
|
||||
return texture;
|
||||
}
|
||||
|
||||
public CharMetrics? GetCharMetrics(char chr, float scale)
|
||||
{
|
||||
var glyph = _getGlyph(chr);
|
||||
if (glyph == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var scaled = _getScaleDatum(scale);
|
||||
return scaled.MetricsMap[glyph];
|
||||
}
|
||||
|
||||
public int GetAscent(float scale)
|
||||
{
|
||||
var scaled = _getScaleDatum(scale);
|
||||
return scaled.Ascent;
|
||||
}
|
||||
|
||||
public int GetDescent(float scale)
|
||||
{
|
||||
var scaled = _getScaleDatum(scale);
|
||||
return scaled.Descent;
|
||||
}
|
||||
|
||||
public int GetHeight(float scale)
|
||||
{
|
||||
var scaled = _getScaleDatum(scale);
|
||||
return scaled.Height;
|
||||
}
|
||||
|
||||
public int GetLineHeight(float scale)
|
||||
{
|
||||
var scaled = _getScaleDatum(scale);
|
||||
return scaled.LineHeight;
|
||||
}
|
||||
|
||||
private uint _getGlyph(char chr)
|
||||
{
|
||||
if (_glyphMap.TryGetValue(chr, out var glyph))
|
||||
if (GlyphMap.TryGetValue(chr, out var glyph))
|
||||
{
|
||||
return glyph;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private ScaledFontData _getScaleDatum(float scale)
|
||||
{
|
||||
if (_scaledData.TryGetValue(scale, out var datum))
|
||||
{
|
||||
return datum;
|
||||
}
|
||||
|
||||
datum = _fontManager._generateScaledDatum(this, scale);
|
||||
_scaledData.Add(scale, datum);
|
||||
return datum;
|
||||
}
|
||||
}
|
||||
|
||||
private class ScaledFontData
|
||||
{
|
||||
public ScaledFontData(IReadOnlyDictionary<uint, CharMetrics> metricsMap, int ascent, int descent,
|
||||
int height, int lineHeight, FontTextureAtlas atlas)
|
||||
{
|
||||
MetricsMap = metricsMap;
|
||||
Ascent = ascent;
|
||||
Descent = descent;
|
||||
Height = height;
|
||||
LineHeight = lineHeight;
|
||||
Atlas = atlas;
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<uint, CharMetrics> MetricsMap { get; }
|
||||
public int Ascent { get; }
|
||||
public int Descent { get; }
|
||||
public int Height { get; }
|
||||
public int LineHeight { get; }
|
||||
public FontTextureAtlas Atlas { get; }
|
||||
}
|
||||
|
||||
private class FontTextureAtlas
|
||||
|
||||
@@ -22,12 +22,12 @@ namespace Robust.Client.Interfaces.Graphics
|
||||
|
||||
internal interface IFontInstanceHandle
|
||||
{
|
||||
Texture GetCharTexture(char chr);
|
||||
CharMetrics? GetCharMetrics(char chr);
|
||||
int Ascent { get; }
|
||||
int Descent { get; }
|
||||
int Height { get; }
|
||||
int LineHeight { get; }
|
||||
Texture GetCharTexture(char chr, float scale);
|
||||
CharMetrics? GetCharMetrics(char chr, float scale);
|
||||
int GetAscent(float scale);
|
||||
int GetDescent(float scale);
|
||||
int GetHeight(float scale);
|
||||
int GetLineHeight(float scale);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -24,6 +24,8 @@ namespace Robust.Client.Interfaces.UserInterface
|
||||
|
||||
Control CurrentlyHovered { get; }
|
||||
|
||||
float UIScale { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The "root" control to which all other controls are parented,
|
||||
/// potentially indirectly.
|
||||
|
||||
@@ -107,15 +107,21 @@ namespace Robust.Client.UserInterface
|
||||
/// </summary>
|
||||
public Vector2 GlobalPosition { get; }
|
||||
|
||||
public Vector2 GlobalPixelPosition { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Position of the mouse, relative to the current control.
|
||||
/// </summary>
|
||||
public Vector2 RelativePosition { get; internal set; }
|
||||
|
||||
public Vector2 RelativePixelPosition { get; internal set; }
|
||||
|
||||
protected GUIMouseEventArgs(Control sourceControl,
|
||||
Mouse.ButtonMask buttonMask,
|
||||
Vector2 globalPosition,
|
||||
Vector2 globalPixelPosition,
|
||||
Vector2 relativePosition,
|
||||
Vector2 relativePixelPosition,
|
||||
bool alt,
|
||||
bool control,
|
||||
bool shift,
|
||||
@@ -126,6 +132,8 @@ namespace Robust.Client.UserInterface
|
||||
ButtonMask = buttonMask;
|
||||
GlobalPosition = globalPosition;
|
||||
RelativePosition = relativePosition;
|
||||
RelativePixelPosition = relativePixelPosition;
|
||||
GlobalPixelPosition = globalPixelPosition;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,12 +155,14 @@ namespace Robust.Client.UserInterface
|
||||
Control sourceControl,
|
||||
Mouse.ButtonMask buttonMask,
|
||||
Vector2 globalPosition,
|
||||
Vector2 globalPixelPosition,
|
||||
Vector2 relativePosition,
|
||||
Vector2 relativePixelPosition,
|
||||
bool alt,
|
||||
bool control,
|
||||
bool shift,
|
||||
bool system)
|
||||
: base(sourceControl, buttonMask, globalPosition, relativePosition, alt, control, shift, system)
|
||||
: base(sourceControl, buttonMask, globalPosition, globalPixelPosition, relativePosition, relativePixelPosition, alt, control, shift, system)
|
||||
{
|
||||
Button = button;
|
||||
DoubleClick = doubleClick;
|
||||
@@ -179,12 +189,14 @@ namespace Robust.Client.UserInterface
|
||||
Control sourceControl,
|
||||
Mouse.ButtonMask buttonMask,
|
||||
Vector2 globalPosition,
|
||||
Vector2 globalPixelPosition,
|
||||
Vector2 relativePosition,
|
||||
Vector2 relativePixelPosition,
|
||||
bool alt,
|
||||
bool control,
|
||||
bool shift,
|
||||
bool system)
|
||||
: base(sourceControl, buttonMask, globalPosition, relativePosition, alt, control, shift, system)
|
||||
: base(sourceControl, buttonMask, globalPosition, globalPixelPosition, relativePosition, relativePixelPosition, alt, control, shift, system)
|
||||
{
|
||||
Relative = relative;
|
||||
Speed = speed;
|
||||
@@ -201,13 +213,15 @@ namespace Robust.Client.UserInterface
|
||||
public GUIMouseWheelEventArgs(Mouse.Wheel wheelDirection,
|
||||
Control sourceControl,
|
||||
Mouse.ButtonMask buttonMask,
|
||||
Shared.Maths.Vector2 globalPosition,
|
||||
Shared.Maths.Vector2 relativePosition,
|
||||
Vector2 globalPosition,
|
||||
Vector2 globalPixelPosition,
|
||||
Vector2 relativePosition,
|
||||
Vector2 relativePixelPosition,
|
||||
bool alt,
|
||||
bool control,
|
||||
bool shift,
|
||||
bool system)
|
||||
: base(sourceControl, buttonMask, globalPosition, relativePosition, alt, control, shift, system)
|
||||
: base(sourceControl, buttonMask, globalPosition, globalPixelPosition, relativePosition, relativePixelPosition, alt, control, shift, system)
|
||||
{
|
||||
WheelDirection = wheelDirection;
|
||||
}
|
||||
|
||||
@@ -310,6 +310,13 @@ namespace Robust.Client.UserInterface
|
||||
EnteredTree();
|
||||
}
|
||||
|
||||
protected internal virtual void UIScaleChanged()
|
||||
{
|
||||
MinimumSizeChanged();
|
||||
}
|
||||
|
||||
protected float UIScale => UserInterfaceManager.UIScale;
|
||||
|
||||
// _marginSetSize is the size calculated by the margins,
|
||||
// but it's different from _size if min size is higher.
|
||||
private Vector2 _sizeByMargins;
|
||||
@@ -328,10 +335,18 @@ namespace Robust.Client.UserInterface
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
public Vector2i PixelSize => (Vector2i) (_size * UserInterfaceManager.UIScale);
|
||||
|
||||
public UIBox2 SizeBox => new UIBox2(Vector2.Zero, Size);
|
||||
public UIBox2i PixelSizeBox => new UIBox2i(Vector2i.Zero, PixelSize);
|
||||
|
||||
public float Width => Size.X;
|
||||
public float Height => Size.Y;
|
||||
|
||||
public int PixelWidth => PixelSize.X;
|
||||
public int PixelHeight => PixelSize.Y;
|
||||
|
||||
private Vector2 _position;
|
||||
|
||||
[ViewVariables]
|
||||
@@ -349,6 +364,9 @@ namespace Robust.Client.UserInterface
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
public Vector2i PixelPosition => (Vector2i)(_position * UserInterfaceManager.UIScale);
|
||||
|
||||
[ViewVariables]
|
||||
public Vector2 GlobalPosition
|
||||
{
|
||||
@@ -366,26 +384,27 @@ namespace Robust.Client.UserInterface
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
public Vector2i GlobalPixelPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
var offset = PixelPosition;
|
||||
var parent = Parent;
|
||||
while (parent != null)
|
||||
{
|
||||
offset += parent.PixelPosition;
|
||||
parent = parent.Parent;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
public UIBox2 Rect => UIBox2.FromDimensions(_position, _size);
|
||||
public UIBox2i PixelRect => UIBox2i.FromDimensions(PixelPosition, PixelSize);
|
||||
|
||||
public Vector2 Scale
|
||||
{
|
||||
get => default;
|
||||
set
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private string _tooltip;
|
||||
|
||||
public string ToolTip
|
||||
{
|
||||
get => _tooltip;
|
||||
set
|
||||
{
|
||||
_tooltip = value;
|
||||
}
|
||||
}
|
||||
public string ToolTip { get; set; }
|
||||
|
||||
[ViewVariables]
|
||||
public MouseFilterMode MouseFilter { get; set; } = MouseFilterMode.Stop;
|
||||
@@ -493,6 +512,8 @@ namespace Robust.Client.UserInterface
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2i CombinedPixelMinimumSize => (Vector2i)(CombinedMinimumSize * UIScale);
|
||||
|
||||
private Vector2? _calculatedMinimumSize;
|
||||
private Vector2 _customMinimumSize;
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
protected override void SortChildren()
|
||||
{
|
||||
var separation = ActualSeparation;
|
||||
var separation = (int) (ActualSeparation * UIScale);
|
||||
|
||||
// Step one: figure out the sizes of all our children and whether they want to stretch.
|
||||
var sizeList = new List<(Control control, int minSize, int finalSize, bool stretch)>();
|
||||
@@ -53,18 +53,18 @@ namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var childMinSize = child.CombinedMinimumSize;
|
||||
var (minX, minY) = child.CombinedPixelMinimumSize;
|
||||
int minSize;
|
||||
bool stretch;
|
||||
|
||||
if (Vertical)
|
||||
{
|
||||
minSize = (int) childMinSize.Y;
|
||||
minSize = (int) minY;
|
||||
stretch = (child.SizeFlagsVertical & SizeFlags.Expand) == SizeFlags.Expand;
|
||||
}
|
||||
else
|
||||
{
|
||||
minSize = (int) childMinSize.X;
|
||||
minSize = (int) minX;
|
||||
stretch = (child.SizeFlagsHorizontal & SizeFlags.Expand) == SizeFlags.Expand;
|
||||
}
|
||||
|
||||
@@ -80,15 +80,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
sizeList.Add((child, minSize, minSize, stretch));
|
||||
}
|
||||
|
||||
int stretchMax;
|
||||
if (Vertical)
|
||||
{
|
||||
stretchMax = (int) Size.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
stretchMax = (int) Size.X;
|
||||
}
|
||||
var stretchMax = Vertical ? PixelHeight : PixelWidth;
|
||||
|
||||
stretchMax -= separation * (ChildCount - 1);
|
||||
// This is the amount of space allocated for stretchable children.
|
||||
@@ -159,17 +151,17 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
first = false;
|
||||
|
||||
UIBox2 targetBox;
|
||||
UIBox2i targetBox;
|
||||
if (Vertical)
|
||||
{
|
||||
targetBox = new UIBox2(0, offset, Size.X, offset+size);
|
||||
targetBox = new UIBox2i(0, offset, PixelWidth, offset+size);
|
||||
}
|
||||
else
|
||||
{
|
||||
targetBox = new UIBox2(offset, 0, offset+size, Size.Y);
|
||||
targetBox = new UIBox2i(offset, 0, offset+size, PixelHeight);
|
||||
}
|
||||
|
||||
FitChildInBox(control, targetBox);
|
||||
FitChildInPixelBox(control, targetBox);
|
||||
|
||||
offset += size;
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
base.Draw(handle);
|
||||
|
||||
var style = ActualStyleBox;
|
||||
var drawBox = SizeBox;
|
||||
var drawBox = PixelSizeBox;
|
||||
style.Draw(handle, drawBox);
|
||||
|
||||
if (_text == null)
|
||||
@@ -142,19 +142,19 @@ namespace Robust.Client.UserInterface.Controls
|
||||
}
|
||||
|
||||
var color = ActualFontColor;
|
||||
var offsetY = (int) (box.Height - font.Height) / 2;
|
||||
var baseLine = new Vector2i(drawOffset, offsetY + font.Ascent) + box.TopLeft;
|
||||
var offsetY = (int) (box.Height - font.GetHeight(UIScale)) / 2;
|
||||
var baseLine = new Vector2i(drawOffset, offsetY + font.GetAscent(UIScale)) + box.TopLeft;
|
||||
|
||||
foreach (var chr in _text)
|
||||
{
|
||||
if (!font.TryGetCharMetrics(chr, out var metrics))
|
||||
if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(ClipText && (baseLine.X < box.Left || baseLine.X + metrics.Advance > box.Right)))
|
||||
{
|
||||
font.DrawChar(handle, chr, baseLine, color);
|
||||
font.DrawChar(handle, chr, baseLine, UIScale, color);
|
||||
}
|
||||
|
||||
baseLine += (metrics.Advance, 0);
|
||||
@@ -166,16 +166,16 @@ namespace Robust.Client.UserInterface.Controls
|
||||
var style = ActualStyleBox;
|
||||
var font = ActualFont;
|
||||
|
||||
var fontHeight = font.Height;
|
||||
var fontHeight = font.GetHeight(UIScale) / UIScale;
|
||||
|
||||
if (ClipText)
|
||||
{
|
||||
return (0, fontHeight) + style.MinimumSize;
|
||||
return (0, fontHeight) + style.MinimumSize/UIScale;
|
||||
}
|
||||
|
||||
var width = EnsureWidthCache();
|
||||
|
||||
return new Vector2(width, fontHeight) + style.MinimumSize;
|
||||
return (width / UIScale, fontHeight) + style.MinimumSize/UIScale;
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
@@ -224,7 +224,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
var textWidth = 0;
|
||||
foreach (var chr in _text)
|
||||
{
|
||||
var metrics = font.GetCharMetrics(chr);
|
||||
var metrics = font.GetCharMetrics(chr, UIScale);
|
||||
if (metrics == null)
|
||||
{
|
||||
continue;
|
||||
@@ -263,5 +263,12 @@ namespace Robust.Client.UserInterface.Controls
|
||||
ClipText = (bool) value;
|
||||
}
|
||||
}
|
||||
|
||||
protected internal override void UIScaleChanged()
|
||||
{
|
||||
_textWidthCache = null;
|
||||
|
||||
base.UIScaleChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,23 +25,23 @@ namespace Robust.Client.UserInterface.Controls
|
||||
if (icon != null)
|
||||
{
|
||||
offset += _getIcon().Width + _getHSeparation();
|
||||
handle.DrawTexture(icon, Vector2.Zero);
|
||||
handle.DrawTextureRect(icon, UIBox2.FromDimensions(Vector2.Zero, icon.Size * UIScale), false);
|
||||
}
|
||||
|
||||
var box = new UIBox2(offset, 0, Width, Height);
|
||||
var box = new UIBox2(offset, 0, PixelWidth, PixelHeight);
|
||||
DrawTextInternal(handle, box);
|
||||
}
|
||||
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
{
|
||||
var minSize = _getIcon()?.Size ?? Vector2i.Zero;
|
||||
var minSize = _getIcon()?.Size / UIScale ?? Vector2.Zero;
|
||||
var font = ActualFont;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Text) && !ClipText)
|
||||
{
|
||||
minSize += new Vector2i(EnsureWidthCache() + _getHSeparation(), 0);
|
||||
minSize += (EnsureWidthCache() / UIScale + _getHSeparation() / UIScale, 0);
|
||||
}
|
||||
minSize = Vector2i.ComponentMax(minSize, new Vector2i(0, font.Height));
|
||||
minSize = Vector2.ComponentMax(minSize, (0, font.GetHeight(UIScale) / UIScale));
|
||||
|
||||
return minSize;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,14 @@ namespace Robust.Client.UserInterface.Controls
|
||||
SortChildren();
|
||||
}
|
||||
|
||||
protected void FitChildInPixelBox(Control child, UIBox2i pixelBox)
|
||||
{
|
||||
var topLeft = pixelBox.TopLeft / UIScale;
|
||||
var bottomRight = pixelBox.BottomRight / UIScale;
|
||||
|
||||
FitChildInBox(child, new UIBox2(topLeft, bottomRight));
|
||||
}
|
||||
|
||||
protected void FitChildInBox(Control child, UIBox2 box)
|
||||
{
|
||||
DebugTools.Assert(child.Parent == this);
|
||||
|
||||
@@ -70,15 +70,15 @@ namespace Robust.Client.UserInterface.Controls
|
||||
set => _hSeparationOverride = value;
|
||||
}
|
||||
|
||||
private (int h, int v) Separations => (_hSeparationOverride ?? 4, _vSeparationOverride ?? 4);
|
||||
private Vector2i Separations => (_hSeparationOverride ?? 4, _vSeparationOverride ?? 4);
|
||||
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
{
|
||||
var firstRow = true;
|
||||
var totalMinSize = Vector2.Zero;
|
||||
var thisRowSize = Vector2.Zero;
|
||||
var totalMinSize = Vector2i.Zero;
|
||||
var thisRowSize = Vector2i.Zero;
|
||||
var currentRowCount = 0;
|
||||
var (h, v) = Separations;
|
||||
var (h, v) = (Vector2i)(Separations * UIScale);
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
@@ -87,7 +87,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
continue;
|
||||
}
|
||||
|
||||
var (minSizeX, minSizeY) = child.CombinedMinimumSize;
|
||||
var (minSizeX, minSizeY) = child.CombinedPixelMinimumSize;
|
||||
thisRowSize = (thisRowSize.X + minSizeX, Math.Max(thisRowSize.Y, minSizeY));
|
||||
if (currentRowCount != 0)
|
||||
{
|
||||
@@ -103,7 +103,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
}
|
||||
firstRow = false;
|
||||
|
||||
thisRowSize = Vector2.Zero;
|
||||
thisRowSize = Vector2i.Zero;
|
||||
currentRowCount = 0;
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
}
|
||||
}
|
||||
|
||||
return totalMinSize;
|
||||
return totalMinSize / UIScale;
|
||||
}
|
||||
|
||||
protected override void SortChildren()
|
||||
@@ -148,15 +148,15 @@ namespace Robust.Client.UserInterface.Controls
|
||||
var row = index / _columns;
|
||||
var column = index % _columns;
|
||||
|
||||
var (minSizeX, minSizeY) = child.CombinedMinimumSize;
|
||||
columnSizes[column] = Math.Max((int) minSizeX, columnSizes[column]);
|
||||
rowSizes[row] = Math.Max((int) minSizeY, rowSizes[row]);
|
||||
var (minSizeX, minSizeY) = child.CombinedPixelMinimumSize;
|
||||
columnSizes[column] = Math.Max(minSizeX, columnSizes[column]);
|
||||
rowSizes[row] = Math.Max(minSizeY, rowSizes[row]);
|
||||
columnExpand[column] = columnExpand[column] || (child.SizeFlagsHorizontal & SizeFlags.Expand) != 0;
|
||||
rowExpand[row] = rowExpand[row] || (child.SizeFlagsVertical & SizeFlags.Expand) != 0;
|
||||
}
|
||||
|
||||
// Basically now we just apply BoxContainer logic on rows and columns.
|
||||
var (vSep, hSep) = Separations;
|
||||
var (vSep, hSep) = (Vector2i)(Separations * UIScale);
|
||||
var stretchMinX = 0;
|
||||
var stretchMinY = 0;
|
||||
// We do not use stretch ratios because Godot doesn't,
|
||||
@@ -191,8 +191,8 @@ namespace Robust.Client.UserInterface.Controls
|
||||
}
|
||||
}
|
||||
|
||||
var stretchMaxX = Size.X - hSep * (_columns - 1);
|
||||
var stretchMaxY = Size.Y - vSep * (rows - 1);
|
||||
var stretchMaxX = Width - hSep * (_columns - 1);
|
||||
var stretchMaxY = Height - vSep * (rows - 1);
|
||||
|
||||
var stretchAvailX = Math.Max(0, stretchMaxX - stretchMinX);
|
||||
var stretchAvailY = Math.Max(0, stretchMaxY - stretchMinY);
|
||||
@@ -243,8 +243,8 @@ namespace Robust.Client.UserInterface.Controls
|
||||
}
|
||||
}
|
||||
|
||||
var box = UIBox2.FromDimensions(hOffset, vOffset, columnSizes[column], rowSizes[row]);
|
||||
FitChildInBox(child, box);
|
||||
var box = UIBox2i.FromDimensions(hOffset, vOffset, columnSizes[column], rowSizes[row]);
|
||||
FitChildInPixelBox(child, box);
|
||||
|
||||
hOffset += columnSizes[column] + hSep;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Diagnostics.Contracts;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Maths;
|
||||
using Color = Robust.Shared.Maths.Color;
|
||||
using Font = Robust.Client.Graphics.Font;
|
||||
@@ -16,7 +15,6 @@ namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
private bool _isAtBottom = true;
|
||||
private int _totalContentHeight;
|
||||
private float _itemListHeight;
|
||||
|
||||
private VScrollBar _scrollBar = new VScrollBar();
|
||||
private readonly List<Item> _itemList = new List<Item>();
|
||||
@@ -33,8 +31,6 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
public bool ScrollFollowing { get; set; } = true;
|
||||
|
||||
private int ScrollLimit => Math.Max(0, _totalContentHeight - (int) _getContentBox().Height + 1);
|
||||
|
||||
public ItemListSelectMode SelectMode { get; set; } = ItemListSelectMode.Single;
|
||||
|
||||
public ItemList()
|
||||
@@ -55,12 +51,19 @@ namespace Robust.Client.UserInterface.Controls
|
||||
_totalContentHeight = 0;
|
||||
foreach (var item in _itemList)
|
||||
{
|
||||
var itemHeight = item.Icon != null
|
||||
? Math.Max(item.IconSize.Y, ActualFont.Height) + ActualItemBackground.MinimumSize.Y
|
||||
: ActualFont.Height + ActualItemBackground.MinimumSize.Y;
|
||||
var itemHeight = 0f;
|
||||
if (item.Icon != null)
|
||||
{
|
||||
itemHeight = item.IconSize.Y;
|
||||
}
|
||||
|
||||
_totalContentHeight += (int)itemHeight;
|
||||
itemHeight = Math.Max(itemHeight, ActualFont.GetHeight(UIScale));
|
||||
itemHeight += ActualItemBackground.MinimumSize.Y;
|
||||
|
||||
_totalContentHeight += (int)Math.Ceiling(itemHeight);
|
||||
}
|
||||
|
||||
_scrollBar.MaxValue = Math.Max(_scrollBar.Page, _totalContentHeight);
|
||||
}
|
||||
|
||||
public void AddItem(string text, Texture icon = null, bool selectable = true)
|
||||
@@ -70,8 +73,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
RecalculateContentHeight();
|
||||
if (_isAtBottom && ScrollFollowing)
|
||||
{
|
||||
_scrollBar.Value = ScrollLimit;
|
||||
|
||||
_scrollBar.MoveToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +273,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
public void ScrollToBottom()
|
||||
{
|
||||
_scrollBar.Value = ScrollLimit;
|
||||
_scrollBar.MoveToEnd();
|
||||
_isAtBottom = true;
|
||||
}
|
||||
|
||||
@@ -285,10 +287,9 @@ namespace Robust.Client.UserInterface.Controls
|
||||
var iconSelectedBg = ActualSelectedItemBackground;
|
||||
var iconDisabledBg = ActualDisabledItemBackground;
|
||||
|
||||
_itemListHeight = 0f;
|
||||
Vector2 separation = (0, -_scrollBar.Value);
|
||||
var offset = -_scrollBar.Value;
|
||||
|
||||
listBg.Draw(handle, SizeBox);
|
||||
listBg.Draw(handle, PixelSizeBox);
|
||||
|
||||
foreach (var item in _itemList)
|
||||
{
|
||||
@@ -300,11 +301,16 @@ namespace Robust.Client.UserInterface.Controls
|
||||
if (item.Selected)
|
||||
bg = iconSelectedBg;
|
||||
|
||||
var itemHeight = item.Icon != null
|
||||
? Math.Max(item.IconSize.Y, font.Height) + bg.MinimumSize.Y
|
||||
: font.Height + bg.MinimumSize.Y;
|
||||
var itemHeight = 0f;
|
||||
if (item.Icon != null)
|
||||
{
|
||||
itemHeight = item.IconSize.Y;
|
||||
}
|
||||
|
||||
item.Region = UIBox2.FromDimensions(separation, (SizeBox.Width, itemHeight));
|
||||
itemHeight = Math.Max(itemHeight, ActualFont.GetHeight(UIScale));
|
||||
itemHeight += ActualItemBackground.MinimumSize.Y;
|
||||
|
||||
item.Region = UIBox2.FromDimensions((0, offset), (PixelWidth, itemHeight));
|
||||
|
||||
bg.Draw(handle, item.Region.Value);
|
||||
|
||||
@@ -312,36 +318,23 @@ namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
if (item.IconRegion.Size == Vector2.Zero)
|
||||
{
|
||||
handle.DrawTextureRect(item.Icon, UIBox2.FromDimensions(separation, item.Icon.Size), false, item.IconModulate, item.IconTranspose);
|
||||
handle.DrawTextureRect(item.Icon, UIBox2.FromDimensions((0, offset), item.Icon.Size), false, item.IconModulate, item.IconTranspose);
|
||||
}
|
||||
else
|
||||
{
|
||||
handle.DrawTextureRectRegion(item.Icon, UIBox2.FromDimensions(separation, item.Icon.Size), item.IconRegion, item.IconModulate);
|
||||
handle.DrawTextureRectRegion(item.Icon, UIBox2.FromDimensions((0, offset), item.Icon.Size), item.IconRegion, item.IconModulate);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.Text != null)
|
||||
{
|
||||
DrawTextInternal(handle, item.Text,
|
||||
UIBox2.FromDimensions((item.IconSize.X, separation.Y), (SizeBox.Width-item.IconSize.X,font.Height*2))
|
||||
UIBox2.FromDimensions((item.IconSize.X, offset), (PixelWidth-item.IconSize.X,font.GetHeight(UIScale)))
|
||||
);
|
||||
}
|
||||
|
||||
separation += (0, itemHeight);
|
||||
_itemListHeight += itemHeight;
|
||||
offset += itemHeight;
|
||||
}
|
||||
|
||||
if (_itemListHeight > Size.Y)
|
||||
{
|
||||
_scrollBar.MaxValue = _itemListHeight;
|
||||
_scrollBar.Page = Size.Y - ActualBackground.MinimumSize.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
_scrollBar.MaxValue = 0f;
|
||||
_scrollBar.Page = 0f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void DrawTextInternal(DrawingHandleScreen handle, string text, UIBox2 box)
|
||||
@@ -349,19 +342,19 @@ namespace Robust.Client.UserInterface.Controls
|
||||
var font = ActualFont;
|
||||
|
||||
var color = ActualFontColor;
|
||||
var offsetY = (int) (box.Height - font.Height) / 2;
|
||||
var baseLine = new Vector2i(0, offsetY + font.Ascent) + box.TopLeft;
|
||||
var offsetY = (int) (box.Height - font.GetHeight(UIScale)) / 2;
|
||||
var baseLine = new Vector2i(0, offsetY + font.GetAscent(UIScale)) + box.TopLeft;
|
||||
|
||||
foreach (var chr in text)
|
||||
{
|
||||
if (!font.TryGetCharMetrics(chr, out var metrics))
|
||||
if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(baseLine.X < box.Left || baseLine.X + metrics.Advance > box.Right))
|
||||
{
|
||||
font.DrawChar(handle, chr, baseLine, color);
|
||||
font.DrawChar(handle, chr, baseLine, UIScale, color);
|
||||
}
|
||||
|
||||
baseLine += (metrics.Advance, 0);
|
||||
@@ -370,7 +363,13 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
{
|
||||
return (ActualBackground?.MinimumSize.X ?? 0, _itemListHeight + ActualBackground?.MinimumSize.Y ?? 0);
|
||||
var size = Vector2.Zero;
|
||||
if (ActualBackground != null)
|
||||
{
|
||||
size += ActualBackground.MinimumSize / UIScale;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
protected internal override void MouseMove(GUIMouseMoveEventArgs args)
|
||||
@@ -393,16 +392,12 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
if (args.WheelDirection == Mouse.Wheel.Up)
|
||||
{
|
||||
_scrollBar.Value = _scrollBar.Value - _getScrollSpeed();
|
||||
_scrollBar.Value -= _getScrollSpeed();
|
||||
_isAtBottom = false;
|
||||
}
|
||||
else if (args.WheelDirection == Mouse.Wheel.Down)
|
||||
{
|
||||
var limit = ScrollLimit;
|
||||
if (_scrollBar.Value + _getScrollSpeed() < limit)
|
||||
_scrollBar.Value = _scrollBar.Value + _getScrollSpeed();
|
||||
else
|
||||
ScrollToBottom();
|
||||
_scrollBar.Value += _getScrollSpeed();
|
||||
if (_scrollBar.IsAtEnd)
|
||||
{
|
||||
_isAtBottom = true;
|
||||
@@ -446,7 +441,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
private int _getScrollSpeed()
|
||||
{
|
||||
var font = ActualFont;
|
||||
return font.Height * 2;
|
||||
return font.GetHeight(UIScale) * 2;
|
||||
}
|
||||
|
||||
[Pure]
|
||||
@@ -456,6 +451,23 @@ namespace Robust.Client.UserInterface.Controls
|
||||
return style?.GetContentBox(SizeBox) ?? SizeBox;
|
||||
}
|
||||
|
||||
protected override void Resized()
|
||||
{
|
||||
base.Resized();
|
||||
|
||||
var styleBoxSize = ActualBackground?.MinimumSize.Y ?? 0;
|
||||
|
||||
_scrollBar.Page = PixelSize.Y - styleBoxSize;
|
||||
RecalculateContentHeight();
|
||||
}
|
||||
|
||||
protected internal override void UIScaleChanged()
|
||||
{
|
||||
RecalculateContentHeight();
|
||||
|
||||
base.UIScaleChanged();
|
||||
}
|
||||
|
||||
public sealed class Item
|
||||
{
|
||||
public string Text = null;
|
||||
|
||||
@@ -41,15 +41,6 @@ namespace Robust.Client.UserInterface.Controls
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
public bool AutoWrap
|
||||
{
|
||||
get => default;
|
||||
set
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
public AlignMode Align { get; set; }
|
||||
|
||||
@@ -124,10 +115,10 @@ namespace Robust.Client.UserInterface.Controls
|
||||
break;
|
||||
case AlignMode.Center:
|
||||
case AlignMode.Fill:
|
||||
hOffset = (int) (Size.X - _textDimensionCache.Value.X) / 2;
|
||||
hOffset = (PixelSize.X - _textDimensionCache.Value.X) / 2;
|
||||
break;
|
||||
case AlignMode.Right:
|
||||
hOffset = (int) (Size.X - _textDimensionCache.Value.X);
|
||||
hOffset = PixelSize.X - _textDimensionCache.Value.X;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
@@ -141,10 +132,10 @@ namespace Robust.Client.UserInterface.Controls
|
||||
break;
|
||||
case VAlignMode.Fill:
|
||||
case VAlignMode.Center:
|
||||
vOffset = (int) (Size.Y - _textDimensionCache.Value.Y) / 2;
|
||||
vOffset = (PixelSize.Y - _textDimensionCache.Value.Y) / 2;
|
||||
break;
|
||||
case VAlignMode.Bottom:
|
||||
vOffset = (int) (Size.Y - _textDimensionCache.Value.Y);
|
||||
vOffset = PixelSize.Y - _textDimensionCache.Value.Y;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
@@ -152,17 +143,17 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
var newlines = 0;
|
||||
var font = ActualFont;
|
||||
var baseLine = new Vector2(hOffset, font.Ascent + vOffset);
|
||||
var baseLine = new Vector2(hOffset, font.GetAscent(UIScale) + vOffset);
|
||||
var actualFontColor = ActualFontColor;
|
||||
foreach (var chr in _text)
|
||||
{
|
||||
if (chr == '\n')
|
||||
{
|
||||
newlines += 1;
|
||||
baseLine = new Vector2(hOffset, font.Ascent + font.LineHeight * newlines);
|
||||
baseLine = new Vector2(hOffset, font.GetAscent(UIScale) + font.GetLineHeight(UIScale) * newlines);
|
||||
}
|
||||
|
||||
var advance = font.DrawChar(handle, chr, baseLine, actualFontColor);
|
||||
var advance = font.DrawChar(handle, chr, baseLine, UIScale, actualFontColor);
|
||||
baseLine += new Vector2(advance, 0);
|
||||
}
|
||||
}
|
||||
@@ -194,6 +185,13 @@ namespace Robust.Client.UserInterface.Controls
|
||||
return _textDimensionCache.Value;
|
||||
}
|
||||
|
||||
protected internal override void UIScaleChanged()
|
||||
{
|
||||
_textDimensionCache = null;
|
||||
|
||||
base.UIScaleChanged();
|
||||
}
|
||||
|
||||
private void _calculateTextDimension()
|
||||
{
|
||||
if (_text == null)
|
||||
@@ -203,7 +201,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
}
|
||||
|
||||
var font = ActualFont;
|
||||
var height = font.Height;
|
||||
var height = font.GetHeight(UIScale);
|
||||
var maxLineSize = 0;
|
||||
var currentLineSize = 0;
|
||||
foreach (var chr in _text)
|
||||
@@ -212,11 +210,11 @@ namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
maxLineSize = Math.Max(currentLineSize, maxLineSize);
|
||||
currentLineSize = 0;
|
||||
height += font.LineHeight;
|
||||
height += font.GetLineHeight(UIScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
var metrics = font.GetCharMetrics(chr);
|
||||
var metrics = font.GetCharMetrics(chr, UIScale);
|
||||
if (!metrics.HasValue)
|
||||
{
|
||||
continue;
|
||||
@@ -228,7 +226,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
maxLineSize = Math.Max(currentLineSize, maxLineSize);
|
||||
|
||||
_textDimensionCache = new Vector2i(maxLineSize, height);
|
||||
_textDimensionCache = (Vector2i)(new Vector2(maxLineSize, height) / UIScale);
|
||||
}
|
||||
|
||||
protected override void StylePropertiesChanged()
|
||||
|
||||
@@ -135,14 +135,14 @@ namespace Robust.Client.UserInterface.Controls
|
||||
protected internal override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
var styleBox = _getStyleBox();
|
||||
var drawBox = SizeBox;
|
||||
var drawBox = PixelSizeBox;
|
||||
var contentBox = styleBox.GetContentBox(drawBox);
|
||||
styleBox.Draw(handle, drawBox);
|
||||
var font = _getFont();
|
||||
var renderedTextColor = _getFontColor();
|
||||
|
||||
var offsetY = (int) (contentBox.Height - font.Height) / 2;
|
||||
var baseLine = new Vector2i(0, offsetY + font.Ascent) + contentBox.TopLeft;
|
||||
var offsetY = (int) (contentBox.Height - font.GetHeight(UIScale)) / 2;
|
||||
var baseLine = new Vector2i(0, offsetY + font.GetAscent(UIScale)) + contentBox.TopLeft;
|
||||
|
||||
string renderedText;
|
||||
|
||||
@@ -165,7 +165,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
var count = 0;
|
||||
foreach (var chr in renderedText)
|
||||
{
|
||||
if (!font.TryGetCharMetrics(chr, out var metrics))
|
||||
if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
|
||||
{
|
||||
count += 1;
|
||||
continue;
|
||||
@@ -177,7 +177,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
break;
|
||||
}
|
||||
|
||||
font.DrawChar(handle, chr, baseLine, renderedTextColor);
|
||||
font.DrawChar(handle, chr, baseLine, UIScale, renderedTextColor);
|
||||
baseLine += new Vector2(metrics.Advance, 0);
|
||||
count += 1;
|
||||
if (count == _cursorPosition)
|
||||
@@ -210,7 +210,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
var font = _getFont();
|
||||
var style = _getStyleBox();
|
||||
return new Vector2(0, font.Height) + style.MinimumSize;
|
||||
return new Vector2(0, font.GetHeight(UIScale)/UIScale) + style.MinimumSize/UIScale;
|
||||
}
|
||||
|
||||
protected internal override void TextEntered(GUITextEventArgs args)
|
||||
@@ -305,9 +305,9 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
// Find closest cursor position under mouse.
|
||||
var style = _getStyleBox();
|
||||
var contentBox = style.GetContentBox(SizeBox);
|
||||
var contentBox = style.GetContentBox(PixelSizeBox);
|
||||
|
||||
var clickPosX = args.RelativePosition.X;
|
||||
var clickPosX = args.RelativePosition.X * UIScale;
|
||||
|
||||
var font = _getFont();
|
||||
var index = 0;
|
||||
@@ -315,7 +315,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
var lastChrPostX = contentBox.Left;
|
||||
foreach (var chr in _text)
|
||||
{
|
||||
if (!font.TryGetCharMetrics(chr, out var metrics))
|
||||
if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
|
||||
{
|
||||
index += 1;
|
||||
continue;
|
||||
|
||||
@@ -4,7 +4,6 @@ using JetBrains.Annotations;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using PureAttribute = System.Diagnostics.Contracts.PureAttribute;
|
||||
@@ -28,8 +27,6 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
public bool ScrollFollowing { get; set; } = true;
|
||||
|
||||
private int ScrollLimit => Math.Max(0, _totalContentHeight - (int) _getContentBox().Height + 1);
|
||||
|
||||
public StyleBox StyleBoxOverride
|
||||
{
|
||||
get => _styleBoxOverride;
|
||||
@@ -56,7 +53,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
_entries.RemoveAt(line);
|
||||
|
||||
var font = _getFont();
|
||||
_totalContentHeight -= entry.Height + font.LineSeparation;
|
||||
_totalContentHeight -= entry.Height + font.GetLineSeparation(UIScale);
|
||||
if (_entries.Count == 0)
|
||||
{
|
||||
Clear();
|
||||
@@ -68,7 +65,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
var entry = new RichTextEntry(message);
|
||||
|
||||
entry.Update(_getFont(), _getContentBox().Width);
|
||||
entry.Update(_getFont(), _getContentBox().Width, UIScale);
|
||||
|
||||
_entries.Add(entry);
|
||||
var font = _getFont();
|
||||
@@ -79,19 +76,19 @@ namespace Robust.Client.UserInterface.Controls
|
||||
}
|
||||
else
|
||||
{
|
||||
_totalContentHeight += font.LineSeparation;
|
||||
_totalContentHeight += font.GetLineSeparation(UIScale);
|
||||
}
|
||||
|
||||
_scrollBar.MaxValue = Math.Max(_scrollBar.Page, _totalContentHeight);
|
||||
if (_isAtBottom && ScrollFollowing)
|
||||
{
|
||||
_scrollBar.Value = ScrollLimit;
|
||||
_scrollBar.MoveToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
public void ScrollToBottom()
|
||||
{
|
||||
_scrollBar.Value = ScrollLimit;
|
||||
_scrollBar.MoveToEnd();
|
||||
_isAtBottom = true;
|
||||
}
|
||||
|
||||
@@ -111,7 +108,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
var style = _getStyleBox();
|
||||
var font = _getFont();
|
||||
style?.Draw(handle, SizeBox);
|
||||
style?.Draw(handle, PixelSizeBox);
|
||||
var contentBox = _getContentBox();
|
||||
|
||||
var entryOffset = -_scrollBar.Value;
|
||||
@@ -125,7 +122,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
if (entryOffset + entry.Height < 0)
|
||||
{
|
||||
entryOffset += entry.Height + font.LineSeparation;
|
||||
entryOffset += entry.Height + font.GetLineSeparation(UIScale);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -134,9 +131,9 @@ namespace Robust.Client.UserInterface.Controls
|
||||
break;
|
||||
}
|
||||
|
||||
entry.Draw(handle, font, contentBox, entryOffset, formatStack);
|
||||
entry.Draw(handle, font, contentBox, entryOffset, formatStack, UIScale);
|
||||
|
||||
entryOffset += entry.Height + font.LineSeparation;
|
||||
entryOffset += entry.Height + font.GetLineSeparation(UIScale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,12 +143,12 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
if (args.WheelDirection == Mouse.Wheel.Up)
|
||||
{
|
||||
_scrollBar.Value = _scrollBar.Value - _getScrollSpeed();
|
||||
_scrollBar.Value -= _getScrollSpeed();
|
||||
_isAtBottom = false;
|
||||
}
|
||||
else if (args.WheelDirection == Mouse.Wheel.Down)
|
||||
{
|
||||
_scrollBar.Value = _scrollBar.Value + _getScrollSpeed();
|
||||
_scrollBar.Value += _getScrollSpeed();
|
||||
if (_scrollBar.IsAtEnd)
|
||||
{
|
||||
_isAtBottom = true;
|
||||
@@ -172,7 +169,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
var styleBoxSize = _getStyleBox()?.MinimumSize.Y ?? 0;
|
||||
|
||||
_scrollBar.Page = Size.Y - styleBoxSize;
|
||||
_scrollBar.Page = PixelSize.Y - styleBoxSize;
|
||||
_invalidateEntries();
|
||||
}
|
||||
|
||||
@@ -189,15 +186,15 @@ namespace Robust.Client.UserInterface.Controls
|
||||
for (var i = 0; i < _entries.Count; i++)
|
||||
{
|
||||
var entry = _entries[i];
|
||||
entry.Update(font, sizeX);
|
||||
entry.Update(font, sizeX, UIScale);
|
||||
_entries[i] = entry;
|
||||
_totalContentHeight += entry.Height + font.LineSeparation;
|
||||
_totalContentHeight += entry.Height + font.GetLineSeparation(UIScale);
|
||||
}
|
||||
|
||||
_scrollBar.MaxValue = Math.Max(_scrollBar.Page, _totalContentHeight);
|
||||
if (_isAtBottom && ScrollFollowing)
|
||||
{
|
||||
_scrollBar.Value = ScrollLimit;
|
||||
_scrollBar.MoveToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,14 +226,21 @@ namespace Robust.Client.UserInterface.Controls
|
||||
private int _getScrollSpeed()
|
||||
{
|
||||
var font = _getFont();
|
||||
return font.Height * 2;
|
||||
return font.GetLineHeight(UIScale) * 2;
|
||||
}
|
||||
|
||||
[Pure]
|
||||
private UIBox2 _getContentBox()
|
||||
{
|
||||
var style = _getStyleBox();
|
||||
return style?.GetContentBox(SizeBox) ?? SizeBox;
|
||||
return style?.GetContentBox(PixelSizeBox) ?? PixelSizeBox;
|
||||
}
|
||||
|
||||
protected internal override void UIScaleChanged()
|
||||
{
|
||||
_invalidateEntries();
|
||||
|
||||
base.UIScaleChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
base.Draw(handle);
|
||||
|
||||
var panel = ActualPanel;
|
||||
panel.Draw(handle, SizeBox);
|
||||
panel.Draw(handle, PixelSizeBox);
|
||||
}
|
||||
|
||||
private protected override void SetGodotProperty(string property, object value, GodotAssetScene context)
|
||||
@@ -63,7 +63,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
{
|
||||
return ActualPanel.MinimumSize;
|
||||
return ActualPanel.MinimumSize/UIScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,18 +31,18 @@ namespace Robust.Client.UserInterface.Controls
|
||||
base.Draw(handle);
|
||||
|
||||
var style = _getStyleBox();
|
||||
style?.Draw(handle, SizeBox);
|
||||
style?.Draw(handle, PixelSizeBox);
|
||||
}
|
||||
|
||||
protected override void SortChildren()
|
||||
{
|
||||
base.SortChildren();
|
||||
|
||||
var contentBox = _getStyleBox()?.GetContentBox(SizeBox) ?? SizeBox;
|
||||
var contentBox = _getStyleBox()?.GetContentBox(PixelSizeBox) ?? SizeBox;
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
FitChildInBox(child, contentBox);
|
||||
FitChildInPixelBox(child, (UIBox2i) contentBox);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
childSize = Vector2.ComponentMax(childSize, child.CombinedMinimumSize);
|
||||
}
|
||||
|
||||
return styleSize + childSize;
|
||||
return styleSize / UIScale + childSize;
|
||||
}
|
||||
|
||||
[System.Diagnostics.Contracts.Pure]
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -35,7 +34,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
return Vector2.Zero;
|
||||
}
|
||||
|
||||
return (0, _entry.Height);
|
||||
return (0, _entry.Height / UIScale);
|
||||
}
|
||||
|
||||
private void _updateEntry()
|
||||
@@ -45,7 +44,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
if (_message != null)
|
||||
{
|
||||
var oldHeight = _entry.Height;
|
||||
_entry.Update(font, Width);
|
||||
_entry.Update(font, Width, UIScale);
|
||||
if (oldHeight != _entry.Height)
|
||||
{
|
||||
MinimumSizeChanged();
|
||||
@@ -62,7 +61,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
return;
|
||||
}
|
||||
|
||||
_entry.Draw(handle, _getFont(), SizeBox, 0, new Stack<FormattedMessage.Tag>());
|
||||
_entry.Draw(handle, _getFont(), SizeBox, 0, new Stack<FormattedMessage.Tag>(), UIScale);
|
||||
}
|
||||
|
||||
protected override void Resized()
|
||||
|
||||
@@ -31,6 +31,12 @@ namespace Robust.Client.UserInterface.Controls
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveToEnd()
|
||||
{
|
||||
// Will be clamped as necessary.
|
||||
Value = MaxValue;
|
||||
}
|
||||
|
||||
protected internal override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
var styleBox = _getGrabberStyleBox();
|
||||
@@ -121,11 +127,11 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
if (_orientation == OrientationMode.Horizontal)
|
||||
{
|
||||
return new UIBox2(grabberOffset, 0, grabberEnd, Height);
|
||||
return new UIBox2(grabberOffset, 0, grabberEnd, PixelHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new UIBox2(0, grabberOffset, Width, grabberEnd);
|
||||
return new UIBox2(0, grabberOffset, PixelWidth, grabberEnd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,11 +152,11 @@ namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
if (_orientation == OrientationMode.Horizontal)
|
||||
{
|
||||
return Width;
|
||||
return PixelWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Height;
|
||||
return PixelHeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
return;
|
||||
}
|
||||
|
||||
handle.DrawEntity(_sprite.Owner, GlobalPosition + Size / 2);
|
||||
handle.DrawEntity(_sprite.Owner, GlobalPixelPosition + PixelSize / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
// First, draw panel.
|
||||
var headerSize = _getHeaderSize();
|
||||
var panel = _getPanel();
|
||||
var panelBox = new UIBox2(0, headerSize, Width, Height);
|
||||
var panelBox = new UIBox2(0, headerSize, PixelWidth, PixelHeight);
|
||||
|
||||
panel?.Draw(handle, panelBox);
|
||||
|
||||
@@ -156,7 +156,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
// Get string length.
|
||||
foreach (var chr in title)
|
||||
{
|
||||
if (!font.TryGetCharMetrics(chr, out var metrics))
|
||||
if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -169,7 +169,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
UIBox2 contentBox;
|
||||
var topLeft = new Vector2(headerOffset, 0);
|
||||
var size = new Vector2(titleLength, font.Height);
|
||||
var size = new Vector2(titleLength, font.GetHeight(UIScale));
|
||||
float boxAdvance;
|
||||
|
||||
if (box != null)
|
||||
@@ -185,16 +185,16 @@ namespace Robust.Client.UserInterface.Controls
|
||||
contentBox = UIBox2.FromDimensions(topLeft, size);
|
||||
}
|
||||
|
||||
var baseLine = new Vector2(0, font.Ascent) + contentBox.TopLeft;
|
||||
var baseLine = new Vector2(0, font.GetAscent(UIScale)) + contentBox.TopLeft;
|
||||
|
||||
foreach (var chr in title)
|
||||
{
|
||||
if (!font.TryGetCharMetrics(chr, out var metrics))
|
||||
if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
font.DrawChar(handle, chr, baseLine, active ? fontColorActive : fontColorInactive);
|
||||
font.DrawChar(handle, chr, baseLine, UIScale, active ? fontColorActive : fontColorInactive);
|
||||
baseLine += new Vector2(metrics.Advance, 0);
|
||||
}
|
||||
|
||||
@@ -204,30 +204,30 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
{
|
||||
var total = new Vector2();
|
||||
var total = Vector2i.Zero;
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
if (child.Visible)
|
||||
{
|
||||
total = Vector2.ComponentMax(child.CombinedMinimumSize, total);
|
||||
total = Vector2i.ComponentMax(child.CombinedPixelMinimumSize, total);
|
||||
}
|
||||
}
|
||||
|
||||
if (TabsVisible)
|
||||
{
|
||||
total += new Vector2(0, _getHeaderSize());
|
||||
total += (0, _getHeaderSize());
|
||||
}
|
||||
|
||||
var panel = _getPanel();
|
||||
total += panel?.MinimumSize ?? Vector2.Zero;
|
||||
total += (Vector2i)(panel?.MinimumSize ?? Vector2.Zero);
|
||||
|
||||
return total;
|
||||
return total / UIScale;
|
||||
}
|
||||
|
||||
private void _fixChildMargins(Control child)
|
||||
{
|
||||
FitChildInBox(child, _getContentBox());
|
||||
FitChildInPixelBox(child, _getContentBox());
|
||||
}
|
||||
|
||||
protected override void SortChildren()
|
||||
@@ -254,14 +254,14 @@ namespace Robust.Client.UserInterface.Controls
|
||||
}
|
||||
|
||||
// Outside of header size, ignore.
|
||||
if (args.RelativePosition.Y < 0 || args.RelativePosition.Y > _getHeaderSize())
|
||||
if (args.RelativePixelPosition.Y < 0 || args.RelativePixelPosition.Y > _getHeaderSize())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
args.Handle();
|
||||
|
||||
var relX = args.RelativePosition.X;
|
||||
var relX = args.RelativePixelPosition.X;
|
||||
|
||||
var font = _getFont();
|
||||
var boxActive = _getTabBoxActive();
|
||||
@@ -277,7 +277,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
// Get string length.
|
||||
foreach (var chr in title)
|
||||
{
|
||||
if (!font.TryGetCharMetrics(chr, out var metrics))
|
||||
if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -301,18 +301,22 @@ namespace Robust.Client.UserInterface.Controls
|
||||
}
|
||||
|
||||
[Pure]
|
||||
private UIBox2 _getContentBox()
|
||||
private UIBox2i _getContentBox()
|
||||
{
|
||||
var headerSize = _getHeaderSize();
|
||||
var panel = _getPanel();
|
||||
var panelBox = new UIBox2(0, headerSize, Width, Height);
|
||||
return panel?.GetContentBox(panelBox) ?? panelBox;
|
||||
var panelBox = new UIBox2i(0, headerSize, PixelWidth, PixelHeight);
|
||||
if (panel != null)
|
||||
{
|
||||
return (UIBox2i) panel.GetContentBox(panelBox);
|
||||
}
|
||||
return panelBox;
|
||||
}
|
||||
|
||||
[Pure]
|
||||
private float _getHeaderSize()
|
||||
private int _getHeaderSize()
|
||||
{
|
||||
var headerSize = 0f;
|
||||
var headerSize = 0;
|
||||
|
||||
if (TabsVisible)
|
||||
{
|
||||
@@ -323,8 +327,8 @@ namespace Robust.Client.UserInterface.Controls
|
||||
var activeSize = active?.MinimumSize ?? Vector2.Zero;
|
||||
var inactiveSize = inactive?.MinimumSize ?? Vector2.Zero;
|
||||
|
||||
headerSize = Math.Max(activeSize.Y, inactiveSize.Y);
|
||||
headerSize += font.Height;
|
||||
headerSize = (int) Math.Max(activeSize.Y, inactiveSize.Y);
|
||||
headerSize += font.GetHeight(UIScale);
|
||||
}
|
||||
|
||||
return headerSize;
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
}
|
||||
}
|
||||
|
||||
handle.DrawTextureRect(texture, SizeBox, false);
|
||||
handle.DrawTextureRect(texture, PixelSizeBox, false);
|
||||
}
|
||||
|
||||
private protected override void SetGodotProperty(string property, object value, GodotAssetScene context)
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
break;
|
||||
case StretchMode.KeepCentered:
|
||||
{
|
||||
var position = (Vector2i) (Size - _texture.Size) / 2;
|
||||
var position = (PixelSize - _texture.Size) / 2;
|
||||
handle.DrawTexture(_texture, position);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
@@ -134,8 +133,8 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
bool DoSearch(Item item, float hOffset)
|
||||
{
|
||||
var itemHeight = font.Height;
|
||||
var itemBox = UIBox2.FromDimensions((hOffset, vOffset), (Width - hOffset, itemHeight));
|
||||
var itemHeight = font.GetHeight(UIScale);
|
||||
var itemBox = UIBox2.FromDimensions((hOffset, vOffset), (PixelWidth - hOffset, itemHeight));
|
||||
if (itemBox.Contains(position))
|
||||
{
|
||||
final = item;
|
||||
@@ -190,7 +189,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
var hOffset = 0f;
|
||||
if (background != null)
|
||||
{
|
||||
background.Draw(handle, SizeBox);
|
||||
background.Draw(handle, PixelSizeBox);
|
||||
var (bho, bvo) = background.GetContentOffset(Vector2.Zero);
|
||||
vOffset += bvo;
|
||||
hOffset += bho;
|
||||
@@ -213,20 +212,20 @@ namespace Robust.Client.UserInterface.Controls
|
||||
DrawingHandleScreen handle, ref float vOffset, float hOffset, Item item,
|
||||
Font font, StyleBox itemSelected)
|
||||
{
|
||||
var itemHeight = font.Height + itemSelected.MinimumSize.Y;
|
||||
var itemHeight = font.GetHeight(UIScale) + itemSelected.MinimumSize.Y;
|
||||
var selected = item.Index == _selectedIndex;
|
||||
if (selected)
|
||||
{
|
||||
itemSelected.Draw(handle, UIBox2.FromDimensions(hOffset, vOffset, Width - hOffset, itemHeight));
|
||||
itemSelected.Draw(handle, UIBox2.FromDimensions(hOffset, vOffset, PixelWidth - hOffset, itemHeight));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(item.Text))
|
||||
{
|
||||
var offset = itemSelected.GetContentOffset(Vector2.Zero);
|
||||
var baseLine = offset + (hOffset, vOffset + font.Ascent);
|
||||
var baseLine = offset + (hOffset, vOffset + font.GetAscent(UIScale));
|
||||
foreach (var chr in item.Text)
|
||||
{
|
||||
baseLine += (font.DrawChar(handle, chr, baseLine, Color.White), 0);
|
||||
baseLine += (font.DrawChar(handle, chr, baseLine, UIScale, Color.White), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,7 +263,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
private float _getItemHeight(Item item, Font font)
|
||||
{
|
||||
float sum = font.Height;
|
||||
float sum = font.GetHeight(UIScale);
|
||||
|
||||
foreach (var child in item.Children)
|
||||
{
|
||||
@@ -278,8 +277,8 @@ namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
var internalHeight = _getInternalHeight();
|
||||
_scrollBar.MaxValue = internalHeight;
|
||||
_scrollBar.Page = Height;
|
||||
_scrollBar.Visible = internalHeight > Height;
|
||||
_scrollBar.Page = PixelHeight;
|
||||
_scrollBar.Visible = internalHeight > PixelHeight;
|
||||
}
|
||||
|
||||
protected override void Resized()
|
||||
|
||||
@@ -177,9 +177,6 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
if (tex != null)
|
||||
{
|
||||
rect.Texture = tex.Default;
|
||||
// Ok I can't find a way to make this TextureRect scale down sanely so let's do this.
|
||||
var scale = (float) TARGET_ICON_HEIGHT / tex.Default.Height;
|
||||
rect.Scale = new Vector2(scale, scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -66,9 +66,9 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
var currentFrameIndex = MathHelper.Mod(_frameIndex - 1 - i, TrackedFrames);
|
||||
var frameTime = _frameTimes[currentFrameIndex];
|
||||
var x = FrameWidth * (TrackedFrames - 1 - i);
|
||||
var x = FrameWidth * UserInterfaceManager.UIScale * (TrackedFrames - 1 - i);
|
||||
var frameHeight = FrameHeight * (frameTime / (1f / TargetFrameRate));
|
||||
var rect = new UIBox2(x, Height - frameHeight, x + FrameWidth, Height);
|
||||
var rect = new UIBox2(x, PixelHeight - frameHeight, x + FrameWidth * UserInterfaceManager.UIScale, PixelHeight);
|
||||
|
||||
Color color;
|
||||
if (frameTime > 1f / (TargetFrameRate / 2 - 1))
|
||||
|
||||
@@ -166,10 +166,15 @@ namespace Robust.Client.UserInterface.CustomControls
|
||||
{
|
||||
base.MouseMove(args);
|
||||
|
||||
if (Parent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (CurrentDrag == DragMode.Move)
|
||||
{
|
||||
var globalPos = args.GlobalPosition;
|
||||
globalPos = Vector2.Clamp(globalPos, Vector2.Zero, _displayManager.ScreenSize);
|
||||
globalPos = Vector2.Clamp(globalPos, Vector2.Zero, Parent.Size);
|
||||
Position = globalPos - DragOffsetTopLeft;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -41,12 +41,13 @@ namespace Robust.Client.UserInterface
|
||||
/// </summary>
|
||||
/// <param name="font">The font being used for display.</param>
|
||||
/// <param name="sizeX">The horizontal size of the container of this entry.</param>
|
||||
public void Update(Font font, float sizeX)
|
||||
/// <param name="uiScale"></param>
|
||||
public void Update(Font font, float sizeX, float uiScale)
|
||||
{
|
||||
// This method is gonna suck due to complexity.
|
||||
// Bear with me here.
|
||||
// I am so deeply sorry for the person adding stuff to this in the future.
|
||||
Height = font.Height;
|
||||
Height = font.GetHeight(uiScale);
|
||||
LineBreaks.Clear();
|
||||
|
||||
// Index we put into the LineBreaks list when a line break should occur.
|
||||
@@ -89,7 +90,7 @@ namespace Robust.Client.UserInterface
|
||||
// We ran into a word boundary and the word is too big to fit the previous line.
|
||||
// So we insert the line break BEFORE the last word.
|
||||
LineBreaks.Add(wordStartBreakIndex.Value);
|
||||
Height += font.LineHeight;
|
||||
Height += font.GetLineHeight(uiScale);
|
||||
posX = wordSizePixels;
|
||||
}
|
||||
|
||||
@@ -103,7 +104,7 @@ namespace Robust.Client.UserInterface
|
||||
if (chr == '\n')
|
||||
{
|
||||
LineBreaks.Add(breakIndexCounter);
|
||||
Height += font.LineHeight;
|
||||
Height += font.GetLineHeight(uiScale);
|
||||
posX = 0;
|
||||
lastChar = chr;
|
||||
wordStartBreakIndex = null;
|
||||
@@ -112,7 +113,7 @@ namespace Robust.Client.UserInterface
|
||||
}
|
||||
|
||||
// Uh just skip unknown characters I guess.
|
||||
if (!font.TryGetCharMetrics(chr, out var metrics))
|
||||
if (!font.TryGetCharMetrics(chr, uiScale, out var metrics))
|
||||
{
|
||||
lastChar = chr;
|
||||
continue;
|
||||
@@ -142,7 +143,7 @@ namespace Robust.Client.UserInterface
|
||||
// Reset forceSplitData so that we can split again if necessary.
|
||||
forceSplitData = null;
|
||||
LineBreaks.Add(breakIndex);
|
||||
Height += font.LineHeight;
|
||||
Height += font.GetLineHeight(uiScale);
|
||||
wordSizePixels -= splitWordSize;
|
||||
wordStartBreakIndex = null;
|
||||
posX = wordSizePixels;
|
||||
@@ -159,7 +160,7 @@ namespace Robust.Client.UserInterface
|
||||
DebugTools.Assert(wordStartBreakIndex.HasValue,
|
||||
"wordStartBreakIndex can only be null if the word begins at a new line, in which case this branch shouldn't be reached as the word would be split due to being longer than a single line.");
|
||||
LineBreaks.Add(wordStartBreakIndex.Value);
|
||||
Height += font.LineHeight;
|
||||
Height += font.GetLineHeight(uiScale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,14 +172,14 @@ namespace Robust.Client.UserInterface
|
||||
// A stack for format tags.
|
||||
// This stack contains the format tag to RETURN TO when popped off.
|
||||
// So when a new color tag gets hit this stack gets the previous color pushed on.
|
||||
Stack<FormattedMessage.Tag> formatStack)
|
||||
Stack<FormattedMessage.Tag> formatStack, float uiScale)
|
||||
{
|
||||
// The tag currently doing color.
|
||||
var currentColorTag = TagWhite;
|
||||
|
||||
var globalBreakCounter = 0;
|
||||
var lineBreakIndex = 0;
|
||||
var baseLine = drawBox.TopLeft + new Vector2(0, font.Ascent + verticalOffset);
|
||||
var baseLine = drawBox.TopLeft + new Vector2(0, font.GetAscent(uiScale) + verticalOffset);
|
||||
formatStack.Clear();
|
||||
foreach (var tag in Message.Tags)
|
||||
{
|
||||
@@ -209,11 +210,11 @@ namespace Robust.Client.UserInterface
|
||||
if (lineBreakIndex < LineBreaks.Count &&
|
||||
LineBreaks[lineBreakIndex] == globalBreakCounter)
|
||||
{
|
||||
baseLine = new Vector2(drawBox.Left, baseLine.Y + font.LineHeight);
|
||||
baseLine = new Vector2(drawBox.Left, baseLine.Y + font.GetLineHeight(uiScale));
|
||||
lineBreakIndex += 1;
|
||||
}
|
||||
|
||||
var advance = font.DrawChar(handle, chr, baseLine, currentColorTag.Color);
|
||||
var advance = font.DrawChar(handle, chr, baseLine, uiScale, currentColorTag.Color);
|
||||
baseLine += new Vector2(advance, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Clyde;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Interfaces;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
@@ -17,7 +15,9 @@ using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Interfaces.Configuration;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Interfaces.Resources;
|
||||
@@ -27,7 +27,7 @@ using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.UserInterface
|
||||
{
|
||||
internal sealed class UserInterfaceManager : IDisposable, IUserInterfaceManagerInternal
|
||||
internal sealed class UserInterfaceManager : IDisposable, IUserInterfaceManagerInternal, IPostInjectInit
|
||||
{
|
||||
[Dependency] private readonly IInputManager _inputManager;
|
||||
[Dependency] private readonly IDisplayManager _displayManager;
|
||||
@@ -40,6 +40,7 @@ namespace Robust.Client.UserInterface
|
||||
[Dependency] private readonly IStateManager _stateManager;
|
||||
[Dependency] private readonly IClientNetManager _netManager;
|
||||
[Dependency] private readonly IMapManager _mapManager;
|
||||
[Dependency] private readonly IConfigurationManager _configurationManager;
|
||||
|
||||
public UITheme ThemeDefaults { get; private set; }
|
||||
public Stylesheet Stylesheet { get; set; }
|
||||
@@ -51,6 +52,7 @@ namespace Robust.Client.UserInterface
|
||||
|
||||
public Control StateRoot { get; private set; }
|
||||
public Control CurrentlyHovered { get; private set; }
|
||||
public float UIScale { get; private set; } = 1;
|
||||
public Control RootControl { get; private set; }
|
||||
public Control WindowRoot { get; private set; }
|
||||
public DebugConsole DebugConsole { get; private set; }
|
||||
@@ -69,6 +71,7 @@ namespace Robust.Client.UserInterface
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
UIScale = _configurationManager.GetCVar<float>("display.uiScale");
|
||||
ThemeDefaults = new UIThemeDefault();
|
||||
|
||||
_initializeCommon();
|
||||
@@ -98,8 +101,8 @@ namespace Robust.Client.UserInterface
|
||||
IsInsideTree = true
|
||||
};
|
||||
RootControl.SetAnchorPreset(Control.LayoutPreset.Wide);
|
||||
RootControl.Size = _displayManager.ScreenSize;
|
||||
_displayManager.OnWindowResized += args => RootControl.Size = args.NewSize;
|
||||
RootControl.Size = _displayManager.ScreenSize / UIScale;
|
||||
_displayManager.OnWindowResized += args => _updateRootSize();
|
||||
|
||||
StateRoot = new Control("StateRoot")
|
||||
{
|
||||
@@ -154,8 +157,8 @@ namespace Robust.Client.UserInterface
|
||||
if (_modalStack.Count != 0)
|
||||
{
|
||||
var top = _modalStack[_modalStack.Count - 1];
|
||||
var offset = args.Position - top.GlobalPosition;
|
||||
if (!top.HasPoint(offset))
|
||||
var offset = args.Position - top.GlobalPixelPosition;
|
||||
if (!top.HasPoint(offset / UIScale))
|
||||
{
|
||||
RemoveModal(top);
|
||||
args.Handle();
|
||||
@@ -178,7 +181,8 @@ namespace Robust.Client.UserInterface
|
||||
}
|
||||
|
||||
var guiArgs = new GUIMouseButtonEventArgs(args.Button, args.DoubleClick, control, Mouse.ButtonMask.None,
|
||||
args.Position, args.Position - control.GlobalPosition, args.Alt, args.Control, args.Shift,
|
||||
args.Position / UIScale, args.Position, args.Position / UIScale - control.GlobalPosition,
|
||||
args.Position - control.GlobalPixelPosition, args.Alt, args.Control, args.Shift,
|
||||
args.System);
|
||||
|
||||
_doMouseGuiInput(control, guiArgs, (c, ev) => c.MouseDown(ev));
|
||||
@@ -198,7 +202,8 @@ namespace Robust.Client.UserInterface
|
||||
|
||||
var guiArgs = new GUIMouseButtonEventArgs(args.Button, args.DoubleClick, _mouseFocused,
|
||||
Mouse.ButtonMask.None,
|
||||
args.Position, args.Position - _mouseFocused.GlobalPosition, args.Alt, args.Control, args.Shift,
|
||||
args.Position / UIScale, args.Position, args.Position / UIScale - _mouseFocused.GlobalPosition,
|
||||
args.Position - _mouseFocused.GlobalPixelPosition, args.Alt, args.Control, args.Shift,
|
||||
args.System);
|
||||
|
||||
_doMouseGuiInput(_mouseFocused, guiArgs, (c, ev) => c.MouseUp(ev));
|
||||
@@ -226,10 +231,12 @@ namespace Robust.Client.UserInterface
|
||||
var target = _mouseFocused ?? newHovered;
|
||||
if (target != null)
|
||||
{
|
||||
var guiArgs = new GUIMouseMoveEventArgs(mouseMoveEventArgs.Relative, mouseMoveEventArgs.Speed,
|
||||
target,
|
||||
mouseMoveEventArgs.ButtonMask, mouseMoveEventArgs.Position,
|
||||
mouseMoveEventArgs.Position - target.GlobalPosition, mouseMoveEventArgs.Alt,
|
||||
var guiArgs = new GUIMouseMoveEventArgs(mouseMoveEventArgs.Relative / UIScale,
|
||||
mouseMoveEventArgs.Speed / UIScale, target,
|
||||
mouseMoveEventArgs.ButtonMask, mouseMoveEventArgs.Position / UIScale, mouseMoveEventArgs.Position,
|
||||
mouseMoveEventArgs.Position / UIScale - target.GlobalPosition,
|
||||
mouseMoveEventArgs.Position - target.GlobalPixelPosition,
|
||||
mouseMoveEventArgs.Alt,
|
||||
mouseMoveEventArgs.Control, mouseMoveEventArgs.Shift, mouseMoveEventArgs.System);
|
||||
|
||||
_doMouseGuiInput(target, guiArgs, (c, ev) => c.MouseMove(ev));
|
||||
@@ -246,8 +253,10 @@ namespace Robust.Client.UserInterface
|
||||
|
||||
args.Handle();
|
||||
|
||||
var guiArgs = new GUIMouseWheelEventArgs(args.WheelDirection, control, Mouse.ButtonMask.None, args.Position,
|
||||
args.Position - control.GlobalPosition, args.Alt, args.Control, args.Shift, args.System);
|
||||
var guiArgs = new GUIMouseWheelEventArgs(args.WheelDirection, control, Mouse.ButtonMask.None,
|
||||
args.Position / UIScale, args.Position,
|
||||
args.Position / UIScale - control.GlobalPosition, args.Position - control.GlobalPixelPosition, args.Alt,
|
||||
args.Control, args.Shift, args.System);
|
||||
|
||||
_doMouseGuiInput(control, guiArgs, (c, ev) => c.MouseWheel(ev), true);
|
||||
}
|
||||
@@ -416,12 +425,13 @@ namespace Robust.Client.UserInterface
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var drawHandle = renderHandle.CreateHandleScreen();
|
||||
|
||||
_render(drawHandle, RootControl, Vector2.Zero, Color.White, null);
|
||||
_render(drawHandle, RootControl, Vector2i.Zero, Color.White, null);
|
||||
}
|
||||
|
||||
private static void _render(DrawingHandleScreen handle, Control control, Vector2 position, Color modulate,
|
||||
private static void _render(DrawingHandleScreen handle, Control control, Vector2i position, Color modulate,
|
||||
UIBox2i? scissorBox)
|
||||
{
|
||||
if (!control.Visible)
|
||||
@@ -430,7 +440,7 @@ namespace Robust.Client.UserInterface
|
||||
}
|
||||
|
||||
// Manual clip test with scissor region as optimization.
|
||||
var controlBox = UIBox2i.FromDimensions((Vector2i)position, (Vector2i)control.Size);
|
||||
var controlBox = UIBox2i.FromDimensions(position, control.PixelSize);
|
||||
|
||||
if (scissorBox != null)
|
||||
{
|
||||
@@ -468,10 +478,11 @@ namespace Robust.Client.UserInterface
|
||||
|
||||
handle.SetScissor(scissorRegion);
|
||||
}
|
||||
|
||||
control.Draw(handle);
|
||||
foreach (var child in control.Children)
|
||||
{
|
||||
_render(handle, child, position + child.Position.Rounded(), modulate, scissorRegion);
|
||||
_render(handle, child, position + child.PixelPosition, modulate, scissorRegion);
|
||||
}
|
||||
|
||||
if (clip)
|
||||
@@ -520,19 +531,19 @@ namespace Robust.Client.UserInterface
|
||||
{
|
||||
foreach (var child in control.Children.Reverse())
|
||||
{
|
||||
if (!child.Visible || (child.RectClipContent && !child.Rect.Contains(position)))
|
||||
if (!child.Visible || (child.RectClipContent && !child.PixelRect.Contains((Vector2i) position)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var maybeFoundOnChild = _mouseFindControlAtPos(child, position - child.Position);
|
||||
var maybeFoundOnChild = _mouseFindControlAtPos(child, position - child.PixelPosition);
|
||||
if (maybeFoundOnChild != null)
|
||||
{
|
||||
return maybeFoundOnChild;
|
||||
}
|
||||
}
|
||||
|
||||
if (control.MouseFilter != Control.MouseFilterMode.Ignore && control.HasPoint(position))
|
||||
if (control.MouseFilter != Control.MouseFilterMode.Ignore && control.HasPoint(position / UIScale))
|
||||
{
|
||||
return control;
|
||||
}
|
||||
@@ -540,7 +551,8 @@ namespace Robust.Client.UserInterface
|
||||
return null;
|
||||
}
|
||||
|
||||
private void _doMouseGuiInput<T>(Control control, T guiEvent, Action<Control, T> action, bool ignoreStop=false)
|
||||
private static void _doMouseGuiInput<T>(Control control, T guiEvent, Action<Control, T> action,
|
||||
bool ignoreStop = false)
|
||||
where T : GUIMouseEventArgs
|
||||
{
|
||||
while (control != null)
|
||||
@@ -556,6 +568,7 @@ namespace Robust.Client.UserInterface
|
||||
}
|
||||
|
||||
guiEvent.RelativePosition += control.Position;
|
||||
guiEvent.RelativePixelPosition += control.PixelPosition;
|
||||
control = control.Parent;
|
||||
guiEvent.SourceControl = control;
|
||||
}
|
||||
@@ -597,5 +610,38 @@ namespace Robust.Client.UserInterface
|
||||
_tooltip.Position = (_tooltip.Position.X, RootControl.Size.Y - _tooltip.Size.Y);
|
||||
}
|
||||
}
|
||||
|
||||
void IPostInjectInit.PostInject()
|
||||
{
|
||||
_configurationManager.RegisterCVar("display.uiScale", 1f, CVar.ARCHIVE, _uiScaleChanged);
|
||||
}
|
||||
|
||||
private void _uiScaleChanged(float newValue)
|
||||
{
|
||||
UIScale = newValue;
|
||||
|
||||
if (RootControl == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_propagateUIScaleChanged(RootControl);
|
||||
_updateRootSize();
|
||||
}
|
||||
|
||||
private static void _propagateUIScaleChanged(Control control)
|
||||
{
|
||||
control.UIScaleChanged();
|
||||
|
||||
foreach (var child in control.Children)
|
||||
{
|
||||
_propagateUIScaleChanged(child);
|
||||
}
|
||||
}
|
||||
|
||||
private void _updateRootSize()
|
||||
{
|
||||
RootControl.Size = _displayManager.ScreenSize / UIScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user