#region Copyright & License Information /* * Copyright (c) The OpenRA Developers and Contributors * 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.Graphics; using OpenRA.Primitives; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets { public class ButtonWidget : InputWidget { public readonly string TooltipContainer; public readonly string TooltipTemplate = "BUTTON_TOOLTIP"; public HotkeyReference Key = new(); public bool DisableKeyRepeat = false; public bool DisableKeySound = false; [FluentReference] public string Text = ""; public TextAlign Align = TextAlign.Center; public int LeftMargin = 5; public int RightMargin = 5; public string Background = "button"; public bool Depressed = false; public int VisualHeight = ChromeMetrics.Get("ButtonDepth"); public string Font = ChromeMetrics.Get("ButtonFont"); public Color TextColor = ChromeMetrics.Get("ButtonTextColor"); public Color TextColorDisabled = ChromeMetrics.Get("ButtonTextColorDisabled"); public bool Contrast = ChromeMetrics.Get("ButtonTextContrast"); public bool Shadow = ChromeMetrics.Get("ButtonTextShadow"); public Color ContrastColorDark = ChromeMetrics.Get("ButtonTextContrastColorDark"); public Color ContrastColorLight = ChromeMetrics.Get("ButtonTextContrastColorLight"); public int ContrastRadius = ChromeMetrics.Get("ButtonTextContrastRadius"); public string ClickSound = ChromeMetrics.Get("ClickSound"); public string ClickDisabledSound = ChromeMetrics.Get("ClickDisabledSound"); public bool Highlighted = false; public Func GetText; public Func GetColor; public Func GetColorDisabled; public Func GetContrastColorDark; public Func GetContrastColorLight; public Func IsHighlighted; public Action OnMouseDown = _ => { }; public Action OnMouseUp = _ => { }; protected Lazy tooltipContainer; [FluentReference] public string TooltipText; public Func GetTooltipText; [FluentReference] public string TooltipDesc; public Func GetTooltipDesc; // Equivalent to OnMouseUp, but without an input arg public Action OnClick = () => { }; public Action OnDoubleClick = null; public Action OnKeyPress = _ => { }; public string Cursor = ChromeMetrics.Get("ButtonCursor"); protected readonly Ruleset ModRules; [ObjectCreator.UseCtor] public ButtonWidget(ModData modData) { ModRules = modData.DefaultRules; var textCache = new CachedTransform(s => !string.IsNullOrEmpty(s) ? FluentProvider.GetMessage(s) : ""); var tooltipTextCache = new CachedTransform(s => !string.IsNullOrEmpty(s) ? FluentProvider.GetMessage(s) : ""); var tooltipDescCache = new CachedTransform(s => !string.IsNullOrEmpty(s) ? FluentProvider.GetMessage(s) : ""); GetText = () => textCache.Update(Text); GetColor = () => TextColor; GetColorDisabled = () => TextColorDisabled; GetContrastColorDark = () => ContrastColorDark; GetContrastColorLight = () => ContrastColorLight; OnMouseUp = _ => OnClick(); OnKeyPress = _ => OnClick(); IsHighlighted = () => Highlighted; GetTooltipText = () => tooltipTextCache.Update(TooltipText); GetTooltipDesc = () => tooltipDescCache.Update(TooltipDesc); tooltipContainer = Exts.Lazy(() => Ui.Root.Get(TooltipContainer)); } protected ButtonWidget(ButtonWidget other) : base(other) { ModRules = other.ModRules; Text = other.Text; Align = other.Align; LeftMargin = other.LeftMargin; RightMargin = other.RightMargin; Font = other.Font; TextColor = other.TextColor; TextColorDisabled = other.TextColorDisabled; Contrast = other.Contrast; Shadow = other.Shadow; Depressed = other.Depressed; Background = other.Background; VisualHeight = other.VisualHeight; GetText = other.GetText; GetColor = other.GetColor; GetColorDisabled = other.GetColorDisabled; ContrastColorDark = other.ContrastColorDark; ContrastColorLight = other.ContrastColorLight; ContrastRadius = other.ContrastRadius; GetContrastColorDark = other.GetContrastColorDark; GetContrastColorLight = other.GetContrastColorLight; OnMouseDown = other.OnMouseDown; Disabled = other.Disabled; Highlighted = other.Highlighted; IsHighlighted = other.IsHighlighted; OnMouseUp = mi => OnClick(); OnKeyPress = _ => OnClick(); TooltipTemplate = other.TooltipTemplate; TooltipText = other.TooltipText; GetTooltipText = other.GetTooltipText; TooltipDesc = other.TooltipDesc; GetTooltipDesc = other.GetTooltipDesc; TooltipContainer = other.TooltipContainer; tooltipContainer = Exts.Lazy(() => Ui.Root.Get(TooltipContainer)); } public override bool YieldMouseFocus(MouseInput mi) { Depressed = false; return base.YieldMouseFocus(mi); } public override bool HandleKeyPress(KeyInput e) { if (!Key.IsActivatedBy(e) || e.Event != KeyInputEvent.Down || (DisableKeyRepeat && e.IsRepeat)) return false; if (!IsDisabled()) { OnKeyPress(e); if (!DisableKeySound) Game.Sound.PlayNotification(ModRules, null, "Sounds", ClickSound, null); } else if (!DisableKeySound) Game.Sound.PlayNotification(ModRules, null, "Sounds", ClickDisabledSound, null); return true; } public override bool HandleMouseInput(MouseInput mi) { if (mi.Button != MouseButton.Left) return false; if (mi.Event == MouseInputEvent.Down && !TakeMouseFocus(mi)) return false; var disabled = IsDisabled(); if (HasMouseFocus && mi.Event == MouseInputEvent.Up && mi.MultiTapCount == 2 && OnDoubleClick != null) { if (!disabled) { OnDoubleClick(); return YieldMouseFocus(mi); } } else if (HasMouseFocus && mi.Event == MouseInputEvent.Up) { // Only fire the onMouseUp event if we successfully lost focus, and were pressed if (Depressed && !disabled) OnMouseUp(mi); return YieldMouseFocus(mi); } if (mi.Event == MouseInputEvent.Down) { // OnMouseDown returns false if the button shouldn't be pressed if (!disabled) { OnMouseDown(mi); Depressed = true; Game.Sound.PlayNotification(ModRules, null, "Sounds", ClickSound, null); } else { YieldMouseFocus(mi); Game.Sound.PlayNotification(ModRules, null, "Sounds", ClickDisabledSound, null); } } else if (mi.Event == MouseInputEvent.Move && HasMouseFocus) Depressed = RenderBounds.Contains(mi.Location); return Depressed; } public override void MouseEntered() { if (TooltipContainer == null) return; if (GetTooltipText != null) tooltipContainer.Value.SetTooltip(TooltipTemplate, new WidgetArgs { { "button", this }, { "getText", GetTooltipText }, { "getDesc", GetTooltipDesc } }); } public override void MouseExited() { if (TooltipContainer == null || !tooltipContainer.IsValueCreated) return; tooltipContainer.Value.RemoveTooltip(); } public override string GetCursor(int2 pos) { return Cursor; } public override int2 ChildOrigin => RenderOrigin + (Depressed ? new int2(VisualHeight, VisualHeight) : new int2(0, 0)); public override void Draw() { var rb = RenderBounds; var disabled = IsDisabled(); var highlighted = IsHighlighted(); var font = Game.Renderer.Fonts[Font]; var text = GetText(); var color = GetColor(); var colordisabled = GetColorDisabled(); var bgDark = GetContrastColorDark(); var bgLight = GetContrastColorLight(); var stateOffset = Depressed ? new int2(VisualHeight, VisualHeight) : new int2(0, 0); var position = GetTextPosition(text, font, rb); var hover = Ui.MouseOverWidget == this || Children.FirstOrDefault(c => c == Ui.MouseOverWidget) != null; DrawBackground(rb, disabled, Depressed, hover, highlighted); if (Contrast) font.DrawTextWithContrast(text, position + stateOffset, disabled ? colordisabled : color, bgDark, bgLight, ContrastRadius); else if (Shadow) font.DrawTextWithShadow(text, position, color, bgDark, bgLight, 1); else font.DrawText(text, position + stateOffset, disabled ? colordisabled : color); } int2 GetTextPosition(string text, SpriteFont font, Rectangle rb) { var textSize = font.Measure(text); var y = rb.Y + (Bounds.Height - textSize.Y - font.TopOffset) / 2; switch (Align) { case TextAlign.Left: return new int2(rb.X + LeftMargin, y); case TextAlign.Center: default: return new int2(rb.X + (UsableWidth - textSize.X) / 2, y); case TextAlign.Right: return new int2(rb.X + UsableWidth - textSize.X - RightMargin, y); } } public override Widget Clone() { return new ButtonWidget(this); } public virtual int UsableWidth => Bounds.Width; public virtual void DrawBackground(Rectangle rect, bool disabled, bool pressed, bool hover, bool highlighted) { DrawBackground(Background, rect, disabled, pressed, hover, highlighted); } public static void DrawBackground(string baseName, Rectangle rect, bool disabled, bool pressed, bool hover, bool highlighted) { if (string.IsNullOrEmpty(baseName)) return; var variantName = highlighted ? baseName + "-highlighted" : baseName; var imageName = WidgetUtils.GetStatefulImageName(variantName, disabled, pressed, hover); WidgetUtils.DrawPanel(imageName, rect); } } }