private void DrawActor(IDrawingCanvas drawingCanvas, ActorVisualElement actor, double offsetY) { Rect box = new Rect(actor.OffsetX, offsetY, m_actorsWidth, m_actorsHeight); actor.Text.SetForegroundBrush(ActorForeground); DrawTextBox(drawingCanvas, box, actor.Text, ActorBackground, ActorBorder, s_actorMargin, s_actorPadding, true); }
private double GetCenterX(ActorVisualElement actorVisualElement) { return(actorVisualElement.TextBB.X + m_actorsWidth / 2); }
private Size?MeasureAndArrangeVisualElements() { // Early out if there sequence diagram view model available var vm = ViewModel; if (vm == null) { return(null); } // Reset visual elements var actors = vm.Actors; var annotations = vm.Annotations; m_actorVisualElements = new List <ActorVisualElement>(actors.Count); m_signalVisualElements = new List <SignalVisualElement>(); m_noteVisualElements = new List <NoteVisualElement>(); m_actorsWidth = 0; m_actorsHeight = 0; m_annotationsBottom = 0; double offsetY = Margin.Top; // Capture typeface which is used to measure various textboxes m_typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch); // Layout actors foreach (var actor in actors) { var text = GetFormattedText(actor.Name, ActorForeground); var textBB = GetTextBB(text, s_actorMargin, s_actorPadding); var actorVisualElement = new ActorVisualElement { Text = text, TextBB = textBB, Distances = new double?[actors.Count] }; m_actorVisualElements.Add(actorVisualElement); m_actorsWidth = Math.Max(textBB.Width, m_actorsWidth); m_actorsHeight = Math.Max(textBB.Height, m_actorsHeight); } // Position at bottom edge of top actor text boxes offsetY += m_actorsHeight; // Layout all signal types foreach (var annotation in annotations) { double extraWidth = 0; bool skipFinalSignalLayout = false; // Indexes of the left and right actors involved int a = 0, b = 0; // Visual element AnnotationVisualElement annotationVisualElement = null; // Handle signals var signal = annotation as SignalViewModel; if (signal != null) { var text = GetFormattedText(annotation.Message, SignalForeground); var textBB = GetTextBB(text, s_signalMargin, s_signalPadding); var signalVisualElement = new SignalVisualElement { Text = text, TextBB = textBB, OffsetY = offsetY, IsSelfSignal = signal.IsSelf(), ActorA = m_actorVisualElements[signal.ActorA.Index], ActorB = m_actorVisualElements[signal.ActorB.Index], LineType = signal.LineType, ArrowType = signal.ArrowType, }; annotationVisualElement = signalVisualElement; m_signalVisualElements.Add(signalVisualElement); if (signal.IsSelf()) { // Self-signals need a minimum height a = signal.ActorA.Index; b = a + 1; // Self-signals take up extra horizontal space extraWidth += s_selfSignalWidth; } else { a = Math.Min(signal.ActorA.Index, signal.ActorB.Index); b = Math.Max(signal.ActorA.Index, signal.ActorB.Index); } } // Handle notes var note = annotation as NoteViewModel; if (note != null) { var text = GetFormattedText(annotation.Message, NoteForeground); var textBB = GetTextBB(text, s_noteMargin, s_notePadding); var noteVisualElement = new NoteVisualElement { Text = text, TextBB = textBB, OffsetY = offsetY, Placement = note.Placement, Message = note.Message, Actors = note.Actors.Select(actor => m_actorVisualElements[actor.Index]).ToArray(), }; annotationVisualElement = noteVisualElement; m_noteVisualElements.Add(noteVisualElement); if (note.Placement == SequenceNotePlacement.LeftOf) { b = note.Actors[0].Index; a = b - 1; } else if (note.Placement == SequenceNotePlacement.RightOf) { a = note.Actors[0].Index; b = a + 1; } else if (note.Placement == SequenceNotePlacement.Over) { if (note.Actors.Length > 1) { // Over multiple actors a = Math.Min(note.Actors[0].Index, note.Actors[1].Index); b = Math.Max(note.Actors[0].Index, note.Actors[1].Index); // We don't need our padding, and we want to overlap extraWidth = -(s_noteMargin.Left + s_noteMargin.Right + s_noteOverlap.Left + s_noteOverlap.Right); } else { // Over single actor a = note.Actors[0].Index; ActorEnsureDistance(a - 1, a, noteVisualElement.TextBB.Width / 2); ActorEnsureDistance(a, a + 1, noteVisualElement.TextBB.Width / 2); // Skip calculation of the signal height in this case skipFinalSignalLayout = true; } } } // Ensure proper spacing between actors if (!skipFinalSignalLayout) { ActorEnsureDistance(a, b, annotationVisualElement.TextBB.Width + extraWidth); } // Adjust offset by by annotiation height offsetY += annotationVisualElement.TextBB.Height; } m_annotationsBottom = offsetY; // Compute the overall size of the diagram double actorsX = 0; foreach (var actor in m_actorVisualElements) { actor.OffsetX = Math.Max(actorsX, actor.OffsetX); // This requires that we enumerate distances in order for (int i = 0; i < actor.Distances.Length; ++i) { double?distance = actor.Distances[i]; // Only process well-defined distances if (distance.HasValue) { ActorVisualElement b = m_actorVisualElements[i]; double d = Math.Max(distance.Value, Math.Max(m_actorsWidth / 2, b.TextBB.Width / 2)); b.OffsetX = Math.Max(b.OffsetX, actor.OffsetX + m_actorsWidth / 2 + d - b.TextBB.Width / 2); } } actorsX = actor.OffsetX + m_actorsWidth + actor.PaddingRight; } // Determine total size Size size = new Size(); size.Width = actorsX + Margin.Left + Margin.Right; size.Height = Margin.Top + Margin.Bottom + m_annotationsBottom + m_actorsHeight; return(size); }