/// <summary> /// Tries to handle cursor activity. If this returns true, then either this element or one of its /// children handled the activity. /// </summary> /// <param name="cursor">Reference to the cursor object</param> /// <returns>Whether this or one of its children handled the cursor activity, blocking other windows from receiving cursor input this frame.</returns> /// <remarks>This method will always allow children to handle the activity first, as children draw in front of their parents. Only components /// can have UI elements. Standard elements such as Sprites or Containers cannot themselves handle the activity, but they do give their children the /// opportunity to handle activity. This is because components (such as buttons) may be part of a container for stacking or other organization. /// /// Ultimately this hierarchical logic exists because only the top-most parent is added to the GuiManager, and it is responsible for /// giving its children the opportunity to perform cursor-related input. </remarks> private bool TryHandleCursorActivity(Cursor cursor, HandledActions handledActions) { bool handledByChild = false; bool handledByThis = false; bool isOver = HasCursorOver(cursor); // Even though the cursor is over "this", we need to check if the cursor is over any children in case "this" exposes its children events: if (isOver && this.ExposeChildrenEvents) { #region Try handling by children // Let's see if any children have the cursor over: for (int i = this.Children.Count - 1; i > -1; i--) { var child = this.Children[i]; if (child is GraphicalUiElement) { var asGue = child as GraphicalUiElement; // Children should always have the opportunity to handle activity, // even if they are not components, because they may contain components as their children // If the child either has events or exposes children events, then give it a chance to handle this activity. if ((asGue.HasEvents || asGue.ExposeChildrenEvents) && asGue.HasCursorOver(cursor)) { handledByChild = asGue.TryHandleCursorActivity(cursor, handledActions); if (handledByChild) { break; } } } } #endregion } if (isOver) { if (this.IsComponentOrInstanceOfComponent()) { if (!handledByChild) { // Feb. 21, 2018 // If not handled by // children, then this // can only handle if this // exposes events. Otherwise, // it shouldn't handle anything // and the parent should be given // the opportunity. // I'm not sure why this was outside // of the if(this.HasEvents)...seems intentional // but it causes problems when the rootmost object // exposes children events but doesn't handle its own // events... //handledByThis = true; if (this.HasEvents) { // moved from above, see comments there... handledByThis = true; cursor.WindowOver = this; if (cursor.PrimaryPush && Enabled) { cursor.WindowPushed = this; if (Push != null) { Push(this); } cursor.GrabWindow(this); } if (cursor.PrimaryClick && Enabled) // both pushing and clicking can occur in one frame because of buffered input { if (cursor.WindowPushed == this) { if (Click != null) { Click(this); } if (cursor.PrimaryClickNoSlide && ClickNoSlide != null) { ClickNoSlide(this); } // if (cursor.PrimaryDoubleClick && DoubleClick != null) // DoubleClick(this); } else { if (SlideOnClick != null) { SlideOnClick(this); } } } } } if (HasEvents && Enabled) { if (handledActions.HandledRollOver == false) { FlatRedBall.Gui.RoutedEventArgs args = new FlatRedBall.Gui.RoutedEventArgs(); RollOverBubbling?.Invoke(this, args); handledActions.HandledRollOver = args.Handled; } if (cursor.ZVelocity != 0 && handledActions.HandledMouseWheel == false) { FlatRedBall.Gui.RoutedEventArgs args = new FlatRedBall.Gui.RoutedEventArgs(); MouseWheelScroll?.Invoke(this, args); handledActions.HandledMouseWheel = args.Handled; } } } } return(handledByThis || handledByChild); }
/// <summary> /// Tries to handle cursor activity. If this returns true, then either this element or one of its /// children handled the activity. /// </summary> /// <param name="cursor">Reference to the cursor object</param> /// <returns>Whether this or one of its children handled the cursor activity, blocking other windows from receiving cursor input this frame.</returns> /// <remarks>This method will always allow children to handle the activity first, as children draw in front of their parents. Only components /// can have UI elements. Standard elements such as Sprites or Containers cannot themselves handle the activity, but they do give their children the /// opportunity to handle activity. This is because components (such as buttons) may be part of a container for stacking or other organization. /// /// Ultimately this hierarchical logic exists because only the top-most parent is added to the GuiManager, and it is responsible for /// giving its children the opportunity to perform cursor-related input. </remarks> private bool TryHandleCursorActivity(Cursor cursor, HandledActions handledActions) { bool handledByChild = false; bool handledByThis = false; bool isOver = HasCursorOver(cursor); // Even though the cursor is over "this", we need to check if the cursor is over any children in case "this" exposes its children events: if (isOver && this.ExposeChildrenEvents) { #region Try handling by children // Let's see if any children have the cursor over: for (int i = this.Children.Count - 1; i > -1; i--) { var child = this.Children[i]; if (child is GraphicalUiElement) { var asGue = child as GraphicalUiElement; // Children should always have the opportunity to handle activity, // even if they are not components, because they may contain components as their children // If the child either has events or exposes children events, then give it a chance to handle this activity. if ((asGue.HasEvents || asGue.ExposeChildrenEvents) && asGue.HasCursorOver(cursor)) { handledByChild = asGue.TryHandleCursorActivity(cursor, handledActions); if (handledByChild) { break; } } } } #endregion } if (isOver) { if (this.IsComponentOrInstanceOfComponent()) { if (!handledByChild) { handledByThis = true; if (this.HasEvents) { cursor.WindowOver = this; if (cursor.PrimaryPush && Enabled) { cursor.WindowPushed = this; if (Push != null) { Push(this); } cursor.GrabWindow(this); } if (cursor.PrimaryClick && Enabled) // both pushing and clicking can occur in one frame because of buffered input { if (cursor.WindowPushed == this) { if (Click != null) { Click(this); } if (cursor.PrimaryClickNoSlide && ClickNoSlide != null) { ClickNoSlide(this); } // if (cursor.PrimaryDoubleClick && DoubleClick != null) // DoubleClick(this); } else { if (SlideOnClick != null) { SlideOnClick(this); } } } } } if (HasEvents && cursor.ZVelocity != 0 && handledActions.HandledMouseWheel == false && Enabled) { FlatRedBall.Gui.RoutedEventArgs args = new FlatRedBall.Gui.RoutedEventArgs(); MouseWheelScroll?.Invoke(this, args); handledActions.HandledMouseWheel = args.Handled; } } } return(handledByThis || handledByChild); }