From f61c87f0d2a852c63de404764bcbdaa91656828e Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Thu, 15 Apr 2010 19:06:01 +1200 Subject: [PATCH] converted moneybin to widget; generic tooltip hax --- OpenRA.Game/Chrome.cs | 40 +----- OpenRA.Game/OpenRA.Game.csproj | 1 + OpenRA.Game/Traits/Chrome/PowerDownButton.cs | 16 +++ OpenRA.Game/Traits/TraitsInterfaces.cs | 2 + OpenRA.Game/Widgets/ButtonWidget.cs | 7 +- OpenRA.Game/Widgets/MoneyBinWidget.cs | 140 +++++++++++++++++++ OpenRA.Game/Widgets/WidgetUtils.cs | 123 ++++++++++++---- mods/ra/menus.yaml | 6 + 8 files changed, 266 insertions(+), 69 deletions(-) create mode 100644 OpenRA.Game/Widgets/MoneyBinWidget.cs diff --git a/OpenRA.Game/Chrome.cs b/OpenRA.Game/Chrome.cs index bd4d808dba..665998d985 100644 --- a/OpenRA.Game/Chrome.cs +++ b/OpenRA.Game/Chrome.cs @@ -21,12 +21,10 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.IO; using System.Linq; using OpenRA.FileFormats; using OpenRA.Graphics; using OpenRA.Orders; -using OpenRA.Support; using OpenRA.Traits; using OpenRA.Widgets; @@ -43,7 +41,6 @@ namespace OpenRA string chromeCollection; string radarCollection; string paletteCollection; - string digitCollection; // Build Palette tabs string currentTab = "Building"; @@ -151,10 +148,9 @@ namespace OpenRA public void Draw( World world ) { - chromeCollection = "chrome-" + world.LocalPlayer.Country.Race; radarCollection = "radar-" + world.LocalPlayer.Country.Race; paletteCollection = "palette-" + world.LocalPlayer.Country.Race; - digitCollection = "digits-" + world.LocalPlayer.Country.Race; + chromeCollection = "chrome-" + world.LocalPlayer.Country.Race; buttons.Clear(); @@ -162,10 +158,7 @@ namespace OpenRA DrawRadar( world ); DrawPower( world ); - rgbaRenderer.DrawSprite(ChromeProvider.GetImage(renderer, chromeCollection, "moneybin"), new float2(Game.viewport.Width - 320, 0), "chrome"); - DrawMoney( world ); rgbaRenderer.Flush(); - DrawButtons( world ); int paletteHeight = DrawBuildPalette(world, currentTab); DrawBuildTabs(world, paletteHeight); @@ -622,17 +615,6 @@ namespace OpenRA Game.IssueOrder(Order.CancelProduction(world.LocalPlayer, item.Item)); } - void DrawMoney( World world ) - { - var moneyDigits = world.LocalPlayer.DisplayCash.ToString(); - var x = Game.viewport.Width - 65; - foreach (var d in moneyDigits.Reverse()) - { - rgbaRenderer.DrawSprite(ChromeProvider.GetImage(renderer, digitCollection, (d - '0').ToString()), new float2(x, 6), "chrome"); - x -= 14; - } - } - float? lastPowerProvidedPos; float? lastPowerDrainedPos; @@ -687,26 +669,6 @@ namespace OpenRA rgbaRenderer.Flush(); } - const int chromeButtonGap = 2; - - void DrawButtons( World world ) - { - var origin = new int2(Game.viewport.Width - 200, 2); - - foreach (var cb in world.WorldActor.traits.WithInterface()) - { - var state = cb.Enabled ? cb.Pressed ? "pressed" : "normal" : "disabled"; - var image = ChromeProvider.GetImage(renderer, cb.Image + "-button", state); - - origin.X -= (int)image.size.X + chromeButtonGap; - rgbaRenderer.DrawSprite(image, origin, "chrome"); - - var button = cb; - AddButton(new RectangleF(origin.X, origin.Y, image.size.X, image.size.Y), - _ => { if (button.Enabled) button.OnClick(); }); - } - } - void DrawDialogBackground(Rectangle r, string collection) { renderer.Device.EnableScissor(r.Left, r.Top, r.Width, r.Height); diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index 6e750f90b5..6bced162e1 100755 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -91,6 +91,7 @@ + diff --git a/OpenRA.Game/Traits/Chrome/PowerDownButton.cs b/OpenRA.Game/Traits/Chrome/PowerDownButton.cs index f478af29d7..1e9860f873 100644 --- a/OpenRA.Game/Traits/Chrome/PowerDownButton.cs +++ b/OpenRA.Game/Traits/Chrome/PowerDownButton.cs @@ -12,6 +12,9 @@ namespace OpenRA.Traits public bool Enabled { get { return true; } } public bool Pressed { get { return Game.controller.orderGenerator is PowerDownOrderGenerator; } } public void OnClick() { Game.controller.ToggleInputMode(); } + + public string Description { get { return "Powerdown"; } } + public string LongDesc { get { return "Disable unneeded structures so their \npower can be used elsewhere"; } } } class SellButtonInfo : TraitInfo { } @@ -22,6 +25,9 @@ namespace OpenRA.Traits public bool Enabled { get { return true; } } public bool Pressed { get { return Game.controller.orderGenerator is SellOrderGenerator; } } public void OnClick() { Game.controller.ToggleInputMode(); } + + public string Description { get { return "Sell"; } } + public string LongDesc { get { return "Sell buildings, reclaiming a \nproportion of their build cost"; } } } class RepairButtonInfo : ITraitInfo @@ -48,5 +54,15 @@ namespace OpenRA.Traits public bool Pressed { get { return Game.controller.orderGenerator is RepairOrderGenerator; } } public void OnClick() { Game.controller.ToggleInputMode(); } + + public string Description { get { return "Repair"; } } + public string LongDesc + { + get + { + var s = "Repair damaged buildings"; + return Enabled ? s : s + "\n\nRequires: Construction Yard"; + } + } } } diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index b86406d04a..2f5a7976a6 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -123,6 +123,8 @@ namespace OpenRA.Traits bool Enabled { get; } bool Pressed { get; } void OnClick(); + string Description { get; } + string LongDesc { get; } } public interface IRenderOverlay { void Render(); } diff --git a/OpenRA.Game/Widgets/ButtonWidget.cs b/OpenRA.Game/Widgets/ButtonWidget.cs index b8a3ea63cb..026c8fbfcb 100644 --- a/OpenRA.Game/Widgets/ButtonWidget.cs +++ b/OpenRA.Game/Widgets/ButtonWidget.cs @@ -70,11 +70,12 @@ namespace OpenRA.Widgets } var stateOffset = (Depressed) ? new int2(VisualHeight, VisualHeight) : new int2(0, 0); - WidgetUtils.DrawPanel(Depressed ? "dialog3" : "dialog2", Bounds, - () => Game.chrome.renderer.BoldFont.DrawText(Text, + WidgetUtils.DrawPanel(Depressed ? "dialog3" : "dialog2", Bounds, null); + + Game.chrome.renderer.BoldFont.DrawText(Text, new int2(Bounds.X + Bounds.Width / 2, Bounds.Y + Bounds.Height / 2) - new int2(Game.chrome.renderer.BoldFont.Measure(Text).X / 2, - Game.chrome.renderer.BoldFont.Measure(Text).Y / 2) + stateOffset, Color.White)); + Game.chrome.renderer.BoldFont.Measure(Text).Y / 2) + stateOffset, Color.White); base.Draw(world); } diff --git a/OpenRA.Game/Widgets/MoneyBinWidget.cs b/OpenRA.Game/Widgets/MoneyBinWidget.cs new file mode 100644 index 0000000000..604603e313 --- /dev/null +++ b/OpenRA.Game/Widgets/MoneyBinWidget.cs @@ -0,0 +1,140 @@ +#region Copyright & License Information +/* + * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford. + * This file is part of OpenRA. + * + * OpenRA is free software: you can redistribute it and/or modify + * it 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. + * + * OpenRA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenRA. If not, see . + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Widgets +{ + class MoneyBinWidget : Widget + { + const int chromeButtonGap = 2; + + /* legacy crap!!! */ + List>> buttons = new List>>(); + void AddButton(Rectangle r, Action b) { buttons.Add(Pair.New(r, b)); } + + public override void Draw(World world) + { + var digitCollection = "digits-" + world.LocalPlayer.Country.Race; + var chromeCollection = "chrome-" + world.LocalPlayer.Country.Race; + + Game.chrome.renderer.RgbaSpriteRenderer.DrawSprite( + ChromeProvider.GetImage(Game.chrome.renderer, chromeCollection, "moneybin"), + new float2(Bounds.Left, 0), "chrome"); + + var moneyDigits = world.LocalPlayer.DisplayCash.ToString(); + var x = Bounds.Right - 65; + + foreach (var d in moneyDigits.Reverse()) + { + Game.chrome.renderer.RgbaSpriteRenderer.DrawSprite( + ChromeProvider.GetImage(Game.chrome.renderer, digitCollection, (d - '0').ToString()), + new float2(x, 6), "chrome"); + x -= 14; + } + + var origin = new int2(Game.viewport.Width - 200, 2); + + foreach (var cb in world.WorldActor.traits.WithInterface()) + { + var state = cb.Enabled ? cb.Pressed ? "pressed" : "normal" : "disabled"; + var image = ChromeProvider.GetImage(Game.chrome.renderer, cb.Image + "-button", state); + + origin.X -= (int)image.size.X + chromeButtonGap; + + var button = cb; + var rect = new Rectangle(origin.X, origin.Y, (int)image.size.X, (int)image.size.Y); + AddButton(rect, _ => { if (button.Enabled) button.OnClick(); }); + + if (rect.Contains(Game.chrome.lastMousePos.ToPoint())) + { + rect = rect.InflateBy(3, 3, 3, 3); + var pos = new int2(rect.Left, rect.Top); + var m = pos + new int2(rect.Width, rect.Height); + var br = pos + new int2(rect.Width, rect.Height + 20); + + var u = Game.chrome.renderer.RegularFont.Measure(cb.LongDesc.Replace("\\n", "\n")); + + br.X -= u.X; + br.Y += u.Y; + br += new int2(-15, 25); + + var images = new[] { "border-t", "border-b", "border-l", "border-r", "corner-tl", "corner-tr", "corner-bl", "corner-br", "background" }; + var ss = images.Select(i => ChromeProvider.GetImage(Game.chrome.renderer, "dialog4", i)).ToArray(); + + WidgetUtils.DrawPanelPartial("dialog4", rect + .InflateBy(0, 0, 0, (int)ss[1].size.Y), + PanelSides.Top | PanelSides.Left | PanelSides.Right); + + WidgetUtils.DrawPanelPartial("dialog4", new Rectangle(br.X, m.Y, pos.X - br.X, br.Y - m.Y) + .InflateBy(0, 0, (int)ss[3].size.X, 0), + PanelSides.Top | PanelSides.Left | PanelSides.Bottom); + + WidgetUtils.DrawPanelPartial("dialog4", new Rectangle(pos.X, m.Y, m.X - pos.X, br.Y - m.Y) + .InflateBy((int)ss[2].size.X, (int)ss[0].size.Y, 0, 0), + PanelSides.Right | PanelSides.Bottom); + + pos.X = br.X + 8; + pos.Y = m.Y + 8; + Game.chrome.renderer.BoldFont.DrawText(cb.Description, pos, Color.White); + + if (cb.LongDesc != null) + { + pos += new int2(0, 20); + Game.chrome.renderer.RegularFont.DrawText(cb.LongDesc.Replace("\\n", "\n"), pos, Color.White); + } + } + + Game.chrome.renderer.RgbaSpriteRenderer.DrawSprite(image, origin, "chrome"); + } + + Game.chrome.renderer.RgbaSpriteRenderer.Flush(); + } + + public override bool HandleInput(MouseInput mi) + { + // Are we able to handle this event? + if (!Visible || !GetEventBounds().Contains(mi.Location.X, mi.Location.Y)) + return base.HandleInput(mi); + + if (base.HandleInput(mi)) + return true; + + if (mi.Event == MouseInputEvent.Down) + { + var action = buttons.Where(a => a.First.Contains(mi.Location.ToPoint())) + .Select(a => a.Second).FirstOrDefault(); + if (action == null) + return false; + + action(mi); + return true; + } + + return false; + } + } +} diff --git a/OpenRA.Game/Widgets/WidgetUtils.cs b/OpenRA.Game/Widgets/WidgetUtils.cs index 1a680e1ac7..88f51b0a56 100644 --- a/OpenRA.Game/Widgets/WidgetUtils.cs +++ b/OpenRA.Game/Widgets/WidgetUtils.cs @@ -42,54 +42,48 @@ namespace OpenRA.Widgets { Game.chrome.renderer.WorldSpriteRenderer.DrawSprite(s,pos,"chrome"); } - + public static void DrawPanel(string collection, Rectangle Bounds, Action a) { var images = new[] { "border-t", "border-b", "border-l", "border-r", "corner-tl", "corner-tr", "corner-bl", "corner-br", "background" }; var ss = images.Select(i => ChromeProvider.GetImage(Game.chrome.renderer, collection, i)).ToArray(); - + // Background FillRectWithSprite(new Rectangle(Bounds.Left + (int)ss[2].size.X, - Bounds.Top + (int)ss[0].size.Y, - Bounds.Right - (int)ss[3].size.X - Bounds.Left - (int)ss[2].size.X, - Bounds.Bottom - (int)ss[1].size.Y - Bounds.Top - (int)ss[0].size.Y), - ss[8]); + Bounds.Top + (int)ss[0].size.Y, + Bounds.Right - (int)ss[3].size.X - Bounds.Left - (int)ss[2].size.X, + Bounds.Bottom - (int)ss[1].size.Y - Bounds.Top - (int)ss[0].size.Y), ss[8]); // Left border FillRectWithSprite(new Rectangle(Bounds.Left, - Bounds.Top + (int)ss[0].size.Y, - (int)ss[2].size.X, - Bounds.Bottom - (int)ss[1].size.Y - Bounds.Top - (int)ss[0].size.Y), - ss[2]); - + Bounds.Top + (int)ss[0].size.Y, + (int)ss[2].size.X, + Bounds.Bottom - (int)ss[1].size.Y - Bounds.Top - (int)ss[0].size.Y), ss[2]); + // Right border FillRectWithSprite(new Rectangle(Bounds.Right - (int)ss[3].size.X, - Bounds.Top + (int)ss[0].size.Y, - (int)ss[2].size.X, - Bounds.Bottom - (int)ss[1].size.Y - Bounds.Top - (int)ss[0].size.Y), - ss[3]); - + Bounds.Top + (int)ss[0].size.Y, + (int)ss[2].size.X, + Bounds.Bottom - (int)ss[1].size.Y - Bounds.Top - (int)ss[0].size.Y), ss[3]); + // Top border FillRectWithSprite(new Rectangle(Bounds.Left + (int)ss[2].size.X, - Bounds.Top, - Bounds.Right - (int)ss[3].size.X - Bounds.Left - (int)ss[2].size.X, - (int)ss[0].size.Y), - ss[0]); - + Bounds.Top, + Bounds.Right - (int)ss[3].size.X - Bounds.Left - (int)ss[2].size.X, + (int)ss[0].size.Y), ss[0]); + // Bottom border FillRectWithSprite(new Rectangle(Bounds.Left + (int)ss[2].size.X, - Bounds.Bottom - (int)ss[1].size.Y, - Bounds.Right - (int)ss[3].size.X - Bounds.Left - (int)ss[2].size.X, - (int)ss[0].size.Y), - ss[1]); - + Bounds.Bottom - (int)ss[1].size.Y, + Bounds.Right - (int)ss[3].size.X - Bounds.Left - (int)ss[2].size.X, + (int)ss[0].size.Y), ss[1]); + DrawRGBA(ss[4], new float2(Bounds.Left, Bounds.Top)); DrawRGBA(ss[5], new float2(Bounds.Right - ss[5].size.X, Bounds.Top)); DrawRGBA(ss[6], new float2(Bounds.Left, Bounds.Bottom - ss[6].size.Y)); DrawRGBA(ss[7], new float2(Bounds.Right - ss[7].size.X, Bounds.Bottom - ss[7].size.Y)); if (a != null) a(); - Game.chrome.renderer.RgbaSpriteRenderer.Flush(); } public static void FillRectWithSprite(Rectangle r, Sprite s) @@ -108,6 +102,7 @@ namespace OpenRA.Widgets } } + // todo: write this in terms of 3 DrawPanelPartial calls public static void DrawRightTooltip(string collection, int2 tl, int2 m, int2 br, Action a) { var images = new[] { "border-t", "border-b", "border-l", "border-r", "corner-tl", "corner-tr", "corner-bl", "corner-br", "background"}; @@ -192,5 +187,79 @@ namespace OpenRA.Widgets if (a != null) a(); } + + static bool HasFlags(this PanelSides a, PanelSides b) { return (a & b) == b; } + public static Rectangle InflateBy(this Rectangle rect, int l, int t, int r, int b) + { + return Rectangle.FromLTRB(rect.Left - l, rect.Top - t, + rect.Right + r, rect.Bottom + b); + } + + public static void DrawPanelPartial(string collection, Rectangle Bounds, PanelSides ps) + { + var images = new[] { "border-t", "border-b", "border-l", "border-r", "corner-tl", "corner-tr", "corner-bl", "corner-br", "background" }; + var ss = images.Select(i => ChromeProvider.GetImage(Game.chrome.renderer, collection, i)).ToArray(); + + // Background + FillRectWithSprite(new Rectangle(Bounds.Left + (int)ss[2].size.X, + Bounds.Top + (int)ss[0].size.Y, + Bounds.Right - (int)ss[3].size.X - Bounds.Left - (int)ss[2].size.X, + Bounds.Bottom - (int)ss[1].size.Y - Bounds.Top - (int)ss[0].size.Y), + ss[8]); + + // Left border + if (ps.HasFlags(PanelSides.Left)) + FillRectWithSprite(new Rectangle(Bounds.Left, + Bounds.Top + (int)ss[0].size.Y, + (int)ss[2].size.X, + Bounds.Bottom - (int)ss[1].size.Y - Bounds.Top - (int)ss[0].size.Y), + ss[2]); + + // Right border + if (ps.HasFlags(PanelSides.Right)) + FillRectWithSprite(new Rectangle(Bounds.Right - (int)ss[3].size.X, + Bounds.Top + (int)ss[0].size.Y, + (int)ss[2].size.X, + Bounds.Bottom - (int)ss[1].size.Y - Bounds.Top - (int)ss[0].size.Y), + ss[3]); + + // Top border + if (ps.HasFlags(PanelSides.Top)) + FillRectWithSprite(new Rectangle(Bounds.Left + (int)ss[2].size.X, + Bounds.Top, + Bounds.Right - (int)ss[3].size.X - Bounds.Left - (int)ss[2].size.X, + (int)ss[0].size.Y), + ss[0]); + + // Bottom border + if (ps.HasFlags(PanelSides.Bottom)) + FillRectWithSprite(new Rectangle(Bounds.Left + (int)ss[2].size.X, + Bounds.Bottom - (int)ss[1].size.Y, + Bounds.Right - (int)ss[3].size.X - Bounds.Left - (int)ss[2].size.X, + (int)ss[0].size.Y), + ss[1]); + + if (ps.HasFlags(PanelSides.Left | PanelSides.Top)) + DrawRGBA(ss[4], new float2(Bounds.Left, Bounds.Top)); + if (ps.HasFlags(PanelSides.Right | PanelSides.Top)) + DrawRGBA(ss[5], new float2(Bounds.Right - ss[5].size.X, Bounds.Top)); + if (ps.HasFlags(PanelSides.Left | PanelSides.Bottom)) + DrawRGBA(ss[6], new float2(Bounds.Left, Bounds.Bottom - ss[6].size.Y)); + if (ps.HasFlags(PanelSides.Right | PanelSides.Bottom)) + DrawRGBA(ss[7], new float2(Bounds.Right - ss[7].size.X, Bounds.Bottom - ss[7].size.Y)); + + Game.chrome.renderer.RgbaSpriteRenderer.Flush(); + } + } + + [Flags] + public enum PanelSides + { + Left = 1, + Top = 2, + Right = 4, + Bottom = 8, + + All = Left | Top | Right | Bottom } } diff --git a/mods/ra/menus.yaml b/mods/ra/menus.yaml index 268a8a2ced..6eb122e5a4 100644 --- a/mods/ra/menus.yaml +++ b/mods/ra/menus.yaml @@ -263,6 +263,12 @@ Container: Width:160 Height:25 Text:Options + MoneyBin@INGAME_MONEY_BIN: + Id:INGAME_MONEY_BIN + X:WINDOW_RIGHT - WIDTH + Y:0 + Width:320 + Height: 32 Background@INGAME_OPTIONS_BG: Id:INGAME_OPTIONS_BG X:(WINDOW_RIGHT - WIDTH)/2