void ProcessEvent(EventBase evt, [NotNull] IPanel panel)
        {
            Event e = evt.imguiEvent;
            // Sometimes (in tests only?) we receive Used events. Protect our verification from this case.
            bool imguiEventIsInitiallyUsed = e != null && e.rawType == EventType.Used;

            using (new EventDispatcherGate(this))
            {
                evt.PreDispatch(panel);

                if (!evt.stopDispatch && !evt.isPropagationStopped)
                {
                    ApplyDispatchingStrategies(evt, panel, imguiEventIsInitiallyUsed);
                }

                // Last chance to build a path. Some dispatching strategies (e.g. PointerCaptureDispatchingStrategy)
                // don't call PropagateEvents but still need to call ExecuteDefaultActions on composite roots.
                var path = evt.path;
                if (path == null && evt.bubblesOrTricklesDown && evt.leafTarget is VisualElement leafTarget)
                {
                    path     = PropagationPaths.Build(leafTarget, evt);
                    evt.path = path;
                    EventDebugger.LogPropagationPaths(evt, path);
                }

                if (path != null)
                {
                    foreach (var element in path.targetElements)
                    {
                        if (element.panel == panel)
                        {
                            evt.target = element;
                            EventDispatchUtilities.ExecuteDefaultAction(evt);
                        }
                    }

                    // Reset target to leaf target
                    evt.target = evt.leafTarget;
                }
                else
                {
                    // If no propagation path, make sure EventDispatchUtilities.ExecuteDefaultAction has a target
                    if (!(evt.target is VisualElement target))
                    {
                        evt.target = target = panel.visualTree;
                    }

                    if (target.panel == panel)
                    {
                        EventDispatchUtilities.ExecuteDefaultAction(evt);
                    }
                }

                m_DebuggerEventDispatchingStrategy.PostDispatch(evt, panel);

                evt.PostDispatch(panel);

                m_ClickDetector.ProcessEvent(evt);

                Debug.Assert(imguiEventIsInitiallyUsed || evt.isPropagationStopped || e == null || e.rawType != EventType.Used, "Event is used but not stopped.");
            }
        }
        private static void HandleEventAcrossPropagationPath(EventBase evt)
        {
            // Build and store propagation path
            var leafTarget = (VisualElement)evt.leafTarget;
            var path       = PropagationPaths.Build(leafTarget, evt);

            evt.path = path;
            EventDebugger.LogPropagationPaths(evt, path);

            var panel = leafTarget.panel;

            // Phase 1: TrickleDown phase
            // Propagate event from root to target.parent
            if (evt.tricklesDown)
            {
                evt.propagationPhase = PropagationPhase.TrickleDown;

                for (int i = path.trickleDownPath.Count - 1; i >= 0; i--)
                {
                    if (evt.isPropagationStopped)
                    {
                        break;
                    }

                    var element = path.trickleDownPath[i];
                    if (evt.Skip(element) || element.panel != panel)
                    {
                        continue;
                    }

                    evt.currentTarget = element;
                    evt.currentTarget.HandleEvent(evt);
                }
            }

            // Phase 2: Target / DefaultActionAtTarget
            // Propagate event from target parent up to root for the target phase

            // Call HandleEvent() even if propagation is stopped, for the default actions at target.
            evt.propagationPhase = PropagationPhase.AtTarget;
            foreach (var element in path.targetElements)
            {
                if (evt.Skip(element) || element.panel != panel)
                {
                    continue;
                }

                evt.target        = element;
                evt.currentTarget = evt.target;
                evt.currentTarget.HandleEvent(evt);
            }

            // Call ExecuteDefaultActionAtTarget
            evt.propagationPhase = PropagationPhase.DefaultActionAtTarget;
            foreach (var element in path.targetElements)
            {
                if (evt.Skip(element) || element.panel != panel)
                {
                    continue;
                }

                evt.target        = element;
                evt.currentTarget = evt.target;
                evt.currentTarget.HandleEvent(evt);
            }

            // Reset target to original target
            evt.target = evt.leafTarget;

            // Phase 3: bubble up phase
            // Propagate event from target parent up to root
            if (evt.bubbles)
            {
                evt.propagationPhase = PropagationPhase.BubbleUp;

                foreach (var element in path.bubbleUpPath)
                {
                    if (evt.Skip(element) || element.panel != panel)
                    {
                        continue;
                    }

                    evt.currentTarget = element;
                    evt.currentTarget.HandleEvent(evt);
                }
            }

            evt.propagationPhase = PropagationPhase.None;
            evt.currentTarget    = null;
        }