File size: 5,529 Bytes
18a519f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine.EventSystems;

namespace UnityEngine.UIElements
{
#if PACKAGE_UITOOLKIT
    /// <summary>
    /// A derived BaseRaycaster to raycast against UI Toolkit panel instances at runtime.
    /// </summary>
    [AddComponentMenu("UI Toolkit/Panel Raycaster (UI Toolkit)")]
    public class PanelRaycaster : BaseRaycaster, IRuntimePanelComponent
    {
        private BaseRuntimePanel m_Panel;

        /// <summary>
        /// The panel that this component relates to. If panel is null, this component will have no effect.
        /// Will be set to null automatically if panel is Disposed from an external source.
        /// </summary>
        public IPanel panel
        {
            get => m_Panel;
            set
            {
                var newPanel = (BaseRuntimePanel)value;
                if (m_Panel != newPanel)
                {
                    UnregisterCallbacks();
                    m_Panel = newPanel;
                    RegisterCallbacks();
                }
            }
        }

        void RegisterCallbacks()
        {
            if (m_Panel != null)
            {
                m_Panel.destroyed += OnPanelDestroyed;
            }
        }

        void UnregisterCallbacks()
        {
            if (m_Panel != null)
            {
                m_Panel.destroyed -= OnPanelDestroyed;
            }
        }

        void OnPanelDestroyed()
        {
            panel = null;
        }

        private GameObject selectableGameObject => m_Panel?.selectableGameObject;

        public override int sortOrderPriority => (int)(m_Panel?.sortingPriority ?? 0f);
        public override int renderOrderPriority => ConvertFloatBitsToInt(m_Panel?.sortingPriority ?? 0f);

        public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
        {
            if (m_Panel == null)
                return;

            var eventPosition = Display.RelativeMouseAt(eventData.position);
            var displayIndex = m_Panel.targetDisplay;

            var originalEventPosition = eventPosition;
            if (eventPosition != Vector3.zero)
            {
                // We support multiple display and display identification based on event position.

                int eventDisplayIndex = (int)eventPosition.z;

                // Discard events that are not part of this display so the user does not interact with multiple displays at once.
                if (eventDisplayIndex != displayIndex)
                    return;
            }
            else
            {
                // The multiple display system is not supported on all platforms, when it is not supported the returned position
                // will be all zeros so when the returned index is 0 we will default to the event data to be safe.
                eventPosition = eventData.position;
#if UNITY_EDITOR
                if (Display.activeEditorGameViewTarget != displayIndex)
                    return;
                eventPosition.z = Display.activeEditorGameViewTarget;
#endif

                // We don't really know in which display the event occurred. We will process the event assuming it occurred in our display.
            }

            var position = eventPosition;
            var delta = eventData.delta;

            float h = Screen.height;
            if (displayIndex > 0 && displayIndex < Display.displays.Length)
            {
                h = Display.displays[displayIndex].systemHeight;
            }

            position.y = h - position.y;
            delta.y = -delta.y;

            var eventSystem = UIElementsRuntimeUtility.activeEventSystem as EventSystem;
            if (eventSystem == null || eventSystem.currentInputModule == null)
                return;
            var pointerId = eventSystem.currentInputModule.ConvertUIToolkitPointerId(eventData);

            var capturingElement = m_Panel.GetCapturingElement(pointerId);
            if (capturingElement is VisualElement ve && ve.panel != m_Panel)
                return;

            var capturingPanel = PointerDeviceState.GetPressedButtons(pointerId) != 0 ?
                                 PointerDeviceState.GetPlayerPanelWithSoftPointerCapture(pointerId) :
                                 null;
            if (capturingPanel != null && capturingPanel != m_Panel)
                return;

            if (capturingElement == null && capturingPanel == null)
            {
                if (!m_Panel.ScreenToPanel(position, delta, out var panelPosition, out _))
                    return;

                var pick = m_Panel.Pick(panelPosition);
                if (pick == null)
                    return;
            }

            resultAppendList.Add(new RaycastResult
            {
                gameObject = selectableGameObject,
                module = this,
                screenPosition = eventPosition,
                displayIndex = m_Panel.targetDisplay,
            });
        }

        public override Camera eventCamera => null;


        [StructLayout(LayoutKind.Explicit, Size = sizeof(int))]
        private struct FloatIntBits
        {
            [FieldOffset(0)]
            public float f;
            [FieldOffset(0)]
            public int i;
        }

        private static int ConvertFloatBitsToInt(float f)
        {
            FloatIntBits bits = new FloatIntBits {f = f};
            return bits.i;
        }
    }
#endif
}