View Issue Details

IDProjectCategoryView StatusLast Update
0003476NoesisGUIUnitypublic2024-10-25 11:42
Reporterstonstad Assigned Tosfernandez  
PrioritynormalSeveritymajor 
Status resolvedResolutionfixed 
Product Version3.2.4 
Target Version3.2.5Fixed in Version3.2.5 
Summary0003476: WorldSpaceUI Responds to Mouse Enter/Leave But Not Mouse Down
Description

In 3.2.4 I'm seeing a regression of https://www.noesisengine.com/bugs/view.php?id=2929

I have buttons in WorldSpaceUI framework elements that respond to MouseEnter/MouseLeave but not MouseDown. I am working with vanilla 3.2.4 with no patches applied. ev.Use() is enabled within NoesisView.cs.

PlatformAny

Relationships

related to 0003734 resolvedsfernandez Blocking interaction in the 3D world 

Activities

stonstad

stonstad

2024-07-08 15:39

reporter   ~0009762

Last edited: 2024-07-08 15:40

For Unity Active Input Handling, I am using "Both". (Legacy and New).

I'll do some detailed testing to make sure there isn't a transparent layer above the elements. I don't think this is the case since Mouse Enter/Mouse Leave events fire consistently -- and it worked in 3.2.2, but I'll double-check.

stonstad

stonstad

2024-07-08 15:46

reporter   ~0009763

Test results --

Adding a semitransparent backgound fill over the WorldSpace UI element does not block MouseEnter/MouseLeave events. MouseDown events still don't fire.

I am thinking all events should fire when a World Space UI element is not covered... and no events fire when covered. What is the expected behavior?

sfernandez

sfernandez

2024-07-09 12:11

manager   ~0009766

Could you please add some logs to the HitTest function in NoesisView to see what element is being hit?

private bool HitTest(float x, float y)
{
Visual root = (Visual)VisualTreeHelper.GetRoot(_uiView.Content);
Point p = root.PointFromScreen(new Point(x, y));
HitTestResult hit = VisualTreeHelper.HitTest(root, p);
if (hit.VisualHit != null)
Debug.Log($"View {gameObject} hit {hit.VisualHit.GetType()}");
return hit.VisualHit != null;
}

It must be some element in the base UI layer.

stonstad

stonstad

2024-07-09 17:56

reporter   ~0009773

Last edited: 2024-07-09 17:57

Here's the scene w/ hierarchy explained (image.png). It has a base view which contains the menu UI. The galaxy UI (orange triangle) is WorldSpaceUI. The hover effect for WorldSpaceUI works, but click does not.

Here's the visual tree w/ hit:

Click. View Base Layer (UnityEngine.GameObject) hit Noesis.Border
-> Parent Noesis.Grid _BaseBlurSource
-> Parent Noesis.Grid _BaseBlurSourceContainer
-> Parent Noesis.Grid _OverlayBlurSource
-> Parent StellarConquest.Presentation.Unity.UI.UIStateMachine
-> Parent Noesis.AdornerDecorator _UIStateMachine

BaseBlurSource is my top level container for everything -- it is higher than game UIs. What this tells me is that nothing is being hit other than the border. Am I thinking about this wrong? Should the element in WorldSpaceUI be hit?

The element I am expecting to receive a hit from is one of these JumpGateControls. (encl. JumpGateControl.cs, JumpGateTemplate.xaml). I apologize -- this must be user error somehow. Is it because I am deriving from a ContentControl for these JumpGates that MouseLeftButtonDown operations are not working?

WorldSpaceUI:
<Viewbox>
<Grid>
<Grid x:Name="_OrbitsGrid" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Grid x:Name="_SystemOrbitsGrid" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Grid x:Name="_JumpGatesGrid" HorizontalAlignment="Center" VerticalAlignment="Center">
<local:JumpGateControl x:Name="_TopJumpGateControl" Template="{StaticResource JumpGateTemplate}" Text="Top" Angle="0"/>
<local:JumpGateControl x:Name="_TopRightJumpGateControl" Template="{StaticResource JumpGateTemplate}" Text="Top Right" Angle="45"/>
<local:JumpGateControl x:Name="_RightJumpGateControl" Template="{StaticResource JumpGateTemplate}" Text="Right" Angle="90"/>
<local:JumpGateControl x:Name="_BottomRightJumpGateControl" Template="{StaticResource JumpGateTemplate}" Text="Bottom Right" Angle="135"/>
<local:JumpGateControl x:Name="_BottomJumpGateControl" Template="{StaticResource JumpGateTemplate}" Text="Bottom" Angle="180" X="0"/>
<local:JumpGateControl x:Name="_BottomLeftJumpGateControl" Template="{StaticResource JumpGateTemplate}" Text="Bottom Left" Angle="225"/>
<local:JumpGateControl x:Name="_LeftJumpGateControl" Template="{StaticResource JumpGateTemplate}" Text="Left" Angle="-90"/>
<local:JumpGateControl x:Name="_TopLeftJumpGateControl" Template="{StaticResource JumpGateTemplate}" Text="TopLeft" Angle="-45"/>
</Grid>
</Grid>
</Viewbox>

