RenderedStringTextComponent* RenderedColourStringTextComponent::split(float split_point, bool first_component)
{
	const Font* fnt = d_font ? d_font : System::getSingleton().getDefaultGUIContext().getDefaultFont();

	// This is checked, but should never fail, since if we had no font our
	// extent would be 0 and we would never cause a split to be needed here.
	if (!fnt)
		CEGUI_THROW(InvalidRequestException( "RenderedStringTextComponent::split: "
		"unable to split with no font set."));

	// create 'left' side of split and clone our basic configuration
	RenderedColourStringTextComponent* lhs = new RenderedColourStringTextComponent;
	lhs->d_padding = d_padding;
	lhs->d_verticalFormatting = d_verticalFormatting;
	lhs->d_font = d_font;
	lhs->d_colours = d_colours;

	// calculate the 'best' place to split the text
	size_t left_len = 0;
	float left_extent = 0.0f;

	while (left_len < d_text.length()) {
		size_t token_len = getNextTokenLength(d_text, left_len);
		// exit loop if no more valid tokens.
		if (token_len == 0)
			break;

		const float token_extent = fnt->getTextExtent(d_text.substr(left_len, token_len));

		// does the next token extend past the split point?
		if (left_extent + token_extent > split_point) {
			// if it was the first token, split the token itself
			if (first_component && left_len == 0)
				left_len = ceguimax(static_cast<size_t>(1), fnt->getCharAtPixel(d_text.substr(0, token_len), split_point));

			// left_len is now the character index at which to split the line
			break;
		}

		// add this token to the left side
		left_len += token_len;
		left_extent += token_extent;
	}

	// perform the split.
	lhs->d_text = d_text.substr(0, left_len);

	// here we're trimming leading delimiters from the substring range
	size_t rhs_start = d_text.find_first_not_of(TextUtils::DefaultWrapDelimiters, left_len);
	if (rhs_start == String::npos)
		rhs_start = left_len;

	d_text = d_text.substr(rhs_start);

	return lhs;
}
/*************************************************************************
	Format the text into lines as needed by the current formatting options.
*************************************************************************/
void MultiLineEditbox::formatText(void)
{
	// clear old formatting data
	d_lines.clear();
	d_widestExtent = 0.0f;

	String paraText;

	const Font* fnt = getFont();

	if (fnt != NULL)
	{
		float areaWidth = getTextRenderArea().getWidth();

		String::size_type	currPos = 0;
		String::size_type	paraLen;
		LineInfo	line;

		while (currPos < d_text.length())
		{
			if ((paraLen = d_text.find_first_of(d_lineBreakChars, currPos)) == String::npos)
			{
				paraLen = d_text.length() - currPos;
			}
			else
			{
				++paraLen -= currPos;
			}

			paraText = d_text.substr(currPos, paraLen);

			if (!d_wordWrap || (areaWidth <= 0.0f))
			{
				// no word wrapping, so we are just one long line.
				line.d_startIdx = currPos;
				line.d_length	= paraLen;
				line.d_extent	= fnt->getTextExtent(paraText); 
				d_lines.push_back(line);

				// update widest, if needed.
				if (line.d_extent > d_widestExtent)
				{
					d_widestExtent = line.d_extent;
				}

			}
			// must word-wrap the paragraph text
			else
			{
				String::size_type lineIndex = 0;

				// while there is text in the string
				while (lineIndex < paraLen)
				{
					String::size_type  lineLen = 0;
					float lineExtent = 0.0f;

					// loop while we have not reached the end of the paragraph string
					while (lineLen < (paraLen - lineIndex))
					{
						// get cp / char count of next token
						size_t nextTokenSize = getNextTokenLength(paraText, lineIndex + lineLen);

						// get pixel width of the token
						float tokenExtent  = fnt->getTextExtent(paraText.substr(lineIndex + lineLen, nextTokenSize));

						// would adding this token would overflow the available width
						if ((lineExtent + tokenExtent) > areaWidth)
						{
							// Was this the first token?
							if (lineLen == 0)
							{
								// get point at which to break the token
								lineLen = fnt->getCharAtPixel(paraText.substr(lineIndex, nextTokenSize), areaWidth);
							}

							// text wraps, exit loop early with line info up until wrap point
							break;
						}

						// add this token to current line
						lineLen    += nextTokenSize;
						lineExtent += tokenExtent;
					}

					// set up line info and add to collection
					line.d_startIdx = currPos + lineIndex;
					line.d_length	= lineLen;
					line.d_extent	= lineExtent;
					d_lines.push_back(line);

					// update widest, if needed.
					if (lineExtent > d_widestExtent)
					{
						d_widestExtent = lineExtent;
					}

					// update position in string
					lineIndex += lineLen;
				}

			}

			// skip to next 'paragraph' in text
			currPos += paraLen;
		}

	}

	configureScrollbars();
	requestRedraw();
}
Esempio n. 3
0
	void MarkupBase::parseBBCodes()
	{
		clear();
		const float maxwidth = m_viewport.getWidth();
		float height = 0.f;
		
		float xpos = 0.f;
		size_t wordcount = 0;
		PTextLine currentLine;
		PText textChunk;
		PImg imgChunk;
		PTooltipArea tooltipChunk;
		PLinkArea urlChunk;
		float linespacing = m_textSpacing;

		const ActiveText::TextViewVector& v = m_parser.getFormattedOutput();
		ActiveText::TextViewVector::const_iterator i = v.begin();
		ActiveText::TextViewVector::const_iterator end = v.end();
		while(i != end)
		{
			const ActiveText::TextView* tv = (*i).get();
			size_t pos = tv->start;
			size_t len = tv->len;
			size_t last = pos + len;
			std::string text = m_text.substr(pos, len);
			
			if(tv->isNewLine)
			{
				height += addTextLine(currentLine);

				// new paragraph
				currentLine.reset(new TextLine());
				currentLine->area = m_viewport;
				currentLine->area.m_top = height;
				currentLine->area.setHeight(0.f);
				linespacing = tv->isList ? m_listSpacing : m_textSpacing;
				wordcount = 0;
				xpos = 0.f;
				
				xpos += m_font->getTextExtent("    ");
			}

			{
				textChunk.reset(new Text());
				textChunk->start = pos;
				textChunk->col = tv->col;
				textChunk->font = tv->font;
				textChunk->selcol = tv->col;
				textChunk->selcol.invertColour();
				textChunk->area.m_left = xpos;
				textChunk->area.setHeight(textChunk->font->getLineSpacing());
				textChunk->area.setWidth(0.f);
			}

			if(tv->isTooltip)
			{
				if(tooltipChunk)
				{
					if(tooltipChunk->parent != tv->tooltipnode)
					{
						m_tooltips.push_back(tooltipChunk);
						tooltipChunk.reset(new TooltipArea());
						tooltipChunk->parent = tv->tooltipnode;
						tooltipChunk->tooltip = tv->tooltip;
					}
				}
				else
				{
					tooltipChunk.reset(new TooltipArea());
					tooltipChunk->parent = tv->tooltipnode;
					tooltipChunk->tooltip = tv->tooltip;
				}
			}

			if(tv->isURL)
			{
				if(urlChunk)
				{
					if(urlChunk->parent != tv->urlnode)
					{
						m_links.push_back(urlChunk);
						urlChunk.reset(new LinkArea());
						urlChunk->parent = tv->urlnode;
						urlChunk->type = tv->type;
						urlChunk->id = tv->id;
					}
				}
				else
				{
					urlChunk.reset(new LinkArea());
					urlChunk->parent = tv->urlnode;
					urlChunk->type = tv->type;
					urlChunk->id = tv->id;
				}
			}

			if(!tv->isImage)
			{ // text
				while(pos < last)
				{
					bool white = false;
					size_t nextTokenLen = getNextTokenLength(m_text, pos, white);
					if(pos + nextTokenLen > last)
						nextTokenLen = last - pos;

					float xlen = tv->font->getTextExtent(m_text.substr(pos, nextTokenLen));

					// if text isn't fit anyway (and must be alone on a string)
					if(xlen > maxwidth && wordcount == 0)
						xlen = maxwidth - xpos;

					if(xpos + xlen > maxwidth)
					{
						textChunk->len = pos - textChunk->start;
						if(white)
						{
							// don't allow whitespace in new line
							pos += nextTokenLen;
						}

						currentLine->addChunk(textChunk, linespacing);
						if(tv->isTooltip)
							tooltipChunk->masked.push_back(textChunk);
						if(tv->isURL)
							urlChunk->masked.push_back(textChunk);

						height += addTextLine(currentLine);
						
						{
							// new line
							currentLine.reset(new TextLine());
							currentLine->area = m_viewport;
							currentLine->area.m_top = height;
							currentLine->area.setHeight(0.f);
							linespacing = tv->isList ? m_listSpacing : m_textSpacing;
							wordcount = 0;
							xpos = 0.f;
						}

						{
							textChunk.reset(new Text());
							textChunk->start = pos;
							textChunk->col = tv->col;
							textChunk->font = tv->font;
							textChunk->selcol = tv->col;
							textChunk->selcol.invertColour();
							textChunk->area.m_left = xpos;
							textChunk->area.setHeight(textChunk->font->getLineSpacing());
							textChunk->area.setWidth(0.f);
						}
					}
					else
					{
						// add next word until width or tag
						pos += nextTokenLen;
						xpos += xlen;
						wordcount++;
						textChunk->area.m_right = xpos;
					}
				}

				// end chunk
				textChunk->len = pos - textChunk->start;
				currentLine->addChunk(textChunk, linespacing);
				if(tv->isTooltip)
					tooltipChunk->masked.push_back(textChunk);
				if(tv->isURL)
					urlChunk->masked.push_back(textChunk);
			}
			else
			{ // image
				imgChunk.reset(new Img());
				const Image* img = tv->img;			
				imgChunk->img = img;
				
				if(img)
				{
					Size imgsize = img->GetSize();

					if(imgsize.width > maxwidth - xpos)
					{
						height += addTextLine(currentLine);
						
						{
							// new line
							currentLine.reset(new TextLine());
							currentLine->area = m_viewport;
							currentLine->area.m_top = height;
							currentLine->area.setHeight(0.f);
							linespacing = tv->isList ? m_listSpacing : m_textSpacing;
							wordcount = 0;
							xpos = 0.f;
						}					
					}

					imgChunk->area.m_left = m_viewport.m_left + xpos;
					imgChunk->area.m_top = /*m_viewport.m_top*/ + currentLine->area.m_top;
					imgChunk->area.m_bottom = imgChunk->area.m_top + imgsize.height;
					imgChunk->area.m_right = imgChunk->area.m_left + imgsize.width;
					xpos += imgsize.width;
					wordcount++;

					currentLine->addChunk(imgChunk);
					m_images.push_back(imgChunk);

					if(tv->isTooltip)
						tooltipChunk->maskedimg.push_back(imgChunk);
					if(tv->isURL)
						urlChunk->maskedimg.push_back(imgChunk);
				}			
			}

			++i;
		}
		
		if(currentLine && !currentLine->isEmpty())
			height += addTextLine(currentLine);
		if(tooltipChunk && !tooltipChunk->isEmpty())
			m_tooltips.push_back(tooltipChunk);
		if(urlChunk && !urlChunk->isEmpty())
			m_links.push_back(urlChunk);

		m_viewport.m_bottom = m_viewport.m_top + height;
		m_area.m_bottom = m_viewport.m_bottom + m_margin.m_bottom;
	}