diff --git a/OpenRA.Game/HotkeyManager.cs b/OpenRA.Game/HotkeyManager.cs index aff7c8516b..432b32b721 100644 --- a/OpenRA.Game/HotkeyManager.cs +++ b/OpenRA.Game/HotkeyManager.cs @@ -67,6 +67,20 @@ namespace OpenRA settings.Remove(name); } + public HotkeyDefinition GetFirstDuplicate(string name, Hotkey value, HotkeyDefinition definition) + { + foreach (var kv in keys) + { + if (kv.Key == name) + continue; + + if (kv.Value == value && definitions[kv.Key].Types.Overlaps(definition.Types)) + return definitions[kv.Key]; + } + + return null; + } + public HotkeyReference this[string name] { get diff --git a/OpenRA.Mods.Common/Widgets/HotkeyEntryWidget.cs b/OpenRA.Mods.Common/Widgets/HotkeyEntryWidget.cs index e35ee9922e..1174f3e8c7 100644 --- a/OpenRA.Mods.Common/Widgets/HotkeyEntryWidget.cs +++ b/OpenRA.Mods.Common/Widgets/HotkeyEntryWidget.cs @@ -24,12 +24,17 @@ namespace OpenRA.Mods.Common.Widgets public int LeftMargin = 5; public int RightMargin = 5; + public Action OnTakeFocus = () => { }; public Action OnLoseFocus = () => { }; + public Action OnEscape = () => { }; + public Action OnReturn = () => { }; public Func IsDisabled = () => false; + public Func IsValid = () => false; public string Font = ChromeMetrics.Get("HotkeyFont"); public Color TextColor = ChromeMetrics.Get("HotkeyColor"); public Color TextColorDisabled = ChromeMetrics.Get("HotkeyColorDisabled"); + public Color TextColorInvalid = ChromeMetrics.Get("HotkeyColorInvalid"); public HotkeyEntryWidget() { } protected HotkeyEntryWidget(HotkeyEntryWidget widget) @@ -38,12 +43,22 @@ namespace OpenRA.Mods.Common.Widgets Font = widget.Font; TextColor = widget.TextColor; TextColorDisabled = widget.TextColorDisabled; + TextColorInvalid = widget.TextColorInvalid; VisualHeight = widget.VisualHeight; } + public override bool TakeKeyboardFocus() + { + OnTakeFocus(); + return base.TakeKeyboardFocus(); + } + public override bool YieldKeyboardFocus() { OnLoseFocus(); + if (!IsValid()) + return false; + return base.YieldKeyboardFocus(); } @@ -80,7 +95,14 @@ namespace OpenRA.Mods.Common.Widgets if (!HasKeyboardFocus || IgnoreKeys.Contains(e.Key)) return false; - Key = Hotkey.FromKeyInput(e); + if (e.Key != Keycode.ESCAPE && e.Key != Keycode.RETURN) + Key = Hotkey.FromKeyInput(e); + + if (e.Key == Keycode.ESCAPE) + OnEscape(); + + if (e.Key == Keycode.RETURN) + OnReturn(); YieldKeyboardFocus(); @@ -109,6 +131,7 @@ namespace OpenRA.Mods.Common.Widgets var textSize = font.Measure(apparentText); var disabled = IsDisabled(); + var valid = IsValid(); var state = disabled ? "textfield-disabled" : HasKeyboardFocus ? "textfield-focused" : Ui.MouseOverWidget == this ? "textfield-hover" : @@ -131,7 +154,7 @@ namespace OpenRA.Mods.Common.Widgets Bounds.Width - LeftMargin - RightMargin, Bounds.Bottom)); } - var color = disabled ? TextColorDisabled : TextColor; + var color = disabled ? TextColorDisabled : !valid ? TextColorInvalid : TextColor; font.DrawText(apparentText, textPos, color); if (isTextOverflowing) diff --git a/OpenRA.Mods.Common/Widgets/Logic/HotkeyDialogLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/HotkeyDialogLogic.cs new file mode 100644 index 0000000000..76f17c2a51 --- /dev/null +++ b/OpenRA.Mods.Common/Widgets/Logic/HotkeyDialogLogic.cs @@ -0,0 +1,149 @@ +#region Copyright & License Information +/* + * Copyright 2007-2019 The OpenRA Developers (see AUTHORS) + * 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.Primitives; +using OpenRA.Widgets; + +namespace OpenRA.Mods.Common.Widgets.Logic +{ + public class HotkeyDialogLogic : ChromeLogic + { + readonly Widget panel; + readonly ButtonWidget resetButton, clearButton, cancelButton; + readonly LabelWidget duplicateNotice, defaultNotice, originalNotice; + readonly Action onSave; + readonly HotkeyDefinition definition; + readonly HotkeyManager manager; + readonly HotkeyEntryWidget hotkeyEntry; + readonly bool isFirstValidation = true; + Hotkey currentHotkey; + HotkeyDefinition duplicateHotkey; + bool isValid = false; + bool isValidating = false; + + [ObjectCreator.UseCtor] + public HotkeyDialogLogic(Widget widget, Action onSave, HotkeyDefinition hotkeyDefinition, HotkeyManager hotkeyManager) + { + panel = widget; + this.onSave = onSave; + definition = hotkeyDefinition; + manager = hotkeyManager; + currentHotkey = manager[definition.Name].GetValue(); + hotkeyEntry = panel.Get("HOTKEY_ENTRY"); + resetButton = panel.Get("RESET_BUTTON"); + clearButton = panel.Get("CLEAR_BUTTON"); + cancelButton = panel.Get("CANCEL_BUTTON"); + duplicateNotice = panel.Get("DUPLICATE_NOTICE"); + defaultNotice = panel.Get("DEFAULT_NOTICE"); + originalNotice = panel.Get("ORIGINAL_NOTICE"); + + panel.Get("HOTKEY_LABEL").GetText = () => hotkeyDefinition.Description + ":"; + + duplicateNotice.TextColor = ChromeMetrics.Get("NoticeErrorColor"); + duplicateNotice.GetText = () => + { + return (duplicateHotkey != null) ? duplicateNotice.Text.F(duplicateHotkey.Description) : duplicateNotice.Text; + }; + defaultNotice.TextColor = ChromeMetrics.Get("NoticeInfoColor"); + originalNotice.TextColor = ChromeMetrics.Get("NoticeInfoColor"); + originalNotice.Text = originalNotice.Text.F(hotkeyDefinition.Default.DisplayString()); + + resetButton.OnClick = Reset; + clearButton.OnClick = Clear; + cancelButton.OnClick = Cancel; + + hotkeyEntry.Key = currentHotkey; + hotkeyEntry.IsValid = () => isValid; + hotkeyEntry.OnTakeFocus = OnHotkeyEntryTakeFocus; + hotkeyEntry.OnLoseFocus = OnHotkeyEntryLoseFocus; + hotkeyEntry.OnEscape = Cancel; + hotkeyEntry.OnReturn = Cancel; + hotkeyEntry.TakeKeyboardFocus(); + + Validate(); + isFirstValidation = false; + } + + void OnHotkeyEntryTakeFocus() + { + cancelButton.Disabled = manager.GetFirstDuplicate(definition.Name, currentHotkey, definition) != null; + } + + void OnHotkeyEntryLoseFocus() + { + cancelButton.Disabled = true; + if (!isValidating) + Validate(); + } + + void Validate() + { + isValidating = true; + + duplicateHotkey = manager.GetFirstDuplicate(definition.Name, hotkeyEntry.Key, definition); + isValid = duplicateHotkey == null; + + duplicateNotice.Visible = !isValid; + clearButton.Disabled = !hotkeyEntry.Key.IsValid(); + + if (hotkeyEntry.Key == definition.Default || (!hotkeyEntry.Key.IsValid() && !definition.Default.IsValid())) + { + defaultNotice.Visible = !duplicateNotice.Visible; + originalNotice.Visible = false; + resetButton.Disabled = true; + } + else + { + defaultNotice.Visible = false; + originalNotice.Visible = !duplicateNotice.Visible; + resetButton.Disabled = false; + } + + if (isValid && !isFirstValidation) + { + currentHotkey = hotkeyEntry.Key; + hotkeyEntry.YieldKeyboardFocus(); + Save(); + } + else + hotkeyEntry.TakeKeyboardFocus(); + + isValidating = false; + } + + void Save() + { + manager.Set(definition.Name, hotkeyEntry.Key); + Game.Settings.Save(); + onSave(); + } + + void Cancel() + { + cancelButton.Disabled = true; + hotkeyEntry.Key = currentHotkey; + Validate(); + } + + void Reset() + { + hotkeyEntry.Key = definition.Default; + Validate(); + } + + void Clear() + { + hotkeyEntry.Key = Hotkey.Invalid; + Validate(); + } + } +} diff --git a/OpenRA.Mods.Common/Widgets/Logic/SettingsLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/SettingsLogic.cs index f54c4f5094..b2cda000a7 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/SettingsLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/SettingsLogic.cs @@ -13,13 +13,14 @@ using System; using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; +using OpenRA.Primitives; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic { public class SettingsLogic : ChromeLogic { - enum PanelType { Display, Audio, Input, Advanced } + enum PanelType { Display, Audio, Input, Hotkeys, Advanced } static readonly string OriginalSoundDevice; static readonly WindowMode OriginalGraphicsMode; @@ -61,6 +62,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic 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.Hotkeys, InitHotkeysPanel, ResetHotkeysPanel, "HOTKEYS_PANEL", "HOTKEYS_TAB"); RegisterSettingsPanel(PanelType.Advanced, InitAdvancedPanel, ResetAdvancedPanel, "ADVANCED_PANEL", "ADVANCED_TAB"); panelContainer.Get("BACK_BUTTON").OnClick = () => @@ -123,7 +125,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic ss.OnChange += x => field.SetValue(group, x); } - static void BindHotkeyPref(HotkeyDefinition hd, HotkeyManager manager, Widget template, Widget parent) + static void BindHotkeyPref(HotkeyDefinition hd, HotkeyManager manager, Widget template, Widget parent, Widget remapDialogRoot, Widget remapDialogPlaceholder) { var key = template.Clone() as Widget; key.Id = hd.Name; @@ -131,9 +133,53 @@ namespace OpenRA.Mods.Common.Widgets.Logic key.Get("FUNCTION").GetText = () => hd.Description + ":"; - var textBox = key.Get("HOTKEY"); - textBox.Key = manager[hd.Name].GetValue(); - textBox.OnLoseFocus = () => manager.Set(hd.Name, textBox.Key); + var remapButton = key.Get("HOTKEY"); + remapButton.GetText = () => manager[hd.Name].GetValue().DisplayString(); + + if (manager.GetFirstDuplicate(hd.Name, manager[hd.Name].GetValue(), hd) != null) + remapButton.GetColor = () => ChromeMetrics.Get("HotkeyColorInvalid"); + + remapButton.OnClick = () => + { + remapDialogRoot.RemoveChildren(); + + if (remapButton.IsHighlighted()) + { + remapButton.IsHighlighted = () => false; + + if (remapDialogPlaceholder != null) + remapDialogPlaceholder.Visible = true; + + return; + } + + if (remapDialogPlaceholder != null) + remapDialogPlaceholder.Visible = false; + + var siblings = parent.Children; + foreach (var sibling in siblings) + { + var button = sibling.GetOrNull("HOTKEY"); + if (button != null) + button.IsHighlighted = () => false; + } + + remapButton.IsHighlighted = () => true; + + Ui.LoadWidget("HOTKEY_DIALOG", remapDialogRoot, new WidgetArgs + { + { + "onSave", () => + { + remapButton.GetText = () => manager[hd.Name].GetValue().DisplayString(); + remapButton.GetColor = () => ChromeMetrics.Get("ButtonTextColor"); + } + }, + { "hotkeyDefinition", hd }, + { "hotkeyManager", manager }, + }); + }; + parent.AddChild(key); } @@ -408,6 +454,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic zoomModifierDropdown.OnMouseDown = _ => ShowZoomModifierDropdown(zoomModifierDropdown, gs); zoomModifierDropdown.GetText = () => gs.ZoomModifier.ToString(); + return () => { }; + } + + Action InitHotkeysPanel(Widget panel) + { var hotkeyList = panel.Get("HOTKEY_LIST"); hotkeyList.Layout = new GridLayout(hotkeyList); var hotkeyHeader = hotkeyList.Get("HEADER"); @@ -434,10 +485,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic var types = FieldLoader.GetValue("Types", typesNode.Value.Value); var added = new HashSet(); var template = templates.Get(templateNode.Value.Value); + var remapDialogRoot = panel.Get("HOTKEY_DIALOG_ROOT"); + var remapDialogPlaceholder = panel.GetOrNull("HOTKEY_DIALOG_PLACEHOLDER"); foreach (var t in types) foreach (var hd in modData.Hotkeys.Definitions.Where(k => k.Types.Contains(t))) if (added.Add(hd)) - BindHotkeyPref(hd, modData.Hotkeys, template, hotkeyList); + BindHotkeyPref(hd, modData.Hotkeys, template, hotkeyList, remapDialogRoot, remapDialogPlaceholder); } } @@ -461,16 +514,22 @@ namespace OpenRA.Mods.Common.Widgets.Logic gs.AllowZoom = dgs.AllowZoom; gs.ZoomModifier = dgs.ZoomModifier; + panel.Get("SCROLLSPEED_SLIDER").Value = gs.ViewportEdgeScrollStep; + panel.Get("UI_SCROLLSPEED_SLIDER").Value = gs.UIScrollSpeed; + + MakeMouseFocusSettingsLive(); + }; + } + + Action ResetHotkeysPanel(Widget panel) + { + return () => + { foreach (var hd in modData.Hotkeys.Definitions) { modData.Hotkeys.Set(hd.Name, hd.Default); panel.Get(hd.Name).Get("HOTKEY").Key = hd.Default; } - - panel.Get("SCROLLSPEED_SLIDER").Value = gs.ViewportEdgeScrollStep; - panel.Get("UI_SCROLLSPEED_SLIDER").Value = gs.UIScrollSpeed; - - MakeMouseFocusSettingsLive(); }; } diff --git a/mods/cnc/chrome/dialog-hotkey.yaml b/mods/cnc/chrome/dialog-hotkey.yaml new file mode 100644 index 0000000000..655db94a04 --- /dev/null +++ b/mods/cnc/chrome/dialog-hotkey.yaml @@ -0,0 +1,83 @@ +Background@HOTKEY_DIALOG: + Logic: HotkeyDialogLogic + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Background: panel-gray + Children: + Label@HOTKEY_LABEL: + X: 15 + Y: 14 + Width: PARENT_RIGHT - 40 + Height: 25 + Font: Bold + HotkeyEntry@HOTKEY_ENTRY: + X: 15 + Y: 40 + Width: 382 + Height: 25 + Container@NOTICES: + X: 15 + Y: 65 + Width: PARENT_RIGHT - 40 + Height: 25 + Children: + Label@DEFAULT_NOTICE: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Font: Tiny + Align: Left + Text: This is the default hotkey. + Label@ORIGINAL_NOTICE: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Font: Tiny + Align: Left + Text: The default is "{0}" + Label@DUPLICATE_NOTICE: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Font: Tiny + Align: Left + Text: This hotkey is already used for "{0}" + Button@CLEAR_BUTTON: + X: PARENT_RIGHT - 65 - 15 - 2 * (WIDTH + 10) + Y: 40 + Width: 25 + Height: 25 + TooltipText: Unbind the hotkey + TooltipContainer: TOOLTIP_CONTAINER + TooltipTemplate: SIMPLE_TOOLTIP + Children: + Image: + ImageCollection: lobby-bits + ImageName: kick + X: 7 + Y: 8 + IgnoreMouseOver: True + Button@RESET_BUTTON: + X: PARENT_RIGHT - 65 - 15 - WIDTH - 10 + Y: 40 + Width: 25 + Height: 25 + TooltipText: Reset to default + TooltipContainer: TOOLTIP_CONTAINER + TooltipTemplate: SIMPLE_TOOLTIP + Children: + Image@IMAGE_RELOAD: + X: 5 + Y: 5 + Width: 16 + Height: 16 + ImageCollection: reload-icon + ImageName: enabled + IgnoreMouseOver: True + Button@CANCEL_BUTTON: + X: PARENT_RIGHT - WIDTH - 15 + Y: 40 + Width: 65 + Height: 25 + Text: Cancel + TooltipText: Cancel the operation + TooltipContainer: TOOLTIP_CONTAINER + TooltipTemplate: SIMPLE_TOOLTIP + TooltipContainer@TOOLTIP_CONTAINER: diff --git a/mods/cnc/chrome/settings.yaml b/mods/cnc/chrome/settings.yaml index f9e60e0ea1..bd16d36080 100644 --- a/mods/cnc/chrome/settings.yaml +++ b/mods/cnc/chrome/settings.yaml @@ -40,22 +40,27 @@ Container@SETTINGS_PANEL: Container@TAB_CONTAINER: Children: Button@DISPLAY_TAB: - Width: 140 + Width: 110 Height: 35 Text: Display Button@AUDIO_TAB: - X: 150 - Width: 140 + X: WIDTH + 10 + Width: 110 Height: 35 Text: Audio Button@INPUT_TAB: - X: 300 - Width: 140 + X: 2 * (WIDTH + 10) + Width: 110 Height: 35 Text: Input + Button@HOTKEYS_TAB: + X: 3 * (WIDTH + 10) + Width: 110 + Height: 35 + Text: Hotkeys Button@ADVANCED_TAB: - X: 450 - Width: 140 + X: 4 * (WIDTH + 10) + Width: 110 Height: 35 Text: Advanced Background@bg: @@ -459,13 +464,17 @@ Container@SETTINGS_PANEL: Font: Bold Text: Hotkeys Align: Center + Container@HOTKEYS_PANEL: + X: 15 + Y: 15 + Width: PARENT_RIGHT - 15 + Height: PARENT_BOTTOM - 15 + Children: ScrollPanel@HOTKEY_LIST: - X: 15 - Y: 185 - Width: 560 + Width: PARENT_RIGHT - 15 TopBottomSpacing: 4 ItemSpacing: 4 - Height: 160 + Height: 210 Children: ScrollItem@HEADER: Width: 528 @@ -489,10 +498,12 @@ Container@SETTINGS_PANEL: Width: PARENT_RIGHT - 85 Height: 25 Align: Right - HotkeyEntry@HOTKEY: + Button@HOTKEY: X: PARENT_RIGHT - WIDTH Width: 80 Height: 25 + Align: Left + TooltipContainer: TOOLTIP_CONTAINER Container@THREE_COLUMN: Width: 173 Height: 25 @@ -503,10 +514,29 @@ Container@SETTINGS_PANEL: Width: PARENT_RIGHT - 84 Height: 25 Align: Right - HotkeyEntry@HOTKEY: + Button@HOTKEY: X: PARENT_RIGHT - WIDTH + 1 Width: 80 Height: 25 + Align: Left + TooltipContainer: TOOLTIP_CONTAINER + Background@HOTKEY_DIALOG_PLACEHOLDER: + Y: 225 + Width: PARENT_RIGHT - 15 + Height: 105 + Background: panel-gray + Children: + Label@HOTKEY_DIALOG_HELPTEXT: + Y: PARENT_BOTTOM / 2 - 12 + Width: PARENT_RIGHT + Height: 25 + Font: Tiny + Align: Center + Text: Click on a hotkey to start rebinding + Container@HOTKEY_DIALOG_ROOT: + Y: 225 + Width: PARENT_RIGHT - 15 + Height: 105 Container@ADVANCED_PANEL: Width: PARENT_RIGHT Height: PARENT_BOTTOM @@ -648,3 +678,4 @@ Container@SETTINGS_PANEL: Width: 140 Height: 35 Text: Reset + TooltipContainer@TOOLTIP_CONTAINER: diff --git a/mods/cnc/hotkeys.yaml b/mods/cnc/hotkeys.yaml index e6276bd9dd..9704e5d79b 100644 --- a/mods/cnc/hotkeys.yaml +++ b/mods/cnc/hotkeys.yaml @@ -1,19 +1,19 @@ ProductionTypeBuilding: E Description: Building Tab - Types: Production + Types: Production, Player ProductionTypeDefense: R Description: Defense Tab - Types: Production + Types: Production, Player ProductionTypeInfantry: T Description: Infantry Tab - Types: Production + Types: Production, Player ProductionTypeVehicle: Y Description: Vehicle Tab - Types: Production + Types: Production, Player ProductionTypeAircraft: U Description: Aircraft Tab - Types: Production \ No newline at end of file + Types: Production, Player diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml index ec37281b08..5023dcf8d5 100644 --- a/mods/cnc/mod.yaml +++ b/mods/cnc/mod.yaml @@ -128,6 +128,7 @@ ChromeLayout: cnc|chrome/assetbrowser.yaml cnc|chrome/missionbrowser.yaml cnc|chrome/editor.yaml + cnc|chrome/dialog-hotkey.yaml Voices: cnc|audio/voices.yaml diff --git a/mods/common/chrome/dialog-hotkey.yaml b/mods/common/chrome/dialog-hotkey.yaml new file mode 100644 index 0000000000..49371f32fa --- /dev/null +++ b/mods/common/chrome/dialog-hotkey.yaml @@ -0,0 +1,69 @@ +Background@HOTKEY_DIALOG: + Logic: HotkeyDialogLogic + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Background: dialog3 + Children: + Label@HOTKEY_LABEL: + X: 20 + Y: 14 + Width: PARENT_RIGHT - 40 + Height: 25 + Font: Bold + HotkeyEntry@HOTKEY_ENTRY: + X: 20 + Y: 40 + Width: 280 + Height: 25 + Container@NOTICES: + X: 20 + Y: 65 + Width: PARENT_RIGHT - 40 + Height: 25 + Children: + Label@DEFAULT_NOTICE: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Font: Tiny + Align: Left + Text: This is the default + Label@ORIGINAL_NOTICE: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Font: Tiny + Align: Left + Text: The default is "{0}" + Label@DUPLICATE_NOTICE: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Font: Tiny + Align: Left + Text: This hotkey is already used for "{0}" + Button@CLEAR_BUTTON: + X: PARENT_RIGHT - 3 * WIDTH - 40 + Y: 41 + Width: 65 + Height: 25 + Text: Clear + TooltipText: Unbind the hotkey + TooltipContainer: TOOLTIP_CONTAINER + TooltipTemplate: SIMPLE_TOOLTIP + Button@RESET_BUTTON: + X: PARENT_RIGHT - 2 * WIDTH - 30 + Y: 41 + Width: 65 + Height: 25 + Text: Reset + TooltipText: Reset to default + TooltipContainer: TOOLTIP_CONTAINER + TooltipTemplate: SIMPLE_TOOLTIP + Button@CANCEL_BUTTON: + X: PARENT_RIGHT - WIDTH - 20 + Y: 41 + Width: 65 + Height: 25 + Text: Cancel + TooltipText: Cancel the operation + TooltipContainer: TOOLTIP_CONTAINER + TooltipTemplate: SIMPLE_TOOLTIP + TooltipContainer@TOOLTIP_CONTAINER: diff --git a/mods/common/chrome/settings.yaml b/mods/common/chrome/settings.yaml index 39da4673de..ec646a6a34 100644 --- a/mods/common/chrome/settings.yaml +++ b/mods/common/chrome/settings.yaml @@ -58,25 +58,31 @@ Background@SETTINGS_PANEL: Height: 25 Children: Button@DISPLAY_TAB: - X: 115 + X: 70 Width: 90 Height: 25 Text: Display Font: Bold Button@AUDIO_TAB: - X: 205 + X: 70 + WIDTH Width: 90 Height: 25 Text: Audio Font: Bold Button@INPUT_TAB: - X: 295 + X: 70 + 2 * WIDTH Width: 90 Height: 25 Text: Input Font: Bold + Button@HOTKEYS_TAB: + X: 70 + 3 * WIDTH + Width: 90 + Height: 25 + Text: Hotkeys + Font: Bold Button@ADVANCED_TAB: - X: 385 + X: 70 + 4 * WIDTH Width: 90 Height: 25 Text: Advanced @@ -457,19 +463,19 @@ Background@SETTINGS_PANEL: Ticks: 5 MinimumValue: 1 MaximumValue: 100 - Label@HOTKEYS_TITLE: - Y: 165 - Width: PARENT_RIGHT - Font: Bold - Text: Hotkeys - Align: Center + Container@HOTKEYS_PANEL: + X: 5 + Y: 50 + Width: PARENT_RIGHT - 10 + Height: PARENT_BOTTOM + Children: ScrollPanel@HOTKEY_LIST: X: 15 - Y: 185 - Width: 560 + Y: 40 + Width: PARENT_RIGHT - 30 TopBottomSpacing: 4 ItemSpacing: 4 - Height: 160 + Height: 183 Children: ScrollItem@HEADER: BaseName: scrollheader @@ -504,10 +510,12 @@ Background@SETTINGS_PANEL: Width: PARENT_RIGHT - 85 Height: 25 Align: Right - HotkeyEntry@HOTKEY: + Button@HOTKEY: X: PARENT_RIGHT - WIDTH Width: 80 Height: 25 + Align: Left + TooltipContainer: TOOLTIP_CONTAINER Container@THREE_COLUMN: Width: 173 Height: 25 @@ -518,10 +526,31 @@ Background@SETTINGS_PANEL: Width: PARENT_RIGHT - 84 Height: 25 Align: Right - HotkeyEntry@HOTKEY: + Button@HOTKEY: X: PARENT_RIGHT - WIDTH + 1 Width: 80 Height: 25 + Align: Left + TooltipContainer: TOOLTIP_CONTAINER + Background@HOTKEY_DIALOG_PLACEHOLDER: + X: 15 + Y: 232 + Width: PARENT_RIGHT - 30 + Height: 108 + Background: dialog3 + Children: + Label@HOTKEY_DIALOG_HELPTEXT: + Y: PARENT_BOTTOM / 2 - 12 + Width: PARENT_RIGHT + Height: 25 + Font: Tiny + Align: Center + Text: Click on a hotkey to start rebinding + Container@HOTKEY_DIALOG_ROOT: + X: 15 + Y: 232 + Width: PARENT_RIGHT - 30 + Height: 108 Container@ADVANCED_PANEL: X: 5 Y: 50 @@ -647,3 +676,4 @@ Background@SETTINGS_PANEL: Height: 20 Font: Regular Text: Strict Activity checking + TooltipContainer@TOOLTIP_CONTAINER: diff --git a/mods/common/hotkeys/game.yaml b/mods/common/hotkeys/game.yaml index 5e52911b21..bfcc24a52f 100644 --- a/mods/common/hotkeys/game.yaml +++ b/mods/common/hotkeys/game.yaml @@ -1,111 +1,111 @@ CycleBase: H Description: Jump to base - Types: World + Types: World, Player, Spectator ToLastEvent: SPACE Description: Jump to last radar event - Types: World + Types: World, Player, Spectator ToSelection: HOME Description: Jump to selection - Types: World + Types: World, Player, Spectator SelectAllUnits: Q Description: Select all combat units - Types: World + Types: World, Player, Spectator SelectUnitsByType: W Description: Select units by type - Types: World + Types: World, Player, Spectator RemoveFromControlGroup: Description: Remove from control group - Types: World + Types: World, Player Pause: PAUSE Description: Pause / Unpause - Types: World + Types: World, Player, Spectator Sell: Z Description: Sell mode - Types: OrderGenerator + Types: OrderGenerator, Player Repair: C Description: Repair mode - Types: OrderGenerator + Types: OrderGenerator, Player PlaceBeacon: B Description: Place beacon - Types: OrderGenerator + Types: OrderGenerator, Player, Spectator CycleStatusBars: COMMA Description: Cycle status bars display - Types: World + Types: World, Player, Spectator TogglePixelDouble: PERIOD Description: Toggle pixel doubling - Types: World + Types: World, Player, Spectator ToggleMute: M Description: Toggle audio mute - Types: World, Menu + Types: World, Menu, Player, Spectator TogglePlayerStanceColor: COMMA Ctrl Description: Toggle player stance colors - Types: World + Types: World, Player, Spectator TakeScreenshot: P Ctrl Description: Take screenshot - Types: World, Menu + Types: World, Menu, Player, Spectator AttackMove: A Description: Attack Move - Types: Unit + Types: Unit, Player Stop: S Description: Stop - Types: Unit + Types: Unit, Player Scatter: X Ctrl Description: Scatter - Types: Unit + Types: Unit, Player Deploy: F Description: Deploy - Types: Unit + Types: Unit, Player Guard: D Description: Guard - Types: Unit + Types: Unit, Player StanceAttackAnything: A Alt Description: Attack anything - Types: Stance + Types: Stance, Player StanceDefend: S Alt Description: Defend - Types: Stance + Types: Stance, Player StanceReturnFire: D Alt Description: Return fire - Types: Stance + Types: Stance, Player StanceHoldFire: F Alt Description: Hold fire - Types: Stance + Types: Stance, Player StopMusic: AUDIOSTOP Description: Stop - Types: Music + Types: Music, Player, Spectator PauseMusic: AUDIOPLAY Description: Pause or Resume - Types: Music + Types: Music, Player, Spectator PrevMusic: AUDIOPREV Description: Previous - Types: Music + Types: Music, Player, Spectator NextMusic: AUDIONEXT Description: Next - Types: Music + Types: Music, Player, Spectator diff --git a/mods/common/hotkeys/observer.yaml b/mods/common/hotkeys/observer.yaml index 3da1dd26b1..604aa83437 100644 --- a/mods/common/hotkeys/observer.yaml +++ b/mods/common/hotkeys/observer.yaml @@ -1,26 +1,26 @@ ObserverCombinedView: MINUS Description: All Players - Types: Observer + Types: Observer, Spectator ObserverWorldView: EQUALS Description: Disable Shroud - Types: Observer + Types: Observer, Spectator ReplaySpeedSlow: F9 Description: Slow speed - Types: Replay + Types: Replay, Spectator ReplaySpeedRegular: F10 Description: Regular speed - Types: Replay + Types: Replay, Spectator ReplaySpeedFast: F11 Description: Fast speed - Types: Replay + Types: Replay, Spectator ReplaySpeedMax: F12 Description: Maximum speed - Types: Replay + Types: Replay, Spectator StatisticsNone: F1 Description: Disable statistics @@ -28,15 +28,15 @@ StatisticsNone: F1 StatisticsBasic: F2 Description: Basic statistics - Types: Observer, Replay + Types: Observer, Replay, Spectator StatisticsEconomy: F3 Description: Economy statistics - Types: Observer, Replay + Types: Observer, Replay, Spectator StatisticsProduction: F4 Description: Production statistics - Types: Observer, Replay + Types: Observer, Replay, Spectator StatisticsSupportPowers: F5 Description: Support Power statistics @@ -44,12 +44,12 @@ StatisticsSupportPowers: F5 StatisticsCombat: F6 Description: Combat statistics - Types: Observer, Replay + Types: Observer, Replay, Spectator StatisticsGraph: F7 Description: Statistics graph - Types: Observer, Replay + Types: Observer, Replay, Spectator StatisticsArmyGraph: F8 Description: Army value graph - Types: Observer, Replay + Types: Observer, Replay, Spectator diff --git a/mods/common/hotkeys/production-common.yaml b/mods/common/hotkeys/production-common.yaml index cf6343d4b8..222c4b61aa 100644 --- a/mods/common/hotkeys/production-common.yaml +++ b/mods/common/hotkeys/production-common.yaml @@ -1,99 +1,99 @@ CycleProductionBuildings: TAB Description: Next facility - Types: Production + Types: Production, Player, Spectator Production01: F1 Description: Slot 01 - Types: ProductionSlot + Types: ProductionSlot, Player Production02: F2 Description: Slot 02 - Types: ProductionSlot + Types: ProductionSlot, Player Production03: F3 Description: Slot 03 - Types: ProductionSlot + Types: ProductionSlot, Player Production04: F4 Description: Slot 04 - Types: ProductionSlot + Types: ProductionSlot, Player Production05: F5 Description: Slot 05 - Types: ProductionSlot + Types: ProductionSlot, Player Production06: F6 Description: Slot 06 - Types: ProductionSlot + Types: ProductionSlot, Player Production07: F7 Description: Slot 07 - Types: ProductionSlot + Types: ProductionSlot, Player Production08: F8 Description: Slot 08 - Types: ProductionSlot + Types: ProductionSlot, Player Production09: F9 Description: Slot 09 - Types: ProductionSlot + Types: ProductionSlot, Player Production10: F10 Description: Slot 10 - Types: ProductionSlot + Types: ProductionSlot, Player Production11: F11 Description: Slot 11 - Types: ProductionSlot + Types: ProductionSlot, Player Production12: F12 Description: Slot 12 - Types: ProductionSlot + Types: ProductionSlot, Player Production13: F1 CTRL Description: Slot 13 - Types: ProductionSlot + Types: ProductionSlot, Player Production14: F2 CTRL Description: Slot 14 - Types: ProductionSlot + Types: ProductionSlot, Player Production15: F3 CTRL Description: Slot 15 - Types: ProductionSlot + Types: ProductionSlot, Player Production16: F4 CTRL Description: Slot 16 - Types: ProductionSlot + Types: ProductionSlot, Player Production17: F5 CTRL Description: Slot 17 - Types: ProductionSlot + Types: ProductionSlot, Player Production18: F6 CTRL Description: Slot 18 - Types: ProductionSlot + Types: ProductionSlot, Player Production19: F7 CTRL Description: Slot 19 - Types: ProductionSlot + Types: ProductionSlot, Player Production20: F8 CTRL Description: Slot 20 - Types: ProductionSlot + Types: ProductionSlot, Player Production21: F9 CTRL Description: Slot 21 - Types: ProductionSlot + Types: ProductionSlot, Player Production22: F10 CTRL Description: Slot 22 - Types: ProductionSlot + Types: ProductionSlot, Player Production23: F11 CTRL Description: Slot 23 - Types: ProductionSlot + Types: ProductionSlot, Player Production24: F12 CTRL Description: Slot 24 - Types: ProductionSlot + Types: ProductionSlot, Player diff --git a/mods/common/hotkeys/production-peractor.yaml b/mods/common/hotkeys/production-peractor.yaml index 6074e8541e..c551d3148d 100644 --- a/mods/common/hotkeys/production-peractor.yaml +++ b/mods/common/hotkeys/production-peractor.yaml @@ -1,7 +1,7 @@ NextProductionTab: PAGEDOWN Description: Next tab - Types: Production + Types: Production, Player PreviousProductionTab: PAGEUP Description: Previous tab - Types: Production + Types: Production, Player diff --git a/mods/common/hotkeys/supportpowers.yaml b/mods/common/hotkeys/supportpowers.yaml index bbf5f12d94..859f568a21 100644 --- a/mods/common/hotkeys/supportpowers.yaml +++ b/mods/common/hotkeys/supportpowers.yaml @@ -1,23 +1,23 @@ SupportPower01: Description: Slot 01 - Types: SupportPower + Types: SupportPower, Player SupportPower02: Description: Slot 02 - Types: SupportPower + Types: SupportPower, Player SupportPower03: Description: Slot 03 - Types: SupportPower + Types: SupportPower, Player SupportPower04: Description: Slot 04 - Types: SupportPower + Types: SupportPower, Player SupportPower05: Description: Slot 05 - Types: SupportPower + Types: SupportPower, Player SupportPower06: Description: Slot 06 - Types: SupportPower + Types: SupportPower, Player diff --git a/mods/common/hotkeys/viewport.yaml b/mods/common/hotkeys/viewport.yaml index 4c6ff70bc0..aff9443dad 100644 --- a/mods/common/hotkeys/viewport.yaml +++ b/mods/common/hotkeys/viewport.yaml @@ -1,63 +1,63 @@ MapScrollUp: UP Description: Scroll up - Types: Viewport + Types: Viewport, Player, Spectator MapScrollDown: DOWN Description: Scroll down - Types: Viewport + Types: Viewport, Player, Spectator MapScrollLeft: LEFT Description: Scroll left - Types: Viewport + Types: Viewport, Player, Spectator MapScrollRight: RIGHT Description: Scroll right - Types: Viewport + Types: Viewport, Player, Spectator MapJumpToTopEdge: UP Alt Description: Jump to top edge - Types: Viewport + Types: Viewport, Player, Spectator MapJumpToBottomEdge: DOWN Alt Description: Jump to bottom edge - Types: Viewport + Types: Viewport, Player, Spectator MapJumpToLeftEdge: LEFT Alt Description: Jump to left edge - Types: Viewport + Types: Viewport, Player, Spectator MapJumpToRightEdge: RIGHT Alt Description: Jump to right edge - Types: Viewport + Types: Viewport, Player, Spectator MapBookmarkSave01: Q Ctrl Description: Record bookmark 1 - Types: Viewport + Types: Viewport, Player, Spectator MapBookmarkRestore01: Q Alt Description: Jump to bookmark 1 - Types: Viewport + Types: Viewport, Player, Spectator MapBookmarkSave02: W Ctrl Description: Record bookmark 2 - Types: Viewport + Types: Viewport, Player, Spectator MapBookmarkRestore02: W Alt Description: Jump to bookmark 2 - Types: Viewport + Types: Viewport, Player, Spectator MapBookmarkSave03: E Ctrl Description: Record bookmark 3 - Types: Viewport + Types: Viewport, Player, Spectator MapBookmarkRestore03: E Alt Description: Jump to bookmark 3 - Types: Viewport + Types: Viewport, Player, Spectator MapBookmarkSave04: R Ctrl Description: Record bookmark 4 - Types: Viewport + Types: Viewport, Player, Spectator MapBookmarkRestore04: R Alt Description: Jump to bookmark 4 - Types: Viewport + Types: Viewport, Player, Spectator diff --git a/mods/common/metrics.yaml b/mods/common/metrics.yaml index bbfcdedd0c..78ced5348b 100644 --- a/mods/common/metrics.yaml +++ b/mods/common/metrics.yaml @@ -11,6 +11,7 @@ Metrics: GameStartedColor: FFA500 HotkeyColor: FFFFFF HotkeyColorDisabled: 808080 + HotkeyColorInvalid: FF0000 HotkeyFont: Regular IncompatibleGameColor: A9A9A9 IncompatibleGameStartedColor: D2691E diff --git a/mods/d2k/hotkeys.yaml b/mods/d2k/hotkeys.yaml index f7db18e4a3..4ae7ab66ed 100644 --- a/mods/d2k/hotkeys.yaml +++ b/mods/d2k/hotkeys.yaml @@ -1,31 +1,31 @@ ProductionTypeBuilding: E Description: Building Tab - Types: Production + Types: Production, Player ProductionTypeUpgrade: R Description: Upgrade Tab - Types: Production + Types: Production, Player ProductionTypeInfantry: T Description: Infantry Tab - Types: Production + Types: Production, Player ProductionTypeVehicle: Y Description: Vehicle Tab - Types: Production + Types: Production, Player ProductionTypeAircraft: U Description: Aircraft Tab - Types: Production + Types: Production, Player ProductionTypeTank: I Description: Tank Tab - Types: Production + Types: Production, Player ProductionTypeMerchant: O Description: Starport Tab - Types: Production + Types: Production, Player PowerDown: X Description: Power-down mode - Types: OrderGenerator + Types: OrderGenerator, Player diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index 8cddaab406..745e46a124 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -109,6 +109,7 @@ ChromeLayout: common|chrome/replaybrowser.yaml common|chrome/gamesave-browser.yaml common|chrome/gamesave-loading.yaml + common|chrome/dialog-hotkey.yaml Weapons: d2k|weapons/debris.yaml diff --git a/mods/ra/hotkeys.yaml b/mods/ra/hotkeys.yaml index f8da28a1cf..5565febfcc 100644 --- a/mods/ra/hotkeys.yaml +++ b/mods/ra/hotkeys.yaml @@ -1,27 +1,27 @@ ProductionTypeBuilding: E Description: Building Tab - Types: Production + Types: Production, Player ProductionTypeDefense: R Description: Defense Tab - Types: Production + Types: Production, Player ProductionTypeInfantry: T Description: Infantry Tab - Types: Production + Types: Production, Player ProductionTypeVehicle: Y Description: Vehicle Tab - Types: Production + Types: Production, Player ProductionTypeAircraft: U Description: Aircraft Tab - Types: Production + Types: Production, Player ProductionTypeNaval: I Description: Naval Tab - Types: Production + Types: Production, Player PowerDown: X Description: Power-down mode - Types: OrderGenerator + Types: OrderGenerator, Player diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml index 3678dc0377..46575b8321 100644 --- a/mods/ra/mod.yaml +++ b/mods/ra/mod.yaml @@ -124,6 +124,7 @@ ChromeLayout: common|chrome/confirmation-dialogs.yaml common|chrome/editor.yaml common|chrome/playerprofile.yaml + common|chrome/dialog-hotkey.yaml Weapons: ra|weapons/explosions.yaml diff --git a/mods/ts/hotkeys.yaml b/mods/ts/hotkeys.yaml index c9254073ed..c3b8928368 100644 --- a/mods/ts/hotkeys.yaml +++ b/mods/ts/hotkeys.yaml @@ -1,23 +1,23 @@ ProductionTypeBuilding: E Description: Building Tab - Types: Production + Types: Production, Player ProductionTypeDefense: R Description: Defense Tab - Types: Production + Types: Production, Player ProductionTypeInfantry: T Description: Infantry Tab - Types: Production + Types: Production, Player ProductionTypeVehicle: Y Description: Vehicle Tab - Types: Production + Types: Production, Player ProductionTypeAircraft: U Description: Aircraft Tab - Types: Production + Types: Production, Player PowerDown: X Description: Power-down mode - Types: OrderGenerator + Types: OrderGenerator, Player diff --git a/mods/ts/mod.yaml b/mods/ts/mod.yaml index cc48d95a55..fb3dc9b75d 100644 --- a/mods/ts/mod.yaml +++ b/mods/ts/mod.yaml @@ -172,6 +172,7 @@ ChromeLayout: common|chrome/missionbrowser.yaml common|chrome/confirmation-dialogs.yaml common|chrome/editor.yaml + common|chrome/dialog-hotkey.yaml Voices: ts|audio/voices.yaml