image.png (3,627,444 bytes)
JumpGateControl.cs (2,188 bytes)   
using Noesis;

namespace StellarConquest.Presentation.Unity.UI
{
    public sealed class JumpGateControl : ContentControl
    {
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(JumpGateControl), new PropertyMetadata(default(string)));

        public static readonly DependencyProperty AngleProperty =
            DependencyProperty.Register("Angle", typeof(float), typeof(JumpGateControl), new PropertyMetadata(default(float)));

        public static readonly DependencyProperty XProperty =
            DependencyProperty.Register("X", typeof(float), typeof(JumpGateControl), new PropertyMetadata(default(float)));

        public static readonly DependencyProperty YProperty =
            DependencyProperty.Register("Y", typeof(float), typeof(JumpGateControl), new PropertyMetadata(default(float)));

        public static readonly DependencyProperty IsPressedProperty =
            DependencyProperty.Register("IsPressed", typeof(bool), typeof(JumpGateControl), new PropertyMetadata(default(bool)));


        public JumpGateControl()
        {
            MouseLeftButtonDown += (sender, e) => IsPressed = true;
            MouseLeftButtonUp += (sender, e) => IsPressed = false;
            MouseLeave += (sender, e) => IsPressed = false;
        }

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public float Angle
        {
            get { return (float)GetValue(AngleProperty); }
            set { SetValue(AngleProperty, value); }
        }

        public float X
        {
            get { return (float)GetValue(XProperty); }
            set { SetValue(XProperty, value); }
        }

        public float Y
        {
            get { return (float)GetValue(YProperty); }
            set { SetValue(YProperty, value); }
        }

