diff --git a/OpenRA.Game/Chrome.cs b/OpenRA.Game/Chrome.cs index bfb71b5a53..1cb574d30e 100644 --- a/OpenRA.Game/Chrome.cs +++ b/OpenRA.Game/Chrome.cs @@ -71,10 +71,10 @@ namespace OpenRA public int2 lastMousePos; public bool HandleInput(World world, MouseInput mi) { - if (selectedWidget != null && selectedWidget.HandleInput(mi)) + if (selectedWidget != null && selectedWidget.HandleMouseInputOuter(mi)) return true; - if (rootWidget.HandleInput(mi)) + if (rootWidget.HandleMouseInputOuter(mi)) return true; if (mi.Event == MouseInputEvent.Move) @@ -89,9 +89,9 @@ namespace OpenRA public bool HandleKeyPress(System.Windows.Forms.KeyPressEventArgs e, Modifiers modifiers) { if (selectedWidget != null) - return selectedWidget.HandleKeyPress(e, modifiers); + return selectedWidget.HandleKeyPressOuter(e, modifiers); - if (rootWidget.HandleKeyPress(e, modifiers)) + if (rootWidget.HandleKeyPressOuter(e, modifiers)) return true; return false; } diff --git a/OpenRA.Game/Widgets/BuildPaletteWidget.cs b/OpenRA.Game/Widgets/BuildPaletteWidget.cs index 2f1b636871..eb95100091 100644 --- a/OpenRA.Game/Widgets/BuildPaletteWidget.cs +++ b/OpenRA.Game/Widgets/BuildPaletteWidget.cs @@ -149,26 +149,17 @@ namespace OpenRA.Widgets } public override bool HandleInput(MouseInput mi) - { - // Are we able to handle this event? - if (!IsVisible() || !GetEventBounds().Contains(mi.Location.X,mi.Location.Y)) - return base.HandleInput(mi); + { + if (mi.Event != MouseInputEvent.Down) + return false; - 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; + 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; } public override void DrawInner(World world) diff --git a/OpenRA.Game/Widgets/ButtonWidget.cs b/OpenRA.Game/Widgets/ButtonWidget.cs index 4b536e66b3..6199f625e1 100644 --- a/OpenRA.Game/Widgets/ButtonWidget.cs +++ b/OpenRA.Game/Widgets/ButtonWidget.cs @@ -46,38 +46,30 @@ namespace OpenRA.Widgets GetText = (widget as ButtonWidget).GetText; } - public override bool HandleInput(MouseInput mi) + public override bool LoseFocus (MouseInput mi) { - if (Chrome.selectedWidget == this) - Depressed = (GetEventBounds().Contains(mi.Location.X,mi.Location.Y)) ? true : false; + Depressed = false; + return base.LoseFocus(mi); + } + + public override bool HandleInput(MouseInput mi) + { + if (mi.Event == MouseInputEvent.Down && !TakeFocus(mi)) + return false; - // Relinquish focus - if (Chrome.selectedWidget == this && mi.Event == MouseInputEvent.Up) + // Only fire the onMouseUp order if we successfully lost focus, and were pressed + if (Focused && mi.Event == MouseInputEvent.Up) { - Chrome.selectedWidget = null; - Depressed = false; + var wasPressed = Depressed; + return (LoseFocus(mi) && wasPressed); } - // 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; - - // Give button focus only while the mouse is down - // This is a bit of a hack: it will become cleaner soonish - // It will also steal events from any potential children - // We also want to play a click sound if (mi.Event == MouseInputEvent.Down) - { - Chrome.selectedWidget = this; Depressed = true; - return true; - } + else if (mi.Event == MouseInputEvent.Move && Focused) + Depressed = RenderBounds.Contains(mi.Location.X,mi.Location.Y); - return false; + return Depressed; } public override void DrawInner(World world) diff --git a/OpenRA.Game/Widgets/CheckboxWidget.cs b/OpenRA.Game/Widgets/CheckboxWidget.cs index 39bc01baf8..d84e83246e 100644 --- a/OpenRA.Game/Widgets/CheckboxWidget.cs +++ b/OpenRA.Game/Widgets/CheckboxWidget.cs @@ -56,6 +56,7 @@ namespace OpenRA.Widgets Game.chrome.lineRenderer.Flush(); } } + public override bool HandleInput(MouseInput mi) { return true; } public CheckboxWidget() : base() { } diff --git a/OpenRA.Game/Widgets/ListBoxWidget.cs b/OpenRA.Game/Widgets/ListBoxWidget.cs index 6278f40da4..c658226059 100644 --- a/OpenRA.Game/Widgets/ListBoxWidget.cs +++ b/OpenRA.Game/Widgets/ListBoxWidget.cs @@ -88,40 +88,27 @@ namespace OpenRA.Widgets if (DownPressed) ListOffset -= ScrollVelocity; } - public override bool HandleInput(MouseInput mi) + public override bool LoseFocus (MouseInput mi) { - if (Chrome.selectedWidget == this) - { - UpPressed = upButtonRect.Contains(mi.Location.X,mi.Location.Y); - DownPressed = downButtonRect.Contains(mi.Location.X,mi.Location.Y); - } + UpPressed = DownPressed = false; + return base.LoseFocus(mi); + } + + public override bool HandleInput(MouseInput mi) + { + if (mi.Event == MouseInputEvent.Down && !TakeFocus(mi)) + return false; - // Relinquish focus - if (Chrome.selectedWidget == this && mi.Event == MouseInputEvent.Up) - { - Chrome.selectedWidget = null; - UpPressed = DownPressed = false; - } + if (!Focused) + return false; + + UpPressed = upButtonRect.Contains(mi.Location.X,mi.Location.Y); + DownPressed = downButtonRect.Contains(mi.Location.X,mi.Location.Y); - // Are we able to handle this event? - if (!Visible || !GetEventBounds().Contains(mi.Location.X,mi.Location.Y)) - return base.HandleInput(mi); + if (Focused && mi.Event == MouseInputEvent.Up) + LoseFocus(mi); - - if (base.HandleInput(mi)) - return true; - - // Give button focus only while the mouse is down - // This is a bit of a hack: it will become cleaner soonish - // It will also steal events from any potential children - // We also want to play a click sound - if (mi.Event == MouseInputEvent.Down) - { - Chrome.selectedWidget = this; - return true; - } - - return false; + return (UpPressed || DownPressed); } public override Widget Clone() { return new ListBoxWidget(this); } diff --git a/OpenRA.Game/Widgets/MoneyBinWidget.cs b/OpenRA.Game/Widgets/MoneyBinWidget.cs index 67d211fa85..b717f5574c 100644 --- a/OpenRA.Game/Widgets/MoneyBinWidget.cs +++ b/OpenRA.Game/Widgets/MoneyBinWidget.cs @@ -137,13 +137,6 @@ namespace OpenRA.Widgets 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())) diff --git a/OpenRA.Game/Widgets/SpecialPowerBinWidget.cs b/OpenRA.Game/Widgets/SpecialPowerBinWidget.cs index a391fdba1b..9517daf72c 100644 --- a/OpenRA.Game/Widgets/SpecialPowerBinWidget.cs +++ b/OpenRA.Game/Widgets/SpecialPowerBinWidget.cs @@ -63,9 +63,7 @@ namespace OpenRA.Widgets } public override bool HandleInput(MouseInput mi) - { - if (!IsVisible()) return false; - + { if (mi.Event == MouseInputEvent.Down) { var action = buttons.Where(a => a.First.Contains(mi.Location.ToPoint())) diff --git a/OpenRA.Game/Widgets/TextFieldWidget.cs b/OpenRA.Game/Widgets/TextFieldWidget.cs index 0ba20e60f0..a6ef50e0d7 100644 --- a/OpenRA.Game/Widgets/TextFieldWidget.cs +++ b/OpenRA.Game/Widgets/TextFieldWidget.cs @@ -46,47 +46,33 @@ namespace OpenRA.Widgets Bold = (widget as TextFieldWidget).Bold; VisualHeight = (widget as TextFieldWidget).VisualHeight; } + + public override bool LoseFocus(MouseInput mi) + { + OnLoseFocus(); + var lose = base.LoseFocus(mi); + System.Console.WriteLine("{1} asked to lose focus; returning {0}",lose, this.Id); + return lose; + } public override bool HandleInput(MouseInput mi) { - // We get this first if we are focussed; if the click was somewhere else remove focus - if (Chrome.selectedWidget == this && mi.Event == MouseInputEvent.Down && !GetEventBounds().Contains(mi.Location.X,mi.Location.Y)) - { - OnLoseFocus(); - Chrome.selectedWidget = null; + // Lose focus if they click outside the box; return false so the next widget can grab this event + if (mi.Event == MouseInputEvent.Down && !RenderBounds.Contains(mi.Location.X,mi.Location.Y) && LoseFocus(mi)) return false; - } - - // 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 && !TakeFocus(mi)) + return false; - if (mi.Event == MouseInputEvent.Down) - { - Focus(); - return true; - } - - return false; - } - - void Focus() - { - Chrome.selectedWidget = this; blinkCycle = 10; showCursor = true; + return true; } public override bool HandleKeyPress(System.Windows.Forms.KeyPressEventArgs e, Modifiers modifiers) - { - if (base.HandleKeyPress(e,modifiers)) - return true; - - // Only take input if we are selected - if (Chrome.selectedWidget != this) + { + // Only take input if we are focused + if (!Focused) return false; if (e.KeyChar == '\r' && OnEnterKey()) @@ -131,7 +117,7 @@ namespace OpenRA.Widgets { int margin = 5; var font = (Bold) ? Game.chrome.renderer.BoldFont : Game.chrome.renderer.RegularFont; - var cursor = (showCursor && Chrome.selectedWidget == this) ? "|" : ""; + var cursor = (showCursor && Focused) ? "|" : ""; var textSize = font.Measure(Text + "|"); var pos = RenderOrigin; @@ -144,7 +130,7 @@ namespace OpenRA.Widgets // Right align when editing and scissor when the text overflows if (textSize.X > Bounds.Width - 2*margin) { - if (Chrome.selectedWidget == this) + if (Focused) textPos += new int2(Bounds.Width - 2*margin - textSize.X,0); Game.chrome.renderer.Device.EnableScissor(pos.X + margin, pos.Y, Bounds.Width - 2*margin, Bounds.Bottom); diff --git a/OpenRA.Game/Widgets/Widget.cs b/OpenRA.Game/Widgets/Widget.cs index 920d3366aa..217dbbf541 100644 --- a/OpenRA.Game/Widgets/Widget.cs +++ b/OpenRA.Game/Widgets/Widget.cs @@ -150,34 +150,73 @@ namespace OpenRA.Widgets .Select(c => c.GetEventBounds()) .Aggregate(RenderBounds, Rectangle.Union); } - - public virtual bool HandleInput(MouseInput mi) + + + public bool Focused { get { return Chrome.selectedWidget == this; } } + public virtual bool TakeFocus(MouseInput mi) + { + if (Focused) + return true; + + if (Chrome.selectedWidget != null && !Chrome.selectedWidget.LoseFocus(mi)) + return false; + Chrome.selectedWidget = this; + return true; + } + + // Remove focus from this widget; return false if you don't want to give it up + public virtual bool LoseFocus(MouseInput mi) + { + if (Chrome.selectedWidget == this) + Chrome.selectedWidget = null; + + return true; + } + + public virtual bool HandleInput(MouseInput mi) { return false; } + public bool HandleMouseInputOuter(MouseInput mi) { // Are we able to handle this event? - if (!IsVisible() || !GetEventBounds().Contains(mi.Location.X,mi.Location.Y)) + if (!(Focused || (IsVisible() && GetEventBounds().Contains(mi.Location.X,mi.Location.Y)))) + return false; + + // Send the event to the deepest children first and bubble up if unhandled + foreach (var child in Children) + if (child.HandleMouseInputOuter(mi)) + return true; + + // Do any widgety behavior (button click etc) + // Return false if it can't handle any user actions + if (!HandleInput(mi)) + return false; + + // Apply any special logic added by delegates; they return true if they caught the input + if (mi.Event == MouseInputEvent.Down && OnMouseDown(mi)) return true; + if (mi.Event == MouseInputEvent.Up && OnMouseUp(mi)) return true; + if (mi.Event == MouseInputEvent.Move && OnMouseMove(mi)) return true; + + return true; + } + + + public virtual bool HandleKeyPress(System.Windows.Forms.KeyPressEventArgs e, Modifiers modifiers) { return false; } + public virtual bool HandleKeyPressOuter(System.Windows.Forms.KeyPressEventArgs e, Modifiers modifiers) + { + if (!IsVisible()) return false; // Can any of our children handle this? foreach (var child in Children) - if (child.HandleInput(mi)) + if (child.HandleKeyPressOuter(e, modifiers)) return true; - if (mi.Event == MouseInputEvent.Down) return OnMouseDown(mi); - if (mi.Event == MouseInputEvent.Up) return OnMouseUp(mi); - if (mi.Event == MouseInputEvent.Move) return OnMouseMove(mi); - - throw new InvalidOperationException("Impossible"); - } - - public virtual bool HandleKeyPress(System.Windows.Forms.KeyPressEventArgs e, Modifiers modifiers) - { - // Can any of our children handle this? - foreach (var child in Children) - if (child.HandleKeyPress(e, modifiers)) - return true; - - // Have we been assigned an action? - return OnKeyPress(e,modifiers); + // Do any widgety behavior (enter text etc) + var handled = HandleKeyPress(e,modifiers); + + // Apply any special logic added by delegates; they return true if they caught the input + if (OnKeyPress(e,modifiers)) return true; + + return handled; } public abstract void DrawInner( World world );