diff --git a/Intersect.Client.Core/Interface/Game/EscapeMenu.cs b/Intersect.Client.Core/Interface/Game/EscapeMenu.cs deleted file mode 100644 index a2908f2af3..0000000000 --- a/Intersect.Client.Core/Interface/Game/EscapeMenu.cs +++ /dev/null @@ -1,207 +0,0 @@ -using Intersect.Client.Core; -using Intersect.Client.Framework.File_Management; -using Intersect.Client.Framework.Gwen.Control; -using Intersect.Client.Framework.Gwen.Control.EventArguments; -using Intersect.Client.General; -using Intersect.Client.Interface.Shared; -using Intersect.Client.Localization; -using Intersect.Framework.Core; -using Intersect.Utilities; - -namespace Intersect.Client.Interface.Game; - -public partial class EscapeMenu : ImagePanel -{ - private readonly Func _settingsWindowProvider; - private readonly Button _buttonCharacterSelect; - private readonly Panel _versionPanel; - - public EscapeMenu(Canvas gameCanvas, Func settingsWindowProvider) : base(gameCanvas, nameof(EscapeMenu)) - { - _settingsWindowProvider = settingsWindowProvider; - - Interface.InputBlockingComponents?.Add(this); - - Width = gameCanvas.Width; - Height = gameCanvas.Height; - - // Create the container - var container = new ImagePanel(this, nameof(EscapeMenu)); - - // Title Label - _ = new Label(container, "TitleLabel") - { - Text = Strings.EscapeMenu.Title, - }; - - var buttonSettings = new Button(container, "SettingsButton") - { - Text = Strings.EscapeMenu.Settings, - }; - buttonSettings.Clicked += (s, e) => OpenSettingsWindow(true); - - // Character Select Button - _buttonCharacterSelect = new Button(container, "CharacterSelectButton") - { - Text = Strings.EscapeMenu.CharacterSelect, - }; - _buttonCharacterSelect.Clicked += _buttonCharacterSelect_Clicked; - - // Logout Button - var buttonLogout = new Button(container, "LogoutButton") - { - Text = Strings.EscapeMenu.Logout, - }; - buttonLogout.Clicked += buttonLogout_Clicked; - - // Exit to Desktop Button - var buttonQuit = new Button(container, "ExitToDesktopButton") - { - Text = Strings.EscapeMenu.ExitToDesktop, - }; - buttonQuit.Clicked += buttonQuit_Clicked; - - // Close Button - var buttonContinue = new Button(container, "CloseButton") - { - Text = Strings.EscapeMenu.Close, - }; - buttonContinue.Clicked += (s, e) => Hide(); - - container.LoadJsonUi(GameContentManager.UI.InGame, Graphics.Renderer?.GetResolutionString()); - - if (Options.Instance.Player.MaxCharacters <= 1) - { - _buttonCharacterSelect.IsDisabled = true; - } - - _versionPanel = new VersionPanel(this, name: nameof(_versionPanel)); - } - - public override void Invalidate() - { - if (IsHidden) - { - RemoveModal(); - } - else - { - MakeModal(true); - } - - base.Invalidate(); - if (Interface.GameUi?.GameCanvas != null) - { - Interface.GameUi.GameCanvas.MouseInputEnabled = IsVisibleInTree; - } - } - - /// - public override void ToggleHidden() - { - var settingsWindow = _settingsWindowProvider(); - if (settingsWindow.IsVisibleInTree) - { - return; - } - - base.ToggleHidden(); - } - - public void Update() - { - if (!IsHidden) - { - BringToFront(); - } - - _buttonCharacterSelect.IsDisabled = Globals.Me?.CombatTimer > Timing.Global.Milliseconds; - } - - public void OpenSettingsWindow(bool returnToMenu = false) - { - var settingsWindow = _settingsWindowProvider(); - settingsWindow.Show(returnToMenu ? this : null); - Hide(); - } - - private void _buttonCharacterSelect_Clicked(Base sender, MouseButtonState arguments) - { - ToggleHidden(); - if (Globals.Me?.CombatTimer > Timing.Global.Milliseconds) - { - ShowCombatWarning(); - } - else - { - LogoutToCharacterSelect(null, null); - } - } - - private void LogoutToCharacterSelect(object? sender, EventArgs? e) - { - if (Globals.Me != null) - { - Globals.Me.CombatTimer = 0; - } - - Main.Logout(true); - } - - private void buttonLogout_Clicked(Base sender, MouseButtonState arguments) - { - ToggleHidden(); - if (Globals.Me?.CombatTimer > Timing.Global.Milliseconds) - { - ShowCombatWarning(); - } - else - { - LogoutToMainMenu(null, null); - } - } - - private void LogoutToMainMenu(object? sender, EventArgs? e) - { - if (Globals.Me != null) - { - Globals.Me.CombatTimer = 0; - } - - Main.Logout(false); - } - - private void buttonQuit_Clicked(Base sender, MouseButtonState arguments) - { - ToggleHidden(); - if (Globals.Me?.CombatTimer > Timing.Global.Milliseconds) - { - ShowCombatWarning(); - } - else - { - ExitToDesktop(null, null); - } - } - - private void ShowCombatWarning() - { - AlertWindow.Open( - Strings.Combat.WarningCharacterSelect, - Strings.Combat.WarningTitle, - AlertType.Warning, - handleSubmit: LogoutToCharacterSelect, - inputType: InputType.YesNo - ); - } - - private void ExitToDesktop(object? sender, EventArgs? e) - { - if (Globals.Me != null) - { - Globals.Me.CombatTimer = 0; - } - - Globals.IsRunning = false; - } -} diff --git a/Intersect.Client.Core/Interface/Game/GameInterface.cs b/Intersect.Client.Core/Interface/Game/GameInterface.cs index 9736d3f5cd..1d968ff795 100644 --- a/Intersect.Client.Core/Interface/Game/GameInterface.cs +++ b/Intersect.Client.Core/Interface/Game/GameInterface.cs @@ -10,6 +10,7 @@ using Intersect.Client.Interface.Game.Inventory; using Intersect.Client.Interface.Game.Shop; using Intersect.Client.Interface.Game.Trades; +using Intersect.Client.Interface.Menu; using Intersect.Client.Interface.Shared; using Intersect.Client.Networking; using Intersect.Core; @@ -112,11 +113,11 @@ public GameInterface(Canvas canvas) : base(canvas) public Canvas GameCanvas { get; } private AnnouncementWindow? _announcementWindow; - private EscapeMenu? _escapeMenu; + private EscapeMenuWindow? _escapeMenu; private SimplifiedEscapeMenu? _simplifiedEscapeMenu; private TargetContextMenu? _targetContextMenu; - public EscapeMenu EscapeMenu => _escapeMenu ??= new EscapeMenu(GameCanvas, GetOrCreateSettingsWindow) + public EscapeMenuWindow EscapeMenu => _escapeMenu ??= new EscapeMenuWindow(GameCanvas, GetOrCreateSettingsWindow) { IsHidden = true, }; diff --git a/Intersect.Client.Core/Interface/Menu/EscapeMenuWindow.Designer.cs b/Intersect.Client.Core/Interface/Menu/EscapeMenuWindow.Designer.cs new file mode 100644 index 0000000000..b81a8cf20c --- /dev/null +++ b/Intersect.Client.Core/Interface/Menu/EscapeMenuWindow.Designer.cs @@ -0,0 +1,52 @@ +using Intersect.Client.Core; +using Intersect.Client.Framework.File_Management; +using Intersect.Client.Framework.Gwen; +using Intersect.Client.Framework.Gwen.Control; + +namespace Intersect.Client.Interface.Menu; + +public partial class EscapeMenuWindow +{ + protected override void EnsureInitialized() + { + var canvas = Canvas ?? throw new InvalidOperationException($"Not attached to a {nameof(Canvas)}"); + + Button[] visibleButtons = new[] + { + _openSettingsButton, + _returnToCharacterSelectionButton, + _logoutButton, + _exitToDesktopButton, + _returnToGameButton, + }.Where(button => button.IsVisibleInParent).ToArray(); + + const int defaultWidth = 87; + const int defaultHeight = 154; + + Size = new Point( + defaultWidth * visibleButtons.Length + InnerPanelPadding.Left + InnerPanelPadding.Right, + defaultHeight + TitleBarBounds.Bottom + InnerPanelPadding.Top + InnerPanelPadding.Bottom + ); + + Titlebar.MouseInputEnabled = false; + TitleLabel.FontSize = 14; + TitleLabel.TextColorOverride = Color.White; + + foreach (var button in visibleButtons) + { + button.Size = new Point(defaultWidth, defaultHeight); + button.FontName = "sourcesansproblack"; + button.FontSize = 12; + button.Padding = new Padding(0, 24, 0, 0); + button.Dock = Pos.Left; + + var buttonName = button.Name; + foreach (var componentState in Enum.GetValues()) + { + button.SetStateTexture(componentState, $"{nameof(EscapeMenuWindow)}{buttonName}_{componentState}.png"); + } + } + + LoadJsonUi(GameContentManager.UI.InGame, Graphics.Renderer.GetResolutionString()); + } +} \ No newline at end of file diff --git a/Intersect.Client.Core/Interface/Menu/EscapeMenuWindow.cs b/Intersect.Client.Core/Interface/Menu/EscapeMenuWindow.cs new file mode 100644 index 0000000000..78069e080d --- /dev/null +++ b/Intersect.Client.Core/Interface/Menu/EscapeMenuWindow.cs @@ -0,0 +1,227 @@ +using Intersect.Client.Core; +using Intersect.Client.Framework.Gwen; +using Intersect.Client.Framework.Gwen.Control; +using Intersect.Client.Framework.Gwen.Control.EventArguments; +using Intersect.Client.General; +using Intersect.Client.Interface.Shared; +using Intersect.Client.Localization; +using Intersect.Framework.Core; +using Intersect.Utilities; + +namespace Intersect.Client.Interface.Menu; + +public partial class EscapeMenuWindow : Window +{ + private readonly Button _openSettingsButton; + private readonly Button _returnToCharacterSelectionButton; + private readonly Button _logoutButton; + private readonly Button _exitToDesktopButton; + private readonly Button _returnToGameButton; + + private readonly Panel _versionPanel; + + private readonly Func _settingsWindowProvider; + + public EscapeMenuWindow(Canvas canvas, Func settingsWindowProvider) + : base(canvas, Strings.EscapeMenu.Title, false, + $"{nameof(EscapeMenuWindow)}_{(ClientContext.IsSinglePlayer ? "singleplayer" : "online")}") + { + _settingsWindowProvider = settingsWindowProvider; + + Alignment = [Alignments.Center]; + + IsClosable = false; + IsResizable = false; + Padding = Padding.Zero; + InnerPanelPadding = new Padding(8); + Titlebar.MouseInputEnabled = false; + + _openSettingsButton = new Button(this, nameof(_openSettingsButton)) + { + IsTabable = true, + Text = Strings.EscapeMenu.Settings, + }; + _openSettingsButton.Clicked += OpenSettingsButtonOnClicked; + + _returnToCharacterSelectionButton = new Button(this, nameof(_returnToCharacterSelectionButton)) + { + IsVisibleInParent = Options.Instance.Player.MaxCharacters > 1, + IsTabable = true, + Text = Strings.EscapeMenu.CharacterSelect, + }; + _returnToCharacterSelectionButton.Clicked += ReturnToCharacterSelectionButtonOnClicked; + + _logoutButton = new Button(this, nameof(_logoutButton)) + { + IsVisibleInParent = !ClientContext.IsSinglePlayer, + IsTabable = true, + Text = Strings.EscapeMenu.Logout, + }; + _logoutButton.Clicked += LogoutButtonOnClicked; + + _exitToDesktopButton = new Button(this, nameof(_exitToDesktopButton)) + { + IsTabable = true, + Text = Strings.EscapeMenu.ExitToDesktop, + }; + _exitToDesktopButton.Clicked += ExitToDesktopButtonOnClicked; + + _returnToGameButton = new Button(this, nameof(_returnToGameButton)) + { + IsTabable = true, + Text = Strings.EscapeMenu.Close, + }; + _returnToGameButton.Clicked += ReturnToGameButtonOnClicked; + + if (!string.IsNullOrEmpty(Strings.MainMenu.SettingsTooltip)) + { + _openSettingsButton.SetToolTipText(Strings.MainMenu.SettingsTooltip); + } + + _versionPanel = new VersionPanel(this, name: nameof(_versionPanel)); + + Interface.InputBlockingComponents.Add(this); + } + + private void ReturnToGameButtonOnClicked(Base s, MouseButtonState e) + { + Hide(); + } + + private void OpenSettingsButtonOnClicked(Base s, MouseButtonState e) + { + OpenSettingsWindow(true); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + Interface.InputBlockingComponents.Remove(this); + } + + protected override void OnVisibilityChanged(object? sender, VisibilityChangedEventArgs eventArgs) + { + base.OnVisibilityChanged(sender, eventArgs); + + if (eventArgs.IsVisibleInTree) + { + var modal = MakeModal(dim: true); + _versionPanel.Parent = modal; + } + else + { + _versionPanel.Parent = this; + RemoveModal(); + } + } + + /// + public override void ToggleHidden() + { + var settingsWindow = _settingsWindowProvider(); + if (settingsWindow.IsVisibleInTree) + { + return; + } + + base.ToggleHidden(); + } + + public void Update() + { + if (!IsHidden) + { + BringToFront(); + } + + _returnToCharacterSelectionButton.IsDisabled = Globals.Me?.CombatTimer > Timing.Global.Milliseconds; + } + + public void OpenSettingsWindow(bool returnToMenu = false) + { + var settingsWindow = _settingsWindowProvider(); + settingsWindow.Show(returnToMenu ? this : null); + Hide(); + } + + private void ReturnToCharacterSelectionButtonOnClicked(Base sender, MouseButtonState arguments) + { + ToggleHidden(); + if (Globals.Me?.CombatTimer > Timing.Global.Milliseconds) + { + ShowCombatWarning(); + } + else + { + LogoutToCharacterSelect(null, null); + } + } + + private void LogoutToCharacterSelect(object? sender, EventArgs? e) + { + if (Globals.Me != null) + { + Globals.Me.CombatTimer = 0; + } + + Main.Logout(true); + } + + private void LogoutButtonOnClicked(Base sender, MouseButtonState arguments) + { + ToggleHidden(); + if (Globals.Me?.CombatTimer > Timing.Global.Milliseconds) + { + ShowCombatWarning(); + } + else + { + LogoutToMainMenu(null, null); + } + } + + private void LogoutToMainMenu(object? sender, EventArgs? e) + { + if (Globals.Me != null) + { + Globals.Me.CombatTimer = 0; + } + + Main.Logout(false); + } + + private void ExitToDesktopButtonOnClicked(Base sender, MouseButtonState arguments) + { + ToggleHidden(); + if (Globals.Me?.CombatTimer > Timing.Global.Milliseconds) + { + ShowCombatWarning(); + } + else + { + ExitToDesktop(null, null); + } + } + + private void ShowCombatWarning() + { + AlertWindow.Open( + Strings.Combat.WarningCharacterSelect, + Strings.Combat.WarningTitle, + AlertType.Warning, + handleSubmit: LogoutToCharacterSelect, + inputType: InputType.YesNo + ); + } + + private void ExitToDesktop(object? sender, EventArgs? e) + { + if (Globals.Me != null) + { + Globals.Me.CombatTimer = 0; + } + + Globals.IsRunning = false; + } +} \ No newline at end of file diff --git a/Intersect.Client.Framework/Gwen/Control/Base.cs b/Intersect.Client.Framework/Gwen/Control/Base.cs index 1c01ff0b98..45e863b782 100644 --- a/Intersect.Client.Framework/Gwen/Control/Base.cs +++ b/Intersect.Client.Framework/Gwen/Control/Base.cs @@ -1120,6 +1120,11 @@ public bool IsVisibleInTree { get { + if (_disposed) + { + return false; + } + if (!_visible) { return false; @@ -2418,20 +2423,27 @@ public virtual IEnumerable FindAll(Predicate predicate, bool recurse /// Makes the window modal: covers the whole canvas and gets all input. /// /// Determines whether all the background should be dimmed. - public void MakeModal(bool dim = false) + public Modal MakeModal(bool dim = false) { - if (_modal != null) + if (_modal is {} modal) { - return; + return modal; } - _modal = new Modal(Canvas) + if (Canvas is not { } canvas) + { + throw new InvalidOperationException("Tried to make a modal without being attached to a canvas"); + } + + modal = new Modal(canvas) { ShouldDrawBackground = dim, }; + _modal = modal; _previousParent = Parent; - Parent = _modal; + Parent = modal; + return modal; } public void RemoveModal() @@ -3341,6 +3353,28 @@ public bool IsActive } } + public virtual ComponentState ComponentState + { + get + { + var componentState = ComponentState.Normal; + if (IsDisabledByTree) + { + componentState = ComponentState.Disabled; + } + else if (IsActive) + { + componentState = ComponentState.Active; + } + else if (IsHovered) + { + componentState = ComponentState.Hovered; + } + + return componentState; + } + } + public bool IsMouseButtonActive(MouseButton mouseButton) => _mouseButtonPressed.Contains(mouseButton); private readonly HashSet _mouseButtonPressed = []; diff --git a/Intersect.Client.Framework/Gwen/Control/Button.cs b/Intersect.Client.Framework/Gwen/Control/Button.cs index 874e22349e..8e3972e013 100644 --- a/Intersect.Client.Framework/Gwen/Control/Button.cs +++ b/Intersect.Client.Framework/Gwen/Control/Button.cs @@ -265,19 +265,28 @@ public virtual void Toggle() /// Skin to use. protected override void Render(Skin.Base skin) { + skin.DrawButton(this); + base.Render(skin); + } - if (ShouldDrawBackground) + public override ComponentState ComponentState + { + get { - var drawDepressed = IsActive && IsHovered; - if (IsToggle) + var componentState = base.ComponentState; + + if (componentState == ComponentState.Disabled) { - drawDepressed = drawDepressed || ToggleState; + return componentState; } - var bDrawHovered = IsHovered && ShouldDrawHover; + if (IsToggle && ToggleState) + { + componentState = ComponentState.Active; + } - skin.DrawButton(this, drawDepressed, bDrawHovered, IsDisabled, HasFocus); + return componentState; } } diff --git a/Intersect.Client.Framework/Gwen/ControlInternal/CloseButton.cs b/Intersect.Client.Framework/Gwen/ControlInternal/CloseButton.cs index 8fd781b1f5..688ecfb834 100644 --- a/Intersect.Client.Framework/Gwen/ControlInternal/CloseButton.cs +++ b/Intersect.Client.Framework/Gwen/ControlInternal/CloseButton.cs @@ -28,7 +28,7 @@ public CloseButton(Base parent, WindowControl owner, string? name = null) : base /// Skin to use. protected override void Render(Skin.Base skin) { - skin.DrawWindowCloseButton(this, IsActive && IsHovered, IsHovered && ShouldDrawHover, !mWindow.IsOnTop); + skin.DrawWindowCloseButton(this); } } diff --git a/Intersect.Client.Framework/Gwen/ControlInternal/SplitterBar.cs b/Intersect.Client.Framework/Gwen/ControlInternal/SplitterBar.cs index 9df8d3acb9..38f6a73d70 100644 --- a/Intersect.Client.Framework/Gwen/ControlInternal/SplitterBar.cs +++ b/Intersect.Client.Framework/Gwen/ControlInternal/SplitterBar.cs @@ -27,7 +27,7 @@ protected override void Render(Skin.Base skin) { if (ShouldDrawBackground) { - skin.DrawButton(this, true, false, IsDisabled, HasFocus); + skin.DrawSplitter(this); } } diff --git a/Intersect.Client.Framework/Gwen/Skin/Base.cs b/Intersect.Client.Framework/Gwen/Skin/Base.cs index 7a010889d7..0f27a9728b 100644 --- a/Intersect.Client.Framework/Gwen/Skin/Base.cs +++ b/Intersect.Client.Framework/Gwen/Skin/Base.cs @@ -67,7 +67,11 @@ public virtual void Dispose() #region UI elements - public virtual void DrawButton(Control.Base control, bool depressed, bool hovered, bool disabled, bool focused) + public virtual void DrawSplitter(SplitterBar splitterBar) + { + } + + public virtual void DrawButton(Button button) { } @@ -127,7 +131,7 @@ public virtual void DrawWindow(Control.Base control, int topHeight, bool inFocus { } - public virtual void DrawWindowCloseButton(CloseButton closeButton, bool depressed, bool hovered, bool disabled) + public virtual void DrawWindowCloseButton(CloseButton closeButton) { } diff --git a/Intersect.Client.Framework/Gwen/Skin/Intersect2021.cs b/Intersect.Client.Framework/Gwen/Skin/Intersect2021.cs index 3294534414..99821e654c 100644 --- a/Intersect.Client.Framework/Gwen/Skin/Intersect2021.cs +++ b/Intersect.Client.Framework/Gwen/Skin/Intersect2021.cs @@ -41,10 +41,13 @@ protected override void InitializeTextures() mTextures.Window.Inactive = new Bordered(_texture, 16, 24, 16, 16, new Margin(4, 4, 4, 4)); mTextures.Window.InactiveTitleBar = new Bordered(_texture, 16, 0, 16, 24, new Margin(4, 4, 4, 4)); - mTextures.Window.CloseButton.Normal = new FivePatch(_texture, 60, 0, 24, 24, Margin.Two, Margin.One); - mTextures.Window.CloseButton.Active = new FivePatch(_texture, 60, 24, 24, 24, Margin.Two, Margin.One); - mTextures.Window.CloseButton.Disabled = new FivePatch(_texture, 60, 48, 24, 24, Margin.Two, Margin.One); - mTextures.Window.CloseButton.Hovered = new FivePatch(_texture, 60, 72, 24, 24, Margin.Two, Margin.One); + mTextures.Window.CloseButton = new SkinTextures._Input._Button + { + Normal = new FivePatch(_texture, 60, 0, 24, 24, Margin.Two, Margin.One), + Disabled = new FivePatch(_texture, 60, 48, 24, 24, Margin.Two, Margin.One), + Hovered = new FivePatch(_texture, 60, 72, 24, 24, Margin.Two, Margin.One), + Active = new FivePatch(_texture, 60, 24, 24, 24, Margin.Two, Margin.One), + }; mTextures.Panel.Control = new Bordered(_texture, 32, 0, 16, 16, Margin.Four); mTextures.Panel.Normal = new Bordered(_texture, 32, 0, 16, 16, Margin.Four); diff --git a/Intersect.Client.Framework/Gwen/Skin/IntersectSkin.cs b/Intersect.Client.Framework/Gwen/Skin/IntersectSkin.cs index 052b086d8e..8822149012 100644 --- a/Intersect.Client.Framework/Gwen/Skin/IntersectSkin.cs +++ b/Intersect.Client.Framework/Gwen/Skin/IntersectSkin.cs @@ -207,10 +207,13 @@ protected override void InitializeTextures() mTextures.Window.Inactive = new Bordered(_texture, 16, 24, 16, 16, Margin.Four); mTextures.Window.InactiveTitleBar = new Bordered(_texture, 16, 0, 16, 24, Margin.Four); - mTextures.Window.CloseButton.Normal = new FivePatch(_texture, 60, 0, 24, 24, Margin.Two, Margin.Two); - mTextures.Window.CloseButton.Disabled = new FivePatch(_texture, 60, 48, 24, 24, Margin.Two, Margin.Two); - mTextures.Window.CloseButton.Hovered = new FivePatch(_texture, 60, 72, 24, 24, Margin.Two, Margin.Two); - mTextures.Window.CloseButton.Active = new FivePatch(_texture, 60, 24, 24, 24, Margin.Two, Margin.Two); + mTextures.Window.CloseButton = new SkinTextures._Input._Button + { + Normal = new FivePatch(_texture, 60, 0, 24, 24, Margin.Two, Margin.Two), + Disabled = new FivePatch(_texture, 60, 48, 24, 24, Margin.Two, Margin.Two), + Hovered = new FivePatch(_texture, 60, 72, 24, 24, Margin.Two, Margin.Two), + Active = new FivePatch(_texture, 60, 24, 24, 24, Margin.Two, Margin.Two), + }; } #endregion diff --git a/Intersect.Client.Framework/Gwen/Skin/Simple.cs b/Intersect.Client.Framework/Gwen/Skin/Simple.cs index 06b0c2a3fe..35806c1957 100644 --- a/Intersect.Client.Framework/Gwen/Skin/Simple.cs +++ b/Intersect.Client.Framework/Gwen/Skin/Simple.cs @@ -1,4 +1,5 @@ using Intersect.Client.Framework.GenericClasses; +using Intersect.Client.Framework.Gwen.Control; using Intersect.Client.Framework.Gwen.ControlInternal; namespace Intersect.Client.Framework.Gwen.Skin; @@ -66,12 +67,15 @@ public Simple(Renderer.Base renderer) : base(renderer) #region UI elements - public override void DrawButton(Control.Base control, bool depressed, bool hovered, bool disabled, bool focused) + public override void DrawButton(Button button) { - var w = control.Width; - var h = control.Height; - - DrawButton(w, h, depressed, hovered); + var componentState = button.ComponentState; + DrawButton( + button.Width, + button.Height, + componentState == ComponentState.Active, + componentState == ComponentState.Hovered + ); } public override void DrawMenuItem(Control.Base control, bool submenuOpen, bool isChecked) @@ -471,10 +475,15 @@ public override void DrawWindow(Control.Base control, int topHeight, bool inFocu mRenderer.DrawShavedCornerRect(new Rectangle(rect.X, rect.Y, rect.Width, rect.Height)); } - public override void DrawWindowCloseButton(CloseButton closeButton, bool depressed, bool hovered, bool disabled) + public override void DrawWindowCloseButton(CloseButton closeButton) { - // TODO - DrawButton(closeButton, depressed, hovered, disabled, closeButton.HasFocus); + var componentState = closeButton.ComponentState; + DrawButton( + closeButton.Width, + closeButton.Height, + componentState == ComponentState.Active, + componentState == ComponentState.Hovered + ); } public override void DrawHighlight(Control.Base control) @@ -501,8 +510,13 @@ public override void DrawScrollBar(Control.Base control, bool horizontal, bool d public override void DrawScrollBarBar(ScrollBarBar scrollBarBar) { - //TODO: something specialized - DrawButton(scrollBarBar, scrollBarBar.IsActive, scrollBarBar.IsHovered, scrollBarBar.IsDisabledByTree, scrollBarBar.HasFocus); + var componentState = scrollBarBar.ComponentState; + DrawButton( + scrollBarBar.Width, + scrollBarBar.Height, + componentState == ComponentState.Active, + componentState == ComponentState.Hovered + ); } public override void DrawTabTitleBar(Control.Base control) @@ -672,7 +686,13 @@ public override void DrawScrollButton( bool disabled ) { - DrawButton(control, depressed, false, false, control.HasFocus); + var componentState = control.ComponentState; + DrawButton( + control.Width, + control.Height, + componentState == ComponentState.Active, + componentState == ComponentState.Hovered + ); mRenderer.DrawColor = Color.FromArgb(240, 0, 0, 0); @@ -853,7 +873,13 @@ public override void DrawMenuRightArrow(Control.Base control) public override void DrawSliderButton(SliderBar sliderBar) { - DrawButton(sliderBar, sliderBar.IsActive, sliderBar.IsHovered, sliderBar.IsDisabled, sliderBar.HasFocus); + var componentState = sliderBar.ComponentState; + DrawButton( + sliderBar.Width, + sliderBar.Height, + componentState == ComponentState.Active, + componentState == ComponentState.Hovered + ); } public override void DrawCategoryHolder(Control.Base control) diff --git a/Intersect.Client.Framework/Gwen/Skin/TexturedBase.cs b/Intersect.Client.Framework/Gwen/Skin/TexturedBase.cs index 3a0780d7de..11a0fb6540 100644 --- a/Intersect.Client.Framework/Gwen/Skin/TexturedBase.cs +++ b/Intersect.Client.Framework/Gwen/Skin/TexturedBase.cs @@ -41,14 +41,6 @@ public partial struct _Panel } - public partial struct _FivePatchButton - { - public FivePatch Normal; - public FivePatch Disabled; - public FivePatch Hovered; - public FivePatch Active; - } - public partial struct _Window { @@ -60,7 +52,7 @@ public partial struct _Window public Bordered InactiveTitleBar; - public _FivePatchButton CloseButton; + public _Input._Button CloseButton; } @@ -192,10 +184,10 @@ public partial struct _Input { public partial struct _Button { - public Bordered Normal; - public Bordered Disabled; - public Bordered Hovered; - public Bordered Active; + public IAtlasDrawable Normal; + public IAtlasDrawable Disabled; + public IAtlasDrawable Hovered; + public IAtlasDrawable Active; } public partial struct _ComboBox @@ -600,10 +592,13 @@ protected virtual void InitializeTextures() mTextures.Tab.Right.Inactive = new Bordered(_texture, 96 + 128, 384, 31, 63, Margin.Eight); mTextures.Tab.HeaderBar = new Bordered(_texture, 128, 352, 127, 31, Margin.Four); - mTextures.Window.CloseButton.Normal = new Bordered(_texture, 0, 224, 24, 24, default); - mTextures.Window.CloseButton.Hovered = new Bordered(_texture, 64, 224, 24, 24, default); - mTextures.Window.CloseButton.Disabled = new Bordered(_texture, 32, 224, 24, 24, default); - mTextures.Window.CloseButton.Active = new Bordered(_texture, 96, 224, 24, 24, default); + mTextures.Window.CloseButton = new SkinTextures._Input._Button + { + Normal = new Bordered(_texture, 0, 224, 24, 24, default), + Disabled = new Bordered(_texture, 32, 224, 24, 24, default), + Hovered = new Bordered(_texture, 64, 224, 24, 24, default), + Active = new Bordered(_texture, 96, 224, 24, 24, default), + }; mTextures.Scroller.TrackV = new Bordered(_texture, 384, 208, 15, 127, Margin.Four); mTextures.Scroller.BarV.Normal = new Bordered(_texture, 384 + 16, 208, 15, 127, Margin.Four); @@ -688,52 +683,38 @@ protected virtual void InitializeTextures() #region UI elements - public override void DrawButton(Control.Base control, bool depressed, bool hovered, bool disabled, bool focused) + public override void DrawSplitter(SplitterBar splitterBar) { - if (control is not Button button) - { - return; - } - - ComponentState componentState = ComponentState.Normal; - if (disabled) - { - componentState = ComponentState.Disabled; - } - else if (depressed) - { - componentState = ComponentState.Active; - } - else if (hovered) - { - componentState = ComponentState.Hovered; - } - - var controlStateTexture = button.GetStateTexture(componentState); - controlStateTexture ??= button.GetStateTexture(ComponentState.Normal); + throw new NotImplementedException(); + } - if (controlStateTexture == null) + protected virtual void DrawButton( + Button button, + SkinTextures._Input._Button textureGroup + ) + { + var componentState = button.ComponentState; + var stateTexture = button.GetStateTexture(componentState); + if (stateTexture == null) { - var buttonTextureGroup = mTextures.Input.Button; - var target = componentState switch + var drawable = componentState switch { - ComponentState.Normal => buttonTextureGroup.Normal, - ComponentState.Hovered => buttonTextureGroup.Hovered, - ComponentState.Active => buttonTextureGroup.Active, - ComponentState.Disabled => buttonTextureGroup.Disabled, + ComponentState.Normal => textureGroup.Normal, + ComponentState.Hovered => textureGroup.Hovered, + ComponentState.Active => textureGroup.Active, + ComponentState.Disabled => textureGroup.Disabled, _ => throw new UnreachableException(), }; - - target.Draw(Renderer, button.RenderBounds, button.RenderColor); + drawable.Draw(Renderer, button.RenderBounds, button.RenderColor); } else { Renderer.DrawColor = button.RenderColor; - Renderer.DrawTexturedRect(controlStateTexture, button.RenderBounds, button.RenderColor); + Renderer.DrawTexturedRect(stateTexture, button.RenderBounds, button.RenderColor); } // ReSharper disable once InvertIf - if (focused) + if (button.HasFocus) { Renderer.PushDrawColor(Color.White); Renderer.PushLineThickness(1); @@ -743,6 +724,16 @@ public override void DrawButton(Control.Base control, bool depressed, bool hover } } + public override void DrawButton(Button button) + { + DrawButton(button, mTextures.Input.Button); + } + + public override void DrawWindowCloseButton(CloseButton closeButton) + { + DrawButton(closeButton, mTextures.Window.CloseButton); + } + public override void DrawMenuRightArrow(Control.Base control) { mTextures.Menu.RightArrow.Draw(Renderer, control.RenderBounds, control.RenderColor); @@ -2327,58 +2318,6 @@ public override void DrawMenuDivider(Control.Base control) Renderer.DrawFilledRect(rect); } - public override void DrawWindowCloseButton(CloseButton closeButton, bool depressed, bool hovered, bool disabled) - { - IGameTexture renderImg = null; - if (disabled && closeButton.GetStateTexture(ComponentState.Disabled) != null) - { - renderImg = closeButton.GetStateTexture(ComponentState.Disabled); - } - else if (depressed && closeButton.GetStateTexture(ComponentState.Active) != null) - { - renderImg = closeButton.GetStateTexture(ComponentState.Active); - } - else if (hovered && closeButton.GetStateTexture(ComponentState.Hovered) != null) - { - renderImg = closeButton.GetStateTexture(ComponentState.Hovered); - } - else if (closeButton.GetStateTexture(ComponentState.Normal) != null) - { - renderImg = closeButton.GetStateTexture(ComponentState.Normal); - } - - if (renderImg != null) - { - Renderer.DrawColor = closeButton.RenderColor; - Renderer.DrawTexturedRect(renderImg, closeButton.RenderBounds, closeButton.RenderColor); - - return; - } - - if (disabled) - { - mTextures.Window.CloseButton.Disabled.Draw(Renderer, closeButton.RenderBounds, closeButton.RenderColor); - - return; - } - - if (depressed) - { - mTextures.Window.CloseButton.Active.Draw(Renderer, closeButton.RenderBounds, closeButton.RenderColor); - - return; - } - - if (hovered) - { - mTextures.Window.CloseButton.Hovered.Draw(Renderer, closeButton.RenderBounds, closeButton.RenderColor); - - return; - } - - mTextures.Window.CloseButton.Normal.Draw(Renderer, closeButton.RenderBounds, closeButton.RenderColor); - } - public override void DrawSliderButton(SliderBar sliderBar) { var overrideTexture = sliderBar.GetImage(ComponentState.Normal); diff --git a/Intersect.Client.Framework/Gwen/Skin/Texturing/Bordered.cs b/Intersect.Client.Framework/Gwen/Skin/Texturing/Bordered.cs index d0ef128f95..235c2d7842 100644 --- a/Intersect.Client.Framework/Gwen/Skin/Texturing/Bordered.cs +++ b/Intersect.Client.Framework/Gwen/Skin/Texturing/Bordered.cs @@ -14,7 +14,7 @@ public partial struct SubRect /// /// 3x3 texture grid. /// -public partial struct Bordered : IEquatable +public partial struct Bordered : IEquatable, IAtlasDrawable { private readonly float mX; private readonly float mY; diff --git a/Intersect.Client.Framework/Gwen/Skin/Texturing/FivePatch.cs b/Intersect.Client.Framework/Gwen/Skin/Texturing/FivePatch.cs index 72a82a4916..930165856c 100644 --- a/Intersect.Client.Framework/Gwen/Skin/Texturing/FivePatch.cs +++ b/Intersect.Client.Framework/Gwen/Skin/Texturing/FivePatch.cs @@ -4,7 +4,7 @@ namespace Intersect.Client.Framework.Gwen.Skin.Texturing; -public readonly record struct FivePatch +public readonly record struct FivePatch : IAtlasDrawable { private readonly IGameTexture _texture; private readonly float _textureWidth; diff --git a/Intersect.Client.Framework/Gwen/Skin/Texturing/IAtlasDrawable.cs b/Intersect.Client.Framework/Gwen/Skin/Texturing/IAtlasDrawable.cs new file mode 100644 index 0000000000..78f3729aa2 --- /dev/null +++ b/Intersect.Client.Framework/Gwen/Skin/Texturing/IAtlasDrawable.cs @@ -0,0 +1,8 @@ +using Intersect.Client.Framework.GenericClasses; + +namespace Intersect.Client.Framework.Gwen.Skin.Texturing; + +public interface IAtlasDrawable +{ + void Draw(Renderer.Base renderer, Rectangle targetBounds, Color color); +} \ No newline at end of file diff --git a/Intersect.Client.Framework/Gwen/Skin/Texturing/Single.cs b/Intersect.Client.Framework/Gwen/Skin/Texturing/Single.cs index ad38a222f3..65a9e4a89c 100644 --- a/Intersect.Client.Framework/Gwen/Skin/Texturing/Single.cs +++ b/Intersect.Client.Framework/Gwen/Skin/Texturing/Single.cs @@ -7,7 +7,7 @@ namespace Intersect.Client.Framework.Gwen.Skin.Texturing; /// /// Single textured element. /// -public partial struct Single +public partial struct Single : IAtlasDrawable { private readonly IGameTexture mTexture;