        public bool IsPressed
        {
            get { return (bool)GetValue(IsPressedProperty); }
            set { SetValue(IsPressedProperty, value); }
        }
    }
}
JumpGateControl.cs (2,188 bytes)   
JumpGateTemplate.xaml (3,674 bytes)   
   <ControlTemplate x:Key="JumpGateTemplate" TargetType="{x:Type local:JumpGateControl}">
       <ControlTemplate.Resources>
           <SolidColorBrush x:Key="JumpGateFillBrush" Color="{StaticResource JumpGateFillColor}"/>
           <SolidColorBrush x:Key="JumpGateStrokeBrush" Color="{StaticResource JumpGateStrokeColor}"/>
           <SolidColorBrush x:Key="JumpGateSelectedFillBrush" Color="{StaticResource JumpGateSelectedFillColor}"/>
       </ControlTemplate.Resources>
       <Grid x:Name="_TemplateRoot" RenderTransformOrigin="0.5,0.5">
           <Grid.RenderTransform>
               <TransformGroup>
                   <ScaleTransform ScaleX="1.0" ScaleY="1.0" />
                   <RotateTransform Angle="{Binding Path=Angle, RelativeSource={RelativeSource TemplatedParent}}"/>
                   <TranslateTransform X="{Binding Path=X, RelativeSource={RelativeSource TemplatedParent}}" Y="{Binding Path=Y, RelativeSource={RelativeSource TemplatedParent}}"/>
               </TransformGroup>
           </Grid.RenderTransform>
           <StackPanel>
               <Path x:Name="_Path" Fill="{StaticResource JumpGateFillBrush}" Stroke="{StaticResource JumpGateStrokeBrush}" 
               StrokeThickness="{StaticResource JumpGateStrokeThickness}" Data="{StaticResource TrianglePathGeometry}" HorizontalAlignment="Center"/>
               <TextBlock x:Name="_TextBlock" Style="{StaticResource JumpGateTextStyle}" Margin="0, 12, 0, 0" Text="{Binding Path=Text, RelativeSource={RelativeSource TemplatedParent}}"/>
           </StackPanel>
       </Grid>

       <ControlTemplate.Triggers>
           <MultiTrigger>
               <MultiTrigger.Conditions>
                   <Condition Property="IsPressed" Value="True"/>
               </MultiTrigger.Conditions>
               <Trigger.EnterActions>
                   <BeginStoryboard Name="_PressStoryboard" Storyboard="{StaticResource Storyboard.Press}"/>
               </Trigger.EnterActions>
               <Trigger.ExitActions>
                   <BeginStoryboard Name="_ReleaseStoryboard" Storyboard="{StaticResource Storyboard.Release}"/>
               </Trigger.ExitActions>
           </MultiTrigger>
           <MultiTrigger>
               <MultiTrigger.Conditions>
                   <Condition Property="IsMouseOver" Value="True"/>
                   <Condition Property="IsEnabled" Value="True"/>
               </MultiTrigger.Conditions>
               <Trigger.EnterActions>
                   <BeginStoryboard Name="_MouseEnterStoryboard" Storyboard="{StaticResource Storyboard.MouseOver}"/>
               </Trigger.EnterActions>
               <Trigger.ExitActions>
                   <BeginStoryboard Name="_MouseExitStoryboard" Storyboard="{StaticResource Storyboard.MouseExit}"/>
               </Trigger.ExitActions>
           </MultiTrigger>
           <MultiTrigger>
               <MultiTrigger.Conditions>
                   <Condition Property="IsEnabled" Value="False"/>
               </MultiTrigger.Conditions>
               <Trigger.EnterActions>
                   <StopStoryboard BeginStoryboardName="_MouseEnterStoryboard"/>
                   <StopStoryboard BeginStoryboardName="_MouseExitStoryboard"/>
                   <BeginStoryboard x:Name="_DisabledStoryboard" Storyboard="{StaticResource Storyboard.Disabled}"/>
               </Trigger.EnterActions>
               <Trigger.ExitActions>
                   <BeginStoryboard Storyboard="{StaticResource Storyboard.MouseExit}"/>
               </Trigger.ExitActions>
           </MultiTrigger>
       </ControlTemplate.Triggers>
   </ControlTemplate>
JumpGateTemplate.xaml (3,674 bytes)   
sfernandez

sfernandez

2024-07-09 18:33

manager   ~0009776

Can you share the xaml that is set in the "Base Layer" View? You can post it in a private note if you want.

What is happening when you click is that is hitting a Border in that View, calling ev.Use(), and the WorldUI View does not receive any MouseDown/Up.

stonstad

stonstad

2024-07-09 19:45

reporter   ~0009783

Last edited: 2024-07-09 19:51

To explain what is happening, a gaussian blur effect is displayed in _BaseBlurSource. The visual tree is contained in _BaseLayer. I just tried adding IsHitTestVisible=False to the border and its container and the same behavior remains. MouseOver/Leave works but Down doesn't fire.

<Grid x:Name="_OverlayBlurSource">
<Grid x:Name="_BaseBlurSourceContainer" Opacity="0" IsHitTestVisible="False">
<Border x:Name="_BaseBlurSource" Background="{DynamicResource RenderTextureImageBrush}" Visibility="Collapsed" IsHitTestVisible="False"/>
</Grid>

<Grid x:Name="_BaseLayer"/> <!-- Hierarchy is here -->

</Grid>

Click. View Base Layer (UnityEngine.GameObject) hit Noesis.Border
-> Parent Noesis.Grid _BaseBlurSource
-> Parent Noesis.Grid _BaseBlurSourceContainer
-> Parent Noesis.Grid _OverlayBlurSource
-> Parent StellarConquest.Presentation.Unity.UI.UIStateMachine
-> Parent Noesis.AdornerDecorator _UIStateMachine

Since _BaseBlurSourceContainer.IsHitTestVisible=False, this shouldn't happen, right?

sfernandez

sfernandez

2024-07-10 12:34

manager   ~0009787

Is the Visibility of "_BaseBlurSource" Border always Collapsed? Or do you set that to Visible/Hidden at some point?
Collapsed elements should not be hit by VisualTreeHelper.HitTest. I've tested it and they are not returned as hit when Visibility=Collapsed, although they are if Visibility is Visible or Hidden.

