diff --git a/C7/C7Game.tscn b/C7/C7Game.tscn index 85650bbfa..6db4d58cc 100644 --- a/C7/C7Game.tscn +++ b/C7/C7Game.tscn @@ -332,4 +332,6 @@ visible = false [connection signal="DiplomacySelection" from="CanvasLayer/PopupOverlay" to="." method="OnDiplomacySelected"] [connection signal="HidePopup" from="CanvasLayer/PopupOverlay" to="CanvasLayer/PopupOverlay" method="OnHidePopup"] [connection signal="Quit" from="CanvasLayer/PopupOverlay" to="." method="OnQuitTheGame"] -[connection signal="Retire" from="CanvasLayer/PopupOverlay" to="." method="_on_QuitButton_pressed"] +[connection signal="Retire" from="CanvasLayer/PopupOverlay" to="." method="OnRetire"] +[connection signal="SaveGame" from="CanvasLayer/PopupOverlay" to="." method="OnSaveGame"] +[connection signal="LoadGame" from="CanvasLayer/PopupOverlay" to="." method="OnLoadGame"] diff --git a/C7/Game.cs b/C7/Game.cs index 0b469c339..55ed8a237 100644 --- a/C7/Game.cs +++ b/C7/Game.cs @@ -125,6 +125,7 @@ public partial class Game : Node { Stopwatch loadTimer = new Stopwatch(); GlobalSingleton Global; + Civ3FileDialog FileDialog; public Player controller; // Player that's controlling the UI. @@ -166,6 +167,10 @@ public override void _EnterTree() { public override async void _Ready() { Global = GetNode("/root/GlobalSingleton"); + FileDialog = GetNode("%LoadDialog"); + FileDialog.Canceled += OnResolved; + FileDialog.FileSelected += path => OnResolved(); + try { await InitializeGame(); await StartGame(); @@ -521,14 +526,41 @@ private void DoActualEndTurn() { EmitSignal(SignalName.PlayerTurnEnd); } - public void _on_QuitButton_pressed() { - // This apparently exits the whole program - // GetTree().Quit(); - - // ChangeSceneToFile deletes the current scene and frees its memory, so this is quitting to main menu + public void OnRetire() { + // Quit to main menu, freeing previous scene data GetTree().ChangeSceneToFile("res://UIElements/MainMenu/main_menu.tscn"); } + public void OnSaveGame() { + popupOverlay.OnHidePopup(); // hide game menu + + // FileDialog is a Window, not a Control, so we have the popup overlay present a blank control + popupOverlay.ShowBlank(); + + // TODO: this should go to our own saves directory. + FileDialog.SetDirectoryForSaving(@"Conquests/Saves"); + + // TODO: sound -- see MainMenu.PlayButtonPressedSound(); + FileDialog.Popup(); + } + + public void OnLoadGame() { + popupOverlay.OnHidePopup(); // hide game menu + + // FileDialog is a Window, not a Control, so we have the popup overlay present a blank control + popupOverlay.ShowBlank(); + + // TODO: this should go to our own saves directory. + FileDialog.SetDirectoryForLoading(@"Conquests/Saves"); + + // TODO: sound -- see MainMenu.PlayButtonPressedSound(); + FileDialog.Popup(); + } + + public void OnResolved() { + popupOverlay.OnHidePopup(); + } + public void _on_Zoom_value_changed(float value) { mapView.setCameraZoomFromMiddle(value); } diff --git a/C7/UIElements/Popups/GameMenu.cs b/C7/UIElements/Popups/GameMenu.cs index 90c59cc24..5d51ce845 100644 --- a/C7/UIElements/Popups/GameMenu.cs +++ b/C7/UIElements/Popups/GameMenu.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using Godot; using Serilog; @@ -16,59 +17,56 @@ public override void _Ready() { AddHeader("Main Menu", 10); - // TODO: enable buttons as the features are implemented - AddButton("Map", 60, map); - AddButton("Load Game", 85, load); - //AddButton("New Game (Ctrl-Shift-Q)", 110, newGame); - //AddButton("Preferences (Ctrl-P)", 135, preferences); - AddButton("Retire", 110, retire); - AddButton("Save Game", 135, save); - AddButton("Quit Game (ESC)", 160, quit); + // Note: Enable buttons as the features are implemented - } + Tuple[] buttons = [ + new("Map", ShowMap), + new("Load Game", Load), + // new("New Game (Ctrl-Shift-Q)", NewGame), + // TODO: Quick Start? + // new("Preferences (Ctrl-P)", OpenPreferences), + new("Retire", Retire), + new("Save Game", Save), + new("Quit Game (ESC)", Quit) + ]; - private void save() { - var loadDialog = GetNode("../%LoadDialog"); - // TODO: this should go to our own saves directory. - loadDialog.SetDirectoryForSaving(@"Conquests/Saves"); + int verticalOffset = 60; + int rowHeight = 25; - // TODO: The main menu does sound playing but we don't know our path in - // the scene, which makes this hard. - // PlayButtonPressedSound(); - GetParent().EmitSignal(PopupOverlay.SignalName.HidePopup); + var indexedButtons = buttons.Select((x, i) => + new { Label = x.Item1, Func = x.Item2, Idx = i }); - loadDialog.Popup(); + foreach (var button in indexedButtons) { + AddButton(button.Label, verticalOffset + button.Idx * rowHeight, button.Func); + } } - private void preferences() { - throw new NotImplementedException(); + private void Load() { + GetParent().EmitSignal(PopupOverlay.SignalName.LoadGame); } - private void newGame() { - throw new NotImplementedException(); + private void Save() { + GetParent().EmitSignal(PopupOverlay.SignalName.SaveGame); } - private void load() { - var loadDialog = GetNode("../%LoadDialog"); - loadDialog.SetDirectoryForLoading(@"Conquests/Saves"); - // TODO: The main menu does sound playing but we don't know our path in - // the scene, which makes this hard. - // PlayButtonPressedSound(); + private void ShowMap() { // i.e., Cancel: return from menu to game GetParent().EmitSignal(PopupOverlay.SignalName.HidePopup); + } - loadDialog.Popup(); + private void Retire() { + GetParent().EmitSignal(PopupOverlay.SignalName.Retire); } - private void quit() { + private void Quit() { GetParent().EmitSignal(PopupOverlay.SignalName.Quit); } - private void retire() { - GetParent().EmitSignal(PopupOverlay.SignalName.Retire); + private void NewGame() { + // TODO: Wire to a NewGame scene } - private void map() { - GetParent().EmitSignal(PopupOverlay.SignalName.HidePopup); + private void OpenPreferences() { + // TODO: Preferences management - disable animation, etc. } } diff --git a/C7/UIElements/Popups/Popup.cs b/C7/UIElements/Popups/Popup.cs index 8284496cb..86275bce5 100644 --- a/C7/UIElements/Popups/Popup.cs +++ b/C7/UIElements/Popups/Popup.cs @@ -47,7 +47,10 @@ protected void AddButton(string label, int verticalPosition, Action action) { }; button.SetPosition(new Vector2(HORIZONTAL_POSITION, verticalPosition)); AddChild(button); - button.Pressed += action; + button.Pressed += () => { + action(); + ReleaseFocus(); + }; } protected void AddHeader(string text, int vOffset) { diff --git a/C7/UIElements/Popups/PopupOverlay.cs b/C7/UIElements/Popups/PopupOverlay.cs index d9ddee64f..323ea981c 100644 --- a/C7/UIElements/Popups/PopupOverlay.cs +++ b/C7/UIElements/Popups/PopupOverlay.cs @@ -8,13 +8,21 @@ public partial class PopupOverlay : HBoxContainer { private ILogger log = LogManager.ForContext(); - [Signal] public delegate void QuitEventHandler(); - [Signal] public delegate void RetireEventHandler(); - [Signal] public delegate void BuildCityEventHandler(string name); - [Signal] public delegate void DiplomacySelectionEventHandler(ParameterWrapper opponentPlayer); + // Meta [Signal] public delegate void HidePopupEventHandler(); [Signal] public delegate void ClickEventHandler(); + // Game events + [Signal] public delegate void BuildCityEventHandler(string name); + [Signal] public delegate void DiplomacySelectionEventHandler(ParameterWrapper opponentPlayer); + + // Menu events + [Signal] public delegate void SaveGameEventHandler(); + [Signal] public delegate void LoadGameEventHandler(); + [Signal] public delegate void RetireEventHandler(); + [Signal] public delegate void QuitEventHandler(); + + Control currentChild = null; [Export] @@ -57,9 +65,6 @@ public void ShowPopup(Popup child, PopupCategory category) { OffsetLeft = child.margins.left; OffsetRight = child.margins.right; - AddChild(child); - currentChild = child; - var soundFile = category switch { PopupCategory.Advisor => "Sounds/PopupAdvisor.wav", PopupCategory.Console => "Sounds/PopupConsole.wav", @@ -69,15 +74,24 @@ public void ShowPopup(Popup child, PopupCategory category) { var wav = soundFile == null ? null : Util.LoadCiv3WAVFromDisk(soundFile); - Isolate(); - - Show(); + ShowChild(child); if (wav != null) { PlaySound(wav); } } + public void ShowBlank() { + ShowChild(new Control()); + } + + private void ShowChild(Control child) { + AddChild(child); + currentChild = child; + Isolate(); + Show(); + } + /// /// Creates a modal context by preventing UI events outside the popup context. /// Inverse of `Reconnect(..)`. @@ -142,7 +156,7 @@ public override void _UnhandledInput(InputEvent @event) { } if (@event is InputEventMouseButton ev) { - // Catch right clicks over UI elements to stop awkward TileInfo renders + // Catch right clicks over UI elements to stop awkward TileInfo renders if (ev.ButtonIndex == MouseButton.Right) { if (IsOverUI()) { AcceptEvent(); diff --git a/C7/UIElements/UpperLeftNav/AdvisorButton.cs b/C7/UIElements/UpperLeftNav/AdvisorButton.cs index a927e3c41..975c44bfd 100644 --- a/C7/UIElements/UpperLeftNav/AdvisorButton.cs +++ b/C7/UIElements/UpperLeftNav/AdvisorButton.cs @@ -7,4 +7,9 @@ public partial class AdvisorButton : Civ3TextureButton { public override void _Ready() { TextureLoader.SetButtonTextures(this, "upper_left_navigation.advisor"); } + + public override void _Pressed() { + base._Pressed(); + ReleaseFocus(); + } } diff --git a/C7/UIElements/UpperLeftNav/CivilopediaButton.cs b/C7/UIElements/UpperLeftNav/CivilopediaButton.cs index b348d0443..e52a64b7b 100644 --- a/C7/UIElements/UpperLeftNav/CivilopediaButton.cs +++ b/C7/UIElements/UpperLeftNav/CivilopediaButton.cs @@ -9,4 +9,9 @@ public override void _Ready() { ImageTexture menuTexture = TextureLoader.Load("upper_left_navigation.civilopedia"); this.TextureNormal = menuTexture; } + + public override void _Pressed() { + base._Pressed(); + ReleaseFocus(); + } } diff --git a/C7/UIElements/UpperLeftNav/MenuButton.cs b/C7/UIElements/UpperLeftNav/MenuButton.cs index 4bd9b024f..d0947e1b3 100644 --- a/C7/UIElements/UpperLeftNav/MenuButton.cs +++ b/C7/UIElements/UpperLeftNav/MenuButton.cs @@ -14,6 +14,7 @@ public override void _Ready() { public override void _Pressed() { popupOverlay.ShowPopup(new GameMenu(), PopupOverlay.PopupCategory.Info); + ReleaseFocus(); } } diff --git a/C7/UIElements/civ3_file_dialog.tscn b/C7/UIElements/civ3_file_dialog.tscn index 6595a6369..638155bea 100644 --- a/C7/UIElements/civ3_file_dialog.tscn +++ b/C7/UIElements/civ3_file_dialog.tscn @@ -4,6 +4,6 @@ [node name="LoadDialog" type="FileDialog"] initial_position = 1 -size = Vector2i(312, 450) +size = Vector2i(512, 450) visible = true script = ExtResource("1_mb1lm")