// Create a description line for a normal header line: name, length, climb private DescriptionLine GetNormalHeaderLine() { DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Header3Box; line.boxes = new object[3]; line.boxes[0] = courseView.CourseFullName; line.boxes[1] = Util.GetLengthInKm(courseView.MinTotalLength, courseView.MaxTotalLength, 1); if (purpose == Purpose.ForMap) { Id <Course> courseId = courseView.CourseDesignator.CourseId; if (courseId.IsNotNone && eventDB.GetCourse(courseId).hideVariationsOnMap) { line.boxes[0] = courseView.CourseNameAndPart; } } if (courseView.TotalClimb < 0) { line.boxes[2] = null; line.textual = string.Format(symbolDB["course_length"].GetText(language), line.boxes[1]); } else { line.boxes[2] = Convert.ToString(Math.Round(courseView.TotalClimb / 5, MidpointRounding.AwayFromZero) * 5.0) + " m"; line.textual = string.Format(symbolDB["course_length_climb"].GetText(language), line.boxes[1], line.boxes[2]); } return(line); }
// Get a directive line for a map exchange at a control (not to the finish). private DescriptionLine GetMapExchangeAtControlLine(CourseView.ControlView controlWithExchange) { DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Directive; line.boxes = new object[2]; // Distance is 0m at the control! string distanceText = string.Format("{0} m", 0); // Box 1: directive graphics. string symbolId = "13.5control"; line.boxes[0] = symbolDB[symbolId]; // Box 2: distance of the flagging line.boxes[1] = distanceText; // Get the text version of the control using the Textifier. Textifier textifier = new Textifier(eventDB, symbolDB, language); line.textual = textifier.CreateTextForDirective(symbolId, distanceText); // The course control IDs, for use in coordinating the selection line.controlId = controlWithExchange.controlId; line.courseControlId = controlWithExchange.courseControlIds[0]; return(line); }
public AddDescriptionMode(Controller controller, UndoMgr undoMgr, SelectionMgr selectionMgr, EventDB eventDB, SymbolDB symbolDB, CourseDesignator courseDesignator, DescriptionLine[] description, DescriptionKind kind) { this.controller = controller; this.undoMgr = undoMgr; this.selectionMgr = selectionMgr; this.symbolDB = symbolDB; this.eventDB = eventDB; this.courseDesignator = courseDesignator; this.description = description; this.kind = kind; }
// Get the header line for the All Controls listing. private DescriptionLine GetAllVariationsHeaderLine() { DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Header2Box; line.boxes = new object[2]; line.boxes[0] = MiscText.AllVariations; line.boxes[1] = string.Format(symbolDB["number_controls"].GetText(language), courseView.TotalNormalControls); line.textual = (string)line.boxes[1]; return(line); }
// Determine if this description line is the same as another, primarily so we don't have to repaint it. public override bool Equals(object obj) { if (obj == null || !(obj is DescriptionLine)) { return(false); } DescriptionLine other = (DescriptionLine)obj; if (other.kind != kind) { return(false); } if (other.textual != textual) { return(false); } if (other.isLeg != isLeg) { return(false); } if (other.courseControlId != courseControlId) { return(false); } if (isLeg && (other.courseControlId2 != courseControlId2)) { return(false); } if (other.controlId != controlId) { return(false); } if (other.boxes.Length != boxes.Length) { return(false); } for (int i = 0; i < boxes.Length; ++i) { if (!object.Equals(boxes[i], other.boxes[i])) { return(false); } } return(true); }
public Id <ControlPoint> controlId; // The control ID, just for editing/selection purposes. // Should there be no boundry between the following description lines. public static bool NoBoundaryBetween(DescriptionLine descLine1, DescriptionLine descLine2) { if (descLine1.kind == descLine2.kind) { switch (descLine1.kind) { case DescriptionLineKind.Title: case DescriptionLineKind.SecondaryTitle: return(true); case DescriptionLineKind.Text: return(descLine1.textLineKind == descLine2.textLineKind); } } return(false); }
// Given the text, create descriptions line for a title line with that text. Lines are split by vertical bars. private DescriptionLine[] GetTitleLineFromText(DescriptionLineKind kind, string text) { string[] texts = text.Split(new char[] { '|' }); int lineCount = texts.Length; DescriptionLine[] lines = new DescriptionLine[lineCount]; for (int index = 0; index < lineCount; ++index) { DescriptionLine line = new DescriptionLine(); line.kind = kind; line.boxes = new object[1]; line.boxes[0] = texts[index]; line.textual = texts[index]; lines[index] = line; } return(lines); }
// Given the text, create one or more text lines for that text. Lines are split by vertical bars. private DescriptionLine[] GetTextLineFromText(string text, Id <CourseControl> courseControlId, Id <ControlPoint> controlId, DescriptionLine.TextLineKind textLineKind) { string[] texts = text.Split(new char[] { '|' }); int lineCount = texts.Length; DescriptionLine[] lines = new DescriptionLine[lineCount]; for (int index = 0; index < lineCount; ++index) { DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Text; line.boxes = new object[1]; line.boxes[0] = texts[index]; line.textual = texts[index]; line.courseControlId = courseControlId; line.controlId = controlId; line.textLineKind = textLineKind; lines[index] = line; } return(lines); }
// Get a directive line for a marked route (not to the finish). The legId must be valid, because a marked route only occurs // with a real leg id. private DescriptionLine GetMarkedRouteLine(CourseView.ControlView controlViewFrom, CourseView.ControlView controlViewTo, Id <Leg> legId) { Leg leg = eventDB.GetLeg(legId); Debug.Assert(leg.flagging != FlaggingKind.None && leg.flagging != FlaggingKind.End); DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Directive; line.boxes = new object[2]; // Figure out the distance in the directive, rounded to nearest 10m. string distanceText; float distance = QueryEvent.ComputeFlaggedLegLength(eventDB, leg.controlId1, leg.controlId2, legId); distance = (float)(Math.Round(distance / 10.0) * 10.0); // round to nearest 10 m. distanceText = string.Format("{0} m", distance); // Box 1: directive graphics. string symbolId = (leg.flagging == FlaggingKind.Begin) ? "13.1" : "13.2"; line.boxes[0] = symbolDB[symbolId]; // Box 2: distance of the flagging line.boxes[1] = distanceText; // Get the text version of the control using the Textifier. Textifier textifier = new Textifier(eventDB, symbolDB, language); line.textual = textifier.CreateTextForDirective(symbolId, distanceText); // The course control IDs, for use in coordinating the selection line.isLeg = true; line.controlId = controlViewFrom.controlId; line.courseControlId = controlViewFrom.courseControlIds[0]; line.courseControlId2 = controlViewTo.courseControlIds[0]; return(line); }
// Get a description line for the header line for a score course, which contains the total points private DescriptionLine GetScoreHeaderLine() { DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Header2Box; line.boxes = new object[2]; line.boxes[0] = courseView.CourseFullName; // If there is scoring, display the total score, else display the total number of controls (e.g., // for a score course with no points for each control. if (courseView.TotalScore > 0) { line.boxes[1] = string.Format(symbolDB["number_points"].GetText(language), courseView.TotalScore); } else { line.boxes[1] = string.Format(symbolDB["number_controls"].GetText(language), courseView.TotalNormalControls); } line.textual = (string)line.boxes[1]; return(line); }
// Get a directive line for a flagged route to map exchange (not to the finish). The distance between the controls is calculated and used for the distance // in the direction. private DescriptionLine GetMapExchangeLine(CourseView.ControlView controlViewFrom, CourseView.ControlView controlViewTo) { DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Directive; line.boxes = new object[2]; // Figure out the distance in the directive, rounded to nearest 10m. float distance; // default distance is zero. string distanceText; distance = controlViewFrom.legLength[0]; distance = (float)(Math.Round(distance / 10.0) * 10.0); // round to nearest 10 m. distanceText = string.Format("{0} m", distance); // Box 1: directive graphics. string symbolId = "13.5"; line.boxes[0] = symbolDB[symbolId]; // Box 2: distance of the flagging line.boxes[1] = distanceText; // Get the text version of the control using the Textifier. Textifier textifier = new Textifier(eventDB, symbolDB, language); line.textual = textifier.CreateTextForDirective(symbolId, distanceText); // The course control IDs, for use in coordinating the selection line.isLeg = true; line.controlId = controlViewFrom.controlId; line.courseControlId = controlViewFrom.courseControlIds[0]; line.courseControlId2 = controlViewTo.courseControlIds[0]; return(line); }
// Remove all text and symbol from a description line, leaving only the "grid" when rendered. public static void ClearTextAndSymbols(DescriptionLine[] lines) { foreach (DescriptionLine line in lines) { line.textual = null; for (int i = 0; i < line.boxes.Length; ++i) line.boxes[i] = null; } }
public static void DumpDescription(SymbolDB symbolDB, DescriptionLine[] lines, TextWriter writer) { foreach (DescriptionLine line in lines) DumpDescriptionLine(symbolDB, line, writer); }
// Get the header line for the All Controls listing. private DescriptionLine GetAllVariationsHeaderLine() { DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Header2Box; line.boxes = new object[2]; line.boxes[0] = MiscText.AllVariations; line.boxes[1] = string.Format(symbolDB["number_controls"].GetText(language), courseView.TotalNormalControls); line.textual = (string)line.boxes[1]; return line; }
// Dump a description line to a text writer. static void DumpDescriptionLine(SymbolDB symbolDB, DescriptionLine line, TextWriter writer) { if (line.controlId.IsNotNone) writer.Write("({0,3}) |", line.controlId); else writer.Write(" |"); switch (line.kind) { case DescriptionLineKind.Title: case DescriptionLineKind.SecondaryTitle: case DescriptionLineKind.Text: writer.Write(" {0,-46}|", line.boxes[0]); break; case DescriptionLineKind.Normal: for (int i = 0; i < 8; ++i) { string text; if (line.boxes[i] == null) text = ""; else if (line.boxes[i] is Symbol) text = ((Symbol)(line.boxes[i])).Id; else text = (string)(line.boxes[i]); writer.Write("{0,5}|", line.boxes[i] is Symbol ? ((Symbol)(line.boxes[i])).Id : (string)(line.boxes[i])); } break; case DescriptionLineKind.Header3Box: writer.Write("{0,-17}|", line.boxes[0] == null ? "" : (string)(line.boxes[0])); writer.Write("{0,-17}|", line.boxes[1] == null ? "" : (string)(line.boxes[1])); writer.Write("{0,-11}|", line.boxes[2] == null ? "" : (string)(line.boxes[2])); break; case DescriptionLineKind.Header2Box: writer.Write("{0,-17}|", line.boxes[0] == null ? "" : (string) (line.boxes[0])); writer.Write("{0,-29}|", line.boxes[1] == null ? "" : (string) (line.boxes[1])); break; case DescriptionLineKind.Key: writer.Write("{0,-17}|", line.boxes[0] == null ? "" : ((Symbol) (line.boxes[0])).Id); writer.Write("{0,-29}|", line.boxes[1] == null ? "" : (string) (line.boxes[1])); break; case DescriptionLineKind.Directive: writer.Write(" {0,16}: {1,-24}|", line.boxes[0] != null ? ((Symbol)(line.boxes[0])).Id : "", line.boxes[1] == null ? "" : (string)(line.boxes[1])); break; } if (line.textual != null) writer.Write(" [{0}]", line.textual); writer.WriteLine(); }
// Get a directive line for a map exchange at a control (not to the finish). private DescriptionLine GetMapExchangeAtControlLine(CourseView.ControlView controlWithExchange) { DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Directive; line.boxes = new object[2]; // Distance is 0m at the control! string distanceText = string.Format("{0} m", 0); // Box 1: directive graphics. string symbolId = "13.5control"; line.boxes[0] = symbolDB[symbolId]; // Box 2: distance of the flagging line.boxes[1] = distanceText; // Get the text version of the control using the Textifier. Textifier textifier = new Textifier(eventDB, symbolDB, language); line.textual = textifier.CreateTextForDirective(symbolId, distanceText); // The course control IDs, for use in coordinating the selection line.controlId = controlWithExchange.controlId; line.courseControlId = controlWithExchange.courseControlIds[0]; return line; }
// Get a directive line for a finish or crossingpoint. private DescriptionLine GetDirectiveLine(CourseView.CourseViewKind kind, CourseView.ControlView controlView, CourseView.ControlView controlViewPrev) { ControlPoint control = eventDB.GetControl(controlView.controlId); CourseControl courseControl; if (controlView.courseControlIds[0].IsNone) { courseControl = null; } else { courseControl = eventDB.GetCourseControl(controlView.courseControlIds[0]); } Debug.Assert(control.kind == ControlPointKind.Finish || control.kind == ControlPointKind.CrossingPoint || control.kind == ControlPointKind.MapIssue); DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Directive; line.boxes = new object[2]; // Figure out the distance in the directive, rounded to nearest 10m. float distance = float.NaN; string distanceText; if (control.kind == ControlPointKind.MapIssue) { if (controlView.legLength != null) { distance = controlView.legLength[0]; } } else { if (controlViewPrev != null && controlViewPrev.legLength != null) { distance = controlViewPrev.legLength[0]; } } if (!float.IsNaN(distance)) { distance = (float)(Math.Round(distance / 10.0) * 10.0); // round to nearest 10 m. distanceText = string.Format("{0} m", distance); } else { distanceText = ""; } // Box 1: directive graphics. string directiveId = control.symbolIds[0]; // Based on the leg flagging, we may modify the finish directive symbol. if (control.kind == ControlPointKind.Finish && (kind == CourseView.CourseViewKind.Normal || kind == CourseView.CourseViewKind.AllVariations)) { FlaggingKind flagging = FlaggingKind.None; if (controlView != null && controlViewPrev != null) { flagging = QueryEvent.GetLegFlagging(eventDB, controlViewPrev.controlId, controlView.controlId); } if (flagging == FlaggingKind.All) { directiveId = "14.1"; // If flagging is All, then finish id must be flagging to finish. } else if (flagging == FlaggingKind.End) { directiveId = "14.2"; // If flagging is Partial, then finish id must be flagging to funnel. } } line.boxes[0] = symbolDB[directiveId]; // Box 2: distance for the control, if any. if (control.kind == ControlPointKind.Finish || control.kind == ControlPointKind.MapIssue) { line.boxes[1] = distanceText; } // Get the text version of the control using the Textifier. Textifier textifier = new Textifier(eventDB, symbolDB, language); line.textual = textifier.CreateTextForDirective(directiveId, distanceText); // The course control ID, for use in coordinating the selection line.controlId = controlView.controlId; line.courseControlId = controlView.courseControlIds[0]; return(line); }
// Given the text, create one or more text lines for that text. Lines are split by vertical bars. private DescriptionLine[] GetTextLineFromText(string text, Id<CourseControl> courseControlId, Id<ControlPoint> controlId, DescriptionLine.TextLineKind textLineKind) { string[] texts = text.Split(new char[] { '|' }); int lineCount = texts.Length; DescriptionLine[] lines = new DescriptionLine[lineCount]; for (int index = 0; index < lineCount; ++index) { DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Text; line.boxes = new object[1]; line.boxes[0] = texts[index]; line.textual = texts[index]; line.courseControlId = courseControlId; line.controlId = controlId; line.textLineKind = textLineKind; lines[index] = line; } return lines; }
// Get a regular 8-box line for a start or regular control. private DescriptionLine GetRegularLine(CourseView.CourseViewKind kind, int scoreColumn, CourseView.ControlView controlView, Dictionary<string, string> descriptionKey) { Event ev = eventDB.GetEvent(); ControlPoint control = eventDB.GetControl(controlView.controlId); CourseControl courseControl; if (controlView.courseControlIds[0].IsNone) courseControl = null; else courseControl = eventDB.GetCourseControl(controlView.courseControlIds[0]); Debug.Assert(control.kind == ControlPointKind.Normal || control.kind == ControlPointKind.Start || control.kind == ControlPointKind.MapExchange); DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Normal; line.boxes = new object[8]; // Box A: ordinal or start triangle or points. if (control.kind == ControlPointKind.Start || control.kind == ControlPointKind.MapExchange) line.boxes[0] = symbolDB["start"]; else if (kind != CourseView.CourseViewKind.AllControls && controlView.ordinal > 0) line.boxes[0] = Convert.ToString(controlView.ordinal); else line.boxes[0] = null; // Box B: code of the control if (control.kind == ControlPointKind.Normal) line.boxes[1] = Convert.ToString(control.code); // Boxes C-H, from the symbols for (int i = 2; i < 8; ++i) { String symbolID = control.symbolIds[i - 2]; if (symbolID != null) { line.boxes[i] = symbolDB[control.symbolIds[i - 2]]; // See if we need to add this to the key. bool addToKey; if (ev.customSymbolKey.TryGetValue(symbolID, out addToKey) && addToKey && Symbol.ContainsLanguage(ev.customSymbolText[symbolID], language)) { descriptionKey[symbolID] = Symbol.GetBestSymbolText(symbolDB, ev.customSymbolText[symbolID], language, false, "", ""); } } } // Box F -- may be text instead of a symbol. if (control.columnFText != null) { Debug.Assert(line.boxes[5] == null); line.boxes[5] = control.columnFText; } // Put points in the score column, for a score course. if (control.kind == ControlPointKind.Normal && scoreColumn >= 0 && courseControl != null) { int points = courseControl.points; if (points > 0) line.boxes[scoreColumn] = Convert.ToString(courseControl.points); else line.boxes[scoreColumn] = null; } // Get the text version of the control using the Textifier. Textifier textifier = new Textifier(eventDB, symbolDB, language); line.textual = textifier.CreateTextForControl(controlView.controlId, ""); // The course control ID, for use in coordinating the selection line.controlId = controlView.controlId; line.courseControlId = controlView.courseControlIds[0]; return line; }
// Get a description line for the header line for a score course, which contains the total points private DescriptionLine GetScoreHeaderLine() { DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Header2Box; line.boxes = new object[2]; line.boxes[0] = courseView.CourseFullName; // If there is scoring, display the total score, else display the total number of controls (e.g., // for a score course with no points for each control. if (courseView.TotalScore > 0) line.boxes[1] = string.Format(symbolDB["number_points"].GetText(language), courseView.TotalScore); else line.boxes[1] = string.Format(symbolDB["number_controls"].GetText(language), courseView.TotalNormalControls); line.textual = (string)line.boxes[1]; return line; }
// Create a description line for a normal header line: name, length, climb private DescriptionLine GetNormalHeaderLine() { DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Header3Box; line.boxes = new object[3]; line.boxes[0] = courseView.CourseFullName; line.boxes[1] = Util.GetLengthInKm(courseView.MinTotalLength, courseView.MaxTotalLength, 1); if (courseView.TotalClimb < 0) { line.boxes[2] = null; line.textual = string.Format(symbolDB["course_length"].GetText(language), line.boxes[1]); } else { line.boxes[2] = Convert.ToString(Math.Round(courseView.TotalClimb / 5, MidpointRounding.AwayFromZero) * 5.0) + " m"; line.textual = string.Format(symbolDB["course_length_climb"].GetText(language), line.boxes[1], line.boxes[2]); } return line; }
// Get a directive line for a marked route (not to the finish). The legId must be valid, because a marked route only occurs // with a real leg id. private DescriptionLine GetMarkedRouteLine(CourseView.ControlView controlViewFrom, CourseView.ControlView controlViewTo, Id<Leg> legId) { Leg leg = eventDB.GetLeg(legId); Debug.Assert(leg.flagging != FlaggingKind.None && leg.flagging != FlaggingKind.End); DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Directive; line.boxes = new object[2]; // Figure out the distance in the directive, rounded to nearest 10m. string distanceText; float distance = QueryEvent.ComputeFlaggedLegLength(eventDB, leg.controlId1, leg.controlId2, legId); distance = (float) (Math.Round(distance / 10.0) * 10.0); // round to nearest 10 m. distanceText = string.Format("{0} m", distance); // Box 1: directive graphics. string symbolId = (leg.flagging == FlaggingKind.Begin) ? "13.1" : "13.2"; line.boxes[0] = symbolDB[symbolId]; // Box 2: distance of the flagging line.boxes[1] = distanceText; // Get the text version of the control using the Textifier. Textifier textifier = new Textifier(eventDB, symbolDB, language); line.textual = textifier.CreateTextForDirective(symbolId, distanceText); // The course control IDs, for use in coordinating the selection line.isLeg = true; line.controlId = controlViewFrom.controlId; line.courseControlId = controlViewFrom.courseControlIds[0]; line.courseControlId2 = controlViewTo.courseControlIds[0]; return line; }
// Get a directive line for a flagged route to map exchange (not to the finish). The distance between the controls is calculated and used for the distance // in the direction. private DescriptionLine GetMapExchangeLine(CourseView.ControlView controlViewFrom, CourseView.ControlView controlViewTo) { DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Directive; line.boxes = new object[2]; // Figure out the distance in the directive, rounded to nearest 10m. float distance; // default distance is zero. string distanceText; distance = controlViewFrom.legLength[0]; distance = (float) (Math.Round(distance / 10.0) * 10.0); // round to nearest 10 m. distanceText = string.Format("{0} m", distance); // Box 1: directive graphics. string symbolId = "13.5"; line.boxes[0] = symbolDB[symbolId]; // Box 2: distance of the flagging line.boxes[1] = distanceText; // Get the text version of the control using the Textifier. Textifier textifier = new Textifier(eventDB, symbolDB, language); line.textual = textifier.CreateTextForDirective(symbolId, distanceText); // The course control IDs, for use in coordinating the selection line.isLeg = true; line.controlId = controlViewFrom.controlId; line.courseControlId = controlViewFrom.courseControlIds[0]; line.courseControlId2 = controlViewTo.courseControlIds[0]; return line; }
// Given some text, a text line for it to a list if the text is non-empty. private void AddTextLine(List<DescriptionLine> list, string text, Id<CourseControl> courseControlId, Id<ControlPoint> controlId, DescriptionLine.TextLineKind textLineKind) { if (!string.IsNullOrEmpty(text)) { list.AddRange(GetTextLineFromText(text, courseControlId, controlId, textLineKind)); } }
// Create a set of description lines for a course. If "createKey" is true, then lines for a key are created based on any symbols // that have custom text. This is typically done only if text description are not already being printed. public DescriptionLine[] CreateDescription(bool createKey) { EventDB eventDB = courseView.EventDB; CourseView.CourseViewKind kind = courseView.Kind; int scoreColumn = courseView.ScoreColumn; List <DescriptionLine> list = new List <DescriptionLine>(courseView.ControlViews.Count + 4); string text; DescriptionLine line; DescriptionLine[] lines; Dictionary <string, string> descriptionKey = new Dictionary <string, string>(); // dictionary for any symbols encountered with custom text. // Get the first title line. text = GetTitleLine1(); Debug.Assert(text != null); lines = GetTitleLineFromText(DescriptionLineKind.Title, text); list.AddRange(lines); // Get the second title line. text = GetTitleLine2(); if (text != null) { lines = GetTitleLineFromText(DescriptionLineKind.SecondaryTitle, text); list.AddRange(lines); } // Get the header line, depending on the kind of course. switch (kind) { case CourseView.CourseViewKind.Normal: line = GetNormalHeaderLine(); break; case CourseView.CourseViewKind.AllControls: line = GetAllControlsHeaderLine(); break; case CourseView.CourseViewKind.Score: line = GetScoreHeaderLine(); break; case CourseView.CourseViewKind.AllVariations: line = GetAllVariationsHeaderLine(); break; default: Debug.Fail("unknown CourseViewKind"); line = null; break; } if (line != null) { list.Add(line); } // Do all the normal lines for (int iLine = 0; iLine < courseView.ControlViews.Count; ++iLine) { CourseView.ControlView controlView = courseView.ControlViews[iLine]; ControlPoint control = eventDB.GetControl(controlView.controlId); CourseControl courseControl = controlView.courseControlIds[0].IsNone ? null : eventDB.GetCourseControl(controlView.courseControlIds[0]); // CONSIDER: this might need to be updated for relay or split controls. ControlPoint controlPrev = (iLine > 0) ? eventDB.GetControl(courseView.ControlViews[iLine - 1].controlId) : null; ControlPoint controlNext = (iLine < courseView.ControlViews.Count - 1) ? eventDB.GetControl(courseView.ControlViews[iLine + 1].controlId) : null; //Id<CourseControl> courseControlIdNext = (iLine < courseView.ControlViews.Count - 1) ? courseView.ControlViews[iLine + 1].courseControlId : Id<CourseControl>.None; //CourseControl courseControlNext = courseControlIdNext.IsNotNone ? eventDB.GetCourseControl(coruseControlIdNext) : null; // Do the control.control if (FilterControl(kind, control, controlPrev, controlNext)) { // Text associated with the course or course control (before) AddTextLine(list, control.descTextBefore, controlView.courseControlIds[0], controlView.controlId, DescriptionLine.TextLineKind.BeforeControl); if (courseControl != null) { AddTextLine(list, courseControl.descTextBefore, controlView.courseControlIds[0], controlView.controlId, DescriptionLine.TextLineKind.BeforeCourseControl); } // The control itself. if (control.kind == ControlPointKind.Finish || control.kind == ControlPointKind.CrossingPoint || control.kind == ControlPointKind.MapIssue) { line = GetDirectiveLine(kind, controlView, iLine > 0 ? courseView.ControlViews[iLine - 1] : null); } else { line = GetRegularLine(kind, scoreColumn, controlView, descriptionKey); } Debug.Assert(line != null); list.Add(line); // Text associated with the course or course control (after) if (courseControl != null) { AddTextLine(list, courseControl.descTextAfter, controlView.courseControlIds[0], controlView.controlId, DescriptionLine.TextLineKind.AfterCourseControl); } AddTextLine(list, control.descTextAfter, controlView.courseControlIds[0], controlView.controlId, DescriptionLine.TextLineKind.AfterControl); } // Add any map exchange lines. if (courseView.Kind == CourseView.CourseViewKind.Normal || courseView.Kind == CourseView.CourseViewKind.AllVariations) { if (controlNext != null && controlNext.kind == ControlPointKind.MapExchange) { line = GetMapExchangeLine(controlView, courseView.ControlViews[controlView.legTo[0]]); list.Add(line); } else if (courseControl != null && courseControl.exchange && control.kind != ControlPointKind.MapExchange && controlPrev != null) { line = GetMapExchangeAtControlLine(controlView); list.Add(line); } } // Do the leg (if any). if (controlView.legTo != null && controlView.legTo.Length > 0) { Id <Leg> legId = controlView.legId[0]; Leg leg = (legId.IsNotNone) ? eventDB.GetLeg(legId) : null; if (FilterLeg(kind, control, controlNext, leg)) { line = GetMarkedRouteLine(controlView, courseView.ControlViews[controlView.legTo[0]], legId); Debug.Assert(line != null); list.Add(line); } } } // Add the key if desired. if (createKey) { foreach (string symbolId in descriptionKey.Keys) { line = new DescriptionLine(); line.kind = DescriptionLineKind.Key; line.boxes = new object[2]; line.boxes[0] = symbolDB[symbolId]; line.boxes[1] = descriptionKey[symbolId]; list.Add(line); } } // And we're done! return(list.ToArray()); }
// Get a regular 8-box line for a start or regular control. private DescriptionLine GetRegularLine(CourseView.CourseViewKind kind, int scoreColumn, CourseView.ControlView controlView, Dictionary <string, string> descriptionKey) { Event ev = eventDB.GetEvent(); ControlPoint control = eventDB.GetControl(controlView.controlId); CourseControl courseControl; if (controlView.courseControlIds[0].IsNone) { courseControl = null; } else { courseControl = eventDB.GetCourseControl(controlView.courseControlIds[0]); } Debug.Assert(control.kind == ControlPointKind.Normal || control.kind == ControlPointKind.Start || control.kind == ControlPointKind.MapExchange); DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Normal; line.boxes = new object[8]; // Box A: ordinal or start triangle or points. if (control.kind == ControlPointKind.Start || control.kind == ControlPointKind.MapExchange) { line.boxes[0] = symbolDB["start"]; } else if (kind != CourseView.CourseViewKind.AllControls && controlView.ordinal > 0) { line.boxes[0] = Convert.ToString(controlView.ordinal); } else { line.boxes[0] = null; } // Box B: code of the control if (control.kind == ControlPointKind.Normal) { line.boxes[1] = Convert.ToString(control.code); } // Boxes C-H, from the symbols for (int i = 2; i < 8; ++i) { String symbolID = control.symbolIds[i - 2]; if (symbolID != null) { line.boxes[i] = symbolDB[control.symbolIds[i - 2]]; // See if we need to add this to the key. bool addToKey; if (ev.customSymbolKey.TryGetValue(symbolID, out addToKey) && addToKey && Symbol.ContainsLanguage(ev.customSymbolText[symbolID], language)) { descriptionKey[symbolID] = Symbol.GetBestSymbolText(symbolDB, ev.customSymbolText[symbolID], language, false, "", ""); } } } // Box F -- may be text instead of a symbol. if (control.columnFText != null) { Debug.Assert(line.boxes[5] == null); line.boxes[5] = control.columnFText; } // Put points in the score column, for a score course. if (control.kind == ControlPointKind.Normal && scoreColumn >= 0 && courseControl != null) { int points = courseControl.points; if (points > 0) { line.boxes[scoreColumn] = Convert.ToString(courseControl.points); } else { line.boxes[scoreColumn] = null; } } // Get the text version of the control using the Textifier. Textifier textifier = new Textifier(eventDB, symbolDB, language); line.textual = textifier.CreateTextForControl(controlView.controlId, ""); // The course control ID, for use in coordinating the selection line.controlId = controlView.controlId; line.courseControlId = controlView.courseControlIds[0]; return(line); }
// Dump a description line to a text writer. static void DumpDescriptionLine(SymbolDB symbolDB, DescriptionLine line, TextWriter writer) { if (line.controlId.IsNotNone) { writer.Write("({0,3}) |", line.controlId); } else { writer.Write(" |"); } switch (line.kind) { case DescriptionLineKind.Title: case DescriptionLineKind.SecondaryTitle: case DescriptionLineKind.Text: writer.Write(" {0,-46}|", line.boxes[0]); break; case DescriptionLineKind.Normal: for (int i = 0; i < 8; ++i) { string text; if (line.boxes[i] == null) { text = ""; } else if (line.boxes[i] is Symbol) { text = ((Symbol)(line.boxes[i])).Id; } else { text = (string)(line.boxes[i]); } writer.Write("{0,5}|", line.boxes[i] is Symbol ? ((Symbol)(line.boxes[i])).Id : (string)(line.boxes[i])); } break; case DescriptionLineKind.Header3Box: writer.Write("{0,-17}|", line.boxes[0] == null ? "" : (string)(line.boxes[0])); writer.Write("{0,-17}|", line.boxes[1] == null ? "" : (string)(line.boxes[1])); writer.Write("{0,-11}|", line.boxes[2] == null ? "" : (string)(line.boxes[2])); break; case DescriptionLineKind.Header2Box: writer.Write("{0,-17}|", line.boxes[0] == null ? "" : (string)(line.boxes[0])); writer.Write("{0,-29}|", line.boxes[1] == null ? "" : (string)(line.boxes[1])); break; case DescriptionLineKind.Key: writer.Write("{0,-17}|", line.boxes[0] == null ? "" : ((Symbol)(line.boxes[0])).Id); writer.Write("{0,-29}|", line.boxes[1] == null ? "" : (string)(line.boxes[1])); break; case DescriptionLineKind.Directive: writer.Write(" {0,16}: {1,-24}|", line.boxes[0] != null ? ((Symbol)(line.boxes[0])).Id : "", line.boxes[1] == null ? "" : (string)(line.boxes[1])); break; } if (line.textual != null) { writer.Write(" [{0}]", line.textual); } writer.WriteLine(); }
// Invalidate any lines that have changed between two descriptions. void InvalidateChangedLines(DescriptionLine[] old, DescriptionLine[] current) { if (old == null || current == null) { descriptionPanel.Invalidate(); return; } int lineCount = Math.Max(old.Length, current.Length); for (int i = 0; i < lineCount; ++i) { bool invalidate = false; if (i >= old.Length || i >= current.Length) invalidate = true; else if (!old[i].Equals(current[i])) invalidate = true; if (invalidate) { RectangleF bounds = renderer.LineBounds(i, i); descriptionPanel.Invalidate(Util.Round(bounds)); } } }
// Get a directive line for a finish or crossingpoint. private DescriptionLine GetDirectiveLine(CourseView.CourseViewKind kind, CourseView.ControlView controlView, CourseView.ControlView controlViewPrev) { ControlPoint control = eventDB.GetControl(controlView.controlId); CourseControl courseControl; if (controlView.courseControlIds[0].IsNone) courseControl = null; else courseControl = eventDB.GetCourseControl(controlView.courseControlIds[0]); Debug.Assert(control.kind == ControlPointKind.Finish || control.kind == ControlPointKind.CrossingPoint); DescriptionLine line = new DescriptionLine(); line.kind = DescriptionLineKind.Directive; line.boxes = new object[2]; // Figure out the distance in the directive, rounded to nearest 10m. string distanceText; if (controlViewPrev != null && controlViewPrev.legLength != null) { float distance = controlViewPrev.legLength[0]; distance = (float)(Math.Round(distance / 10.0) * 10.0); // round to nearest 10 m. distanceText = string.Format("{0} m", distance); } else distanceText = ""; // Box 1: directive graphics. line.boxes[0] = symbolDB[control.symbolIds[0]]; // Box 2: distance for the control, if any. if (control.kind == ControlPointKind.Finish) line.boxes[1] = distanceText; // Get the text version of the control using the Textifier. Textifier textifier = new Textifier(eventDB, symbolDB, language); line.textual = textifier.CreateTextForControl(controlView.controlId, distanceText); // The course control ID, for use in coordinating the selection line.controlId = controlView.controlId; line.courseControlId = controlView.courseControlIds[0]; return line; }
// Get the rectangle used by the description. static RectangleF GetRect(PointF topLeft, float cellSize, SymbolDB symbolDB, DescriptionLine[] description, DescriptionKind kind, int numColumns) { // Create the renderer. DescriptionRenderer renderer = new DescriptionRenderer(symbolDB); renderer.Description = description; renderer.DescriptionKind = kind; renderer.Margin = cellSize / 20; // about the thickness of the thick lines. renderer.CellSize = cellSize; renderer.NumberOfColumns = numColumns; SizeF size = renderer.Measure(); return new RectangleF(topLeft.X, topLeft.Y - size.Height, size.Width, size.Height); }
// Select a text line public void SelectTextLine(Id<ControlPoint> controlId, Id<CourseControl> courseControlId, DescriptionLine.TextLineKind textLineKind) { SetSelection(SelectionKind.TextLine, courseControlId, Id<CourseControl>.None, controlId, Id<Special>.None, null, textLineKind); }
DescriptionRenderer renderer; // The description renderer that holds the description. #endregion Fields #region Constructors // Create a new description course object. public DescriptionCourseObj(Id<Special> specialId, PointF topLeft, float cellSize, SymbolDB symbolDB, DescriptionLine[] description, DescriptionKind kind, int numColumns) : base(Id<ControlPoint>.None, Id<CourseControl>.None, specialId, 1, new CourseAppearance(), GetRect(topLeft, cellSize, symbolDB, description, kind, numColumns)) { // Create the renderer. renderer = new DescriptionRenderer(symbolDB); renderer.Description = description; renderer.DescriptionKind = kind; renderer.Margin = cellSize / 20; // about the thickness of the thick lines. renderer.CellSize = cellSize; renderer.NumberOfColumns = numColumns; aspectAnglesByColumns = ComputeAspectAngles(); }
// Update the thick line counter to indicate when a thick line should be drawn (whever counter is 0) private void UpdateThickLineCounter(DescriptionLine descriptionLine, DescriptionKind descriptionKind, ref int thickLineCounter) { if (descriptionLine.kind == DescriptionLineKind.Normal) { if (descriptionLine.boxes[0] != null && descriptionLine.boxes[0] is Symbol) thickLineCounter = 0; // after start, put a thick line also. else { // put a thick line after every three normal lines. thickLineCounter += 1; if (thickLineCounter == 3) thickLineCounter = 0; } } else { thickLineCounter = 0; } }
// Given the text, create descriptions line for a title line with that text. Lines are split by vertical bars. private DescriptionLine[] GetTitleLineFromText(DescriptionLineKind kind, string text) { string[] texts = text.Split(new char[] { '|' }); int lineCount = texts.Length; DescriptionLine[] lines = new DescriptionLine[lineCount]; for (int index = 0; index < lineCount; ++index) { DescriptionLine line = new DescriptionLine(); line.kind = kind; line.boxes = new object[1]; line.boxes[0] = texts[index]; line.textual = texts[index]; lines[index] = line; } return lines; }
// Create a set of description lines for a course. If "createKey" is true, then lines for a key are created based on any symbols // that have custom text. This is typically done only if text description are not already being printed. public DescriptionLine[] CreateDescription(bool createKey) { EventDB eventDB = courseView.EventDB; CourseView.CourseViewKind kind = courseView.Kind; int scoreColumn = courseView.ScoreColumn; List<DescriptionLine> list = new List<DescriptionLine>(courseView.ControlViews.Count + 4); string text; DescriptionLine line; DescriptionLine[] lines; Dictionary<string, string> descriptionKey = new Dictionary<string, string>(); // dictionary for any symbols encountered with custom text. // Get the first title line. text = GetTitleLine1(); Debug.Assert(text != null); lines = GetTitleLineFromText(DescriptionLineKind.Title, text); list.AddRange(lines); // Get the second title line. text = GetTitleLine2(); if (text != null) { lines = GetTitleLineFromText(DescriptionLineKind.SecondaryTitle, text); list.AddRange(lines); } // Get the header line, depending on the kind of course. switch (kind) { case CourseView.CourseViewKind.Normal: line = GetNormalHeaderLine(); break; case CourseView.CourseViewKind.AllControls: line = GetAllControlsHeaderLine(); break; case CourseView.CourseViewKind.Score: line = GetScoreHeaderLine(); break; case CourseView.CourseViewKind.AllVariations: line = GetAllVariationsHeaderLine(); break; default: Debug.Fail("unknown CourseViewKind"); line = null; break; } if (line != null) list.Add(line); // Do all the normal lines for (int iLine = 0; iLine < courseView.ControlViews.Count; ++iLine) { CourseView.ControlView controlView = courseView.ControlViews[iLine]; ControlPoint control = eventDB.GetControl(controlView.controlId); CourseControl courseControl = controlView.courseControlIds[0].IsNone ? null : eventDB.GetCourseControl(controlView.courseControlIds[0]); // CONSIDER: this might need to be updated for relay or split controls. ControlPoint controlPrev = (iLine > 0) ? eventDB.GetControl(courseView.ControlViews[iLine - 1].controlId) : null; ControlPoint controlNext = (iLine < courseView.ControlViews.Count - 1) ? eventDB.GetControl(courseView.ControlViews[iLine + 1].controlId) : null; //Id<CourseControl> courseControlIdNext = (iLine < courseView.ControlViews.Count - 1) ? courseView.ControlViews[iLine + 1].courseControlId : Id<CourseControl>.None; //CourseControl courseControlNext = courseControlIdNext.IsNotNone ? eventDB.GetCourseControl(coruseControlIdNext) : null; // Do the control.control if (FilterControl(kind, control, controlPrev, controlNext)) { // Text associated with the course or course control (before) AddTextLine(list, control.descTextBefore, controlView.courseControlIds[0], controlView.controlId, DescriptionLine.TextLineKind.BeforeControl); if (courseControl != null) AddTextLine(list, courseControl.descTextBefore, controlView.courseControlIds[0], controlView.controlId, DescriptionLine.TextLineKind.BeforeCourseControl); // The control itself. if (control.kind == ControlPointKind.Finish || control.kind == ControlPointKind.CrossingPoint) { line = GetDirectiveLine(kind, controlView, iLine > 0 ? courseView.ControlViews[iLine - 1] : null); } else { line = GetRegularLine(kind, scoreColumn, controlView, descriptionKey); } Debug.Assert(line != null); list.Add(line); // Text associated with the course or course control (after) if (courseControl != null) AddTextLine(list, courseControl.descTextAfter, controlView.courseControlIds[0], controlView.controlId, DescriptionLine.TextLineKind.AfterCourseControl); AddTextLine(list, control.descTextAfter, controlView.courseControlIds[0], controlView.controlId, DescriptionLine.TextLineKind.AfterControl); } // Add any map exchange lines. if (courseView.Kind == CourseView.CourseViewKind.Normal || courseView.Kind == CourseView.CourseViewKind.AllVariations) { if (controlNext != null && controlNext.kind == ControlPointKind.MapExchange) { line = GetMapExchangeLine(controlView, courseView.ControlViews[controlView.legTo[0]]); list.Add(line); } else if (courseControl != null && courseControl.exchange && control.kind != ControlPointKind.MapExchange && controlPrev != null) { line = GetMapExchangeAtControlLine(controlView); list.Add(line); } } // Do the leg (if any). if (controlView.legTo != null && controlView.legTo.Length > 0) { Id<Leg> legId = controlView.legId[0]; Leg leg = (legId.IsNotNone) ? eventDB.GetLeg(legId) : null; if (FilterLeg(kind, control, controlNext, leg)) { line = GetMarkedRouteLine(controlView, courseView.ControlViews[controlView.legTo[0]], legId); Debug.Assert(line != null); list.Add(line); } } } // Add the key if desired. if (createKey) { foreach (string symbolId in descriptionKey.Keys) { line = new DescriptionLine(); line.kind = DescriptionLineKind.Key; line.boxes = new object[2]; line.boxes[0] = symbolDB[symbolId]; line.boxes[1] = descriptionKey[symbolId]; list.Add(line); } } // And we're done! return list.ToArray(); }
// Describe text line private static TextPart[] DescribeTextLine(EventDB eventDB, Id<ControlPoint> controlId, DescriptionLine.TextLineKind textLineKind) { List<TextPart> list = new List<TextPart>(); list.Add(new TextPart(TextFormat.Title, SelectionDescriptionText.TextLine)); list.Add(new TextPart(TextFormat.Header, SelectionDescriptionText.Location)); string format; switch (textLineKind) { case DescriptionLine.TextLineKind.BeforeControl: format = SelectionDescriptionText.TextLine_AboveAllCourses; break; case DescriptionLine.TextLineKind.BeforeCourseControl: format = SelectionDescriptionText.TextLine_AboveThisCourse; break; case DescriptionLine.TextLineKind.AfterControl: format = SelectionDescriptionText.TextLine_BelowAllCourses; break; case DescriptionLine.TextLineKind.AfterCourseControl: format = SelectionDescriptionText.TextLine_BelowThisCourse; break; case DescriptionLine.TextLineKind.None: default: return list.ToArray(); } list.Add(new TextPart(TextFormat.NewLine, string.Format(format, Util.ControlPointName(eventDB, controlId, NameStyle.Long)))); return list.ToArray(); }
// Should there be no boundry between the following description lines. public static bool NoBoundaryBetween(DescriptionLine descLine1, DescriptionLine descLine2) { if (descLine1.kind == descLine2.kind) { switch (descLine1.kind) { case DescriptionLineKind.Title: case DescriptionLineKind.SecondaryTitle: return true; case DescriptionLineKind.Text: return descLine1.textLineKind == descLine2.textLineKind; } } return false; }
// Sets the current selection. No feedback is provided as to whether the selection // is valid; if invalid, the selection will simply be cleared when it is retrieved. private void SetSelection(SelectionKind selectionKind, Id<CourseControl> courseControlId, Id<CourseControl> courseControlId2, Id<ControlPoint> controlId, Id<Special> specialId, Symbol keySymbol, DescriptionLine.TextLineKind textLineKind) { if (this.selectionKind != selectionKind || this.selectedCourseControl != courseControlId || this.selectedCourseControl2 != courseControlId2 || this.selectedControl != controlId || this.selectedSpecial != specialId) { controller.ScrollHighlightIntoView = true; // scroll the newly selection item into view. } ++selectionChangeNum; this.selectionKind = selectionKind; this.selectedCourseControl = courseControlId; this.selectedCourseControl2 = courseControlId2; this.selectedControl = controlId; this.selectedSpecial = specialId; this.selectedKeySymbol = keySymbol; this.selectedTextLineKind = textLineKind; }
// Render a single line of the description. "lastLine" is true if this is the last line (draws the bottom line). The "thickLineCounter" // is used to decide when to draw the thick lines. // clipRect is the clipping rectangle in world coordinates. Only need to draw things that intersect it. private void RenderLine(IRenderer renderer, DescriptionLine descriptionLine, DescriptionKind descriptionKind, bool lastLine, bool drawThickLine, bool noTopLine, RectangleF clipRect) { float fullWidth = WidthInCells() * 100; // Draw top line. if (!noTopLine) { if (descriptionLine.kind != DescriptionLineKind.Normal || drawThickLine) { renderer.DrawLine(thickPen, 0, 0, fullWidth, 0); } else { renderer.DrawLine(thinPen, 0, 0, fullWidth, 0); } } // Draw bottom line, if requested if (lastLine) renderer.DrawLine(thickPen, 0, 100, fullWidth, 100); // Draw side lines. float lineTop = -DescriptionAppearance.thickDescriptionLine / 2; float lineBottom = 100 + DescriptionAppearance.thickDescriptionLine / 2; renderer.DrawLine(thickPen, 0, lineTop, 0, lineBottom); if (! (descriptionKind == DescriptionKind.SymbolsAndText && (descriptionLine.kind == DescriptionLineKind.Title || descriptionLine.kind == DescriptionLineKind.SecondaryTitle || descriptionLine.kind == DescriptionLineKind.Text))) renderer.DrawLine(thickPen, 800, lineTop, 800, lineBottom); if (descriptionKind == DescriptionKind.SymbolsAndText) renderer.DrawLine(thickPen, 1300, lineTop, 1300, lineBottom); switch (descriptionLine.kind) { case DescriptionLineKind.Title: RenderSingleLineText(renderer, TITLE_FONT, StringAlignment.Center, (string) (descriptionLine.boxes[0]), 0, 0, fullWidth, 100, clipRect); break; case DescriptionLineKind.SecondaryTitle: RenderSingleLineText(renderer, TITLE_FONT, StringAlignment.Center, (string) (descriptionLine.boxes[0]), 0, 0, fullWidth, 100, clipRect); break; case DescriptionLineKind.Header2Box: renderer.DrawLine(thickPen, 300, lineTop, 300, lineBottom); RenderSingleLineText(renderer, TITLE_FONT, StringAlignment.Center, (string) (descriptionLine.boxes[0]), 0, 0, 300, 100, clipRect); RenderSingleLineText(renderer, TITLE_FONT, StringAlignment.Center, (string) (descriptionLine.boxes[1]), 300, 0, 800, 100, clipRect); break; case DescriptionLineKind.Header3Box: renderer.DrawLine(thickPen, 300, lineTop, 300, lineBottom); renderer.DrawLine(thickPen, 600, lineTop, 600, lineBottom); RenderSingleLineText(renderer, TITLE_FONT, StringAlignment.Center, (string) (descriptionLine.boxes[0]), 0, 0, 300, 100, clipRect); RenderSingleLineText(renderer, TITLE_FONT, StringAlignment.Center, (string) (descriptionLine.boxes[1]), 300, 0, 600, 100, clipRect); RenderSingleLineText(renderer, TITLE_FONT, StringAlignment.Center, (string) (descriptionLine.boxes[2]), 600, 0, 800, 100, clipRect); break; case DescriptionLineKind.Directive: if (descriptionKind == DescriptionKind.Text) { RenderWrappedText(renderer, TEXT_FONT, StringAlignment.Near, descriptionLine.textual, 15, 0, 785, 100, clipRect); } else { RenderSymbol(renderer, (Symbol)descriptionLine.boxes[0], 0, 0, 800, 100, clipRect); RenderSingleLineText(renderer, DIRECTIVE_FONT, StringAlignment.Center, (string) (descriptionLine.boxes[1]), 300, 0, 500, 100, clipRect); if (descriptionKind == DescriptionKind.SymbolsAndText) RenderWrappedText(renderer, TEXT_FONT, StringAlignment.Near, descriptionLine.textual, 815, 0, 1285, 100, clipRect); } break; case DescriptionLineKind.Normal: int numBoxes; if (descriptionKind == DescriptionKind.Text) { renderer.DrawLine(thinPen, 100, lineTop, 100, lineBottom); renderer.DrawLine(thickPen, 200, lineTop, 200, lineBottom); RenderWrappedText(renderer, TEXT_FONT, StringAlignment.Near, descriptionLine.textual, 215, 0, 785, 100, clipRect); numBoxes = 2; } else { renderer.DrawLine(thinPen, 100, lineTop, 100, lineBottom); renderer.DrawLine(thinPen, 200, lineTop, 200, lineBottom); renderer.DrawLine(thickPen, 300, lineTop, 300, lineBottom); renderer.DrawLine(thinPen, 400, lineTop, 400, lineBottom); renderer.DrawLine(thinPen, 500, lineTop, 500, lineBottom); renderer.DrawLine(thickPen, 600, lineTop, 600, lineBottom); renderer.DrawLine(thinPen, 700, lineTop, 700, lineBottom); numBoxes = 8; if (descriptionKind == DescriptionKind.SymbolsAndText) { renderer.DrawLine(thickPen, 1300, lineTop, 1300, lineBottom); RenderWrappedText(renderer, TEXT_FONT, StringAlignment.Near, descriptionLine.textual, 815, 0, 1285, 100, clipRect); } } for (int i = 0; i < numBoxes; ++i) { if (descriptionLine.boxes[i] is Symbol) { RenderSymbol(renderer, (Symbol)descriptionLine.boxes[i], i * 100, 0, i * 100 + 100, 100, clipRect); } else if (descriptionLine.boxes[i] is String) { if (i == 5) RenderColumnFText(renderer, (string)descriptionLine.boxes[i], i * 100, 0, i * 100 + 100, 100, clipRect); else if (i == 0) RenderSingleLineText(renderer, COLUMNA_FONT, StringAlignment.Center, (string) descriptionLine.boxes[i], i * 100, 0, i * 100 + 100, 100, clipRect); else RenderSingleLineText(renderer, COLUMNB_FONT, StringAlignment.Center, (string) descriptionLine.boxes[i], i * 100, 0, i * 100 + 100, 100, clipRect); } } break; case DescriptionLineKind.Key: RenderSymbol(renderer, (Symbol) descriptionLine.boxes[0], 100, 0, 200, 100, clipRect); RenderSingleLineText(renderer, KEY_FONT, StringAlignment.Near, "= " + (string) (descriptionLine.boxes[1]), 200, 0, 800, 100, clipRect); break; case DescriptionLineKind.Text: RenderWrappedText(renderer, TEXTLINE_FONT, StringAlignment.Near, (string) (descriptionLine.boxes[0]), 20, 0, fullWidth, 100, clipRect); break; default: Debug.Fail("unknown description line kind"); break; } }