// TODO: Destructor. // TODO: ~RenderedStringWordWrapper(){DeleteFormatters();} // implementation of base interface // TODO: specialised version of format used with Justified text public override void Format(Window refWnd, Sizef areaSize) { DeleteFormatters(); var lstring = new RenderedString(); var rstring = new RenderedString(d_renderedString); T frs; for (var line = 0; line < rstring.GetLineCount(); ++line) { float rsWidth; while ((rsWidth = rstring.GetPixelSize(refWnd, line).Width) > 0) { // skip line if no wrapping occurs if (rsWidth <= areaSize.Width) { break; } // split rstring at width into lstring and remaining rstring rstring.Split(refWnd, line, areaSize.Width, lstring); //frs = _constructor(new RenderedString(lstring)); frs = new T(); frs.SetRenderedString(new RenderedString(lstring)); frs.Format(refWnd, areaSize); Lines.Add(frs); line = 0; } } // last line. //frs = _constructor(new RenderedString(rstring)); frs = new T(); frs.SetRenderedString(new RenderedString(rstring)); frs.Format(refWnd, areaSize); Lines.Add(frs); }
/// <summary> /// split the string in line \a line as close to \a split_point as possible. /// <para> /// The RenderedString \a left will receive the left portion of the split, /// while the right portion of the split will remain in this RenderedString. /// </para> /// </summary> /// <param name="refWnd"></param> /// <param name="line"> /// The line number on which the split is to occur. /// </param> /// <param name="splitPoint"> /// float value specifying the pixel location where the split should occur. /// The actual split will occur as close to this point as possible, though /// preferring a shorter 'left' portion when the split can not be made /// exactly at the requested point. /// </param> /// <param name="left"> /// RenderedString object that will receieve the left portion of the split. /// Any existing content in the RenderedString is replaced. /// </param> /// <exception cref="InvalidRequestException"> /// thrown if \a line is out of range. /// </exception> public void Split(Window refWnd, int line, float splitPoint, RenderedString left) { // FIXME: This function is big and nasty; it breaks all the rules for a // 'good' function and desperately needs some refactoring work done to it. // On the plus side, it does seem to work though ;) if (line >= GetLineCount()) { throw new InvalidRequestException("line number specified is invalid."); } left.ClearComponents(); if (d_components.Count == 0) { return; } // move all components in lines prior to the line being split to the left if (line > 0) { // calculate size of range var sz = d_lines[line - 1].First + d_lines[line - 1].Second; //// range start //ComponentList::iterator cb = d_components.begin(); //// range end (exclusive) //ComponentList::iterator ce = cb + sz; //// copy components to left side //left.d_components.assign(cb, ce); //// erase components from this side. //d_components.erase(cb, ce); for (int i = 0; i < sz; i++) { left.d_components.Add(d_components[0]); d_components.RemoveAt(0); } //LineList::iterator lb = d_lines.begin(); //LineList::iterator le = lb + line; //// copy lines to left side //left.d_lines.assign(lb, le); //// erase lines from this side //d_lines.erase(lb, le); for (int i = 0; i < line; i++) { left.d_lines.Add(d_lines[0]); d_lines.RemoveAt(0); } } // find the component where the requested split point lies. var partialExtent = 0f; var idx = 0; var lastComponent = d_lines[0].Second; for (; idx < lastComponent; ++idx) { partialExtent += d_components[idx].GetPixelSize(refWnd).Width; if (splitPoint <= partialExtent) { break; } } // case where split point is past the end if (idx >= lastComponent) { // transfer this line's components to the 'left' string. // // calculate size of range var sz = d_lines[0].Second; //// range start //ComponentList::iterator cb = d_components.begin(); //// range end (exclusive) //ComponentList::iterator ce = cb + sz; //// copy components to left side //left.d_components.insert(left.d_components.end(), cb, ce); //// erase components from this side. //d_components.erase(cb, ce); for (int i = 0; i < sz; i++) { left.d_components.Add(d_components[0]); d_components.RemoveAt(0); } // copy line info to left side left.d_lines.Add(d_lines[0]); // erase line from this side d_lines.RemoveAt(0); // fix up lines in this object for (int comp = 0, i = 0; i < d_lines.Count; ++i) { d_lines[i].First = comp; comp += d_lines[i].Second; } return; } left.AppendLineBreak(); var leftLine = left.GetLineCount() - 1; // Everything up to 'idx' is xfered to 'left' for (var i = 0; i < idx; ++i) { left.d_components.Add(d_components[0]); d_components.RemoveAt(0); ++left.d_lines[leftLine].Second; --d_lines[0].Second; } // now to split item 'idx' putting half in left and leaving half in this. RenderedStringComponent c = d_components[0]; if (c.CanSplit()) { var lc = c.Split(refWnd, splitPoint - (partialExtent - c.GetPixelSize(refWnd).Width), idx == 0); if (lc != null) { left.d_components.Add(lc); ++left.d_lines[leftLine].Second; } } // can't split, if component width is >= split_point xfer the whole // component to it's own line in the left part (FIX #306) else if (c.GetPixelSize(refWnd).Width >= splitPoint) { left.AppendLineBreak(); left.d_components.Add(d_components[0]); d_components.RemoveAt(0); ++left.d_lines[leftLine + 1].Second; --d_lines[0].Second; } // fix up lines in this object for (int comp = 0, i = 0; i < d_lines.Count; ++i) { d_lines[i].First = comp; comp += d_lines[i].Second; } }