diff --git a/Scripts/Main.cs b/Scripts/Main.cs index d2be020..ce303ab 100644 --- a/Scripts/Main.cs +++ b/Scripts/Main.cs @@ -133,14 +133,35 @@ public partial class Main : Node2D uiRoot.MouseFilter = Control.MouseFilterEnum.Ignore; _uiLayer.AddChild(uiRoot); - // Level title (top-left) + // Level title bar (top-left) + var titleBar = new HBoxContainer(); + titleBar.SetAnchorsPreset(Control.LayoutPreset.TopLeft); + titleBar.OffsetLeft = 12; + titleBar.OffsetTop = 8; + titleBar.AddThemeConstantOverride("separation", 12); + + var backButton = new Button { Text = "← Menu", CustomMinimumSize = new Vector2(70, 28) }; + backButton.AddThemeFontSizeOverride("font_size", 11); + var backStyle = new StyleBoxFlat + { + BgColor = new Color("#2A2A2E"), + BorderColor = new Color("#444448"), + BorderWidthBottom = 1, BorderWidthTop = 1, BorderWidthLeft = 1, BorderWidthRight = 1, + CornerRadiusTopLeft = 4, CornerRadiusTopRight = 4, + CornerRadiusBottomLeft = 4, CornerRadiusBottomRight = 4, + ContentMarginLeft = 8, ContentMarginRight = 8, + ContentMarginTop = 2, ContentMarginBottom = 2 + }; + backButton.AddThemeStyleboxOverride("normal", backStyle); + backButton.Pressed += OnBackToMenu; + titleBar.AddChild(backButton); + _levelTitle = new Label { Text = "CHESSISTICS" }; - _levelTitle.SetAnchorsPreset(Control.LayoutPreset.TopLeft); - _levelTitle.OffsetLeft = 16; - _levelTitle.OffsetTop = 12; _levelTitle.AddThemeFontSizeOverride("font_size", 20); _levelTitle.MouseFilter = Control.MouseFilterEnum.Ignore; - uiRoot.AddChild(_levelTitle); + titleBar.AddChild(_levelTitle); + + uiRoot.AddChild(titleBar); // --- Side Panel (anchored to right edge) --- _sidePanel = new PanelContainer(); @@ -268,12 +289,23 @@ public partial class Main : Node2D var snap = _sim.GetSnapshot(); if (snap.Phase != SimPhase.Edit) return; + _boardView.ClearHighlights(); + var coords = new Coords(col, row); var piece = snap.Pieces.FirstOrDefault(p => p.StartCell == coords || p.EndCell == coords); if (piece != null) + { _detailPanel.ShowPiece(piece); + + // Highlight start and end cells to show trajectory + var pieceColor = PieceView.GetPieceColor(piece.Kind); + var highlightColor = new Color(pieceColor, 0.3f); + _boardView.HighlightCells([piece.StartCell, piece.EndCell], highlightColor); + } else + { _detailPanel.Hide(); + } } // --- Level Management --- @@ -491,13 +523,32 @@ public partial class Main : Node2D _running = false; _simTimer.Stop(); _sim.ProcessCommand(new StopSimulationCommand()); - _eventAnimator.ResetPiecePositions(_sim.GetSnapshot()); + + // Full visual rebuild: clear everything and recreate from snapshot + _eventAnimator.ClearAll(); + var snap = _sim.GetSnapshot(); + foreach (var ps in snap.Pieces) + { + var pieceView = new PieceView(); + pieceView.Setup(ps.Id, ps.Kind, ps.StartCell, ps.EndCell, _boardView); + _boardView.AddChild(pieceView); + + var color = PieceView.GetPieceColor(ps.Kind); + var trajectView = new TrajectView(); + trajectView.Setup(ps.Id, + _boardView.CoordsToPixel(ps.StartCell), + _boardView.CoordsToPixel(ps.EndCell), + color); + _boardView.AddChild(trajectView); + + _eventAnimator.RegisterPiece(ps.Id, pieceView, trajectView); + } + _controlBar.UpdateForPhase(SimPhase.Edit); _controlBar.ResetTurn(); _metricsOverlay.Hide(); - _inputMapper.SetSnapshot(_sim.GetSnapshot()); + _inputMapper.SetSnapshot(snap); - // Reset objective panel if (_currentLevel != null) _objectivePanel.Setup(_currentLevel.Demands); } @@ -550,4 +601,18 @@ public partial class Main : Node2D else ShowLevelSelect(); } + + private void OnBackToMenu() + { + SfxManager.Instance?.PlayClick(); + _running = false; + _simTimer.Stop(); + _eventAnimator.ClearAll(); + + FadeOut(0.2f, () => + { + ShowLevelSelect(); + FadeIn(0.3f); + }); + } } diff --git a/Scripts/UI/DetailPanel.cs b/Scripts/UI/DetailPanel.cs index 8dbb3c8..5ffb0ea 100644 --- a/Scripts/UI/DetailPanel.cs +++ b/Scripts/UI/DetailPanel.cs @@ -1,5 +1,6 @@ using Godot; using Chessistics.Engine.Model; +using Chessistics.Scripts.Pieces; namespace Chessistics.Scripts.UI; @@ -14,17 +15,41 @@ public partial class DetailPanel : PanelContainer public override void _Ready() { + var style = new StyleBoxFlat + { + BgColor = new Color(0.14f, 0.14f, 0.16f, 0.95f), + BorderColor = new Color("#444448"), + BorderWidthTop = 1, + CornerRadiusTopLeft = 4, CornerRadiusTopRight = 4, + ContentMarginLeft = 12, ContentMarginRight = 12, + ContentMarginTop = 8, ContentMarginBottom = 8 + }; + AddThemeStyleboxOverride("panel", style); + var vbox = new VBoxContainer(); + vbox.AddThemeConstantOverride("separation", 4); var title = new Label { Text = "DETAIL" }; - title.AddThemeFontSizeOverride("font_size", 14); + title.AddThemeFontSizeOverride("font_size", 13); + title.AddThemeColorOverride("font_color", new Color("#B8942A")); vbox.AddChild(title); _infoLabel = new Label { Text = "" }; _infoLabel.AddThemeFontSizeOverride("font_size", 11); + _infoLabel.AddThemeColorOverride("font_color", new Color("#CCCCCC")); vbox.AddChild(_infoLabel); - _removeButton = new Button { Text = "Retirer" }; + _removeButton = new Button { Text = "Retirer", CustomMinimumSize = new Vector2(80, 26) }; + _removeButton.AddThemeFontSizeOverride("font_size", 11); + var btnStyle = new StyleBoxFlat + { + BgColor = new Color("#5A2A2A"), + CornerRadiusTopLeft = 4, CornerRadiusTopRight = 4, + CornerRadiusBottomLeft = 4, CornerRadiusBottomRight = 4, + ContentMarginLeft = 8, ContentMarginRight = 8, + ContentMarginTop = 2, ContentMarginBottom = 2 + }; + _removeButton.AddThemeStyleboxOverride("normal", btnStyle); _removeButton.Pressed += () => EmitSignal(SignalName.RemoveRequested, _currentPieceId); vbox.AddChild(_removeButton); @@ -37,6 +62,7 @@ public partial class DetailPanel : PanelContainer _currentPieceId = piece.Id; var kindName = piece.Kind switch { + PieceKind.Pawn => "Pion", PieceKind.Rook => "Tour II", PieceKind.Bishop => "Fou II", PieceKind.Knight => "Cavalier", diff --git a/Scripts/UI/PieceStockPanel.cs b/Scripts/UI/PieceStockPanel.cs index 1cd87c1..dc40b83 100644 --- a/Scripts/UI/PieceStockPanel.cs +++ b/Scripts/UI/PieceStockPanel.cs @@ -2,6 +2,7 @@ using Godot; using System; using System.Collections.Generic; using Chessistics.Engine.Model; +using Chessistics.Scripts.Pieces; namespace Chessistics.Scripts.UI; @@ -15,6 +16,13 @@ public partial class PieceStockPanel : VBoxContainer public PieceKind? SelectedKind => _selectedKind; + private static readonly Color NormalBg = new("#2A2A2E"); + private static readonly Color SelectedBg = new("#3D6B8E"); + private static readonly Color HoverBg = new("#353538"); + private static readonly Color DisabledBg = new("#1E1E20"); + private static readonly Color BorderNormal = new("#444448"); + private static readonly Color BorderSelected = new("#5A9ECC"); + public void Setup(IReadOnlyList stock) { foreach (var child in GetChildren()) @@ -24,7 +32,7 @@ public partial class PieceStockPanel : VBoxContainer var title = new Label { Text = "PIECES" }; title.AddThemeFontSizeOverride("font_size", 16); - title.AddThemeColorOverride("font_color", new Color("#FFD700")); + title.AddThemeColorOverride("font_color", new Color("#B8942A")); AddChild(title); AddChild(new HSeparator()); @@ -32,16 +40,31 @@ public partial class PieceStockPanel : VBoxContainer foreach (var entry in stock) { var hbox = new HBoxContainer(); + hbox.AddThemeConstantOverride("separation", 8); + + // Color dot matching piece color + var dot = new ColorRect + { + CustomMinimumSize = new Vector2(10, 10), + Size = new Vector2(10, 10), + Color = PieceView.GetPieceColor(entry.Kind), + MouseFilter = Control.MouseFilterEnum.Ignore + }; + var dotCenter = new CenterContainer { CustomMinimumSize = new Vector2(14, 32) }; + dotCenter.AddChild(dot); + hbox.AddChild(dotCenter); var button = new Button { Text = GetPieceName(entry.Kind), CustomMinimumSize = new Vector2(120, 32), - ToggleMode = true + ToggleMode = false // We manage selection state ourselves }; + ApplyButtonStyle(button, false); var countLabel = new Label { Text = $"x{entry.Count}" }; - countLabel.AddThemeFontSizeOverride("font_size", 14); + countLabel.AddThemeFontSizeOverride("font_size", 13); + countLabel.AddThemeColorOverride("font_color", new Color("#999999")); var kind = entry.Kind; button.Pressed += () => OnPieceButtonPressed(kind); @@ -72,11 +95,45 @@ public partial class PieceStockPanel : VBoxContainer { foreach (var (k, (button, _, remaining)) in _entries) { - button.ButtonPressed = k == _selectedKind; + bool selected = k == _selectedKind; button.Disabled = remaining <= 0; + ApplyButtonStyle(button, selected); } } + private static void ApplyButtonStyle(Button button, bool selected) + { + var bg = selected ? SelectedBg : NormalBg; + var border = selected ? BorderSelected : BorderNormal; + + var normal = MakeStyle(bg, border); + var hover = MakeStyle(selected ? SelectedBg.Lightened(0.1f) : HoverBg, border); + var disabled = MakeStyle(DisabledBg, new Color("#2A2A2E")); + + button.AddThemeStyleboxOverride("normal", normal); + button.AddThemeStyleboxOverride("hover", hover); + button.AddThemeStyleboxOverride("pressed", MakeStyle(bg.Darkened(0.15f), border)); + button.AddThemeStyleboxOverride("disabled", disabled); + button.AddThemeFontSizeOverride("font_size", 12); + button.AddThemeColorOverride("font_color", selected ? Colors.White : new Color("#CCCCCC")); + button.AddThemeColorOverride("font_disabled_color", new Color("#555555")); + } + + private static StyleBoxFlat MakeStyle(Color bg, Color border) + { + return new StyleBoxFlat + { + BgColor = bg, + BorderColor = border, + BorderWidthBottom = 1, BorderWidthTop = 1, + BorderWidthLeft = 1, BorderWidthRight = 1, + CornerRadiusTopLeft = 4, CornerRadiusTopRight = 4, + CornerRadiusBottomLeft = 4, CornerRadiusBottomRight = 4, + ContentMarginLeft = 8, ContentMarginRight = 8, + ContentMarginTop = 4, ContentMarginBottom = 4 + }; + } + public void UpdateCount(PieceKind kind, int remaining) { if (!_entries.TryGetValue(kind, out var entry)) return;