Initial commit: OpenRA game engine
Fork from OpenRA/OpenRA with one-click launch script (start-ra.cmd) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
public class AdvancedSettingsLogic : ChromeLogic
|
||||
{
|
||||
readonly DebugSettings debugSettings;
|
||||
readonly GameSettings gameSettings;
|
||||
readonly ServerSettings serverSettings;
|
||||
static ServerSettings originalServerSettings;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public AdvancedSettingsLogic(ModData modData, SettingsLogic settingsLogic, string panelID, string label)
|
||||
{
|
||||
debugSettings = modData.GetSettings<DebugSettings>();
|
||||
gameSettings = modData.GetSettings<GameSettings>();
|
||||
serverSettings = modData.GetSettings<ServerSettings>();
|
||||
originalServerSettings ??= serverSettings.Clone();
|
||||
settingsLogic.RegisterSettingsPanel(panelID, label, InitPanel, ResetPanel);
|
||||
}
|
||||
|
||||
Func<bool> InitPanel(Widget panel)
|
||||
{
|
||||
var scrollPanel = panel.Get<ScrollPanelWidget>("SETTINGS_SCROLLPANEL");
|
||||
|
||||
// Advanced
|
||||
SettingsUtils.BindCheckboxPref(panel, "NAT_DISCOVERY", serverSettings, "DiscoverNatDevices");
|
||||
SettingsUtils.BindCheckboxPref(panel, "PERFTEXT_CHECKBOX", debugSettings, "PerfText");
|
||||
SettingsUtils.BindCheckboxPref(panel, "PERFGRAPH_CHECKBOX", debugSettings, "PerfGraph");
|
||||
SettingsUtils.BindCheckboxPref(panel, "FETCH_NEWS_CHECKBOX", gameSettings, "FetchNews");
|
||||
SettingsUtils.BindCheckboxPref(panel, "SENDSYSINFO_CHECKBOX", debugSettings, "SendSystemInformation");
|
||||
SettingsUtils.BindCheckboxPref(panel, "CHECK_VERSION_CHECKBOX", debugSettings, "CheckVersion");
|
||||
|
||||
var ssi = panel.Get<CheckboxWidget>("SENDSYSINFO_CHECKBOX");
|
||||
ssi.IsDisabled = () => !gameSettings.FetchNews;
|
||||
|
||||
// Developer
|
||||
SettingsUtils.BindCheckboxPref(panel, "BOTDEBUG_CHECKBOX", debugSettings, "BotDebug");
|
||||
SettingsUtils.BindCheckboxPref(panel, "LUADEBUG_CHECKBOX", debugSettings, "LuaDebug");
|
||||
SettingsUtils.BindCheckboxPref(panel, "REPLAY_COMMANDS_CHECKBOX", debugSettings, "EnableDebugCommandsInReplays");
|
||||
SettingsUtils.BindCheckboxPref(panel, "CHECKUNSYNCED_CHECKBOX", debugSettings, "SyncCheckUnsyncedCode");
|
||||
SettingsUtils.BindCheckboxPref(panel, "CHECKBOTSYNC_CHECKBOX", debugSettings, "SyncCheckBotModuleCode");
|
||||
SettingsUtils.BindCheckboxPref(panel, "PERFLOGGING_CHECKBOX", debugSettings, "EnableSimulationPerfLogging");
|
||||
|
||||
panel.Get("BOTDEBUG_CHECKBOX_CONTAINER").IsVisible = () => debugSettings.DisplayDeveloperSettings;
|
||||
panel.Get("CHECKUNSYNCED_CHECKBOX_CONTAINER").IsVisible = () => debugSettings.DisplayDeveloperSettings;
|
||||
panel.Get("CHECKBOTSYNC_CHECKBOX_CONTAINER").IsVisible = () => debugSettings.DisplayDeveloperSettings;
|
||||
panel.Get("LUADEBUG_CHECKBOX_CONTAINER").IsVisible = () => debugSettings.DisplayDeveloperSettings;
|
||||
panel.Get("REPLAY_COMMANDS_CHECKBOX_CONTAINER").IsVisible = () => debugSettings.DisplayDeveloperSettings;
|
||||
panel.Get("PERFLOGGING_CHECKBOX_CONTAINER").IsVisible = () => debugSettings.DisplayDeveloperSettings;
|
||||
panel.Get("DEBUG_HIDDEN_CONTAINER").IsVisible = () => !debugSettings.DisplayDeveloperSettings;
|
||||
|
||||
SettingsUtils.AdjustSettingsScrollPanelLayout(scrollPanel);
|
||||
|
||||
return () => serverSettings.DiscoverNatDevices != originalServerSettings.DiscoverNatDevices;
|
||||
}
|
||||
|
||||
Action ResetPanel(Widget panel)
|
||||
{
|
||||
var defaultDebugSettings = new DebugSettings();
|
||||
var defaultServerSettings = new ServerSettings();
|
||||
|
||||
return () =>
|
||||
{
|
||||
serverSettings.DiscoverNatDevices = defaultServerSettings.DiscoverNatDevices;
|
||||
debugSettings.PerfText = defaultDebugSettings.PerfText;
|
||||
debugSettings.PerfGraph = defaultDebugSettings.PerfGraph;
|
||||
debugSettings.SyncCheckUnsyncedCode = defaultDebugSettings.SyncCheckUnsyncedCode;
|
||||
debugSettings.SyncCheckBotModuleCode = defaultDebugSettings.SyncCheckBotModuleCode;
|
||||
debugSettings.BotDebug = defaultDebugSettings.BotDebug;
|
||||
debugSettings.LuaDebug = defaultDebugSettings.LuaDebug;
|
||||
debugSettings.SendSystemInformation = defaultDebugSettings.SendSystemInformation;
|
||||
debugSettings.CheckVersion = defaultDebugSettings.CheckVersion;
|
||||
debugSettings.EnableDebugCommandsInReplays = defaultDebugSettings.EnableDebugCommandsInReplays;
|
||||
debugSettings.EnableSimulationPerfLogging = defaultDebugSettings.EnableSimulationPerfLogging;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
173
OpenRA.Mods.Common/Widgets/Logic/Settings/AudioSettingsLogic.cs
Normal file
173
OpenRA.Mods.Common/Widgets/Logic/Settings/AudioSettingsLogic.cs
Normal file
@@ -0,0 +1,173 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
public class AudioSettingsLogic : ChromeLogic
|
||||
{
|
||||
readonly WorldRenderer worldRenderer;
|
||||
readonly SoundSettings soundSettings;
|
||||
static SoundSettings originalSoundSettings;
|
||||
|
||||
SoundDevice soundDevice;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public AudioSettingsLogic(ModData modData, SettingsLogic settingsLogic, string panelID, string label, WorldRenderer worldRenderer)
|
||||
{
|
||||
this.worldRenderer = worldRenderer;
|
||||
soundSettings = modData.GetSettings<SoundSettings>();
|
||||
originalSoundSettings ??= soundSettings.Clone();
|
||||
|
||||
settingsLogic.RegisterSettingsPanel(panelID, label, InitPanel, ResetPanel);
|
||||
}
|
||||
|
||||
Func<bool> InitPanel(Widget panel)
|
||||
{
|
||||
var musicPlaylist = worldRenderer.World.WorldActor.Trait<MusicPlaylist>();
|
||||
var scrollPanel = panel.Get<ScrollPanelWidget>("SETTINGS_SCROLLPANEL");
|
||||
|
||||
SettingsUtils.BindCheckboxPref(panel, "CASH_TICKS", soundSettings, "CashTicks");
|
||||
SettingsUtils.BindCheckboxPref(panel, "MUTE_SOUND", soundSettings, "Mute");
|
||||
SettingsUtils.BindCheckboxPref(panel, "MUTE_BACKGROUND_MUSIC", soundSettings, "MuteBackgroundMusic");
|
||||
|
||||
SettingsUtils.BindSliderPref(panel, "SOUND_VOLUME", soundSettings, "SoundVolume");
|
||||
SettingsUtils.BindSliderPref(panel, "MUSIC_VOLUME", soundSettings, "MusicVolume");
|
||||
SettingsUtils.BindSliderPref(panel, "VIDEO_VOLUME", soundSettings, "VideoVolume");
|
||||
|
||||
var muteCheckbox = panel.Get<CheckboxWidget>("MUTE_SOUND");
|
||||
var muteCheckboxOnClick = muteCheckbox.OnClick;
|
||||
var muteCheckboxIsChecked = muteCheckbox.IsChecked;
|
||||
muteCheckbox.IsChecked = () => muteCheckboxIsChecked() || Game.Sound.DummyEngine;
|
||||
muteCheckbox.IsDisabled = () => Game.Sound.DummyEngine;
|
||||
muteCheckbox.OnClick = () =>
|
||||
{
|
||||
muteCheckboxOnClick();
|
||||
|
||||
if (soundSettings.Mute)
|
||||
Game.Sound.MuteAudio();
|
||||
else
|
||||
Game.Sound.UnmuteAudio();
|
||||
};
|
||||
|
||||
var muteBackgroundMusicCheckbox = panel.Get<CheckboxWidget>("MUTE_BACKGROUND_MUSIC");
|
||||
var muteBackgroundMusicCheckboxOnClick = muteBackgroundMusicCheckbox.OnClick;
|
||||
muteBackgroundMusicCheckbox.OnClick = () =>
|
||||
{
|
||||
muteBackgroundMusicCheckboxOnClick();
|
||||
|
||||
if (!musicPlaylist.AllowMuteBackgroundMusic)
|
||||
return;
|
||||
|
||||
if (musicPlaylist.CurrentSongIsBackground)
|
||||
musicPlaylist.Stop();
|
||||
};
|
||||
|
||||
// Replace controls with a warning label if sound is disabled
|
||||
var noDeviceLabel = panel.GetOrNull("NO_AUDIO_DEVICE_CONTAINER");
|
||||
if (noDeviceLabel != null)
|
||||
noDeviceLabel.Visible = Game.Sound.DummyEngine;
|
||||
|
||||
panel.Get("CASH_TICKS_CONTAINER").Visible = !Game.Sound.DummyEngine;
|
||||
panel.Get("MUTE_SOUND_CONTAINER").Visible = !Game.Sound.DummyEngine;
|
||||
panel.Get("MUTE_BACKGROUND_MUSIC_CONTAINER").Visible = !Game.Sound.DummyEngine;
|
||||
panel.Get("SOUND_VOLUME_CONTAINER").Visible = !Game.Sound.DummyEngine;
|
||||
panel.Get("MUSIC_VOLUME_CONTAINER").Visible = !Game.Sound.DummyEngine;
|
||||
panel.Get("VIDEO_VOLUME_CONTAINER").Visible = !Game.Sound.DummyEngine;
|
||||
|
||||
var soundVolumeSlider = panel.Get<SliderWidget>("SOUND_VOLUME");
|
||||
soundVolumeSlider.OnChange += x => Game.Sound.SoundVolume = x;
|
||||
|
||||
var musicVolumeSlider = panel.Get<SliderWidget>("MUSIC_VOLUME");
|
||||
musicVolumeSlider.OnChange += x => Game.Sound.MusicVolume = x;
|
||||
|
||||
var videoVolumeSlider = panel.Get<SliderWidget>("VIDEO_VOLUME");
|
||||
videoVolumeSlider.OnChange += x => Game.Sound.VideoVolume = x;
|
||||
|
||||
var devices = Game.Sound.AvailableDevices();
|
||||
soundDevice = devices.FirstOrDefault(d => d.Device == soundSettings.Device) ?? devices[0];
|
||||
|
||||
var audioDeviceDropdown = panel.Get<DropDownButtonWidget>("AUDIO_DEVICE");
|
||||
audioDeviceDropdown.OnMouseDown = _ => ShowAudioDeviceDropdown(audioDeviceDropdown, devices, scrollPanel);
|
||||
|
||||
var deviceFont = Game.Renderer.Fonts[audioDeviceDropdown.Font];
|
||||
var deviceLabel = new CachedTransform<SoundDevice, string>(
|
||||
s => WidgetUtils.TruncateText(s.Label, audioDeviceDropdown.UsableWidth, deviceFont));
|
||||
audioDeviceDropdown.GetText = () => deviceLabel.Update(soundDevice);
|
||||
|
||||
var restartDesc = panel.Get("AUDIO_RESTART_REQUIRED_DESC");
|
||||
restartDesc.IsVisible = () => soundDevice.Device != originalSoundSettings.Device;
|
||||
|
||||
SettingsUtils.AdjustSettingsScrollPanelLayout(scrollPanel);
|
||||
|
||||
return () =>
|
||||
{
|
||||
soundSettings.Device = soundDevice.Device;
|
||||
return soundSettings.Device != originalSoundSettings.Device;
|
||||
};
|
||||
}
|
||||
|
||||
Action ResetPanel(Widget panel)
|
||||
{
|
||||
var defaultSoundSettings = new SoundSettings();
|
||||
return () =>
|
||||
{
|
||||
soundSettings.SoundVolume = defaultSoundSettings.SoundVolume;
|
||||
soundSettings.MusicVolume = defaultSoundSettings.MusicVolume;
|
||||
soundSettings.VideoVolume = defaultSoundSettings.VideoVolume;
|
||||
soundSettings.CashTicks = defaultSoundSettings.CashTicks;
|
||||
soundSettings.Mute = defaultSoundSettings.Mute;
|
||||
soundSettings.MuteBackgroundMusic = defaultSoundSettings.MuteBackgroundMusic;
|
||||
soundSettings.Device = defaultSoundSettings.Device;
|
||||
|
||||
panel.Get<SliderWidget>("SOUND_VOLUME").Value = soundSettings.SoundVolume;
|
||||
Game.Sound.SoundVolume = soundSettings.SoundVolume;
|
||||
panel.Get<SliderWidget>("MUSIC_VOLUME").Value = soundSettings.MusicVolume;
|
||||
Game.Sound.MusicVolume = soundSettings.MusicVolume;
|
||||
panel.Get<SliderWidget>("VIDEO_VOLUME").Value = soundSettings.VideoVolume;
|
||||
Game.Sound.VideoVolume = soundSettings.VideoVolume;
|
||||
Game.Sound.UnmuteAudio();
|
||||
soundDevice = Game.Sound.AvailableDevices().First();
|
||||
};
|
||||
}
|
||||
|
||||
void ShowAudioDeviceDropdown(DropDownButtonWidget dropdown, SoundDevice[] devices, ScrollPanelWidget scrollPanel)
|
||||
{
|
||||
var i = 0;
|
||||
var options = devices.ToDictionary(d => i++.ToStringInvariant(), d => d);
|
||||
|
||||
ScrollItemWidget SetupItem(string o, ScrollItemWidget itemTemplate)
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => soundDevice == options[o],
|
||||
() =>
|
||||
{
|
||||
soundDevice = options[o];
|
||||
SettingsUtils.AdjustSettingsScrollPanelLayout(scrollPanel);
|
||||
});
|
||||
|
||||
var deviceLabel = item.Get<LabelWidget>("LABEL");
|
||||
var font = Game.Renderer.Fonts[deviceLabel.Font];
|
||||
var label = WidgetUtils.TruncateText(options[o].Label, deviceLabel.Bounds.Width, font);
|
||||
deviceLabel.GetText = () => label;
|
||||
return item;
|
||||
}
|
||||
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options.Keys, SetupItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,512 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
public class DisplaySettingsLogic : ChromeLogic
|
||||
{
|
||||
[FluentReference]
|
||||
const string Close = "options-camera.close";
|
||||
|
||||
[FluentReference]
|
||||
const string Medium = "options-camera.medium";
|
||||
|
||||
[FluentReference]
|
||||
const string Far = "options-camera.far";
|
||||
|
||||
[FluentReference]
|
||||
const string Furthest = "options-camera.furthest";
|
||||
|
||||
[FluentReference]
|
||||
const string Windowed = "options-display-mode.windowed";
|
||||
|
||||
[FluentReference]
|
||||
const string LegacyFullscreen = "options-display-mode.legacy-fullscreen";
|
||||
|
||||
[FluentReference]
|
||||
const string Fullscreen = "options-display-mode.fullscreen";
|
||||
|
||||
[FluentReference("number")]
|
||||
const string Display = "label-video-display-index";
|
||||
|
||||
[FluentReference]
|
||||
const string Standard = "options-status-bars.standard";
|
||||
|
||||
[FluentReference]
|
||||
const string ShowOnDamage = "options-status-bars.show-on-damage";
|
||||
|
||||
[FluentReference]
|
||||
const string AlwaysShow = "options-status-bars.always-show";
|
||||
|
||||
[FluentReference]
|
||||
const string Automatic = "options-target-lines.automatic";
|
||||
|
||||
[FluentReference]
|
||||
const string Manual = "options-target-lines.manual";
|
||||
|
||||
[FluentReference]
|
||||
const string Disabled = "options-target-lines.disabled";
|
||||
|
||||
[FluentReference("fps")]
|
||||
const string FrameLimiter = "checkbox-frame-limiter";
|
||||
|
||||
readonly ModData modData;
|
||||
readonly WorldRenderer worldRenderer;
|
||||
readonly WorldViewportSizes viewportSizes;
|
||||
readonly GameSettings gameSettings;
|
||||
readonly GraphicSettings graphicSettings;
|
||||
static GraphicSettings originalGraphicSettings;
|
||||
|
||||
readonly string showOnDamage;
|
||||
readonly string alwaysShow;
|
||||
|
||||
readonly string automatic;
|
||||
readonly string manual;
|
||||
readonly string disabled;
|
||||
|
||||
readonly string legacyFullscreen;
|
||||
readonly string fullscreen;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public DisplaySettingsLogic(ModData modData, SettingsLogic settingsLogic, string panelID, string label, WorldRenderer worldRenderer)
|
||||
{
|
||||
this.worldRenderer = worldRenderer;
|
||||
this.modData = modData;
|
||||
viewportSizes = modData.GetOrCreate<WorldViewportSizes>();
|
||||
gameSettings = modData.GetSettings<GameSettings>();
|
||||
graphicSettings = modData.GetSettings<GraphicSettings>();
|
||||
originalGraphicSettings ??= graphicSettings.Clone();
|
||||
|
||||
legacyFullscreen = FluentProvider.GetMessage(LegacyFullscreen);
|
||||
fullscreen = FluentProvider.GetMessage(Fullscreen);
|
||||
|
||||
settingsLogic.RegisterSettingsPanel(panelID, label, InitPanel, ResetPanel);
|
||||
|
||||
showOnDamage = FluentProvider.GetMessage(ShowOnDamage);
|
||||
alwaysShow = FluentProvider.GetMessage(AlwaysShow);
|
||||
|
||||
automatic = FluentProvider.GetMessage(Automatic);
|
||||
manual = FluentProvider.GetMessage(Manual);
|
||||
disabled = FluentProvider.GetMessage(Disabled);
|
||||
}
|
||||
|
||||
public static string GetViewportSizeName(ModData modData, WorldViewport worldViewport)
|
||||
{
|
||||
switch (worldViewport)
|
||||
{
|
||||
case WorldViewport.Close:
|
||||
return FluentProvider.GetMessage(Close);
|
||||
case WorldViewport.Medium:
|
||||
return FluentProvider.GetMessage(Medium);
|
||||
case WorldViewport.Far:
|
||||
return FluentProvider.GetMessage(Far);
|
||||
case WorldViewport.Native:
|
||||
return FluentProvider.GetMessage(Furthest);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
Func<bool> InitPanel(Widget panel)
|
||||
{
|
||||
var world = worldRenderer.World;
|
||||
var scrollPanel = panel.Get<ScrollPanelWidget>("SETTINGS_SCROLLPANEL");
|
||||
|
||||
SettingsUtils.BindCheckboxPref(panel, "CURSORDOUBLE_CHECKBOX", graphicSettings, "CursorDouble");
|
||||
SettingsUtils.BindCheckboxPref(panel, "VSYNC_CHECKBOX", graphicSettings, "VSync");
|
||||
SettingsUtils.BindCheckboxPref(panel, "FRAME_LIMIT_CHECKBOX", graphicSettings, "CapFramerate");
|
||||
SettingsUtils.BindCheckboxPref(panel, "FRAME_LIMIT_GAMESPEED_CHECKBOX", graphicSettings, "CapFramerateToGameFps");
|
||||
SettingsUtils.BindIntSliderPref(panel, "FRAME_LIMIT_SLIDER", graphicSettings, "MaxFramerate");
|
||||
SettingsUtils.BindCheckboxPref(panel, "PLAYER_STANCE_COLORS_CHECKBOX", gameSettings, "UsePlayerStanceColors");
|
||||
|
||||
var cb = panel.Get<CheckboxWidget>("PLAYER_STANCE_COLORS_CHECKBOX");
|
||||
cb.IsChecked = () => gameSettings.UsePlayerStanceColors;
|
||||
cb.OnClick = () =>
|
||||
{
|
||||
gameSettings.UsePlayerStanceColors = cb.IsChecked() ^ true;
|
||||
Player.SetupRelationshipColors(world.Players, world.LocalPlayer, worldRenderer, false);
|
||||
};
|
||||
|
||||
if (panel.GetOrNull<CheckboxWidget>("PAUSE_SHELLMAP_CHECKBOX") != null)
|
||||
SettingsUtils.BindCheckboxPref(panel, "PAUSE_SHELLMAP_CHECKBOX", gameSettings, "PauseShellmap");
|
||||
|
||||
var windowModeDropdown = panel.Get<DropDownButtonWidget>("MODE_DROPDOWN");
|
||||
windowModeDropdown.OnMouseDown = _ => ShowWindowModeDropdown(windowModeDropdown, graphicSettings, scrollPanel);
|
||||
windowModeDropdown.GetText = () => graphicSettings.Mode == WindowMode.Windowed
|
||||
? FluentProvider.GetMessage(Windowed)
|
||||
: graphicSettings.Mode == WindowMode.Fullscreen ? legacyFullscreen : fullscreen;
|
||||
|
||||
var displaySelectionDropDown = panel.Get<DropDownButtonWidget>("DISPLAY_SELECTION_DROPDOWN");
|
||||
displaySelectionDropDown.OnMouseDown = _ => ShowDisplaySelectionDropdown(displaySelectionDropDown, graphicSettings);
|
||||
var displaySelectionLabel = new CachedTransform<int, string>(i => FluentProvider.GetMessage(Display, "number", i + 1));
|
||||
displaySelectionDropDown.GetText = () => displaySelectionLabel.Update(graphicSettings.VideoDisplay);
|
||||
displaySelectionDropDown.IsDisabled = () => Game.Renderer.DisplayCount < 2;
|
||||
|
||||
var glProfileLabel = new CachedTransform<GLProfile, string>(p => p.ToString());
|
||||
var glProfileDropdown = panel.Get<DropDownButtonWidget>("GL_PROFILE_DROPDOWN");
|
||||
var disableProfile = Game.Renderer.SupportedGLProfiles.Length < 2 && graphicSettings.GLProfile == GLProfile.Automatic;
|
||||
glProfileDropdown.OnMouseDown = _ => ShowGLProfileDropdown(glProfileDropdown, graphicSettings);
|
||||
glProfileDropdown.GetText = () => glProfileLabel.Update(graphicSettings.GLProfile);
|
||||
glProfileDropdown.IsDisabled = () => disableProfile;
|
||||
|
||||
var statusBarsDropDown = panel.Get<DropDownButtonWidget>("STATUS_BAR_DROPDOWN");
|
||||
statusBarsDropDown.OnMouseDown = _ => ShowStatusBarsDropdown(statusBarsDropDown, gameSettings);
|
||||
statusBarsDropDown.GetText = () => gameSettings.StatusBars == StatusBarsType.Standard
|
||||
? FluentProvider.GetMessage(Standard)
|
||||
: gameSettings.StatusBars == StatusBarsType.DamageShow
|
||||
? showOnDamage
|
||||
: alwaysShow;
|
||||
|
||||
var targetLinesDropDown = panel.Get<DropDownButtonWidget>("TARGET_LINES_DROPDOWN");
|
||||
targetLinesDropDown.OnMouseDown = _ => ShowTargetLinesDropdown(targetLinesDropDown, gameSettings);
|
||||
targetLinesDropDown.GetText = () => gameSettings.TargetLines == TargetLinesType.Automatic
|
||||
? automatic
|
||||
: gameSettings.TargetLines == TargetLinesType.Manual
|
||||
? manual
|
||||
: disabled;
|
||||
|
||||
var battlefieldCameraDropDown = panel.Get<DropDownButtonWidget>("BATTLEFIELD_CAMERA_DROPDOWN");
|
||||
var battlefieldCameraLabel = new CachedTransform<WorldViewport, string>(vs => GetViewportSizeName(modData, vs));
|
||||
battlefieldCameraDropDown.OnMouseDown = _ => ShowBattlefieldCameraDropdown(modData, battlefieldCameraDropDown, viewportSizes, graphicSettings);
|
||||
battlefieldCameraDropDown.GetText = () => battlefieldCameraLabel.Update(graphicSettings.ViewportDistance);
|
||||
|
||||
BindTextNotificationPoolFilterSettings(panel, gameSettings);
|
||||
|
||||
// Update vsync immediately
|
||||
var vsyncCheckbox = panel.Get<CheckboxWidget>("VSYNC_CHECKBOX");
|
||||
var vsyncOnClick = vsyncCheckbox.OnClick;
|
||||
vsyncCheckbox.OnClick = () =>
|
||||
{
|
||||
vsyncOnClick();
|
||||
Game.Renderer.SetVSyncEnabled(graphicSettings.VSync);
|
||||
};
|
||||
|
||||
var uiScaleDropdown = panel.Get<DropDownButtonWidget>("UI_SCALE_DROPDOWN");
|
||||
var uiScaleLabel = new CachedTransform<float, string>(s => $"{(int)(100 * s)}%");
|
||||
uiScaleDropdown.OnMouseDown = _ => ShowUIScaleDropdown(uiScaleDropdown, graphicSettings);
|
||||
uiScaleDropdown.GetText = () => uiScaleLabel.Update(graphicSettings.UIScale);
|
||||
|
||||
var minResolution = viewportSizes.MinEffectiveResolution;
|
||||
var resolution = Game.Renderer.Resolution;
|
||||
var disableUIScale = world.Type != WorldType.Shellmap ||
|
||||
resolution.Width * graphicSettings.UIScale < 1.25f * minResolution.Width ||
|
||||
resolution.Height * graphicSettings.UIScale < 1.25f * minResolution.Height;
|
||||
|
||||
uiScaleDropdown.IsDisabled = () => disableUIScale;
|
||||
|
||||
panel.Get("DISPLAY_SELECTION_CONTAINER").IsVisible = () => graphicSettings.Mode != WindowMode.Windowed;
|
||||
panel.Get("WINDOW_RESOLUTION_CONTAINER").IsVisible = () => graphicSettings.Mode == WindowMode.Windowed;
|
||||
var windowWidth = panel.Get<TextFieldWidget>("WINDOW_WIDTH");
|
||||
var origWidthText = windowWidth.Text = graphicSettings.WindowedSize.X.ToString(NumberFormatInfo.CurrentInfo);
|
||||
|
||||
var windowHeight = panel.Get<TextFieldWidget>("WINDOW_HEIGHT");
|
||||
var origHeightText = windowHeight.Text = graphicSettings.WindowedSize.Y.ToString(NumberFormatInfo.CurrentInfo);
|
||||
windowHeight.Text = graphicSettings.WindowedSize.Y.ToString(NumberFormatInfo.CurrentInfo);
|
||||
|
||||
var restartDesc = panel.Get("VIDEO_RESTART_REQUIRED_DESC");
|
||||
restartDesc.IsVisible = () => graphicSettings.Mode != originalGraphicSettings.Mode ||
|
||||
graphicSettings.VideoDisplay != originalGraphicSettings.VideoDisplay ||
|
||||
graphicSettings.GLProfile != originalGraphicSettings.GLProfile ||
|
||||
(graphicSettings.Mode == WindowMode.Windowed && (origWidthText != windowWidth.Text || origHeightText != windowHeight.Text));
|
||||
|
||||
var frameLimitGamespeedCheckbox = panel.Get<CheckboxWidget>("FRAME_LIMIT_GAMESPEED_CHECKBOX");
|
||||
var frameLimitCheckbox = panel.Get<CheckboxWidget>("FRAME_LIMIT_CHECKBOX");
|
||||
var frameLimitLabel = new CachedTransform<int, string>(fps => FluentProvider.GetMessage(FrameLimiter, "fps", fps));
|
||||
frameLimitCheckbox.GetText = () => frameLimitLabel.Update(graphicSettings.MaxFramerate);
|
||||
frameLimitCheckbox.IsDisabled = () => graphicSettings.CapFramerateToGameFps;
|
||||
|
||||
panel.Get<SliderWidget>("FRAME_LIMIT_SLIDER").IsDisabled = () => !frameLimitCheckbox.IsChecked() || frameLimitGamespeedCheckbox.IsChecked();
|
||||
|
||||
SettingsUtils.AdjustSettingsScrollPanelLayout(scrollPanel);
|
||||
|
||||
return () =>
|
||||
{
|
||||
int.TryParse(windowWidth.Text, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out var x);
|
||||
int.TryParse(windowHeight.Text, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out var y);
|
||||
graphicSettings.WindowedSize = new int2(x, y);
|
||||
|
||||
return graphicSettings.Mode != originalGraphicSettings.Mode ||
|
||||
graphicSettings.VideoDisplay != originalGraphicSettings.VideoDisplay ||
|
||||
graphicSettings.WindowedSize != originalGraphicSettings.WindowedSize ||
|
||||
graphicSettings.FullscreenSize != originalGraphicSettings.FullscreenSize ||
|
||||
graphicSettings.GLProfile != originalGraphicSettings.GLProfile;
|
||||
};
|
||||
}
|
||||
|
||||
Action ResetPanel(Widget panel)
|
||||
{
|
||||
var defaultGameSettings = new GameSettings();
|
||||
var defaultGraphicSettings = new GraphicSettings();
|
||||
return () =>
|
||||
{
|
||||
graphicSettings.CapFramerate = defaultGraphicSettings.CapFramerate;
|
||||
graphicSettings.MaxFramerate = defaultGraphicSettings.MaxFramerate;
|
||||
graphicSettings.CapFramerateToGameFps = defaultGraphicSettings.CapFramerateToGameFps;
|
||||
graphicSettings.GLProfile = defaultGraphicSettings.GLProfile;
|
||||
graphicSettings.Mode = defaultGraphicSettings.Mode;
|
||||
graphicSettings.VideoDisplay = defaultGraphicSettings.VideoDisplay;
|
||||
graphicSettings.WindowedSize = defaultGraphicSettings.WindowedSize;
|
||||
graphicSettings.CursorDouble = defaultGraphicSettings.CursorDouble;
|
||||
graphicSettings.ViewportDistance = defaultGraphicSettings.ViewportDistance;
|
||||
|
||||
if (graphicSettings.UIScale != defaultGraphicSettings.UIScale)
|
||||
{
|
||||
var oldScale = graphicSettings.UIScale;
|
||||
graphicSettings.UIScale = defaultGraphicSettings.UIScale;
|
||||
Game.Renderer.SetUIScale(defaultGraphicSettings.UIScale);
|
||||
RecalculateWidgetLayout(Ui.Root);
|
||||
Viewport.LastMousePos = (Viewport.LastMousePos.ToFloat2() * oldScale / graphicSettings.UIScale).ToInt2();
|
||||
}
|
||||
|
||||
gameSettings.TextNotificationPoolFilters = defaultGameSettings.TextNotificationPoolFilters;
|
||||
};
|
||||
}
|
||||
|
||||
static void ShowWindowModeDropdown(DropDownButtonWidget dropdown, GraphicSettings graphicSettings, ScrollPanelWidget scrollPanel)
|
||||
{
|
||||
var options = new Dictionary<string, WindowMode>()
|
||||
{
|
||||
{ FluentProvider.GetMessage(Fullscreen), WindowMode.PseudoFullscreen },
|
||||
{ FluentProvider.GetMessage(LegacyFullscreen), WindowMode.Fullscreen },
|
||||
{ FluentProvider.GetMessage(Windowed), WindowMode.Windowed },
|
||||
};
|
||||
|
||||
ScrollItemWidget SetupItem(string o, ScrollItemWidget itemTemplate)
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => graphicSettings.Mode == options[o],
|
||||
() =>
|
||||
{
|
||||
graphicSettings.Mode = options[o];
|
||||
SettingsUtils.AdjustSettingsScrollPanelLayout(scrollPanel);
|
||||
});
|
||||
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => o;
|
||||
return item;
|
||||
}
|
||||
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options.Keys, SetupItem);
|
||||
}
|
||||
|
||||
public static void BindTextNotificationPoolFilterSettings(Widget panel, GameSettings gameSettings)
|
||||
{
|
||||
void ToggleFilterFlag(TextNotificationPoolFilters f)
|
||||
{
|
||||
gameSettings.TextNotificationPoolFilters ^= f;
|
||||
gameSettings.Save();
|
||||
}
|
||||
|
||||
var feedbackCheckbox = panel.GetOrNull<CheckboxWidget>("UI_FEEDBACK_CHECKBOX");
|
||||
if (feedbackCheckbox != null)
|
||||
{
|
||||
feedbackCheckbox.IsChecked = () => gameSettings.TextNotificationPoolFilters.HasFlag(TextNotificationPoolFilters.Feedback);
|
||||
feedbackCheckbox.OnClick = () => ToggleFilterFlag(TextNotificationPoolFilters.Feedback);
|
||||
}
|
||||
|
||||
var transientsCheckbox = panel.GetOrNull<CheckboxWidget>("TRANSIENTS_CHECKBOX");
|
||||
if (transientsCheckbox != null)
|
||||
{
|
||||
transientsCheckbox.IsChecked = () => gameSettings.TextNotificationPoolFilters.HasFlag(TextNotificationPoolFilters.Transients);
|
||||
transientsCheckbox.OnClick = () => ToggleFilterFlag(TextNotificationPoolFilters.Transients);
|
||||
}
|
||||
}
|
||||
|
||||
static void ShowStatusBarsDropdown(DropDownButtonWidget dropdown, GameSettings gameSettings)
|
||||
{
|
||||
var options = new Dictionary<string, StatusBarsType>()
|
||||
{
|
||||
{ FluentProvider.GetMessage(Standard), StatusBarsType.Standard },
|
||||
{ FluentProvider.GetMessage(ShowOnDamage), StatusBarsType.DamageShow },
|
||||
{ FluentProvider.GetMessage(AlwaysShow), StatusBarsType.AlwaysShow },
|
||||
};
|
||||
|
||||
ScrollItemWidget SetupItem(string o, ScrollItemWidget itemTemplate)
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => gameSettings.StatusBars == options[o],
|
||||
() => gameSettings.StatusBars = options[o]);
|
||||
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => o;
|
||||
return item;
|
||||
}
|
||||
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options.Keys, SetupItem);
|
||||
}
|
||||
|
||||
static void ShowDisplaySelectionDropdown(DropDownButtonWidget dropdown, GraphicSettings graphicSettings)
|
||||
{
|
||||
ScrollItemWidget SetupItem(int o, ScrollItemWidget itemTemplate)
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => graphicSettings.VideoDisplay == o,
|
||||
() => graphicSettings.VideoDisplay = o);
|
||||
|
||||
var label = $"Display {o + 1}";
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => label;
|
||||
return item;
|
||||
}
|
||||
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, Enumerable.Range(0, Game.Renderer.DisplayCount), SetupItem);
|
||||
}
|
||||
|
||||
static void ShowGLProfileDropdown(DropDownButtonWidget dropdown, GraphicSettings graphicSettings)
|
||||
{
|
||||
ScrollItemWidget SetupItem(GLProfile o, ScrollItemWidget itemTemplate)
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => graphicSettings.GLProfile == o,
|
||||
() => graphicSettings.GLProfile = o);
|
||||
|
||||
var label = o.ToString();
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => label;
|
||||
return item;
|
||||
}
|
||||
|
||||
var profiles = new[] { GLProfile.Automatic }.Concat(Game.Renderer.SupportedGLProfiles);
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, profiles, SetupItem);
|
||||
}
|
||||
|
||||
static void ShowTargetLinesDropdown(DropDownButtonWidget dropdown, GameSettings gameSettings)
|
||||
{
|
||||
var options = new Dictionary<string, TargetLinesType>()
|
||||
{
|
||||
{ FluentProvider.GetMessage(Automatic), TargetLinesType.Automatic },
|
||||
{ FluentProvider.GetMessage(Manual), TargetLinesType.Manual },
|
||||
{ FluentProvider.GetMessage(Disabled), TargetLinesType.Disabled },
|
||||
};
|
||||
|
||||
ScrollItemWidget SetupItem(string o, ScrollItemWidget itemTemplate)
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => gameSettings.TargetLines == options[o],
|
||||
() => gameSettings.TargetLines = options[o]);
|
||||
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => o;
|
||||
return item;
|
||||
}
|
||||
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options.Keys, SetupItem);
|
||||
}
|
||||
|
||||
public static void ShowBattlefieldCameraDropdown(ModData modData, DropDownButtonWidget dropdown,
|
||||
WorldViewportSizes viewportSizes, GraphicSettings graphicSettings)
|
||||
{
|
||||
ScrollItemWidget SetupItem(WorldViewport o, ScrollItemWidget itemTemplate)
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => graphicSettings.ViewportDistance == o,
|
||||
() => graphicSettings.ViewportDistance = o);
|
||||
|
||||
var label = GetViewportSizeName(modData, o);
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => label;
|
||||
return item;
|
||||
}
|
||||
|
||||
var windowHeight = Game.Renderer.NativeResolution.Height;
|
||||
|
||||
var validSizes = new List<WorldViewport>() { WorldViewport.Close };
|
||||
if (viewportSizes.GetSizeRange(WorldViewport.Medium).X < windowHeight)
|
||||
validSizes.Add(WorldViewport.Medium);
|
||||
|
||||
var farRange = viewportSizes.GetSizeRange(WorldViewport.Far);
|
||||
if (farRange.X < windowHeight)
|
||||
validSizes.Add(WorldViewport.Far);
|
||||
|
||||
if (viewportSizes.AllowNativeZoom && farRange.Y < windowHeight)
|
||||
validSizes.Add(WorldViewport.Native);
|
||||
|
||||
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 and settings tab container
|
||||
// These have a fixed size, with calculated size and children positions that break if we adjust them here
|
||||
if (w.Id == "BADGES_CONTAINER" || w.Id == "SETTINGS_TAB_CONTAINER")
|
||||
return;
|
||||
|
||||
var parentBounds = w.Parent == null
|
||||
? new WidgetBounds(0, 0, Game.Renderer.Resolution.Width, Game.Renderer.Resolution.Height)
|
||||
: w.Parent.Bounds;
|
||||
|
||||
var substitutions = new Dictionary<string, int>
|
||||
{
|
||||
{ "WINDOW_WIDTH", Game.Renderer.Resolution.Width },
|
||||
{ "WINDOW_HEIGHT", Game.Renderer.Resolution.Height },
|
||||
{ "PARENT_WIDTH", parentBounds.Width },
|
||||
{ "PARENT_HEIGHT", parentBounds.Height }
|
||||
};
|
||||
|
||||
var readOnlySubstitutions = new ReadOnlyDictionary<string, int>(substitutions);
|
||||
var width = w.Width?.Evaluate(readOnlySubstitutions) ?? 0;
|
||||
var height = w.Height?.Evaluate(readOnlySubstitutions) ?? 0;
|
||||
|
||||
substitutions.Add("WIDTH", width);
|
||||
substitutions.Add("HEIGHT", height);
|
||||
|
||||
if (insideScrollPanel)
|
||||
w.Bounds = new WidgetBounds(w.Bounds.X, w.Bounds.Y, width, w.Bounds.Height);
|
||||
else
|
||||
w.Bounds = new WidgetBounds(
|
||||
w.X?.Evaluate(readOnlySubstitutions) ?? 0,
|
||||
w.Y?.Evaluate(readOnlySubstitutions) ?? 0,
|
||||
width,
|
||||
height);
|
||||
|
||||
foreach (var c in w.Children)
|
||||
RecalculateWidgetLayout(c, insideScrollPanel || w is ScrollPanelWidget);
|
||||
}
|
||||
|
||||
public static void ShowUIScaleDropdown(DropDownButtonWidget dropdown, GraphicSettings graphicSettings)
|
||||
{
|
||||
ScrollItemWidget SetupItem(float o, ScrollItemWidget itemTemplate)
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => graphicSettings.UIScale == o,
|
||||
() =>
|
||||
{
|
||||
Game.RunAfterTick(() =>
|
||||
{
|
||||
var oldScale = graphicSettings.UIScale;
|
||||
graphicSettings.UIScale = o;
|
||||
|
||||
Game.Renderer.SetUIScale(o);
|
||||
RecalculateWidgetLayout(Ui.Root);
|
||||
Viewport.LastMousePos = (Viewport.LastMousePos.ToFloat2() * oldScale / graphicSettings.UIScale).ToInt2();
|
||||
});
|
||||
});
|
||||
|
||||
var label = $"{(int)(100 * o)}%";
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => label;
|
||||
return item;
|
||||
}
|
||||
|
||||
var viewportSizes = Game.ModData.GetOrCreate<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
public class GameplaySettingsLogic : ChromeLogic
|
||||
{
|
||||
[FluentReference]
|
||||
const string AutoSaveIntervalOptions = "auto-save-interval.options";
|
||||
|
||||
[FluentReference]
|
||||
const string AutoSaveIntervalDisabled = "auto-save-interval.disabled";
|
||||
|
||||
[FluentReference]
|
||||
const string AutoSaveIntervalMinuteOptions = "auto-save-interval.minute-options";
|
||||
|
||||
[FluentReference]
|
||||
const string AutoSaveMaxFileNumber = "auto-save-max-file-number";
|
||||
readonly int[] autoSaveSeconds = [0, 10, 30, 45, 60, 120, 180, 300, 600];
|
||||
|
||||
readonly int[] autoSaveFileNumbers = [3, 5, 10, 20, 50, 100];
|
||||
readonly AutoSaveSettings autoSaveSettings;
|
||||
readonly GameSettings gameSettings;
|
||||
readonly PlayerSettings playerSettings;
|
||||
readonly WorldRenderer worldRenderer;
|
||||
readonly ModData modData;
|
||||
|
||||
TextFieldWidget nameTextfield;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public GameplaySettingsLogic(ModData modData, SettingsLogic settingsLogic, string panelID, string label, WorldRenderer worldRenderer)
|
||||
{
|
||||
this.modData = modData;
|
||||
this.worldRenderer = worldRenderer;
|
||||
|
||||
autoSaveSettings = modData.GetSettings<AutoSaveSettings>();
|
||||
gameSettings = modData.GetSettings<GameSettings>();
|
||||
playerSettings = modData.GetSettings<PlayerSettings>();
|
||||
settingsLogic.RegisterSettingsPanel(panelID, label, InitPanel, ResetPanel);
|
||||
}
|
||||
|
||||
Func<bool> InitPanel(Widget panel)
|
||||
{
|
||||
var scrollPanel = panel.Get<ScrollPanelWidget>("SETTINGS_SCROLLPANEL");
|
||||
var world = worldRenderer.World;
|
||||
|
||||
var escPressed = false;
|
||||
nameTextfield = panel.Get<TextFieldWidget>("PLAYERNAME");
|
||||
nameTextfield.IsDisabled = () => world.Type != WorldType.Shellmap;
|
||||
nameTextfield.Text = Settings.SanitizedPlayerName(playerSettings.Name);
|
||||
nameTextfield.OnLoseFocus = () =>
|
||||
{
|
||||
if (escPressed)
|
||||
{
|
||||
escPressed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
nameTextfield.Text = nameTextfield.Text.Trim();
|
||||
if (nameTextfield.Text.Length == 0)
|
||||
nameTextfield.Text = Settings.SanitizedPlayerName(playerSettings.Name);
|
||||
else
|
||||
{
|
||||
nameTextfield.Text = Settings.SanitizedPlayerName(nameTextfield.Text);
|
||||
playerSettings.Name = nameTextfield.Text;
|
||||
}
|
||||
};
|
||||
|
||||
nameTextfield.OnEnterKey = _ => { nameTextfield.YieldKeyboardFocus(); return true; };
|
||||
nameTextfield.OnEscKey = _ =>
|
||||
{
|
||||
nameTextfield.Text = Settings.SanitizedPlayerName(playerSettings.Name);
|
||||
escPressed = true;
|
||||
nameTextfield.YieldKeyboardFocus();
|
||||
return true;
|
||||
};
|
||||
|
||||
var colorManager = modData.DefaultRules.Actors[SystemActors.World].TraitInfo<IColorPickerManagerInfo>();
|
||||
|
||||
var colorDropdown = panel.Get<DropDownButtonWidget>("PLAYERCOLOR");
|
||||
colorDropdown.IsDisabled = () => world.Type != WorldType.Shellmap;
|
||||
colorDropdown.OnMouseDown = _ => colorManager.ShowColorDropDown(colorDropdown, playerSettings.Color, null, worldRenderer, color =>
|
||||
{
|
||||
playerSettings.Color = color;
|
||||
playerSettings.Save();
|
||||
});
|
||||
colorDropdown.Get<ColorBlockWidget>("COLORBLOCK").GetColor = () => playerSettings.Color;
|
||||
|
||||
SettingsUtils.BindCheckboxPref(panel, "HIDE_REPLAY_CHAT_CHECKBOX", gameSettings, "HideReplayChat");
|
||||
|
||||
var autoSaveIntervalDropDown = panel.Get<DropDownButtonWidget>("AUTO_SAVE_INTERVAL_DROP_DOWN");
|
||||
autoSaveIntervalDropDown.OnClick = () =>
|
||||
ShowAutoSaveIntervalDropdown(autoSaveIntervalDropDown, autoSaveSeconds);
|
||||
autoSaveIntervalDropDown.GetText = () => GetMessageForAutoSaveInterval(autoSaveSettings.AutoSaveInterval);
|
||||
|
||||
// Setup dropdown for auto-save number.
|
||||
var autoSaveNoDropDown = panel.Get<DropDownButtonWidget>("AUTO_SAVE_FILE_NUMBER_DROP_DOWN");
|
||||
|
||||
autoSaveNoDropDown.OnMouseDown = _ => ShowAutoSaveFileNumberDropdown(autoSaveNoDropDown, autoSaveFileNumbers);
|
||||
autoSaveNoDropDown.GetText = () => FluentProvider.GetMessage(AutoSaveMaxFileNumber, "saves", autoSaveSettings.AutoSaveMaxFileCount);
|
||||
autoSaveNoDropDown.IsDisabled = () => autoSaveSettings.AutoSaveInterval <= 0;
|
||||
|
||||
SettingsUtils.AdjustSettingsScrollPanelLayout(scrollPanel);
|
||||
|
||||
return () =>
|
||||
{
|
||||
nameTextfield.YieldKeyboardFocus();
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
Action ResetPanel(Widget panel)
|
||||
{
|
||||
var defaultAutoSaveSettings = new AutoSaveSettings();
|
||||
var defaultGameSettings = new GameSettings();
|
||||
var defaultPlayerSettings = new PlayerSettings();
|
||||
return () =>
|
||||
{
|
||||
nameTextfield.Text = playerSettings.Name = defaultPlayerSettings.Name;
|
||||
playerSettings.Color = defaultPlayerSettings.Color;
|
||||
autoSaveSettings.AutoSaveInterval = defaultAutoSaveSettings.AutoSaveInterval;
|
||||
autoSaveSettings.AutoSaveMaxFileCount = defaultAutoSaveSettings.AutoSaveMaxFileCount;
|
||||
gameSettings.HideReplayChat = defaultGameSettings.HideReplayChat;
|
||||
};
|
||||
}
|
||||
|
||||
void ShowAutoSaveIntervalDropdown(DropDownButtonWidget dropdown, IEnumerable<int> options)
|
||||
{
|
||||
ScrollItemWidget SetupItem(int o, ScrollItemWidget itemTemplate)
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => autoSaveSettings.AutoSaveInterval == o,
|
||||
() =>
|
||||
{
|
||||
autoSaveSettings.AutoSaveInterval = o;
|
||||
autoSaveSettings.Save();
|
||||
});
|
||||
|
||||
var deviceLabel = item.Get<LabelWidget>("LABEL");
|
||||
deviceLabel.GetText = () => GetMessageForAutoSaveInterval(o);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options, SetupItem);
|
||||
}
|
||||
|
||||
void ShowAutoSaveFileNumberDropdown(DropDownButtonWidget dropdown, IEnumerable<int> options)
|
||||
{
|
||||
ScrollItemWidget SetupItem(int o, ScrollItemWidget itemTemplate)
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => autoSaveSettings.AutoSaveMaxFileCount == o,
|
||||
() =>
|
||||
{
|
||||
autoSaveSettings.AutoSaveMaxFileCount = o;
|
||||
autoSaveSettings.Save();
|
||||
});
|
||||
|
||||
var deviceLabel = item.Get<LabelWidget>("LABEL");
|
||||
|
||||
deviceLabel.GetText = () => FluentProvider.GetMessage(AutoSaveMaxFileNumber, "saves", o);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options, SetupItem);
|
||||
}
|
||||
|
||||
static string GetMessageForAutoSaveInterval(int value) =>
|
||||
value switch
|
||||
{
|
||||
0 => FluentProvider.GetMessage(AutoSaveIntervalDisabled),
|
||||
< 60 => FluentProvider.GetMessage(AutoSaveIntervalOptions, "seconds", value),
|
||||
_ => FluentProvider.GetMessage(AutoSaveIntervalMinuteOptions, "minutes", value / 60)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
[IncludeChromeLogicArgsFluentReferences(nameof(DynamicFluentReferences))]
|
||||
[IncludeStaticFluentReferences(typeof(KeycodeExts), typeof(ModifiersExts))]
|
||||
public class HotkeysSettingsLogic : ChromeLogic
|
||||
{
|
||||
[FluentReference("key")]
|
||||
const string OriginalNotice = "label-original-notice";
|
||||
|
||||
[FluentReference("key", "context")]
|
||||
const string DuplicateNotice = "label-duplicate-notice";
|
||||
|
||||
[FluentReference]
|
||||
const string AnyContext = HotkeyDefinition.ContextFluentPrefix + "-any";
|
||||
|
||||
public static IEnumerable<(string Key, FluentReferenceAttribute Reference)> DynamicFluentReferences(Dictionary<string, MiniYaml> logicArgs)
|
||||
{
|
||||
if (logicArgs.TryGetValue("HotkeyGroups", out var hotkeyGroupsYaml))
|
||||
foreach (var node in hotkeyGroupsYaml.Nodes)
|
||||
yield return (node.Key, new FluentReferenceAttribute());
|
||||
}
|
||||
|
||||
readonly ModData modData;
|
||||
readonly Dictionary<string, MiniYaml> logicArgs;
|
||||
|
||||
ScrollPanelWidget hotkeyList;
|
||||
ButtonWidget selectedHotkeyButton;
|
||||
HotkeyEntryWidget hotkeyEntryWidget;
|
||||
HotkeyDefinition duplicateHotkeyDefinition, selectedHotkeyDefinition;
|
||||
int validHotkeyEntryWidth;
|
||||
int invalidHotkeyEntryWidth;
|
||||
bool isHotkeyValid;
|
||||
bool isHotkeyDefault;
|
||||
|
||||
string currentContext = AnyContext;
|
||||
readonly HashSet<string> contexts = [AnyContext];
|
||||
readonly Dictionary<string, FrozenSet<string>> hotkeyGroups = [];
|
||||
TextFieldWidget filterInput;
|
||||
|
||||
Widget headerTemplate;
|
||||
Widget template;
|
||||
Widget emptyListMessage;
|
||||
Widget remapDialog;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public HotkeysSettingsLogic(ModData modData, SettingsLogic settingsLogic, string panelID, string label, Dictionary<string, MiniYaml> logicArgs)
|
||||
{
|
||||
this.modData = modData;
|
||||
this.logicArgs = logicArgs;
|
||||
|
||||
settingsLogic.RegisterSettingsPanel(panelID, label, InitPanel, ResetPanel);
|
||||
}
|
||||
|
||||
void BindHotkeyPref(HotkeyDefinition hd, Widget template)
|
||||
{
|
||||
var key = template.Clone();
|
||||
key.Id = hd.Name;
|
||||
key.IsVisible = () => true;
|
||||
|
||||
var desc = FluentProvider.GetMessage(hd.Description) + ":";
|
||||
key.Get<LabelWidget>("FUNCTION").GetText = () => desc;
|
||||
|
||||
var remapButton = key.Get<ButtonWidget>("HOTKEY");
|
||||
WidgetUtils.TruncateButtonToTooltip(remapButton, modData.Hotkeys[hd.Name].GetValue().DisplayString());
|
||||
|
||||
remapButton.IsHighlighted = () => selectedHotkeyDefinition == hd;
|
||||
|
||||
var hotkeyValidColor = ChromeMetrics.Get<Color>("HotkeyColor");
|
||||
var hotkeyInvalidColor = ChromeMetrics.Get<Color>("HotkeyColorInvalid");
|
||||
|
||||
remapButton.GetColor = () => hd.HasDuplicates ? hotkeyInvalidColor : hotkeyValidColor;
|
||||
|
||||
if (selectedHotkeyDefinition == hd)
|
||||
{
|
||||
selectedHotkeyButton = remapButton;
|
||||
hotkeyEntryWidget.Key = modData.Hotkeys[hd.Name].GetValue();
|
||||
ValidateHotkey();
|
||||
}
|
||||
|
||||
remapButton.OnClick = () =>
|
||||
{
|
||||
selectedHotkeyDefinition = hd;
|
||||
selectedHotkeyButton = remapButton;
|
||||
hotkeyEntryWidget.Key = modData.Hotkeys[hd.Name].GetValue();
|
||||
ValidateHotkey();
|
||||
|
||||
if (hd.Readonly)
|
||||
hotkeyEntryWidget.YieldKeyboardFocus();
|
||||
else
|
||||
hotkeyEntryWidget.TakeKeyboardFocus();
|
||||
};
|
||||
|
||||
hotkeyList.AddChild(key);
|
||||
}
|
||||
|
||||
Func<bool> InitPanel(Widget panel)
|
||||
{
|
||||
hotkeyList = panel.Get<ScrollPanelWidget>("HOTKEY_LIST");
|
||||
hotkeyList.Layout = new GridLayout(hotkeyList);
|
||||
headerTemplate = hotkeyList.Get("HEADER");
|
||||
template = hotkeyList.Get("TEMPLATE");
|
||||
emptyListMessage = panel.Get("HOTKEY_EMPTY_LIST");
|
||||
remapDialog = panel.Get("HOTKEY_REMAP_DIALOG");
|
||||
|
||||
foreach (var hd in modData.Hotkeys.Definitions)
|
||||
contexts.UnionWith(hd.Contexts);
|
||||
|
||||
filterInput = panel.Get<TextFieldWidget>("FILTER_INPUT");
|
||||
filterInput.OnTextEdited = InitHotkeyList;
|
||||
filterInput.OnEscKey = _ =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(filterInput.Text))
|
||||
filterInput.YieldKeyboardFocus();
|
||||
else
|
||||
{
|
||||
filterInput.Text = "";
|
||||
filterInput.OnTextEdited();
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
var contextDropdown = panel.GetOrNull<DropDownButtonWidget>("CONTEXT_DROPDOWN");
|
||||
if (contextDropdown != null)
|
||||
{
|
||||
contextDropdown.OnMouseDown = _ => ShowContextDropdown(contextDropdown);
|
||||
var contextName = new CachedTransform<string, string>(GetContextDisplayName);
|
||||
contextDropdown.GetText = () => contextName.Update(currentContext);
|
||||
}
|
||||
|
||||
if (logicArgs.TryGetValue("HotkeyGroups", out var hotkeyGroupsYaml))
|
||||
{
|
||||
foreach (var hg in hotkeyGroupsYaml.Nodes)
|
||||
{
|
||||
var typesNode = hg.Value.NodeWithKeyOrDefault("Types");
|
||||
if (typesNode != null)
|
||||
hotkeyGroups.Add(hg.Key, FieldLoader.GetValue<FrozenSet<string>>("Types", typesNode.Value.Value));
|
||||
}
|
||||
|
||||
InitHotkeyRemapDialog(panel);
|
||||
InitHotkeyList();
|
||||
}
|
||||
|
||||
return () =>
|
||||
{
|
||||
hotkeyEntryWidget.Key =
|
||||
selectedHotkeyDefinition != null ?
|
||||
modData.Hotkeys[selectedHotkeyDefinition.Name].GetValue() :
|
||||
Hotkey.Invalid;
|
||||
|
||||
hotkeyEntryWidget.ForceYieldKeyboardFocus();
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
Action ResetPanel(Widget panel)
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
foreach (var hd in modData.Hotkeys.Definitions)
|
||||
{
|
||||
modData.Hotkeys.Set(hd.Name, hd.Default);
|
||||
var hotkeyButton = panel.GetOrNull(hd.Name)?.Get<ButtonWidget>("HOTKEY");
|
||||
if (hotkeyButton != null)
|
||||
WidgetUtils.TruncateButtonToTooltip(hotkeyButton, hd.Default.DisplayString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void InitHotkeyList()
|
||||
{
|
||||
hotkeyList.RemoveChildren();
|
||||
selectedHotkeyDefinition = null;
|
||||
|
||||
foreach (var hg in hotkeyGroups)
|
||||
{
|
||||
var typesInGroup = hg.Value;
|
||||
var keysInGroup = modData.Hotkeys.Definitions
|
||||
.Where(hd => IsHotkeyVisibleInFilter(hd) && hd.Types.Overlaps(typesInGroup))
|
||||
.ToList();
|
||||
|
||||
if (keysInGroup.Count == 0)
|
||||
continue;
|
||||
|
||||
var header = headerTemplate.Clone();
|
||||
var groupName = FluentProvider.GetMessage(hg.Key);
|
||||
header.Get<LabelWidget>("LABEL").GetText = () => groupName;
|
||||
hotkeyList.AddChild(header);
|
||||
|
||||
var added = new HashSet<HotkeyDefinition>();
|
||||
|
||||
foreach (var type in typesInGroup)
|
||||
{
|
||||
foreach (var hd in keysInGroup.Where(k => k.Types.Contains(type)))
|
||||
{
|
||||
if (added.Add(hd))
|
||||
{
|
||||
selectedHotkeyDefinition ??= hd;
|
||||
|
||||
BindHotkeyPref(hd, template);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emptyListMessage.Visible = selectedHotkeyDefinition == null;
|
||||
remapDialog.Visible = selectedHotkeyDefinition != null;
|
||||
|
||||
hotkeyList.ScrollToTop();
|
||||
}
|
||||
|
||||
void InitHotkeyRemapDialog(Widget panel)
|
||||
{
|
||||
var label = panel.Get<LabelWidget>("HOTKEY_LABEL");
|
||||
var labelText = new CachedTransform<HotkeyDefinition, string>(
|
||||
hd => (hd != null ? FluentProvider.GetMessage(hd.Description) : "") + ":");
|
||||
label.IsVisible = () => selectedHotkeyDefinition != null;
|
||||
label.GetText = () => labelText.Update(selectedHotkeyDefinition);
|
||||
|
||||
var duplicateNotice = panel.Get<LabelWidget>("DUPLICATE_NOTICE");
|
||||
duplicateNotice.TextColor = ChromeMetrics.Get<Color>("NoticeErrorColor");
|
||||
duplicateNotice.IsVisible = () => !isHotkeyValid;
|
||||
var duplicateNoticeText = new CachedTransform<HotkeyDefinition, string>(hd =>
|
||||
hd != null
|
||||
? FluentProvider.GetMessage(
|
||||
DuplicateNotice,
|
||||
"key", FluentProvider.GetMessage(hd.Description),
|
||||
"context", FluentProvider.GetMessage(hd.Contexts.First(c => selectedHotkeyDefinition.Contexts.Contains(c))))
|
||||
: "");
|
||||
duplicateNotice.GetText = () => duplicateNoticeText.Update(duplicateHotkeyDefinition);
|
||||
|
||||
var originalNotice = panel.Get<LabelWidget>("ORIGINAL_NOTICE");
|
||||
originalNotice.TextColor = ChromeMetrics.Get<Color>("NoticeInfoColor");
|
||||
originalNotice.IsVisible = () => isHotkeyValid && !isHotkeyDefault;
|
||||
var originalNoticeText = new CachedTransform<HotkeyDefinition, string>(hd =>
|
||||
FluentProvider.GetMessage(OriginalNotice, "key", hd?.Default.DisplayString()));
|
||||
originalNotice.GetText = () => originalNoticeText.Update(selectedHotkeyDefinition);
|
||||
|
||||
var readonlyNotice = panel.Get<LabelWidget>("READONLY_NOTICE");
|
||||
readonlyNotice.TextColor = ChromeMetrics.Get<Color>("NoticeInfoColor");
|
||||
readonlyNotice.IsVisible = () => selectedHotkeyDefinition.Readonly;
|
||||
|
||||
var resetButton = panel.Get<ButtonWidget>("RESET_HOTKEY_BUTTON");
|
||||
resetButton.IsDisabled = () => isHotkeyDefault || selectedHotkeyDefinition.Readonly;
|
||||
resetButton.OnClick = ResetHotkey;
|
||||
|
||||
var clearButton = panel.Get<ButtonWidget>("CLEAR_HOTKEY_BUTTON");
|
||||
clearButton.IsDisabled = () => selectedHotkeyDefinition.Readonly || !hotkeyEntryWidget.Key.IsValid();
|
||||
clearButton.OnClick = ClearHotkey;
|
||||
|
||||
var overrideButton = panel.Get<ButtonWidget>("OVERRIDE_HOTKEY_BUTTON");
|
||||
overrideButton.IsDisabled = () => isHotkeyValid;
|
||||
overrideButton.IsVisible = () => !isHotkeyValid && !duplicateHotkeyDefinition.Readonly;
|
||||
overrideButton.OnClick = OverrideHotkey;
|
||||
|
||||
hotkeyEntryWidget = panel.Get<HotkeyEntryWidget>("HOTKEY_ENTRY");
|
||||
hotkeyEntryWidget.IsValid = () => isHotkeyValid;
|
||||
hotkeyEntryWidget.OnLoseFocus = ValidateHotkey;
|
||||
hotkeyEntryWidget.OnEscKey = _ =>
|
||||
hotkeyEntryWidget.Key = modData.Hotkeys[selectedHotkeyDefinition.Name].GetValue();
|
||||
hotkeyEntryWidget.IsDisabled = () => selectedHotkeyDefinition.Readonly;
|
||||
|
||||
validHotkeyEntryWidth = hotkeyEntryWidget.Bounds.Width;
|
||||
invalidHotkeyEntryWidth = validHotkeyEntryWidth - (clearButton.Bounds.X - overrideButton.Bounds.X);
|
||||
}
|
||||
|
||||
void ValidateHotkey()
|
||||
{
|
||||
if (selectedHotkeyDefinition == null)
|
||||
return;
|
||||
|
||||
duplicateHotkeyDefinition = modData.Hotkeys.GetFirstDuplicate(selectedHotkeyDefinition, hotkeyEntryWidget.Key);
|
||||
isHotkeyValid = duplicateHotkeyDefinition == null || selectedHotkeyDefinition.Readonly;
|
||||
isHotkeyDefault =
|
||||
hotkeyEntryWidget.Key == selectedHotkeyDefinition.Default ||
|
||||
(!hotkeyEntryWidget.Key.IsValid() && !selectedHotkeyDefinition.Default.IsValid());
|
||||
|
||||
if (isHotkeyValid)
|
||||
{
|
||||
hotkeyEntryWidget.Bounds.Width = validHotkeyEntryWidth;
|
||||
SaveHotkey();
|
||||
}
|
||||
else
|
||||
{
|
||||
hotkeyEntryWidget.Bounds.Width = duplicateHotkeyDefinition.Readonly ? validHotkeyEntryWidth : invalidHotkeyEntryWidth;
|
||||
hotkeyEntryWidget.TakeKeyboardFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void SaveHotkey()
|
||||
{
|
||||
if (selectedHotkeyDefinition.Readonly)
|
||||
return;
|
||||
|
||||
WidgetUtils.TruncateButtonToTooltip(selectedHotkeyButton, hotkeyEntryWidget.Key.DisplayString());
|
||||
modData.Hotkeys.Set(selectedHotkeyDefinition.Name, hotkeyEntryWidget.Key);
|
||||
modData.Hotkeys.Save();
|
||||
}
|
||||
|
||||
void ResetHotkey()
|
||||
{
|
||||
hotkeyEntryWidget.Key = selectedHotkeyDefinition.Default;
|
||||
hotkeyEntryWidget.YieldKeyboardFocus();
|
||||
}
|
||||
|
||||
void ClearHotkey()
|
||||
{
|
||||
hotkeyEntryWidget.Key = Hotkey.Invalid;
|
||||
hotkeyEntryWidget.YieldKeyboardFocus();
|
||||
}
|
||||
|
||||
void OverrideHotkey()
|
||||
{
|
||||
var duplicateHotkeyButton = hotkeyList.GetOrNull<ContainerWidget>(duplicateHotkeyDefinition.Name)?.Get<ButtonWidget>("HOTKEY");
|
||||
if (duplicateHotkeyButton != null)
|
||||
WidgetUtils.TruncateButtonToTooltip(duplicateHotkeyButton, Hotkey.Invalid.DisplayString());
|
||||
modData.Hotkeys.Set(duplicateHotkeyDefinition.Name, Hotkey.Invalid);
|
||||
modData.Hotkeys.Save();
|
||||
hotkeyEntryWidget.YieldKeyboardFocus();
|
||||
}
|
||||
|
||||
bool IsHotkeyVisibleInFilter(HotkeyDefinition hd)
|
||||
{
|
||||
var filter = filterInput.Text;
|
||||
var isFilteredByName = string.IsNullOrWhiteSpace(filter) ||
|
||||
FluentProvider.GetMessage(hd.Description).Contains(filter, StringComparison.CurrentCultureIgnoreCase);
|
||||
var isFilteredByContext = currentContext == AnyContext || hd.Contexts.Contains(currentContext);
|
||||
|
||||
return isFilteredByName && isFilteredByContext;
|
||||
}
|
||||
|
||||
bool ShowContextDropdown(DropDownButtonWidget dropdown)
|
||||
{
|
||||
hotkeyEntryWidget.YieldKeyboardFocus();
|
||||
|
||||
var contextName = new CachedTransform<string, string>(GetContextDisplayName);
|
||||
ScrollItemWidget SetupItem(string context, ScrollItemWidget itemTemplate)
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => currentContext == context,
|
||||
() => { currentContext = context; InitHotkeyList(); });
|
||||
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => contextName.Update(context);
|
||||
return item;
|
||||
}
|
||||
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, contexts, SetupItem);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static string GetContextDisplayName(string context)
|
||||
{
|
||||
if (string.IsNullOrEmpty(context))
|
||||
context = AnyContext;
|
||||
|
||||
return FluentProvider.GetMessage(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
232
OpenRA.Mods.Common/Widgets/Logic/Settings/InputSettingsLogic.cs
Normal file
232
OpenRA.Mods.Common/Widgets/Logic/Settings/InputSettingsLogic.cs
Normal file
@@ -0,0 +1,232 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
public class InputSettingsLogic : ChromeLogic
|
||||
{
|
||||
[FluentReference]
|
||||
const string Classic = "options-control-scheme.classic";
|
||||
|
||||
[FluentReference]
|
||||
const string Modern = "options-control-scheme.modern";
|
||||
|
||||
[FluentReference]
|
||||
const string OtherRTS = "options-control-scheme.otherrts";
|
||||
|
||||
[FluentReference]
|
||||
const string Disabled = "options-mouse-scroll-type.disabled";
|
||||
|
||||
[FluentReference]
|
||||
const string Standard = "options-mouse-scroll-type.standard";
|
||||
|
||||
[FluentReference]
|
||||
const string Inverted = "options-mouse-scroll-type.inverted";
|
||||
|
||||
[FluentReference]
|
||||
const string Joystick = "options-mouse-scroll-type.joystick";
|
||||
|
||||
readonly GameSettings gameSettings;
|
||||
|
||||
readonly Dictionary<MouseControlStyle, string> controlTypes;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public InputSettingsLogic(ModData modData, SettingsLogic settingsLogic, string panelID, string label)
|
||||
{
|
||||
controlTypes = new Dictionary<MouseControlStyle, string>
|
||||
{
|
||||
{ MouseControlStyle.Classic, FluentProvider.GetMessage(Classic) },
|
||||
{ MouseControlStyle.Modern, FluentProvider.GetMessage(Modern) },
|
||||
{ MouseControlStyle.OtherRTS, FluentProvider.GetMessage(OtherRTS) },
|
||||
};
|
||||
gameSettings = modData.GetSettings<GameSettings>();
|
||||
|
||||
settingsLogic.RegisterSettingsPanel(panelID, label, InitPanel, ResetPanel);
|
||||
}
|
||||
|
||||
Func<bool> InitPanel(Widget panel)
|
||||
{
|
||||
var scrollPanel = panel.Get<ScrollPanelWidget>("SETTINGS_SCROLLPANEL");
|
||||
|
||||
SettingsUtils.BindCheckboxPref(panel, "ALTERNATE_SCROLL_CHECKBOX", gameSettings, "UseAlternateScrollButton");
|
||||
SettingsUtils.BindCheckboxPref(panel, "EDGESCROLL_CHECKBOX", gameSettings, "ViewportEdgeScroll");
|
||||
SettingsUtils.BindCheckboxPref(panel, "LOCKMOUSE_CHECKBOX", gameSettings, "LockMouseWindow");
|
||||
SettingsUtils.BindSliderPref(panel, "ZOOMSPEED_SLIDER", gameSettings, "ZoomSpeed");
|
||||
SettingsUtils.BindSliderPref(panel, "SCROLLSPEED_SLIDER", gameSettings, "ViewportEdgeScrollStep");
|
||||
SettingsUtils.BindSliderPref(panel, "UI_SCROLLSPEED_SLIDER", gameSettings, "UIScrollSpeed");
|
||||
|
||||
var mouseControlDropdown = panel.Get<DropDownButtonWidget>("MOUSE_CONTROL_DROPDOWN");
|
||||
mouseControlDropdown.OnMouseDown = _ => ShowMouseControlDropdown(mouseControlDropdown, controlTypes, gameSettings);
|
||||
mouseControlDropdown.GetText = () => controlTypes[gameSettings.MouseControlStyle];
|
||||
|
||||
var mouseScrollDropdown = panel.Get<DropDownButtonWidget>("MOUSE_SCROLL_TYPE_DROPDOWN");
|
||||
mouseScrollDropdown.OnMouseDown = _ => ShowMouseScrollDropdown(mouseScrollDropdown, gameSettings);
|
||||
|
||||
// MouseScroll can change, must display latest value.
|
||||
#pragma warning disable IDE0200 // Remove unnecessary lambda expression
|
||||
mouseScrollDropdown.GetText = () => gameSettings.MouseScroll.ToString();
|
||||
#pragma warning restore IDE0200
|
||||
|
||||
var mouseControlDescClassic = panel.Get("MOUSE_CONTROL_DESC_CLASSIC");
|
||||
mouseControlDescClassic.IsVisible = () => gameSettings.MouseControlStyle == MouseControlStyle.Classic;
|
||||
|
||||
var mouseControlDescModern = panel.Get("MOUSE_CONTROL_DESC_MODERN");
|
||||
mouseControlDescModern.IsVisible = () => gameSettings.MouseControlStyle == MouseControlStyle.Modern;
|
||||
|
||||
var mouseControlDescOtherRTS = panel.Get("MOUSE_CONTROL_DESC_OTHERRTS");
|
||||
mouseControlDescOtherRTS.IsVisible = () => gameSettings.MouseControlStyle == MouseControlStyle.OtherRTS;
|
||||
|
||||
foreach (var container in new[] { mouseControlDescClassic, mouseControlDescModern, mouseControlDescOtherRTS })
|
||||
{
|
||||
var classicScrollRight = container.Get("DESC_SCROLL_RIGHT");
|
||||
classicScrollRight.IsVisible = () => (gameSettings.MouseControlStyle == MouseControlStyle.Classic) ^ gameSettings.UseAlternateScrollButton;
|
||||
|
||||
var classicScrollMiddle = container.Get("DESC_SCROLL_MIDDLE");
|
||||
classicScrollMiddle.IsVisible = () => (gameSettings.MouseControlStyle != MouseControlStyle.Classic) ^ gameSettings.UseAlternateScrollButton;
|
||||
|
||||
var zoomDesc = container.Get("DESC_ZOOM");
|
||||
zoomDesc.IsVisible = () => gameSettings.ZoomModifier == Modifiers.None;
|
||||
|
||||
var zoomDescModifier = container.Get<LabelWidget>("DESC_ZOOM_MODIFIER");
|
||||
zoomDescModifier.IsVisible = () => gameSettings.ZoomModifier != Modifiers.None;
|
||||
|
||||
var zoomDescModifierTemplate = zoomDescModifier.GetText();
|
||||
var zoomDescModifierLabel = new CachedTransform<Modifiers, string>(
|
||||
mod => zoomDescModifierTemplate.Replace("MODIFIER", mod.ToString()));
|
||||
zoomDescModifier.GetText = () => zoomDescModifierLabel.Update(gameSettings.ZoomModifier);
|
||||
|
||||
var edgescrollDesc = container.Get<LabelWidget>("DESC_EDGESCROLL");
|
||||
edgescrollDesc.IsVisible = () => gameSettings.ViewportEdgeScroll;
|
||||
}
|
||||
|
||||
// Apply mouse focus preferences immediately
|
||||
var lockMouseCheckbox = panel.Get<CheckboxWidget>("LOCKMOUSE_CHECKBOX");
|
||||
var oldOnClick = lockMouseCheckbox.OnClick;
|
||||
lockMouseCheckbox.OnClick = () =>
|
||||
{
|
||||
// Still perform the old behaviour for clicking the checkbox, before
|
||||
// applying the changes live.
|
||||
oldOnClick();
|
||||
|
||||
MakeMouseFocusSettingsLive(gameSettings);
|
||||
};
|
||||
|
||||
var zoomModifierDropdown = panel.Get<DropDownButtonWidget>("ZOOM_MODIFIER");
|
||||
zoomModifierDropdown.OnMouseDown = _ => ShowZoomModifierDropdown(zoomModifierDropdown, gameSettings);
|
||||
|
||||
// ZoomModifier can change, must display latest value.
|
||||
#pragma warning disable IDE0200 // Remove unnecessary lambda expression
|
||||
zoomModifierDropdown.GetText = () => gameSettings.ZoomModifier.ToString();
|
||||
#pragma warning restore IDE0200
|
||||
|
||||
SettingsUtils.AdjustSettingsScrollPanelLayout(scrollPanel);
|
||||
|
||||
return () => false;
|
||||
}
|
||||
|
||||
Action ResetPanel(Widget panel)
|
||||
{
|
||||
var defaultGameSettings = new GameSettings();
|
||||
|
||||
return () =>
|
||||
{
|
||||
gameSettings.MouseControlStyle = defaultGameSettings.MouseControlStyle;
|
||||
gameSettings.MouseScroll = defaultGameSettings.MouseScroll;
|
||||
gameSettings.UseAlternateScrollButton = defaultGameSettings.UseAlternateScrollButton;
|
||||
gameSettings.LockMouseWindow = defaultGameSettings.LockMouseWindow;
|
||||
gameSettings.ViewportEdgeScroll = defaultGameSettings.ViewportEdgeScroll;
|
||||
gameSettings.ViewportEdgeScrollStep = defaultGameSettings.ViewportEdgeScrollStep;
|
||||
gameSettings.ZoomSpeed = defaultGameSettings.ZoomSpeed;
|
||||
gameSettings.UIScrollSpeed = defaultGameSettings.UIScrollSpeed;
|
||||
gameSettings.ZoomModifier = defaultGameSettings.ZoomModifier;
|
||||
|
||||
panel.Get<SliderWidget>("SCROLLSPEED_SLIDER").Value = gameSettings.ViewportEdgeScrollStep;
|
||||
panel.Get<SliderWidget>("UI_SCROLLSPEED_SLIDER").Value = gameSettings.UIScrollSpeed;
|
||||
|
||||
MakeMouseFocusSettingsLive(gameSettings);
|
||||
};
|
||||
}
|
||||
|
||||
public static void ShowMouseControlDropdown(DropDownButtonWidget dropdown, Dictionary<MouseControlStyle, string> controlTypes, GameSettings gameSettings)
|
||||
{
|
||||
ScrollItemWidget SetupItem(MouseControlStyle o, ScrollItemWidget itemTemplate)
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => gameSettings.MouseControlStyle == o,
|
||||
() => gameSettings.MouseControlStyle = o);
|
||||
|
||||
var label = controlTypes[o];
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => label;
|
||||
return item;
|
||||
}
|
||||
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, controlTypes.Keys, SetupItem);
|
||||
}
|
||||
|
||||
static void ShowMouseScrollDropdown(DropDownButtonWidget dropdown, GameSettings gameSettings)
|
||||
{
|
||||
var options = new Dictionary<string, MouseScrollType>()
|
||||
{
|
||||
{ FluentProvider.GetMessage(Disabled), MouseScrollType.Disabled },
|
||||
{ FluentProvider.GetMessage(Standard), MouseScrollType.Standard },
|
||||
{ FluentProvider.GetMessage(Inverted), MouseScrollType.Inverted },
|
||||
{ FluentProvider.GetMessage(Joystick), MouseScrollType.Joystick },
|
||||
};
|
||||
|
||||
ScrollItemWidget SetupItem(string o, ScrollItemWidget itemTemplate)
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => gameSettings.MouseScroll == options[o],
|
||||
() => gameSettings.MouseScroll = options[o]);
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => o;
|
||||
return item;
|
||||
}
|
||||
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options.Keys, SetupItem);
|
||||
}
|
||||
|
||||
static void ShowZoomModifierDropdown(DropDownButtonWidget dropdown, GameSettings gameSettings)
|
||||
{
|
||||
var options = new Dictionary<string, Modifiers>()
|
||||
{
|
||||
{ ModifiersExts.DisplayString(Modifiers.Alt), Modifiers.Alt },
|
||||
{ ModifiersExts.DisplayString(Modifiers.Ctrl), Modifiers.Ctrl },
|
||||
{ ModifiersExts.DisplayString(Modifiers.Meta), Modifiers.Meta },
|
||||
{ ModifiersExts.DisplayString(Modifiers.Shift), Modifiers.Shift },
|
||||
{ ModifiersExts.DisplayString(Modifiers.None), Modifiers.None }
|
||||
};
|
||||
|
||||
ScrollItemWidget SetupItem(string o, ScrollItemWidget itemTemplate)
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => gameSettings.ZoomModifier == options[o],
|
||||
() => gameSettings.ZoomModifier = options[o]);
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => o;
|
||||
return item;
|
||||
}
|
||||
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options.Keys, SetupItem);
|
||||
}
|
||||
|
||||
static void MakeMouseFocusSettingsLive(GameSettings gameSettings)
|
||||
{
|
||||
if (gameSettings.LockMouseWindow)
|
||||
Game.Renderer.GrabWindowMouseFocus();
|
||||
else
|
||||
Game.Renderer.ReleaseWindowMouseFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
197
OpenRA.Mods.Common/Widgets/Logic/Settings/SettingsLogic.cs
Normal file
197
OpenRA.Mods.Common/Widgets/Logic/Settings/SettingsLogic.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
public interface ISettingsLogic
|
||||
{
|
||||
void RegisterSettingsPanel(string panelID, string label, Func<Widget, Func<bool>> init, Func<Widget, Action> reset);
|
||||
}
|
||||
|
||||
[IncludeChromeLogicArgsFluentReferences(nameof(DynamicFluentReferences))]
|
||||
public class SettingsLogic : ChromeLogic, ISettingsLogic
|
||||
{
|
||||
[FluentReference]
|
||||
const string SettingsSaveTitle = "dialog-settings-save.title";
|
||||
|
||||
[FluentReference]
|
||||
const string SettingsSavePrompt = "dialog-settings-save.prompt";
|
||||
|
||||
[FluentReference]
|
||||
const string SettingsSaveCancel = "dialog-settings-save.cancel";
|
||||
|
||||
[FluentReference]
|
||||
const string RestartTitle = "dialog-settings-restart.title";
|
||||
|
||||
[FluentReference]
|
||||
const string RestartPrompt = "dialog-settings-restart.prompt";
|
||||
|
||||
[FluentReference]
|
||||
const string RestartAccept = "dialog-settings-restart.confirm";
|
||||
|
||||
[FluentReference]
|
||||
const string RestartCancel = "dialog-settings-restart.cancel";
|
||||
|
||||
[FluentReference("panel")]
|
||||
const string ResetTitle = "dialog-settings-reset.title";
|
||||
|
||||
[FluentReference]
|
||||
const string ResetPrompt = "dialog-settings-reset.prompt";
|
||||
|
||||
[FluentReference]
|
||||
const string ResetAccept = "dialog-settings-reset.confirm";
|
||||
|
||||
[FluentReference]
|
||||
const string ResetCancel = "dialog-settings-reset.cancel";
|
||||
|
||||
public static IEnumerable<(string Key, FluentReferenceAttribute Reference)> DynamicFluentReferences(Dictionary<string, MiniYaml> logicArgs)
|
||||
{
|
||||
if (logicArgs.TryGetValue("Panels", out var settingsPanels))
|
||||
foreach (var node in settingsPanels.Nodes)
|
||||
yield return (node.Value.Value, new FluentReferenceAttribute());
|
||||
}
|
||||
|
||||
readonly Dictionary<string, Func<bool>> leavePanelActions = [];
|
||||
readonly Dictionary<string, Action> resetPanelActions = [];
|
||||
|
||||
readonly Widget panelContainer, tabContainer;
|
||||
readonly ButtonWidget tabTemplate;
|
||||
readonly int2 buttonStride;
|
||||
readonly List<ButtonWidget> buttons = [];
|
||||
readonly Dictionary<string, string> panels = [];
|
||||
string activePanel;
|
||||
|
||||
bool needsRestart = false;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public SettingsLogic(Widget widget, Action onExit, WorldRenderer worldRenderer, Dictionary<string, MiniYaml> logicArgs, ModData modData)
|
||||
{
|
||||
panelContainer = widget.Get("PANEL_CONTAINER");
|
||||
var panelTemplate = panelContainer.Get<ContainerWidget>("PANEL_TEMPLATE");
|
||||
panelContainer.RemoveChild(panelTemplate);
|
||||
|
||||
tabContainer = widget.Get("SETTINGS_TAB_CONTAINER");
|
||||
tabTemplate = tabContainer.Get<ButtonWidget>("BUTTON_TEMPLATE");
|
||||
tabContainer.RemoveChild(tabTemplate);
|
||||
|
||||
if (logicArgs.TryGetValue("ButtonStride", out var buttonStrideNode))
|
||||
buttonStride = FieldLoader.GetValue<int2>("ButtonStride", buttonStrideNode.Value);
|
||||
|
||||
if (logicArgs.TryGetValue("Panels", out var settingsPanels))
|
||||
{
|
||||
panels = settingsPanels.ToDictionary(kv => kv.Value);
|
||||
|
||||
foreach (var panel in panels)
|
||||
{
|
||||
var container = panelTemplate.Clone();
|
||||
container.Id = panel.Key;
|
||||
panelContainer.AddChild(container);
|
||||
|
||||
Game.LoadWidget(worldRenderer.World, panel.Key, container, new WidgetArgs()
|
||||
{
|
||||
{ "settingsLogic", this },
|
||||
{ "panelID", panel.Key },
|
||||
{ "label", FluentProvider.GetMessage(panel.Value) }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
widget.Get<ButtonWidget>("BACK_BUTTON").OnClick = () =>
|
||||
{
|
||||
needsRestart |= leavePanelActions[activePanel]();
|
||||
Game.Settings.Save();
|
||||
|
||||
void CloseAndExit() { Ui.CloseWindow(); onExit(); }
|
||||
if (needsRestart)
|
||||
{
|
||||
void NoRestart() => ConfirmationDialogs.ButtonPrompt(modData,
|
||||
title: SettingsSaveTitle,
|
||||
text: SettingsSavePrompt,
|
||||
onCancel: CloseAndExit,
|
||||
cancelText: SettingsSaveCancel);
|
||||
|
||||
if (!Game.ExternalMods.TryGetValue(ExternalMod.MakeKey(Game.ModData.Manifest), out var external))
|
||||
{
|
||||
NoRestart();
|
||||
return;
|
||||
}
|
||||
|
||||
ConfirmationDialogs.ButtonPrompt(modData,
|
||||
title: RestartTitle,
|
||||
text: RestartPrompt,
|
||||
onConfirm: () => Game.SwitchToExternalMod(external, null, NoRestart),
|
||||
confirmText: RestartAccept,
|
||||
onCancel: CloseAndExit,
|
||||
cancelText: RestartCancel);
|
||||
}
|
||||
else
|
||||
CloseAndExit();
|
||||
};
|
||||
|
||||
widget.Get<ButtonWidget>("RESET_BUTTON").OnClick = () =>
|
||||
{
|
||||
void Reset()
|
||||
{
|
||||
resetPanelActions[activePanel]();
|
||||
Game.Settings.Save();
|
||||
}
|
||||
|
||||
ConfirmationDialogs.ButtonPrompt(modData,
|
||||
title: ResetTitle,
|
||||
text: ResetPrompt,
|
||||
titleArguments: ["panel", panels[activePanel]],
|
||||
onConfirm: Reset,
|
||||
confirmText: ResetAccept,
|
||||
onCancel: () => { },
|
||||
cancelText: ResetCancel);
|
||||
};
|
||||
}
|
||||
|
||||
public void RegisterSettingsPanel(string panelID, string label, Func<Widget, Func<bool>> init, Func<Widget, Action> reset)
|
||||
{
|
||||
var panel = panelContainer.Get(panelID);
|
||||
|
||||
activePanel ??= panelID;
|
||||
|
||||
panel.IsVisible = () => activePanel == panelID;
|
||||
|
||||
leavePanelActions.Add(panelID, init(panel));
|
||||
resetPanelActions.Add(panelID, reset(panel));
|
||||
|
||||
var tab = tabTemplate.Clone();
|
||||
var lastButton = buttons.LastOrDefault();
|
||||
if (lastButton != null)
|
||||
{
|
||||
tab.Bounds.X = lastButton.Bounds.X + buttonStride.X;
|
||||
tab.Bounds.Y = lastButton.Bounds.Y + buttonStride.Y;
|
||||
}
|
||||
|
||||
tab.Id = panelID;
|
||||
tab.GetText = () => label;
|
||||
tab.IsHighlighted = () => activePanel == panelID;
|
||||
tab.OnClick = () =>
|
||||
{
|
||||
needsRestart |= leavePanelActions[activePanel]();
|
||||
Game.Settings.Save();
|
||||
activePanel = panelID;
|
||||
};
|
||||
|
||||
tabContainer.AddChild(tab);
|
||||
buttons.Add(tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
77
OpenRA.Mods.Common/Widgets/Logic/Settings/SettingsUtils.cs
Normal file
77
OpenRA.Mods.Common/Widgets/Logic/Settings/SettingsUtils.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version. For more
|
||||
* information, see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
public static class SettingsUtils
|
||||
{
|
||||
public static void BindCheckboxPref(Widget parent, string id, object group, string pref)
|
||||
{
|
||||
var field = group.GetType().GetField(pref);
|
||||
if (field == null)
|
||||
throw new InvalidOperationException($"{group.GetType().Name} does not contain a preference type {pref}");
|
||||
|
||||
var cb = parent.Get<CheckboxWidget>(id);
|
||||
cb.IsChecked = () => (bool)field.GetValue(group);
|
||||
cb.OnClick = () => field.SetValue(group, cb.IsChecked() ^ true);
|
||||
}
|
||||
|
||||
public static void BindSliderPref(Widget parent, string id, object group, string pref)
|
||||
{
|
||||
var field = group.GetType().GetField(pref);
|
||||
if (field == null)
|
||||
throw new InvalidOperationException($"{group.GetType().Name} does not contain a preference type {pref}");
|
||||
|
||||
var ss = parent.Get<SliderWidget>(id);
|
||||
ss.Value = (float)field.GetValue(group);
|
||||
ss.OnChange += x => field.SetValue(group, x);
|
||||
}
|
||||
|
||||
public static void BindIntSliderPref(Widget parent, string id, object group, string pref)
|
||||
{
|
||||
var field = group.GetType().GetField(pref);
|
||||
if (field == null)
|
||||
throw new InvalidOperationException($"{group.GetType().Name} does not contain a preference type {pref}");
|
||||
|
||||
var ss = parent.Get<SliderWidget>(id);
|
||||
ss.Value = (int)field.GetValue(group);
|
||||
ss.OnChange += x => field.SetValue(group, (int)x);
|
||||
}
|
||||
|
||||
public static void AdjustSettingsScrollPanelLayout(ScrollPanelWidget scrollPanel)
|
||||
{
|
||||
foreach (var row in scrollPanel.Children)
|
||||
{
|
||||
if (row.Children.Count == 0)
|
||||
continue;
|
||||
|
||||
var hasVisibleChildren = false;
|
||||
|
||||
foreach (var container in row.Children)
|
||||
{
|
||||
if (container.IsVisible())
|
||||
{
|
||||
hasVisibleChildren = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasVisibleChildren)
|
||||
row.Visible = false;
|
||||
}
|
||||
|
||||
scrollPanel.Layout.AdjustChildren();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user