IsHitTestVisible is a bit confusing, because the default VisualTreeHelper.HitTest behavior will return elements with that property set to false too. Perhaps we should use the callback version to filter out elements that have IsHitTestVisible=False. You can try it by changing NoesisView.HitTest method to the following code:

private bool HitTest(float x, float y)
{
Visual root = (Visual)VisualTreeHelper.GetRoot(_uiView.Content);
Point p = root.PointFromScreen(new Point(x, y));

DependencyObject hit = null;
VisualTreeHelper.HitTest(root,
    (visual) =>
    {
        UIElement element = visual as UIElement;
        if (element != null && !element.IsHitTestVisible)
        {
            return HitTestFilterBehavior.ContinueSkipSelfAndChildren;
        }

        return HitTestFilterBehavior.Continue;
    },
    (hitResult) =>
    {
        if (hitResult.VisualHit != null)
        {
            hit = hitResult.VisualHit;
            return HitTestResultBehavior.Stop;
        }

        return HitTestResultBehavior.Continue;
    },
    new PointHitTestParameters(p));

return hit != null;

}

stonstad

stonstad

2024-07-10 15:29

reporter   ~0009791

Yes, _BaseBlurSource visibility is toggled but with its parent set to IsHitTestVisible=False, BaseBlurSource should never trigger events.

The new code for HitTest() fixes the issue! Is this the final code that you would use to solve the issue, or might there be a more optimized version? Thank you for the troubleshooting. Is there anything you would like me to test while we have an easy reproduction for this behavior?

sfernandez

sfernandez

2024-07-10 17:25

manager   ~0009792

Another question... if you switch back "_BaseBlurSource" Visibility to Collapsed, does it work also as expected, allowing clicks in the WorldUI components?

stonstad

stonstad

2024-07-10 23:12

reporter   ~0009794

It works but this framework element is always visible because it is the background blur source for gaussian blur effects. This is why I am setting IsHitTestVisible=False.

sfernandez

sfernandez

2024-10-25 11:42

manager   ~0010057

We implemented my previous code, this means that all elements in the UI that are marked with IsHitTestVisible=False will be ignored by Noesis and the mouse events will reach the Scene3D objects.
If you want to use the old behavior just go to NoesisView.cs and comment the define IGNORE_ISHITTESTVISIBLE_FALSE_ELEMENTS at the top of the file.

Issue History

Date Modified Username Field Change
2024-07-08 15:36 stonstad New Issue
2024-07-08 15:39 stonstad Note Added: 0009762
2024-07-08 15:40 stonstad Note Edited: 0009762
2024-07-08 15:46 stonstad Note Added: 0009763
2024-07-09 12:11 sfernandez Assigned To => sfernandez
2024-07-09 12:11 sfernandez Status new => feedback
2024-07-09 12:11 sfernandez Note Added: 0009766
2024-07-09 17:56 stonstad Note Added: 0009773
2024-07-09 17:56 stonstad File Added: image.png
2024-07-09 17:56 stonstad File Added: JumpGateControl.cs
2024-07-09 17:56 stonstad File Added: JumpGateTemplate.xaml
2024-07-09 17:56 stonstad Status feedback => assigned
2024-07-09 17:57 stonstad Note Edited: 0009773
2024-07-09 18:33 sfernandez Status assigned => feedback
2024-07-09 18:33 sfernandez Note Added: 0009776
2024-07-09 19:30 stonstad Status feedback => assigned
2024-07-09 19:45 stonstad Note Added: 0009783
2024-07-09 19:51 stonstad Note Edited: 0009783
2024-07-10 12:34 sfernandez Status assigned => feedback
2024-07-10 12:34 sfernandez Note Added: 0009787
2024-07-10 15:29 stonstad Note Added: 0009791
2024-07-10 15:29 stonstad Status feedback => assigned
2024-07-10 17:25 sfernandez Status assigned => feedback
2024-07-10 17:25 sfernandez Note Added: 0009792
2024-07-10 23:12 stonstad Note Added: 0009794
2024-07-10 23:12 stonstad Status feedback => assigned
2024-10-07 15:15 jsantos Relationship added related to 0003734
2024-10-25 11:41 sfernandez Status assigned => resolved
2024-10-25 11:41 sfernandez Resolution open => fixed
2024-10-25 11:41 sfernandez Fixed in Version => 3.2.5
2024-10-25 11:41 sfernandez Target Version => 3.2.5
2024-10-25 11:42 sfernandez Note Added: 0010057
2025-10-10 13:29 jsantos Category Unity3D => Unity