public void OnGUI(Rect timeRect)
        {
            var tracingControlState = m_WindowGraphToolState.TracingControlState;

            // sync timeline and tracing toolbar state both ways
            m_State.CurrentTime = TimelineState.FrameToTime(tracingControlState.CurrentTracingFrame);

            m_Overlay.HandleEvents();
            int timeChangedByTimeline = TimelineState.TimeToFrame(m_State.CurrentTime);

            using (var updater = tracingControlState.UpdateScope)
            {
                // force graph update
                if (timeChangedByTimeline != tracingControlState.CurrentTracingFrame)
                {
                    updater.CurrentTracingStep = -1;
                }
                updater.CurrentTracingFrame = timeChangedByTimeline;
            }

            GUI.BeginGroup(timeRect);

            var         debugger = ((Stencil)m_WindowGraphToolState?.WindowState.GraphModel?.Stencil)?.Debugger;
            IGraphTrace trace    = debugger?.GetGraphTrace(m_WindowGraphToolState?.WindowState.GraphModel, tracingControlState.CurrentTracingTarget);

            if (trace?.AllFrames != null && trace.AllFrames.Count > 0)
            {
                float frameDeltaToPixel = m_TimeArea.FrameDeltaToPixel();
                int   firstFrame        = trace.AllFrames[0].Frame;
                int   lastFrame         = trace.AllFrames[trace.AllFrames.Count - 1].Frame;
                float start             = m_TimeArea.FrameToPixel(firstFrame);
                float width             = frameDeltaToPixel * Mathf.Max(lastFrame - firstFrame, 1);

                // draw active range
                EditorGUI.DrawRect(new Rect(start,
                                            timeRect.yMax - k_FrameRectangleHeight, width, k_FrameRectangleHeight), k_FrameHasDataColor);

                // draw per-node active ranges
                var framesPerNode = IndexFramesPerNode(ref s_FramesPerNodeCache, (Stencil)m_WindowGraphToolState?.WindowState.GraphModel?.Stencil, trace, firstFrame, lastFrame, tracingControlState.CurrentTracingTarget, out bool invalidated);

                // while recording in unpaused playmode, adjust the timeline to show all data
                // same if the cached data changed (eg. Load a trace dump)
                if (EditorApplication.isPlaying && !EditorApplication.isPaused || invalidated)
                {
                    m_TimeArea.SetShownRange(
                        firstFrame - k_MinTimeVisibleOnTheRight,
                        lastFrame + k_MinTimeVisibleOnTheRight);
                }

                if (framesPerNode != null)
                {
                    INodeModel nodeModelSelected = m_GraphView.GetSelection()
                                                   .OfType <INodeModel>()
                                                   .FirstOrDefault();

                    if (nodeModelSelected != null && framesPerNode.TryGetValue(nodeModelSelected.Guid, out List <(int InclusiveFirstFrame, int ExclusiveLastFrame)> frames))
                    {
                        foreach (var frameInterval in frames)
                        {
                            float xStart = m_TimeArea.FrameToPixel(frameInterval.InclusiveFirstFrame);
                            float xEnd   = m_TimeArea.FrameToPixel(frameInterval.ExclusiveLastFrame) - Mathf.Min(1, frameDeltaToPixel * 0.1f);
                            Rect  rect   = new Rect(
                                xStart,
                                timeRect.yMin,
                                xEnd - xStart,
                                timeRect.yMax);
                            EditorGUI.DrawRect(rect, k_FrameHasNodeColor);
                        }
                    }
                }
            }
            GUI.EndGroup();


            // time scales
            GUILayout.BeginArea(timeRect);
            m_TimeArea.Draw(timeRect);
            GUILayout.EndArea();

            // playing head
            m_Overlay.OnGUI(timeRect, timeRect);
        }