private void DrawGroupsAndTracks(TimelinePath path, ITimeline timeline, bool expandedTimeline, ISelectionContext selection, Context c, TimelineLayout layout, RectangleF clipBounds) { RectangleF canvasBounds = clipBounds; //clipBounds minus the left-side header canvasBounds.X = HeaderWidth; canvasBounds.Width -= HeaderWidth; RectangleF bounds; foreach (IGroup group in timeline.Groups) { TimelinePath groupPath = path + group; if (!layout.TryGetBounds(groupPath, out bounds)) continue; if (bounds.IntersectsWith(clipBounds)) { DrawMode drawMode = DrawMode.Normal; if (selection.SelectionContains(groupPath)) drawMode |= DrawMode.Selected; if (expandedTimeline) Draw(group, bounds, drawMode, c); IList<ITrack> tracks = group.Tracks; bool collapsed = !expandedTimeline || (!group.Expanded && tracks.Count > 1); foreach (ITrack track in tracks) { TimelinePath trackPath = path + track; bounds = layout.GetBounds(trackPath); if (bounds.IntersectsWith(clipBounds)) { drawMode = DrawMode.Normal; if (selection.SelectionContains(trackPath)) drawMode |= DrawMode.Selected; if (collapsed) drawMode = DrawMode.Collapsed; Draw(track, bounds, drawMode, c); foreach (IInterval interval in track.Intervals) { TimelinePath intervalPath = path + interval; bounds = layout.GetBounds(intervalPath); if (bounds.IntersectsWith(canvasBounds)) { drawMode = DrawMode.Normal; if (selection.SelectionContains(intervalPath)) drawMode |= DrawMode.Selected; if (collapsed) drawMode = DrawMode.Collapsed; Draw(interval, bounds, drawMode, c); } } foreach (IKey key in track.Keys) { TimelinePath keyPath = path + key; bounds = layout.GetBounds(keyPath); if (bounds.IntersectsWith(canvasBounds)) { drawMode = DrawMode.Normal; if (selection.SelectionContains(keyPath)) drawMode |= DrawMode.Selected; if (collapsed) drawMode = DrawMode.Collapsed; Draw(key, bounds, drawMode, c); } } } } } } }
private void DrawSubTimeline( TimelinePath path, ISelectionContext selection, TimelinePath activeGroup, TimelinePath activeTrack, TimelineLayout layout, Context c) { // Include the reference's offset into the Transform and InverseTransform properties. Matrix localToWorld = D2dTimelineControl.CalculateLocalToWorld(path); c.PushTransform(localToWorld, MatrixOrder.Prepend); // draw the row that has this timeline reference's name ITimelineReference reference = (ITimelineReference)path.Last; RectangleF clipBounds = m_graphics.ClipBounds; RectangleF bounds = layout.GetBounds(path); IHierarchicalTimeline timeline = reference.Target; if (bounds.IntersectsWith(clipBounds)) { DrawMode drawMode = DrawMode.Normal; if (selection.SelectionContains(path)) drawMode |= DrawMode.Selected; DrawTimelineReference(reference, bounds, drawMode, c); } // draw the timeline document as if it were the main document if (timeline != null) DrawSubTimeline(path, timeline, true, reference.Options.Expanded, selection, activeGroup, activeTrack, layout, c); c.PopTransform(); }
private void DrawSubTimeline( TimelinePath path, ITimeline timeline, bool subTimeline, bool expandedTimeline, ISelectionContext selection, TimelinePath activeGroup, TimelinePath activeTrack, TimelineLayout layout, Context c) { //if (c.TestRecursion(timeline)) // return; if (!subTimeline) m_offsetX = c.Transform.OffsetX; RectangleF clipBounds = m_graphics.ClipBounds; DrawGroupsAndTracks(path, timeline, expandedTimeline, selection, c, layout, clipBounds); // draw markers over keys, intervals, tracks, and group if (subTimeline) { // Give the Markers in the main timeline precedence; draw on top of everything. clipBounds.X = HeaderWidth; clipBounds.Width -= HeaderWidth; DrawMarkers(path, timeline, selection, c, layout, clipBounds); } // Draw the group and track handles only if the owning timeline is expanded. if (expandedTimeline) { if (m_printing) c.Graphics.TranslateTransform(m_marginBounds.Left, 0); RectangleF bounds; foreach (IGroup group in timeline.Groups) { IList<ITrack> tracks = group.Tracks; TimelinePath groupPath = path + group; bounds = layout.GetBounds(groupPath); bounds = GetGroupHandleRect(bounds, !group.Expanded); RectangleF groupLabelBounds = new RectangleF(bounds.X, bounds.Y, HeaderWidth, bounds.Height); // Draw group's move handle. DrawMoveHandle(bounds, selection.SelectionContains(groupPath), groupPath == activeGroup); // Draw expander? if (tracks.Count > 1) { RectangleF expanderRect = GetExpanderRect(bounds); m_graphics.DrawExpander( expanderRect.X, expanderRect.Y, expanderRect.Width, m_expanderBrush, group.Expanded); groupLabelBounds.X += TrackIndent; groupLabelBounds.Width -= TrackIndent; } // Draw tracks' move handles? if (group.Expanded || tracks.Count == 1) { foreach (ITrack track in tracks) { TimelinePath trackPath = path + track; bounds = layout.GetBounds(trackPath); bounds = GetTrackHandleRect(bounds); DrawMoveHandle(bounds, selection.SelectionContains(trackPath), trackPath == activeTrack); if (bounds.Width > 0f) m_graphics.DrawText(track.Name, m_trackTextFormat, bounds, m_nameBrush); } } // Draw group name. if (groupLabelBounds.Width > 0) m_graphics.DrawText(group.Name, c.TextFormat, groupLabelBounds, m_nameBrush); } if (m_printing) c.Graphics.TranslateTransform(-m_marginBounds.Left, 0); } return; }
/// <summary> /// Prioritizes the hits, using layout and picking rectangle information. This is called after /// PrioritizeHits().</summary> /// <param name="hits">The timeline objects to sort, that intersect the given rectangle</param> /// <param name="layout">The layout</param> /// <param name="pickRect">The picking rectangle</param> protected virtual void PrioritizeHits(List<HitRecord> hits, TimelineLayout layout, RectangleF pickRect) { if (hits.Count <= 1) return; float pickCenterX = pickRect.X + pickRect.Width*0.5f; float pickCenterY = pickRect.Y + pickRect.Height*0.5f; hits.Sort((a, b) => { if (a.Type < b.Type) return -1; if (a.Type > b.Type) return 1; // The HeaderResize type doesn't have a HitPath. if (a.HitPath == null || b.HitPath == null) return 0; // They're the same type, so now sort by distance from center of picking rectangle. RectangleF aRect = layout.GetBounds(a.HitPath); RectangleF bRect = layout.GetBounds(b.HitPath); float aDist = Math.Min( Math.Abs(aRect.X + aRect.Width*0.5f - pickCenterX), Math.Abs(aRect.Y + aRect.Height*0.5f - pickCenterY)); float bDist = Math.Min( Math.Abs(bRect.X + bRect.Width * 0.5f - pickCenterX), Math.Abs(bRect.Y + bRect.Height * 0.5f - pickCenterY)); if (aDist < bDist) return -1; if (aDist > bDist) return 1; return 0; }); }