/// <summary> /// Gets the possible lines that may be formed from the given items. /// </summary> /// <param name="Start">The item to start the lines on.</param> /// <param name="Prefered">The prefered size of a line.</param> /// <param name="Max">The maximum size of a line.</param> private static IEnumerable<_PlannedLine> _GetPossibleLines(List<FlowItem> Items, int Start, double Prefered, double Max, FlowBlockStyle Style) { int cur = Start; int size = 0; double len = 0.0; bool hasline = false; while (cur < Items.Count) { // Insure line does not exceed size limit if (len - Layout.ErrorThreshold > Prefered && hasline) { yield break; } if (len - Layout.ErrorThreshold > Max) { yield break; } // Examine current item FlowItem item = Items[cur]; // Break item if (item == BreakFlowItem.Instance) { yield return new _PlannedLine { Length = len, Next = cur + 1, Size = size, Cut = false }; hasline = true; cur++; size++; continue; } // Cut item if (item == CutFlowItem.Instance) { yield return new _PlannedLine { Length = len, Next = cur + 1, Size = size, Cut = true }; yield break; } // Character item CharacterFlowItem cfi = item as CharacterFlowItem; if (cfi != null) { len += cfi.Font.GetSize(cfi.Name)[Style.MinorAxis]; cur++; size++; continue; } // Space item SpaceFlowItem sfi = item as SpaceFlowItem; if (sfi != null) { if (sfi.Breaking) { yield return new _PlannedLine { Length = len, Next = cur + 1, Size = size, Cut = false }; hasline = true; } len += sfi.Length; cur++; size++; continue; } } // End of items can act as a valid break yield return new _PlannedLine { Length = len, Next = Items.Count, Size = size, Cut = false }; }
/// <summary> /// Greedily creates a list of lines for a sequence of items, or returns null if not possible. /// </summary> /// <param name="Prefered">The prefered size of a line.</param> /// <param name="Max">The maximum size of a line.</param> private static List<_PlannedLine> _GetLinesGreedy(List<FlowItem> Items, double Prefered, double Max, FlowBlockStyle Style) { int cur = 0; List<_PlannedLine> lines = new List<_PlannedLine>(); while (cur < Items.Count) { bool hasline = false; _PlannedLine last = new _PlannedLine(); foreach(_PlannedLine line in _GetPossibleLines(Items, cur, Prefered, Max, Style)) { hasline = true; last = line; } // Exit if no lines are found. if (!hasline) { return null; } cur = last.Next; lines.Add(last); } return lines; }
/// <summary> /// Builds the layout lines for a list of planned lines. /// </summary> private static List<_Layout.Line> _BuildLayout( List<_PlannedLine> Lines, List<FlowItem> Items, FlowBlockStyle Style, double MinorSize, double MinMajorSize, out double MajorSize) { List<_Layout.Line> lines = new List<_Layout.Line>(Lines.Count); int cur = 0; double majoroff = 0.0; MajorSize = 0.0; // Build lines foreach (_PlannedLine pl in Lines) { _Layout.Line line = _BuildLayoutLine(cur, pl.Size, pl.Length, pl.Cut, Items, Style, MinorSize); lines.Add(line); cur = pl.Next; line.MajorOffset = majoroff; MajorSize = majoroff + line.MajorSize; majoroff = MajorSize + Style.LineSpacing; } MajorSize = Math.Max(MajorSize, MinMajorSize); // Reverse line direction if needed if ((int)Style.Direction % 2 > 0) { majoroff = MajorSize; foreach (_Layout.Line line in lines) { line.MajorOffset = majoroff - line.MajorSize; majoroff = line.MajorOffset - Style.LineSpacing; } } return lines; }
/// <summary> /// Builds a layout line for a given subset of a list of items. The major offset of the line will not be set. /// </summary> /// <param name="Length">The known minimum length of the line.</param> private static _Layout.Line _BuildLayoutLine(int Start, int Size, double Length, bool Cut, List<FlowItem> Items, FlowBlockStyle Style, double MinorSize) { Axis minoraxis = Style.MinorAxis; double majorsize = Style.LineSize; _Layout.Item[] items = new _Layout.Item[Size]; // Add visible items while determining their sizes double totalspace = 0.0; for (int t = 0; t < items.Length; t++) { FlowItem item = Items[Start++]; // Character item CharacterFlowItem cfi = item as CharacterFlowItem; if (cfi != null) { Point size = cfi.Font.GetSize(cfi.Name).Shift(Style.MinorAxis); majorsize = Math.Max(majorsize, size.Y); items[t] = new _Layout.Item { MinorSize = size.X, Source = cfi }; } // Space item SpaceFlowItem sfi = item as SpaceFlowItem; if (sfi != null) { totalspace += sfi.Length; items[t] = new _Layout.Item { MinorSize = sfi.Length, Source = sfi }; } } // If the flow is justified, adjust the sizes of spaces if (Style.Justification == FlowJustification.Justify && !Cut) { double spacemult = (MinorSize - Length + totalspace) / totalspace; for (int t = 0; t < items.Length; t++) { if (items[t].Source is SpaceFlowItem) { items[t].MinorSize *= spacemult; } } } // Set item offsets if ((int)Style.Direction % 4 < 2) { double off = Style.Justification == FlowJustification.Center ? MinorSize * 0.5 - Length * 0.5 : 0.0; for (int t = 0; t < items.Length; t++) { items[t].MinorOffset = off; off += items[t].MinorSize; } } else { double off = Style.Justification == FlowJustification.Center ? MinorSize * 0.5 + Length * 0.5 : MinorSize; for (int t = 0; t < items.Length; t++) { off -= items[t].MinorSize; items[t].MinorOffset = off; } } return new _Layout.Line { MajorSize = majorsize, Items = items }; }
public FlowBlock(List<FlowItem> Items, FlowFit Fit, FlowBlockStyle Style) { this.Style = Style; this.Fit = Fit; this.Items = Items; }