diff --git a/OpenRA.Mods.Cnc/Widgets/Logic/CncSettingsLogic.cs b/OpenRA.Mods.Cnc/Widgets/Logic/CncSettingsLogic.cs index 66dbf85ffe..b1d15b834c 100644 --- a/OpenRA.Mods.Cnc/Widgets/Logic/CncSettingsLogic.cs +++ b/OpenRA.Mods.Cnc/Widgets/Logic/CncSettingsLogic.cs @@ -25,150 +25,348 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic { public class CncSettingsLogic { - enum PanelType { General, Input } + enum PanelType { Display, Audio, Input, Advanced } + Dictionary leavePanelActions = new Dictionary(); + Dictionary resetPanelActions = new Dictionary(); + PanelType settingsPanel = PanelType.Display; + Widget panelContainer, tabContainer; + WorldRenderer worldRenderer; SoundDevice soundDevice; - PanelType settingsPanel = PanelType.General; - ColorPreviewManagerWidget colorPreview; - World world; [ObjectCreator.UseCtor] - public CncSettingsLogic(Widget widget, World world, Action onExit, WorldRenderer worldRenderer) + public CncSettingsLogic(Widget widget, Action onExit, WorldRenderer worldRenderer) { - this.world = world; - var panel = widget.Get("SETTINGS_PANEL"); + this.worldRenderer = worldRenderer; - // General pane - var generalButton = panel.Get("GENERAL_BUTTON"); - generalButton.OnClick = () => settingsPanel = PanelType.General; - generalButton.IsHighlighted = () => settingsPanel == PanelType.General; + panelContainer = widget.Get("SETTINGS_PANEL"); + tabContainer = panelContainer; - var generalPane = panel.Get("GENERAL_CONTROLS"); - generalPane.IsVisible = () => settingsPanel == PanelType.General; + RegisterSettingsPanel(PanelType.Display, InitDisplayPanel, ResetDisplayPanel, "DISPLAY_PANEL", "DISPLAY_TAB"); + RegisterSettingsPanel(PanelType.Audio, InitAudioPanel, ResetAudioPanel, "AUDIO_PANEL", "AUDIO_TAB"); + RegisterSettingsPanel(PanelType.Input, InitInputPanel, ResetInputPanel, "INPUT_PANEL", "INPUT_TAB"); + RegisterSettingsPanel(PanelType.Advanced, InitAdvancedPanel, ResetAdvancedPanel, "ADVANCED_PANEL", "ADVANCED_TAB"); - var gameSettings = Game.Settings.Game; - var playerSettings = Game.Settings.Player; - var debugSettings = Game.Settings.Debug; - var graphicsSettings = Game.Settings.Graphics; - var soundSettings = Game.Settings.Sound; - - // Player profile - var nameTextfield = generalPane.Get("NAME_TEXTFIELD"); - nameTextfield.Text = playerSettings.Name; - - colorPreview = panel.Get("COLOR_MANAGER"); - colorPreview.Color = playerSettings.Color; - - var colorDropdown = generalPane.Get("COLOR"); - colorDropdown.OnMouseDown = _ => ShowColorPicker(colorDropdown, playerSettings); - colorDropdown.Get("COLORBLOCK").GetColor = () => playerSettings.Color.RGB; - - // Debug - var perftextCheckbox = generalPane.Get("PERFTEXT_CHECKBOX"); - perftextCheckbox.IsChecked = () => debugSettings.PerfText; - perftextCheckbox.OnClick = () => debugSettings.PerfText ^= true; - - var perfgraphCheckbox = generalPane.Get("PERFGRAPH_CHECKBOX"); - perfgraphCheckbox.IsChecked = () => debugSettings.PerfGraph; - perfgraphCheckbox.OnClick = () => debugSettings.PerfGraph ^= true; - - var checkunsyncedCheckbox = generalPane.Get("CHECKUNSYNCED_CHECKBOX"); - checkunsyncedCheckbox.IsChecked = () => debugSettings.SanityCheckUnsyncedCode; - checkunsyncedCheckbox.OnClick = () => debugSettings.SanityCheckUnsyncedCode ^= true; - - var showFatalErrorDialog = generalPane.Get("SHOW_FATAL_ERROR_DIALOG_CHECKBOX"); - showFatalErrorDialog.IsChecked = () => Game.Settings.Debug.ShowFatalErrorDialog; - showFatalErrorDialog.OnClick = () => Game.Settings.Debug.ShowFatalErrorDialog ^= true; - - // Video - var windowModeDropdown = generalPane.Get("MODE_DROPDOWN"); - windowModeDropdown.OnMouseDown = _ => SettingsMenuLogic.ShowWindowModeDropdown(windowModeDropdown, graphicsSettings); - windowModeDropdown.GetText = () => graphicsSettings.Mode == WindowMode.Windowed ? - "Windowed" : graphicsSettings.Mode == WindowMode.Fullscreen ? "Fullscreen" : "Pseudo-Fullscreen"; - - var pixelDoubleCheckbox = generalPane.Get("PIXELDOUBLE_CHECKBOX"); - pixelDoubleCheckbox.IsChecked = () => graphicsSettings.PixelDouble; - pixelDoubleCheckbox.OnClick = () => + panelContainer.Get("BACK_BUTTON").OnClick = () => { - graphicsSettings.PixelDouble ^= true; - worldRenderer.Viewport.Zoom = graphicsSettings.PixelDouble ? 2 : 1; - }; - - var showShellmapCheckbox = generalPane.Get("SHOW_SHELLMAP"); - showShellmapCheckbox.IsChecked = () => gameSettings.ShowShellmap; - showShellmapCheckbox.OnClick = () => gameSettings.ShowShellmap ^= true; - - generalPane.Get("WINDOW_RESOLUTION").IsVisible = () => graphicsSettings.Mode == WindowMode.Windowed; - var windowWidth = generalPane.Get("WINDOW_WIDTH"); - windowWidth.Text = graphicsSettings.WindowedSize.X.ToString(); - - var windowHeight = generalPane.Get("WINDOW_HEIGHT"); - windowHeight.Text = graphicsSettings.WindowedSize.Y.ToString(); - - var languageDropDownButton = generalPane.Get("LANGUAGE_DROPDOWNBUTTON"); - languageDropDownButton.OnMouseDown = _ => SettingsMenuLogic.ShowLanguageDropdown(languageDropDownButton); - languageDropDownButton.GetText = () => FieldLoader.Translate(Game.Settings.Graphics.Language); - - // Audio - var soundSlider = generalPane.Get("SOUND_SLIDER"); - soundSlider.OnChange += x => { soundSettings.SoundVolume = x; Sound.SoundVolume = x; }; - soundSlider.Value = soundSettings.SoundVolume; - - var musicSlider = generalPane.Get("MUSIC_SLIDER"); - musicSlider.OnChange += x => { soundSettings.MusicVolume = x; Sound.MusicVolume = x; }; - musicSlider.Value = soundSettings.MusicVolume; - - var shellmapMusicCheckbox = generalPane.Get("SHELLMAP_MUSIC"); - shellmapMusicCheckbox.IsChecked = () => soundSettings.MapMusic; - shellmapMusicCheckbox.OnClick = () => soundSettings.MapMusic ^= true; - - var devices = Sound.AvailableDevices(); - soundDevice = devices.FirstOrDefault(d => d.Engine == soundSettings.Engine && d.Device == soundSettings.Device) ?? devices.First(); - - var audioDeviceDropdown = generalPane.Get("AUDIO_DEVICE"); - audioDeviceDropdown.OnMouseDown = _ => ShowAudioDeviceDropdown(audioDeviceDropdown, soundSettings, devices); - audioDeviceDropdown.GetText = () => soundDevice.Label; - - // Input pane - var inputPane = panel.Get("INPUT_CONTROLS"); - inputPane.IsVisible = () => settingsPanel == PanelType.Input; - - var inputButton = panel.Get("INPUT_BUTTON"); - inputButton.OnClick = () => settingsPanel = PanelType.Input; - inputButton.IsHighlighted = () => settingsPanel == PanelType.Input; - - var classicMouseCheckbox = inputPane.Get("CLASSICORDERS_CHECKBOX"); - classicMouseCheckbox.IsChecked = () => gameSettings.UseClassicMouseStyle; - classicMouseCheckbox.OnClick = () => gameSettings.UseClassicMouseStyle ^= true; - - var scrollSlider = inputPane.Get("SCROLLSPEED_SLIDER"); - scrollSlider.Value = gameSettings.ViewportEdgeScrollStep; - scrollSlider.OnChange += x => gameSettings.ViewportEdgeScrollStep = x; - - var edgescrollCheckbox = inputPane.Get("EDGESCROLL_CHECKBOX"); - edgescrollCheckbox.IsChecked = () => gameSettings.ViewportEdgeScroll; - edgescrollCheckbox.OnClick = () => gameSettings.ViewportEdgeScroll ^= true; - - var mouseScrollDropdown = inputPane.Get("MOUSE_SCROLL"); - mouseScrollDropdown.OnMouseDown = _ => ShowMouseScrollDropdown(mouseScrollDropdown, gameSettings); - mouseScrollDropdown.GetText = () => gameSettings.MouseScroll.ToString(); - - panel.Get("BACK_BUTTON").OnClick = () => - { - playerSettings.Name = nameTextfield.Text; - int x, y; - int.TryParse(windowWidth.Text, out x); - int.TryParse(windowHeight.Text, out y); - graphicsSettings.WindowedSize = new int2(x, y); - soundSettings.Device = soundDevice.Device; - soundSettings.Engine = soundDevice.Engine; + leavePanelActions[settingsPanel](); Game.Settings.Save(); Ui.CloseWindow(); onExit(); }; + + panelContainer.Get("RESET_BUTTON").OnClick = () => + { + resetPanelActions[settingsPanel](); + Game.Settings.Save(); + }; } - static bool ShowMouseScrollDropdown(DropDownButtonWidget dropdown, GameSettings s) + static void BindCheckboxPref(Widget parent, string id, object group, string pref) + { + var field = group.GetType().GetField(pref); + if (field == null) + throw new InvalidOperationException("{0} does not contain a preference type {1}".F(group.GetType().Name, pref)); + + var cb = parent.Get(id); + cb.IsChecked = () => (bool)field.GetValue(group); + cb.OnClick = () => field.SetValue(group, cb.IsChecked() ^ true); + } + + static void BindSliderPref(Widget parent, string id, object group, string pref) + { + var field = group.GetType().GetField(pref); + if (field == null) + throw new InvalidOperationException("{0} does not contain a preference type {1}".F(group.GetType().Name, pref)); + + var ss = parent.Get(id); + ss.Value = (float)field.GetValue(group); + ss.OnChange += x => field.SetValue(group, x); + } + + static void BindHotkeyPref(KeyValuePair kv, KeySettings ks, Widget template, Widget parent) + { + var key = template.Clone() as Widget; + key.Id = kv.Key; + key.IsVisible = () => true; + + var field = ks.GetType().GetField(kv.Key); + if (field == null) + throw new InvalidOperationException("Game.Settings.Keys does not contain {1}".F(kv.Key)); + + key.Get("FUNCTION").GetText = () => kv.Value + ":"; + + var textBox = key.Get("HOTKEY"); + textBox.Key = (Hotkey)field.GetValue(ks); + textBox.OnLoseFocus = () => field.SetValue(ks, textBox.Key); + parent.AddChild(key); + } + + void RegisterSettingsPanel(PanelType type, Func init, Func reset, string panelID, string buttonID) + { + var panel = panelContainer.Get(panelID); + var tab = tabContainer.Get(buttonID); + + panel.IsVisible = () => settingsPanel == type; + tab.IsHighlighted = () => settingsPanel == type; + tab.OnClick = () => { leavePanelActions[settingsPanel](); Game.Settings.Save(); settingsPanel = type; }; + + leavePanelActions.Add(type, init(panel)); + resetPanelActions.Add(type, reset(panel)); + } + + Action InitDisplayPanel(Widget panel) + { + var ds = Game.Settings.Graphics; + var gs = Game.Settings.Game; + + BindCheckboxPref(panel, "PIXELDOUBLE_CHECKBOX", ds, "PixelDouble"); + BindCheckboxPref(panel, "FRAME_LIMIT_CHECKBOX", ds, "CapFramerate"); + BindCheckboxPref(panel, "SHOW_SHELLMAP", gs, "ShowShellmap"); + + var languageDropDownButton = panel.Get("LANGUAGE_DROPDOWNBUTTON"); + languageDropDownButton.OnMouseDown = _ => SettingsMenuLogic.ShowLanguageDropdown(languageDropDownButton); + languageDropDownButton.GetText = () => FieldLoader.Translate(ds.Language); + + var windowModeDropdown = panel.Get("MODE_DROPDOWN"); + windowModeDropdown.OnMouseDown = _ => SettingsMenuLogic.ShowWindowModeDropdown(windowModeDropdown, ds); + windowModeDropdown.GetText = () => ds.Mode == WindowMode.Windowed ? + "Windowed" : ds.Mode == WindowMode.Fullscreen ? "Fullscreen" : "Pseudo-Fullscreen"; + + // Update zoom immediately + var pixelDoubleCheckbox = panel.Get("PIXELDOUBLE_CHECKBOX"); + var oldOnClick = pixelDoubleCheckbox.OnClick; + pixelDoubleCheckbox.OnClick = () => + { + oldOnClick(); + worldRenderer.Viewport.Zoom = ds.PixelDouble ? 2 : 1; + }; + + panel.Get("WINDOW_RESOLUTION").IsVisible = () => ds.Mode == WindowMode.Windowed; + var windowWidth = panel.Get("WINDOW_WIDTH"); + windowWidth.Text = ds.WindowedSize.X.ToString(); + + var windowHeight = panel.Get("WINDOW_HEIGHT"); + windowHeight.Text = ds.WindowedSize.Y.ToString(); + + var frameLimitTextfield = panel.Get("FRAME_LIMIT_TEXTFIELD"); + frameLimitTextfield.Text = ds.MaxFramerate.ToString(); + frameLimitTextfield.IsDisabled = () => !ds.CapFramerate; + + return () => + { + int x, y; + int.TryParse(windowWidth.Text, out x); + int.TryParse(windowHeight.Text, out y); + ds.WindowedSize = new int2(x, y); + int.TryParse(frameLimitTextfield.Text, out ds.MaxFramerate); + }; + } + + Action ResetDisplayPanel(Widget panel) + { + var ds = Game.Settings.Graphics; + var gs = Game.Settings.Game; + var dds = new GraphicSettings(); + var dgs = new GameSettings(); + return () => + { + gs.ShowShellmap = dgs.ShowShellmap; + + ds.CapFramerate = dds.CapFramerate; + ds.MaxFramerate = dds.MaxFramerate; + ds.Language = dds.Language; + ds.Mode = dds.Mode; + ds.WindowedSize = dds.WindowedSize; + + ds.PixelDouble = dds.PixelDouble; + worldRenderer.Viewport.Zoom = ds.PixelDouble ? 2 : 1; + }; + } + + Action InitAudioPanel(Widget panel) + { + var ss = Game.Settings.Sound; + + BindCheckboxPref(panel, "SHELLMAP_MUSIC", ss, "MapMusic"); + BindCheckboxPref(panel, "CASH_TICKS", ss, "CashTicks"); + + BindSliderPref(panel, "SOUND_VOLUME", ss, "SoundVolume"); + BindSliderPref(panel, "MUSIC_VOLUME", ss, "MusicVolume"); + BindSliderPref(panel, "VIDEO_VOLUME", ss, "VideoVolume"); + + // Update volume immediately + panel.Get("SOUND_VOLUME").OnChange += x => Sound.SoundVolume = x; + panel.Get("MUSIC_VOLUME").OnChange += x => Sound.MusicVolume = x; + panel.Get("VIDEO_VOLUME").OnChange += x => Sound.VideoVolume = x; + + var devices = Sound.AvailableDevices(); + soundDevice = devices.FirstOrDefault(d => d.Engine == ss.Engine && d.Device == ss.Device) ?? devices.First(); + + var audioDeviceDropdown = panel.Get("AUDIO_DEVICE"); + audioDeviceDropdown.OnMouseDown = _ => ShowAudioDeviceDropdown(audioDeviceDropdown, ss, devices); + audioDeviceDropdown.GetText = () => soundDevice.Label; + + return () => + { + ss.Device = soundDevice.Device; + ss.Engine = soundDevice.Engine; + }; + } + + Action ResetAudioPanel(Widget panel) + { + var ss = Game.Settings.Sound; + var dss = new SoundSettings(); + return () => + { + ss.MapMusic = dss.MapMusic; + ss.SoundVolume = dss.SoundVolume; + ss.MusicVolume = dss.MusicVolume; + ss.VideoVolume = dss.VideoVolume; + ss.CashTicks = dss.CashTicks; + ss.Device = dss.Device; + ss.Engine = dss.Engine; + + panel.Get("SOUND_VOLUME").Value = ss.SoundVolume; + panel.Get("MUSIC_VOLUME").Value = ss.MusicVolume; + panel.Get("VIDEO_VOLUME").Value = ss.VideoVolume; + soundDevice = Sound.AvailableDevices().First(); + }; + } + + Action InitInputPanel(Widget panel) + { + // TODO: Extract these to a yaml file + var specialHotkeys = new Dictionary() + { + { "PauseKey", "Pause / Unpause" }, + { "CycleBaseKey", "Jump to base" }, + { "ToLastEventKey", "Jump to last radar event" }, + { "ToSelectionKey", "Jump to selection" }, + { "SellKey", "Sell mode" }, + { "PowerDownKey", "Power-down mode" }, + { "RepairKey", "Repair mode" }, + { "CycleTabsKey", "Cycle production tabs" } + }; + + var unitHotkeys = new Dictionary() + { + { "AttackMoveKey", "Attack Move" }, + { "StopKey", "Stop" }, + { "ScatterKey", "Scatter" }, + { "StanceCycleKey", "Cycle Stance" }, + { "DeployKey", "Deploy" }, + { "GuardKey", "Guard" } + }; + + var gs = Game.Settings.Game; + var ks = Game.Settings.Keys; + + BindCheckboxPref(panel, "CLASSICORDERS_CHECKBOX", gs, "UseClassicMouseStyle"); + BindCheckboxPref(panel, "EDGESCROLL_CHECKBOX", gs, "ViewportEdgeScroll"); + BindSliderPref(panel, "SCROLLSPEED_SLIDER", gs, "ViewportEdgeScrollStep"); + + var mouseScrollDropdown = panel.Get("MOUSE_SCROLL"); + mouseScrollDropdown.OnMouseDown = _ => ShowMouseScrollDropdown(mouseScrollDropdown, gs); + mouseScrollDropdown.GetText = () => gs.MouseScroll.ToString(); + + var hotkeyList = panel.Get("HOTKEY_LIST"); + hotkeyList.Layout = new GridLayout(hotkeyList); + var hotkeyHeader = hotkeyList.Get("HEADER"); + var globalTemplate = hotkeyList.Get("GLOBAL_TEMPLATE"); + var unitTemplate = hotkeyList.Get("UNIT_TEMPLATE"); + hotkeyList.RemoveChildren(); + + var globalHeader = ScrollItemWidget.Setup(hotkeyHeader, () => true, () => {}); + globalHeader.Get("LABEL").GetText = () => "Global Commands"; + hotkeyList.AddChild(globalHeader); + + foreach (var kv in specialHotkeys) + BindHotkeyPref(kv, ks, globalTemplate, hotkeyList); + + var unitHeader = ScrollItemWidget.Setup(hotkeyHeader, () => true, () => {}); + unitHeader.Get("LABEL").GetText = () => "Unit Commands"; + hotkeyList.AddChild(unitHeader); + + foreach (var kv in unitHotkeys) + BindHotkeyPref(kv, ks, unitTemplate, hotkeyList); + + return () => + { + // Remove focus from the selected hotkey widget + // This is a bit of a hack, but works + if (Ui.KeyboardFocusWidget != null && panel.GetOrNull(Ui.KeyboardFocusWidget.Id) != null) + { + Ui.KeyboardFocusWidget.YieldKeyboardFocus(); + Ui.KeyboardFocusWidget = null; + } + }; + } + + Action ResetInputPanel(Widget panel) + { + var gs = Game.Settings.Game; + var ks = Game.Settings.Keys; + var dgs = new GameSettings(); + var dks = new KeySettings(); + + return () => + { + gs.UseClassicMouseStyle = dgs.UseClassicMouseStyle; + gs.MouseScroll = dgs.MouseScroll; + gs.ViewportEdgeScroll = dgs.ViewportEdgeScroll; + gs.ViewportEdgeScrollStep = dgs.ViewportEdgeScrollStep; + + foreach (var f in ks.GetType().GetFields()) + { + var value = (Hotkey)f.GetValue(dks); + f.SetValue(ks, value); + panel.Get(f.Name).Get("HOTKEY").Key = value; + } + + panel.Get("SCROLLSPEED_SLIDER").Value = gs.ViewportEdgeScrollStep; + }; + } + + Action InitAdvancedPanel(Widget panel) + { + var ds = Game.Settings.Debug; + var ss = Game.Settings.Server; + + BindCheckboxPref(panel, "NAT_DISCOVERY", ss, "DiscoverNatDevices"); + BindCheckboxPref(panel, "VERBOSE_NAT_CHECKBOX", ss, "VerboseNatDiscovery"); + BindCheckboxPref(panel, "PERFTEXT_CHECKBOX", ds, "PerfText"); + BindCheckboxPref(panel, "PERFGRAPH_CHECKBOX", ds, "PerfGraph"); + BindCheckboxPref(panel, "CHECKUNSYNCED_CHECKBOX", ds, "SanityCheckUnsyncedCode"); + BindCheckboxPref(panel, "BOTDEBUG_CHECKBOX", ds, "BotDebug"); + BindCheckboxPref(panel, "DEVELOPER_MENU_CHECKBOX", ds, "DeveloperMenu"); + BindCheckboxPref(panel, "CRASH_DIALOG_CHECKBOX", ds, "ShowFatalErrorDialog"); + + return () => { }; + } + + Action ResetAdvancedPanel(Widget panel) + { + var ds = Game.Settings.Debug; + var ss = Game.Settings.Server; + var dds = new DebugSettings(); + var dss = new ServerSettings(); + + return () => + { + ss.DiscoverNatDevices = dss.DiscoverNatDevices; + ss.VerboseNatDiscovery = dss.VerboseNatDiscovery; + ds.PerfText = dds.PerfText; + ds.PerfGraph = dds.PerfGraph; + ds.SanityCheckUnsyncedCode = dds.SanityCheckUnsyncedCode; + ds.BotDebug = dds.BotDebug; + ds.DeveloperMenu = dds.DeveloperMenu; + ds.ShowFatalErrorDialog = dds.ShowFatalErrorDialog; + }; + } + + bool ShowMouseScrollDropdown(DropDownButtonWidget dropdown, GameSettings s) { var options = new Dictionary() { @@ -190,26 +388,6 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic return true; } - bool ShowColorPicker(DropDownButtonWidget color, PlayerSettings s) - { - Action onChange = c => colorPreview.Color = c; - Action onExit = () => - { - s.Color = colorPreview.Color; - color.RemovePanel(); - }; - - var colorChooser = Game.LoadWidget(world, "COLOR_CHOOSER", null, new WidgetArgs() - { - { "onExit", onExit }, - { "onChange", onChange }, - { "initialColor", s.Color } - }); - - color.AttachPanel(colorChooser, onExit); - return true; - } - bool ShowAudioDeviceDropdown(DropDownButtonWidget dropdown, SoundSettings s, SoundDevice[] devices) { var i = 0; diff --git a/mods/cnc/chrome/settings.yaml b/mods/cnc/chrome/settings.yaml index 7b3b7097d6..6a9bf9a893 100644 --- a/mods/cnc/chrome/settings.yaml +++ b/mods/cnc/chrome/settings.yaml @@ -1,313 +1,441 @@ Container@SETTINGS_PANEL: Logic:CncSettingsLogic X:(WINDOW_RIGHT - WIDTH)/2 - Y:(WINDOW_BOTTOM - 250)/2 - Width:740 - Height:565 + Y:(WINDOW_BOTTOM - HEIGHT)/2 + Width:590 + Height:260+68 Children: - ColorPreviewManager@COLOR_MANAGER: Label@TITLE: - Width:740 + Width:590 Y:0-25 Font:BigBold Contrast:true Align:Center Text:Settings - Background@GENERAL_CONTROLS: - Width:740 - Height:320 - Background:panel-black - Children: - Label@TITLE: - X:15 - Y:20 - Font:Bold - Text:Player Profile - Align:Center - Width:340 - Label@NAME_LABEL: - X:15 - Y:39 - Width:45 - Height:25 - Align:Right - Text:Name: - TextField@NAME_TEXTFIELD: - X:65 - Y:40 - Width:205 - Height:25 - MaxLength:16 - DropDownButton@COLOR: - X:275 - Y:40 - Width:80 - Height:25 - IgnoreChildMouseOver: true - Children: - ColorBlock@COLORBLOCK: - X:5 - Y:6 - Width:PARENT_RIGHT-35 - Height:PARENT_BOTTOM-12 - Checkbox@SHOW_SHELLMAP: - X:15 - Y:80 - Width:200 - Height:20 - Font:Regular - Text:Show Shellmap - Checkbox@SHELLMAP_MUSIC: - X:15 - Y:110 - Width:200 - Height:20 - Font:Regular - Text:Shellmap Music - Label@DEBUG_TITLE: - X:15 - Y:180 - Width:340 - Font:Bold - Text:Debug - Align:Center - Checkbox@PERFTEXT_CHECKBOX: - X:15 - Y:200 - Width:300 - Height:20 - Font:Regular - Text:Show Performance Text - Checkbox@PERFGRAPH_CHECKBOX: - X:15 - Y:230 - Width:300 - Height:20 - Font:Regular - Text:Show Performance Graph - Checkbox@CHECKUNSYNCED_CHECKBOX: - X:15 - Y:260 - Width:300 - Height:20 - Font:Regular - Text:Check Sync around Unsynced Code - Checkbox@SHOW_FATAL_ERROR_DIALOG_CHECKBOX: - X:15 - Y:290 - Width:300 - Height:20 - Font:Regular - Text:Show Fatal Error dialog - Label@VIDEO_TITLE: - Y:20 - X:375 - Font:Bold - Text:Graphics - Align:Center - Width:340 - Label@MODE_LABEL: - X:375 - Y:39 - Width:45 - Height:25 - Align:Right - Text:Mode: - DropDownButton@MODE_DROPDOWN: - X:425 - Y:40 - Width:170 - Height:25 - Font:Regular - Text:Windowed - Container@WINDOW_RESOLUTION: - X:595 - Y:40 - Children: - Label@At: - Text:@ - Font:Bold - Y:0-1 - Height:25 - Width:25 - Align:Center - TextField@WINDOW_WIDTH: - X:25 - Width:45 - Height:25 - MaxLength:5 - Label@X: - Text:x - Font:Bold - X:70 - Y:0-1 - Height:25 - Width:15 - Align:Center - TextField@WINDOW_HEIGHT: - X:85 - Width:45 - Height:25 - MaxLength:5 - Label@LANGUAGE_LABEL: - X:375 - Y:70 - Width:75 - Height:25 - Align:Right - Text:Language: - DropDownButton@LANGUAGE_DROPDOWNBUTTON: - X:455 - Y:70 - Width:140 - Height:25 - Label@VIDEO_DESC: - X:375 - Y:100 - Width:340 - Height:25 - Font:Tiny - Align:Center - Text:Mode/Resolution/Language changes will be applied after the game is restarted - Checkbox@PIXELDOUBLE_CHECKBOX: - X:375 - Y:140 - Width:200 - Height:20 - Font:Regular - Text:Enable Pixel Doubling - Label@AUDIO_TITLE: - X:375 - Y:180 - Width:340 - Font:Bold - Text:Sound - Align:Center - Label@SOUND_LABEL: - X:375 - Y:194 - Width:95 - Height:25 - Align:Right - Text:Sound Volume: - Slider@SOUND_SLIDER: - X:475 - Y:200 - Width:240 - Height:20 - Ticks:5 - Label@MUSIC_LABEL: - X:375 - Y:224 - Width:95 - Height:25 - Align:Right - Text:Music Volume: - Slider@MUSIC_SLIDER: - X:475 - Y:230 - Width:240 - Height:20 - Ticks:5 - Label@AUDIO_DEVICE_LABEL: - X:375 - Y:259 - Width:75 - Height:20 - Text:Audio Device: - DropDownButton@AUDIO_DEVICE: - X:475 - Y:260 - Width:240 - Height:25 - Font:Regular - Text:Default Device - Label@AUDIO_DESC: - X:375 - Y:288 - Width:340 - Height:25 - Font:Tiny - Align:Center - Text:Device changes will be applied after the game is restarted - Background@INPUT_CONTROLS: - Width:740 - Height:290 - Background:panel-black - Visible:false - Children: - Label@MOUSE_TITLE: - Font:Bold - Text:Mouse Input - Align:Center - X:15 - Y:20 - Width:340 - Checkbox@CLASSICORDERS_CHECKBOX: - X:15 - Y:35 - Width:250 - Height:20 - Font:Regular - Text:Left-Click Orders - Label@SCROLL_TITLE: - Font:Bold - Text:Scroll Behavior - Align:Center - X:20 - Y:100 - Width:335 - Label@SCROLL_SPEED_LABEL: - X:10 - Y:115 - Width:95 - Height:25 - Text:Scroll Speed: - Slider@SCROLLSPEED_SLIDER: - X:100 - Y:120 - Width:240 - Height:20 - Ticks:5 - MinimumValue: 10 - MaximumValue: 50 - Checkbox@EDGESCROLL_CHECKBOX: - X:15 - Y:150 - Width:130 - Height:20 - Font:Regular - Text:Edge Scrolling - Label@MOUSE_SCROLL_LABEL: - X:15 - Y:180 - Width:160 - Height:20 - Font:Regular - Text:Middle-Mouse Scrolling: - Align:Right - DropDownButton@MOUSE_SCROLL: - X:180 - Y:180 - Width:100 - Height:25 - Font:Regular - Text:Enabled - Button@GENERAL_BUTTON: - Y:319 + Button@DISPLAY_TAB: Width:140 Height:35 - Text:General - Button@INPUT_BUTTON: + Text:Display + Button@AUDIO_TAB: X:150 - Y:319 + Width:140 + Height:35 + Text:Audio + Button@INPUT_TAB: + X:300 Width:140 Height:35 Text:Input + Button@ADVANCED_TAB: + X:450 + Width:140 + Height:35 + Text:Advanced + Button@RESET_BUTTON: + Y:293 + Width:140 + Height:35 + Text:Reset Button@BACK_BUTTON: Key:escape - X:600 - Y:319 + X:PARENT_RIGHT-WIDTH + Y:293 Width:140 Height:35 Text:Back + Background@bg: + Y:34 + Width:590 + Height:260 + Background:panel-black + Children: + Container@DISPLAY_PANEL: + Width:PARENT_RIGHT + Height:PARENT_BOTTOM + Children: + Label@VIDEO_TITLE: + Y:20 + Width:PARENT_RIGHT + Font:Bold + Text:Graphics + Align:Center + Label@MODE_LABEL: + X:120 + Y:39 + Width:45 + Height:25 + Align:Right + Text:Mode: + DropDownButton@MODE_DROPDOWN: + X:170 + Y:40 + Width:170 + Height:25 + Font:Regular + Text:Windowed + Container@WINDOW_RESOLUTION: + X:340 + Y:40 + Children: + Label@At: + Text:@ + Font:Bold + Y:0-1 + Height:25 + Width:25 + Align:Center + TextField@WINDOW_WIDTH: + X:25 + Width:45 + Height:25 + MaxLength:5 + Label@X: + Text:x + Font:Bold + X:70 + Y:0-1 + Height:25 + Width:15 + Align:Center + TextField@WINDOW_HEIGHT: + X:85 + Width:45 + Height:25 + MaxLength:5 + Label@VIDEO_DESC: + Y:60 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Text:Mode/Resolution changes will be applied after the game is restarted + Checkbox@FRAME_LIMIT_CHECKBOX: + X:15 + Y:100 + Width:200 + Height:20 + Font:Regular + Text:Enable Frame Limiter + Checkbox@PIXELDOUBLE_CHECKBOX: + X:310 + Y:105 + Width:200 + Height:20 + Font:Regular + Text:Enable Pixel Doubling + Label@FRAME_LIMIT_DESC_A: + X:45 + Y:132 + Width:50 + Height:25 + Text:Limit to + Align:Right + TextField@FRAME_LIMIT_TEXTFIELD: + X:100 + Y:133 + Width:45 + Height:25 + MaxLength:3 + Label@FRAME_LIMIT_DESC_B: + X:150 + Y:132 + Height:25 + Text: FPS + Checkbox@SHOW_SHELLMAP: + X:310 + Y:135 + Width:200 + Height:20 + Font:Regular + Text:Show Shellmap + Label@VIDEO_TITLE: + Y:175 + Width:PARENT_RIGHT + Font:Bold + Text:Localization + Align:Center + Label@LANGUAGE_LABEL: + X:230 - WIDTH - 5 + Y:194 + Width:75 + Height:25 + Align:Right + Text:Language: + DropDownButton@LANGUAGE_DROPDOWNBUTTON: + X:230 + Y:195 + Width:200 + Height:25 + Label@VIDEO_DESC_A: + Y:215 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Text:Language changes will be applied after the game is restarted + Label@VIDEO_DESC_B: + Y:230 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Text:Translations apply to text strings only; Speech and build icons will remain in English + Container@AUDIO_PANEL: + Width:PARENT_RIGHT + Height:PARENT_BOTTOM + Children: + Label@AUDIO_TITLE: + Y:20 + Width:PARENT_RIGHT + Font:Bold + Text:Audio + Align:Center + Checkbox@SHELLMAP_MUSIC: + X:15 + Y:40 + Width:200 + Height:20 + Font:Regular + Text:Shellmap / Mission Music + Label@SOUND_LABEL: + X:PARENT_RIGHT - WIDTH - 270 + Y:37 + Width:95 + Height:25 + Align:Right + Text:Sound Volume: + Slider@SOUND_VOLUME: + X:PARENT_RIGHT - WIDTH - 15 + Y:43 + Width:250 + Height:20 + Ticks:5 + Checkbox@CASH_TICKS: + X:15 + Y:70 + Width:200 + Height:20 + Font:Regular + Text:Cash Ticks + Label@MUSIC_LABEL: + X:PARENT_RIGHT - WIDTH - 270 + Y:67 + Width:95 + Height:25 + Align:Right + Text:Music Volume: + Slider@VIDEO_VOLUME: + X:PARENT_RIGHT - WIDTH - 15 + Y:73 + Width:250 + Height:20 + Ticks:5 + Label@VIDEO_LABEL: + X:PARENT_RIGHT - WIDTH - 270 + Y:97 + Width:95 + Height:25 + Align:Right + Text:Video Volume: + Slider@MUSIC_VOLUME: + X:PARENT_RIGHT - WIDTH - 15 + Y:103 + Width:250 + Height:20 + Ticks:5 + Label@AUDIO_DEVICE_LABEL: + X:190 - WIDTH - 5 + Y:194 + Width:75 + Height:25 + Align:Right + Text:Audio Device: + DropDownButton@AUDIO_DEVICE: + X:190 + Y:195 + Width:300 + Height:25 + Label@AUDIO_DEVICE_DESC: + Y:215 + Width:PARENT_RIGHT + Height:25 + Font:Tiny + Align:Center + Text:Device changes will be applied after the game is restarted + Container@INPUT_PANEL: + Width:PARENT_RIGHT + Height:PARENT_BOTTOM + Children: + Label@INPUT_TITLE: + Y:20 + Width:PARENT_RIGHT + Font:Bold + Text:Input + Align:Center + Checkbox@CLASSICORDERS_CHECKBOX: + X:15 + Y:40 + Width:250 + Height:20 + Font:Regular + Text:Left-Click Orders + Label@MOUSE_SCROLL_LABEL: + X:PARENT_RIGHT - WIDTH - 120 + Y:39 + Width:160 + Height:20 + Font:Regular + Text:Middle-Mouse Scrolling: + Align:Right + DropDownButton@MOUSE_SCROLL: + X:PARENT_RIGHT - WIDTH - 15 + Y:38 + Width:100 + Height:25 + Font:Regular + Text:Enabled + Checkbox@EDGESCROLL_CHECKBOX: + X:15 + Y:70 + Width:130 + Height:20 + Font:Regular + Text:Edge Scrolling + Label@SCROLL_SPEED_LABEL: + X:PARENT_RIGHT - WIDTH - 270 + Y:67 + Width:95 + Height:25 + Text:Scroll Speed: + Align:Right + Slider@SCROLLSPEED_SLIDER: + X:PARENT_RIGHT - WIDTH - 15 + Y:73 + Width:250 + Height:20 + Ticks:5 + MinimumValue: 10 + MaximumValue: 50 + Label@HOTKEY_TITLE: + Y:115 + Width:PARENT_RIGHT + Font:Bold + Text:Hotkeys + Align:Center + ScrollPanel@HOTKEY_LIST: + X:15 + Y:135 + Width:560 + ItemSpacing:4 + Height:110 + Children: + ScrollItem@HEADER: + Width:528 + Height:13 + Visible:false + Children: + Label@LABEL: + Font:TinyBold + Width:PARENT_RIGHT + Height:10 + Align:Center + Container@GLOBAL_TEMPLATE: + Width:262 + Height:25 + Visible:false + Children: + Label@FUNCTION: + Y:0-1 + Width:PARENT_RIGHT - 85 + Height:25 + Align:Right + HotkeyEntry@HOTKEY: + X:PARENT_RIGHT-WIDTH + Width:80 + Height:25 + Container@UNIT_TEMPLATE: + Width:173 + Height:25 + Visible:false + Children: + Label@FUNCTION: + Y:0-1 + Width:PARENT_RIGHT - 84 + Height:25 + Align:Right + HotkeyEntry@HOTKEY: + X:PARENT_RIGHT-WIDTH+1 + Width:80 + Height:25 + Container@ADVANCED_PANEL: + Width:PARENT_RIGHT + Height:PARENT_BOTTOM + Children: + Label@HOTKEY_TITLE: + Y:20 + Width:PARENT_RIGHT + Font:Bold + Text:Advanced + Align:Center + Checkbox@NAT_DISCOVERY: + X:15 + Y:40 + Width:200 + Height:20 + Font:Regular + Text: Enable Network Discovery (UPnP) + Checkbox@CRASH_DIALOG_CHECKBOX: + X:310 + Y:40 + Width:300 + Height:20 + Font:Regular + Text:Show Fatal Error dialog + Checkbox@PERFTEXT_CHECKBOX: + X:15 + Y:70 + Width:300 + Height:20 + Font:Regular + Text:Show Performance Text + Checkbox@PERFGRAPH_CHECKBOX: + X:310 + Y:70 + Width:300 + Height:20 + Font:Regular + Text:Show Performance Graph + Checkbox@DEVELOPER_MENU_CHECKBOX: + X:15 + Y:100 + Width:300 + Height:20 + Font:Regular + Text:Enable Asset Browser (requires restart) + Label@HOTKEY_TITLE: + Y:140 + Width:PARENT_RIGHT + Font:Bold + Text:Debug + Align:Center + Checkbox@BOTDEBUG_CHECKBOX: + X:15 + Y:160 + Width:300 + Height:20 + Font:Regular + Text:Show Bot Debug Messages + Checkbox@VERBOSE_NAT_CHECKBOX: + X:310 + Y:160 + Width:300 + Height:20 + Font:Regular + Text:Detailed NAT logging + Checkbox@CHECKUNSYNCED_CHECKBOX: + X:15 + Y:190 + Width:300 + Height:20 + Font:Regular + Text:Check Sync around Unsynced Code