Add UI Scale dropdown to the settings menu.
This commit is contained in:
@@ -57,6 +57,7 @@ namespace OpenRA
|
|||||||
IHardwareCursor CreateHardwareCursor(string name, Size size, byte[] data, int2 hotspot, bool pixelDouble);
|
IHardwareCursor CreateHardwareCursor(string name, Size size, byte[] data, int2 hotspot, bool pixelDouble);
|
||||||
void SetHardwareCursor(IHardwareCursor cursor);
|
void SetHardwareCursor(IHardwareCursor cursor);
|
||||||
void SetRelativeMouseMode(bool mode);
|
void SetRelativeMouseMode(bool mode);
|
||||||
|
void SetScaleModifier(float scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IGraphicsContext : IDisposable
|
public interface IGraphicsContext : IDisposable
|
||||||
|
|||||||
@@ -91,6 +91,11 @@ namespace OpenRA
|
|||||||
return new Size(size.X, size.Y);
|
return new Size(size.X, size.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetUIScale(float scale)
|
||||||
|
{
|
||||||
|
Window.SetScaleModifier(scale);
|
||||||
|
}
|
||||||
|
|
||||||
public void InitializeFonts(ModData modData)
|
public void InitializeFonts(ModData modData)
|
||||||
{
|
{
|
||||||
if (Fonts != null)
|
if (Fonts != null)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using OpenRA.Primitives;
|
||||||
|
|
||||||
namespace OpenRA
|
namespace OpenRA
|
||||||
{
|
{
|
||||||
@@ -23,6 +24,8 @@ namespace OpenRA
|
|||||||
public readonly int MaxZoomWindowHeight = 240;
|
public readonly int MaxZoomWindowHeight = 240;
|
||||||
public readonly bool AllowNativeZoom = true;
|
public readonly bool AllowNativeZoom = true;
|
||||||
|
|
||||||
|
public readonly Size MinEffectiveResolution = new Size(1024, 720);
|
||||||
|
|
||||||
public int2 GetSizeRange(WorldViewport distance)
|
public int2 GetSizeRange(WorldViewport distance)
|
||||||
{
|
{
|
||||||
return distance == WorldViewport.Close ? CloseWindowHeights
|
return distance == WorldViewport.Close ? CloseWindowHeights
|
||||||
|
|||||||
@@ -112,6 +112,15 @@ namespace OpenRA.Mods.Common.LoadScreens
|
|||||||
|
|
||||||
public virtual bool BeforeLoad()
|
public virtual bool BeforeLoad()
|
||||||
{
|
{
|
||||||
|
// Reset the UI scaling if the user has configured a UI scale that pushes us below the minimum allowed effective resolution
|
||||||
|
var minResolution = ModData.Manifest.Get<WorldViewportSizes>().MinEffectiveResolution;
|
||||||
|
var resolution = Game.Renderer.Resolution;
|
||||||
|
if ((resolution.Width < minResolution.Width || resolution.Height < minResolution.Height) && Game.Settings.Graphics.UIScale > 1.0f)
|
||||||
|
{
|
||||||
|
Game.Settings.Graphics.UIScale = 1.0f;
|
||||||
|
Game.Renderer.SetUIScale(1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
// If a ModContent section is defined then we need to make sure that the
|
// If a ModContent section is defined then we need to make sure that the
|
||||||
// required content is installed or switch to the defined content installer.
|
// required content is installed or switch to the defined content installer.
|
||||||
if (!ModData.Manifest.Contains<ModContent>())
|
if (!ModData.Manifest.Contains<ModContent>())
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenRA.Graphics;
|
using OpenRA.Graphics;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
|
using OpenRA.Support;
|
||||||
using OpenRA.Widgets;
|
using OpenRA.Widgets;
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||||
@@ -34,6 +35,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
|
|
||||||
readonly ModData modData;
|
readonly ModData modData;
|
||||||
readonly WorldRenderer worldRenderer;
|
readonly WorldRenderer worldRenderer;
|
||||||
|
readonly WorldViewportSizes viewportSizes;
|
||||||
readonly Dictionary<string, MiniYaml> logicArgs;
|
readonly Dictionary<string, MiniYaml> logicArgs;
|
||||||
|
|
||||||
SoundDevice soundDevice;
|
SoundDevice soundDevice;
|
||||||
@@ -61,6 +63,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
this.worldRenderer = worldRenderer;
|
this.worldRenderer = worldRenderer;
|
||||||
this.modData = modData;
|
this.modData = modData;
|
||||||
this.logicArgs = logicArgs;
|
this.logicArgs = logicArgs;
|
||||||
|
viewportSizes = modData.Manifest.Get<WorldViewportSizes>();
|
||||||
|
|
||||||
panelContainer = widget.Get("SETTINGS_PANEL");
|
panelContainer = widget.Get("SETTINGS_PANEL");
|
||||||
tabContainer = widget.Get("TAB_CONTAINER");
|
tabContainer = widget.Get("TAB_CONTAINER");
|
||||||
@@ -261,7 +264,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
|
|
||||||
var battlefieldCameraDropDown = panel.Get<DropDownButtonWidget>("BATTLEFIELD_CAMERA_DROPDOWN");
|
var battlefieldCameraDropDown = panel.Get<DropDownButtonWidget>("BATTLEFIELD_CAMERA_DROPDOWN");
|
||||||
var battlefieldCameraLabel = new CachedTransform<WorldViewport, string>(vs => ViewportSizeNames[vs]);
|
var battlefieldCameraLabel = new CachedTransform<WorldViewport, string>(vs => ViewportSizeNames[vs]);
|
||||||
battlefieldCameraDropDown.OnMouseDown = _ => ShowBattlefieldCameraDropdown(battlefieldCameraDropDown, ds);
|
battlefieldCameraDropDown.OnMouseDown = _ => ShowBattlefieldCameraDropdown(battlefieldCameraDropDown, viewportSizes, ds);
|
||||||
battlefieldCameraDropDown.GetText = () => battlefieldCameraLabel.Update(ds.ViewportDistance);
|
battlefieldCameraDropDown.GetText = () => battlefieldCameraLabel.Update(ds.ViewportDistance);
|
||||||
|
|
||||||
// Update vsync immediately
|
// Update vsync immediately
|
||||||
@@ -273,6 +276,19 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
Game.Renderer.SetVSyncEnabled(ds.VSync);
|
Game.Renderer.SetVSyncEnabled(ds.VSync);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var uiScaleDropdown = panel.Get<DropDownButtonWidget>("UI_SCALE_DROPDOWN");
|
||||||
|
var uiScaleLabel = new CachedTransform<float, string>(s => "{0}%".F((int)(100 * s)));
|
||||||
|
uiScaleDropdown.OnMouseDown = _ => ShowUIScaleDropdown(uiScaleDropdown, ds);
|
||||||
|
uiScaleDropdown.GetText = () => uiScaleLabel.Update(ds.UIScale);
|
||||||
|
|
||||||
|
var minResolution = viewportSizes.MinEffectiveResolution;
|
||||||
|
var resolution = Game.Renderer.Resolution;
|
||||||
|
var disableUIScale = worldRenderer.World.Type != WorldType.Shellmap ||
|
||||||
|
resolution.Width * ds.UIScale < 1.25f * minResolution.Width ||
|
||||||
|
resolution.Height * ds.UIScale < 1.25f * minResolution.Height;
|
||||||
|
|
||||||
|
uiScaleDropdown.IsDisabled = () => disableUIScale;
|
||||||
|
|
||||||
panel.Get("WINDOW_RESOLUTION").IsVisible = () => ds.Mode == WindowMode.Windowed;
|
panel.Get("WINDOW_RESOLUTION").IsVisible = () => ds.Mode == WindowMode.Windowed;
|
||||||
var windowWidth = panel.Get<TextFieldWidget>("WINDOW_WIDTH");
|
var windowWidth = panel.Get<TextFieldWidget>("WINDOW_WIDTH");
|
||||||
var origWidthText = windowWidth.Text = ds.WindowedSize.X.ToString();
|
var origWidthText = windowWidth.Text = ds.WindowedSize.X.ToString();
|
||||||
@@ -357,6 +373,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
ds.CursorDouble = dds.CursorDouble;
|
ds.CursorDouble = dds.CursorDouble;
|
||||||
ds.ViewportDistance = dds.ViewportDistance;
|
ds.ViewportDistance = dds.ViewportDistance;
|
||||||
|
|
||||||
|
if (ds.UIScale != dds.UIScale)
|
||||||
|
{
|
||||||
|
var oldScale = ds.UIScale;
|
||||||
|
ds.UIScale = dds.UIScale;
|
||||||
|
Game.Renderer.SetUIScale(dds.UIScale);
|
||||||
|
RecalculateWidgetLayout(Ui.Root);
|
||||||
|
Viewport.LastMousePos = (Viewport.LastMousePos.ToFloat2() * oldScale / ds.UIScale).ToInt2();
|
||||||
|
}
|
||||||
|
|
||||||
ps.Color = dps.Color;
|
ps.Color = dps.Color;
|
||||||
ps.Name = dps.Name;
|
ps.Name = dps.Name;
|
||||||
};
|
};
|
||||||
@@ -827,7 +852,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options.Keys, setupItem);
|
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options.Keys, setupItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ShowBattlefieldCameraDropdown(DropDownButtonWidget dropdown, GraphicSettings gs)
|
static void ShowBattlefieldCameraDropdown(DropDownButtonWidget dropdown, WorldViewportSizes viewportSizes, GraphicSettings gs)
|
||||||
{
|
{
|
||||||
Func<WorldViewport, ScrollItemWidget, ScrollItemWidget> setupItem = (o, itemTemplate) =>
|
Func<WorldViewport, ScrollItemWidget, ScrollItemWidget> setupItem = (o, itemTemplate) =>
|
||||||
{
|
{
|
||||||
@@ -840,7 +865,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
return item;
|
return item;
|
||||||
};
|
};
|
||||||
|
|
||||||
var viewportSizes = Game.ModData.Manifest.Get<WorldViewportSizes>();
|
|
||||||
var windowHeight = Game.Renderer.NativeResolution.Height;
|
var windowHeight = Game.Renderer.NativeResolution.Height;
|
||||||
|
|
||||||
var validSizes = new List<WorldViewport>() { WorldViewport.Close };
|
var validSizes = new List<WorldViewport>() { WorldViewport.Close };
|
||||||
@@ -857,6 +881,78 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, validSizes, setupItem);
|
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, validSizes, setupItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void RecalculateWidgetLayout(Widget w, bool insideScrollPanel = false)
|
||||||
|
{
|
||||||
|
// HACK: Recalculate the widget bounds to fit within the new effective window bounds
|
||||||
|
// This is fragile, and only works when called when Settings is opened via the main menu.
|
||||||
|
|
||||||
|
// HACK: Skip children badges container on the main menu
|
||||||
|
// This has a fixed size, with calculated size and children positions that break if we adjust them here
|
||||||
|
if (w.Id == "BADGES_CONTAINER")
|
||||||
|
return;
|
||||||
|
|
||||||
|
var parentBounds = w.Parent == null
|
||||||
|
? new Rectangle(0, 0, Game.Renderer.Resolution.Width, Game.Renderer.Resolution.Height)
|
||||||
|
: w.Parent.Bounds;
|
||||||
|
|
||||||
|
var substitutions = new Dictionary<string, int>();
|
||||||
|
substitutions.Add("WINDOW_RIGHT", Game.Renderer.Resolution.Width);
|
||||||
|
substitutions.Add("WINDOW_BOTTOM", Game.Renderer.Resolution.Height);
|
||||||
|
substitutions.Add("PARENT_RIGHT", parentBounds.Width);
|
||||||
|
substitutions.Add("PARENT_LEFT", parentBounds.Left);
|
||||||
|
substitutions.Add("PARENT_TOP", parentBounds.Top);
|
||||||
|
substitutions.Add("PARENT_BOTTOM", parentBounds.Height);
|
||||||
|
|
||||||
|
var width = Evaluator.Evaluate(w.Width, substitutions);
|
||||||
|
var height = Evaluator.Evaluate(w.Height, substitutions);
|
||||||
|
|
||||||
|
substitutions.Add("WIDTH", width);
|
||||||
|
substitutions.Add("HEIGHT", height);
|
||||||
|
|
||||||
|
if (insideScrollPanel)
|
||||||
|
w.Bounds = new Rectangle(w.Bounds.X, w.Bounds.Y, width, w.Bounds.Height);
|
||||||
|
else
|
||||||
|
w.Bounds = new Rectangle(Evaluator.Evaluate(w.X, substitutions),
|
||||||
|
Evaluator.Evaluate(w.Y, substitutions),
|
||||||
|
width,
|
||||||
|
height);
|
||||||
|
|
||||||
|
foreach (var c in w.Children)
|
||||||
|
RecalculateWidgetLayout(c, insideScrollPanel || w is ScrollPanelWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ShowUIScaleDropdown(DropDownButtonWidget dropdown, GraphicSettings gs)
|
||||||
|
{
|
||||||
|
Func<float, ScrollItemWidget, ScrollItemWidget> setupItem = (o, itemTemplate) =>
|
||||||
|
{
|
||||||
|
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||||
|
() => gs.UIScale == o,
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
Game.RunAfterTick(() =>
|
||||||
|
{
|
||||||
|
var oldScale = gs.UIScale;
|
||||||
|
gs.UIScale = o;
|
||||||
|
|
||||||
|
Game.Renderer.SetUIScale(o);
|
||||||
|
RecalculateWidgetLayout(Ui.Root);
|
||||||
|
Viewport.LastMousePos = (Viewport.LastMousePos.ToFloat2() * oldScale / gs.UIScale).ToInt2();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var label = "{0}%".F((int)(100 * o));
|
||||||
|
item.Get<LabelWidget>("LABEL").GetText = () => label;
|
||||||
|
return item;
|
||||||
|
};
|
||||||
|
|
||||||
|
var viewportSizes = Game.ModData.Manifest.Get<WorldViewportSizes>();
|
||||||
|
var maxScales = new float2(Game.Renderer.NativeResolution) / new float2(viewportSizes.MinEffectiveResolution);
|
||||||
|
var maxScale = Math.Min(maxScales.X, maxScales.Y);
|
||||||
|
|
||||||
|
var validScales = new[] { 1f, 1.25f, 1.5f, 1.75f, 2f }.Where(x => x <= maxScale);
|
||||||
|
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, validScales, setupItem);
|
||||||
|
}
|
||||||
|
|
||||||
void MakeMouseFocusSettingsLive()
|
void MakeMouseFocusSettingsLive()
|
||||||
{
|
{
|
||||||
var gameSettings = Game.Settings.Game;
|
var gameSettings = Game.Settings.Game;
|
||||||
|
|||||||
@@ -443,5 +443,12 @@ namespace OpenRA.Platforms.Default
|
|||||||
SDL.SDL_DestroyWindow(window);
|
SDL.SDL_DestroyWindow(window);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetScaleModifier(float scale)
|
||||||
|
{
|
||||||
|
var oldScaleModifier = scaleModifier;
|
||||||
|
scaleModifier = scale;
|
||||||
|
OnWindowScaleChanged(windowScale, windowScale * oldScaleModifier, windowScale, windowScale * scaleModifier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,6 +140,19 @@ Container@SETTINGS_PANEL:
|
|||||||
Width: 160
|
Width: 160
|
||||||
Height: 25
|
Height: 25
|
||||||
Font: Regular
|
Font: Regular
|
||||||
|
Label@UI_SCALE:
|
||||||
|
X: 15
|
||||||
|
Y: 100
|
||||||
|
Width: 120
|
||||||
|
Height: 25
|
||||||
|
Text: UI Scale:
|
||||||
|
Align: Right
|
||||||
|
DropDownButton@UI_SCALE_DROPDOWN:
|
||||||
|
X: 140
|
||||||
|
Y: 100
|
||||||
|
Width: 160
|
||||||
|
Height: 25
|
||||||
|
Font: Regular
|
||||||
Label@STATUS_BARS:
|
Label@STATUS_BARS:
|
||||||
X: 265
|
X: 265
|
||||||
Y: 100
|
Y: 100
|
||||||
|
|||||||
@@ -154,6 +154,19 @@ Background@SETTINGS_PANEL:
|
|||||||
Width: 160
|
Width: 160
|
||||||
Height: 25
|
Height: 25
|
||||||
Font: Regular
|
Font: Regular
|
||||||
|
Label@UI_SCALE:
|
||||||
|
X: 15
|
||||||
|
Y: 100
|
||||||
|
Width: 120
|
||||||
|
Height: 25
|
||||||
|
Text: UI Scale:
|
||||||
|
Align: Right
|
||||||
|
DropDownButton@UI_SCALE_DROPDOWN:
|
||||||
|
X: 140
|
||||||
|
Y: 100
|
||||||
|
Width: 160
|
||||||
|
Height: 25
|
||||||
|
Font: Regular
|
||||||
Label@STATUS_BARS:
|
Label@STATUS_BARS:
|
||||||
X: 265
|
X: 265
|
||||||
Y: 100
|
Y: 100
|
||||||
|
|||||||
Reference in New Issue
Block a user