/// <summary> /// append the text string \a text to the RenderedString \a rs. /// </summary> /// <param name="rs"></param> /// <param name="text"></param> private void AppendRenderedText(RenderedString rs, string text) { var cpos = 0; // split the given string into lines based upon the newline character while (text.Length > cpos) { // find next newline var nlpos = text.IndexOf("\n", cpos); // calculate length of this substring var len = ((nlpos != -1) ? nlpos : text.Length) - cpos; // construct new text component and append it. var rtc = new RenderedStringTextComponent(text.Substring(cpos, len), d_fontName); rtc.SetPadding(d_padding); rtc.SetColours(new ColourRect(d_colours)); rtc.SetVerticalFormatting(d_vertAlignment); rtc.SetAspectLock(d_aspectLock); rs.AppendComponent(rtc); // break line if needed if (nlpos != -1) { rs.AppendLineBreak(); } // advance current position. +1 to skip the \n char cpos += len + 1; } }
/// <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; } }