/// <summary>Called when a button on the game pad has been released</summary> /// <param name="button">Button that has been released</param> internal void ProcessButtonRelease(Buttons button) { // If we're the top level control, we will receive button presses and their related // releases even if nobody was interested in the button presses. Thus, we silently // ignore those presses we didn't accept. if (_heldButtonCount == 0) { return; } // If we receive a release, we must have a control on which the mouse // was pressed (possibly even ourselves) Debug.Assert( _activatedControl != null, "ProcessButtonRelease() had no control a button was pressed on; " + "ProcessButtonRelease() was called on a control instance, but the control " + "did not register a prior button press for itself or any of its child controls" ); --_heldButtonCount; if (_activatedControl != this) { _activatedControl.ProcessButtonRelease(button); } else { OnButtonReleased(button); } // If no more keys buttons are being held down, clear the activated control if (!AnyKeysOrButtonsPressed) { _activatedControl = null; } }
/// <summary>Called when a mouse button has been pressed down</summary> /// <param name="button">Index of the button that has been pressed</param> /// <returns>Whether the control has processed the mouse press</returns> internal bool ProcessMousePress(MouseButton button) { // We remember the control the mouse was pressed over and won't replace it for // as long as the mouse is being held down. This ensures the mouse release // notification is always delivered to a control, even if the mouse is released // after moving it away from the control. if (_activatedControl == null) { _activatedControl = _mouseOverControl; // If we received an initial mouse press outside of our control area, // someone is feeding us notifications we shouldn't be receiving. The best // thing we can do is ignore this notification. This is a normal situation // for the top level control which does the input filtering. if (_activatedControl == null) { return(false); } // If we're a control that can appear on top of or below our siblings in // the z order, bring us into foreground since the user just clicked on us. if (_activatedControl != this) { if (_activatedControl._affectsOrdering) { _children.MoveToStart(_children.IndexOf(_activatedControl)); } } } // Add the buttons to the list of mouse buttons being held down. This is used // to track when we should clear the mouse-over control again. _heldMouseButtons |= button; // If the mouse is over another control, pass on the mouse press. if (_activatedControl != this) { return(_activatedControl.ProcessMousePress(button)); } // Otherwise, the mouse press applies to us // If this control can take the input focus, make it the focused control if (_screen != null) { var focusable = this as IFocusable; if ((focusable != null) && focusable.CanGetFocus) { _screen.FocusedControl = this; } } // Deliver the notification to the control deriving from us OnMousePressed(button); return(true); }
/// <summary>Switches the mouse over control to a different control</summary> /// <param name="newMouseOverControl">New control the mouse is hovering over</param> private void SwitchMouseOverControl(GuiControl newMouseOverControl, float x, float y) { if (_mouseOverControl != newMouseOverControl) { // Tell the previous mouse-over control that the mouse is no longer // hovering over it if (_mouseOverControl != null) { _mouseOverControl.ProcessMouseLeave(x, y); } _mouseOverControl = newMouseOverControl; // Inform the new mouse-over control that the mouse is now over it newMouseOverControl.OnMouseEntered(); } }
/// <summary>Assigns a new parent to the control</summary> /// <param name="parent">New parent to assign to the control</param> internal void SetParent(GuiControl parent) { _parent = parent; // Have we been assigned to a parent? if (_parent != null) { // If this ownership change transferred us to a different gui, we will // have to migrate our visual and also the visuals of all our children. if (!ReferenceEquals(_screen, parent._screen)) { SetScreen(parent._screen); } } else { // No parent, we're now officially an orphan ;) // Orphans don't have screens! SetScreen(null); } }
/// <summary>Called when a mouse button has been released again</summary> /// <param name="button">Index of the button that has been released</param> internal void ProcessMouseRelease(MouseButton button) { // When the mouse is clicked on game window's border and the user drags it // into the GUI area, we will get a rogue mouse release message without // the related mouse press. We ignore such rogue mouse release messages. if ((_heldMouseButtons & button) != button) { return; } // If we receive a release, we must have a control on which the mouse // was pressed (possibly even ourselves) Debug.Assert( _activatedControl != null, "ProcessMouseRelease() had no control the mouse was pressed on; " + "ProcessMouseRelease() was called on a control instance, but the control " + "did not register a prior mouse press over itself or any of its child controls" ); // Remove the button from the list of mouse buttons being held down. This // allows us to see when we can clear the mouse-press control. _heldMouseButtons &= ~button; // If the mouse was held over one of our childs, pass on the notification if (_activatedControl != this) { _activatedControl.ProcessMouseRelease(button); } else { OnMouseReleased(button); } // If no more mouse buttons are being held down, clear the mouse-press control if (!AnyKeysOrButtonsPressed) { _activatedControl = null; } }
/// <summary> /// Called when the mouse has left the control and is no longer hovering over it /// </summary> internal void ProcessMouseLeave(float x, float y) { // Because the mouse has left us, if we have a mouse-over control, it also // cannot be over one of our children Children leaving the parent container // are not supported by design and for consistency, the behavior is tweaked // so the children are left when the parent is left - this avoids strange // behavior like being able to select a control if entering it with the mouse // from the container side but being unable to select it if entering from // the outside. if (_mouseOverControl != null) { if (_mouseOverControl != this) { _mouseOverControl.ProcessMouseLeave(x, y); } else { OnMouseLeft(x, y); } _mouseOverControl = null; } }
/// <summary>Called when a key on the keyboard has been released again</summary> /// <param name="keyCode">Code of the key that was released</param> internal void ProcessKeyRelease(Keys keyCode) { // Any key release should have an associated key press, otherwise, someone // delivered notifications to us we should not have received. Debug.Assert( _heldKeyCount > 0, "ProcessKeyRelease() called more often then ProcessKeyPress(); " + "ProcessKeyRelease() was called more often the ProcessKeyPress() has been " + "called with the repetition parameter set to false" ); // If we receive a release, we must have a control on which the mouse // was pressed (possibly even ourselves) Debug.Assert( _activatedControl != null, "ProcessKeyRelease() had no control a key was pressed on; " + "ProcessKeyRelease() was called on a control instance, but the control " + "did not register a prior key press for itself or any of its child controls" ); --_heldKeyCount; if (_activatedControl != this) { _activatedControl.ProcessKeyRelease(keyCode); } else { OnKeyReleased(keyCode); } // If no more keys buttons are being held down, clear the activated control if (!AnyKeysOrButtonsPressed) { _activatedControl = null; } }
/// <summary>Called when a key on the keyboard has been pressed down</summary> /// <param name="keyCode">Code of the key that was pressed</param> /// <param name="repetition">Whether the key press is due to the user holding down a key</param> internal bool ProcessKeyPress(Keys keyCode, bool repetition) { // If there's an activated control (one being held down by the mouse or having // accepted a previous key press), this control will get the key press delivered, // whether it wants to or not. We don't want to track for each key which control // is currently processing it. ;-) if (_activatedControl != null) { if (!repetition) { ++_heldKeyCount; } // If one of our children is the activated control, pass on the message if (_activatedControl != this) { _activatedControl.ProcessKeyPress(keyCode, repetition); } else { OnKeyPressed(keyCode); // We're the activated control } return(true); // Ignore user code and always accept the key press } // A key has been pressed but no control is activated currently. This means we // have to look for a control which feels responsible for the key press, starting // with ourselves. // Does the user code in our derived class feel responsible for this key? // If so, we're the new activated control and the key has been handled. if (OnKeyPressed(keyCode)) { _activatedControl = this; ++_heldKeyCount; return(true); } // Nope, we have to ask our children (and they, potentially recursively, theirs) // to find a control that feels responsible. var encounteredOrderingControl = false; for (var index = 0; index < _children.Count; ++index) { var child = _children[index]; // We only process one child that has the affectsOrdering field set. This // ensures that key presses will not be delivered to windows sitting behind // another window. Other siblings that are not windows are asked still. if (child._affectsOrdering) { if (encounteredOrderingControl) { continue; } else { encounteredOrderingControl = true; } } // Does this child feel responsible for the key press? if (child.ProcessKeyPress(keyCode, repetition)) { _activatedControl = child; ++_heldKeyCount; return(true); } } // Neither we nor any of our children felt responsible for the key. Give up. return(false); }
/// <summary>Called when a button on the game pad has been pressed</summary> /// <param name="button">Button that has been pressed</param> /// <returns> /// True if the button press was processed by the control and future game pad /// input belongs to the control until all buttons are released again /// </returns> internal bool ProcessButtonPress(Buttons button) { // If there's an activated control (one being held down by the mouse or having // accepted a previous button press), this control will get the button press // delivered, whether it wants to or not. if (_activatedControl != null) { ++_heldButtonCount; // If one of our children is the activated control, pass on the message if (_activatedControl != this) { _activatedControl.ProcessButtonPress(button); } else { OnButtonPressed(button); } // We're already activated, so this button press is accepted in any case return(true); } // A button has been pressed but no control is activated currently. This means we // have to look for a control which feels responsible for the button press, // starting with ourselves. // Does the user code in our derived class feel responsible for this button? // If so, we're the new activated control and the button has been handled. if (OnButtonPressed(button)) { _activatedControl = this; ++_heldButtonCount; return(true); } // Nope, we have to ask our children to find a control that feels responsible. var encounteredOrderingControl = false; foreach (var child in _children) { // We only process one child that has the affectsOrdering field set. This // ensures that key presses will not be delivered to windows sitting behind // another window. Other siblings that are not windows are asked still, so // a bunch of buttons on the desktop would be asked in addition to a window. if (child._affectsOrdering) { if (encounteredOrderingControl) { continue; } encounteredOrderingControl = true; } // Does this child feel responsible for the button press? if (child.ProcessButtonPress(button)) { _activatedControl = child; ++_heldButtonCount; return(true); } } // Neither we nor any of our children felt responsible for the button. Give up. return(false); }
/// <summary>Initializes a new control event args instance</summary> /// <param name="control">Control to provide to the subscribers of the event</param> public ControlEventArgs(GuiControl control) { _control = control; }