1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // Copyright (C) 2016 Nathanaƫlle Courant:
3 // Modified the functions to use EnrichedText instead of string.
4 // This file is part of the "Irrlicht Engine".
5 // For conditions of distribution and use, see copyright notice in irrlicht.h
7 #include "static_text.h"
10 #include <IVideoDriver.h>
14 #include "CGUITTFont.h"
15 #include "util/string.h"
23 StaticText::StaticText(const EnrichedString &text, bool border,
24 IGUIEnvironment* environment, IGUIElement* parent,
25 s32 id, const core::rect<s32>& rectangle,
27 : IGUIStaticText(environment, parent, id, rectangle),
28 HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_UPPERLEFT),
29 Border(border), WordWrap(false), Background(background),
30 RestrainTextInside(true), RightToLeft(false),
31 OverrideFont(0), LastBreakFont(0)
34 setDebugName("StaticText");
42 StaticText::~StaticText()
48 //! draws the element and its children
49 void StaticText::draw()
54 IGUISkin* skin = Environment->getSkin();
57 video::IVideoDriver* driver = Environment->getVideoDriver();
59 core::rect<s32> frameRect(AbsoluteRect);
64 driver->draw2DRectangle(getBackgroundColor(), frameRect, &AbsoluteClippingRect);
70 skin->draw3DSunkenPane(this, 0, true, false, frameRect, &AbsoluteClippingRect);
71 frameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X);
75 IGUIFont *font = getActiveFont();
76 if (font && BrokenText.size()) {
77 if (font != LastBreakFont)
80 core::rect<s32> r = frameRect;
81 s32 height_line = font->getDimension(L"A").Height + font->getKerningHeight();
82 s32 height_total = height_line * BrokenText.size();
83 if (VAlign == EGUIA_CENTER && WordWrap)
85 r.UpperLeftCorner.Y = r.getCenter().Y - (height_total / 2);
87 else if (VAlign == EGUIA_LOWERRIGHT)
89 r.UpperLeftCorner.Y = r.LowerRightCorner.Y - height_total;
91 if (HAlign == EGUIA_LOWERRIGHT)
93 r.UpperLeftCorner.X = r.LowerRightCorner.X -
97 irr::video::SColor previous_color(255, 255, 255, 255);
98 for (const EnrichedString &str : BrokenText) {
99 if (HAlign == EGUIA_LOWERRIGHT)
101 r.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
102 font->getDimension(str.c_str()).Width;
105 if (font->getType() == irr::gui::EGFT_CUSTOM) {
106 CGUITTFont *tmp = static_cast<CGUITTFont*>(font);
108 r, HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER,
109 (RestrainTextInside ? &AbsoluteClippingRect : NULL));
112 // Draw non-colored text
113 font->draw(str.c_str(),
114 r, str.getDefaultColor(), // TODO: Implement colorization
115 HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER,
116 (RestrainTextInside ? &AbsoluteClippingRect : NULL));
120 r.LowerRightCorner.Y += height_line;
121 r.UpperLeftCorner.Y += height_line;
129 //! Sets another skin independent font.
130 void StaticText::setOverrideFont(IGUIFont* font)
132 if (OverrideFont == font)
136 OverrideFont->drop();
141 OverrideFont->grab();
146 //! Gets the override font (if any)
147 IGUIFont * StaticText::getOverrideFont() const
152 //! Get the font which is used right now for drawing
153 IGUIFont* StaticText::getActiveFont() const
157 IGUISkin* skin = Environment->getSkin();
159 return skin->getFont();
163 //! Sets another color for the text.
164 void StaticText::setOverrideColor(video::SColor color)
166 ColoredText.setDefaultColor(color);
171 //! Sets another color for the text.
172 void StaticText::setBackgroundColor(video::SColor color)
174 ColoredText.setBackground(color);
179 //! Sets whether to draw the background
180 void StaticText::setDrawBackground(bool draw)
186 //! Gets the background color
187 video::SColor StaticText::getBackgroundColor() const
189 IGUISkin *skin = Environment->getSkin();
191 return (ColoredText.hasBackground() || !skin) ?
192 ColoredText.getBackground() : skin->getColor(gui::EGDC_3D_FACE);
196 //! Checks if background drawing is enabled
197 bool StaticText::isDrawBackgroundEnabled() const
203 //! Sets whether to draw the border
204 void StaticText::setDrawBorder(bool draw)
210 //! Checks if border drawing is enabled
211 bool StaticText::isDrawBorderEnabled() const
217 void StaticText::setTextRestrainedInside(bool restrainTextInside)
219 RestrainTextInside = restrainTextInside;
223 bool StaticText::isTextRestrainedInside() const
225 return RestrainTextInside;
229 void StaticText::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
236 video::SColor StaticText::getOverrideColor() const
238 return ColoredText.getDefaultColor();
241 video::SColor StaticText::getActiveColor() const
243 return getOverrideColor();
246 //! Sets if the static text should use the overide color or the
247 //! color in the gui skin.
248 void StaticText::enableOverrideColor(bool enable)
254 bool StaticText::isOverrideColorEnabled() const
260 //! Enables or disables word wrap for using the static text as
261 //! multiline text control.
262 void StaticText::setWordWrap(bool enable)
269 bool StaticText::isWordWrapEnabled() const
275 void StaticText::setRightToLeft(bool rtl)
277 if (RightToLeft != rtl)
285 bool StaticText::isRightToLeft() const
291 //! Breaks the single text line.
292 // Updates the font colors
293 void StaticText::updateText()
295 const EnrichedString &cText = ColoredText;
298 if (cText.hasBackground())
299 setBackgroundColor(cText.getBackground());
301 setDrawBackground(false);
304 BrokenText.push_back(cText);
310 IGUISkin* skin = Environment->getSkin();
311 IGUIFont* font = getActiveFont();
315 LastBreakFont = font;
319 EnrichedString whitespace;
320 s32 size = cText.size();
322 s32 elWidth = RelativeRect.getWidth();
324 elWidth -= 2*skin->getSize(EGDS_TEXT_DISTANCE_X);
327 //std::vector<irr::video::SColor> colors;
329 // We have to deal with right-to-left and left-to-right differently
330 // However, most parts of the following code is the same, it's just
331 // some order and boundaries which change.
334 // regular (left-to-right)
335 for (s32 i=0; i<size; ++i)
337 c = cText.getString()[i];
338 bool lineBreak = false;
340 if (c == L'\r') // Mac or Windows breaks
343 //if (Text[i+1] == L'\n') // Windows breaks
350 else if (c == L'\n') // Unix breaks
356 bool isWhitespace = (c == L' ' || c == 0);
361 word.addChar(cText, i);
364 if ( isWhitespace || i == (size-1))
368 // here comes the next whitespace, look if
369 // we must break the last word to the next line.
370 const s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
371 //const std::wstring sanitized = removeEscapes(word.c_str());
372 const s32 wordlgth = font->getDimension(word.c_str()).Width;
374 if (wordlgth > elWidth)
376 // This word is too long to fit in the available space, look for
377 // the Unicode Soft HYphen (SHY / 00AD) character for a place to
379 int where = core::stringw(word.c_str()).findFirst( wchar_t(0x00AD) );
382 EnrichedString first = word.substr(0, where);
383 EnrichedString second = word.substr(where, word.size() - where);
384 first.addCharNoColor(L'-');
385 BrokenText.push_back(line + first);
386 const s32 secondLength = font->getDimension(second.c_str()).Width;
388 length = secondLength;
393 // No soft hyphen found, so there's nothing more we can do
394 // break to next line
396 BrokenText.push_back(line);
401 else if (length && (length + wordlgth + whitelgth > elWidth))
403 // break to next line
404 BrokenText.push_back(line);
413 length += whitelgth + wordlgth;
420 if ( isWhitespace && c != 0)
422 whitespace.addChar(cText, i);
425 // compute line break
430 BrokenText.push_back(line);
441 BrokenText.push_back(line);
446 for (s32 i=size; i>=0; --i)
448 c = cText.getString()[i];
449 bool lineBreak = false;
451 if (c == L'\r') // Mac or Windows breaks
454 //if ((i>0) && Text[i-1] == L'\n') // Windows breaks
461 else if (c == L'\n') // Unix breaks
467 if (c==L' ' || c==0 || i==0)
471 // here comes the next whitespace, look if
472 // we must break the last word to the next line.
473 const s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
474 const s32 wordlgth = font->getDimension(word.c_str()).Width;
476 if (length && (length + wordlgth + whitelgth > elWidth))
478 // break to next line
479 BrokenText.push_back(line);
486 line = whitespace + line;
488 length += whitelgth + wordlgth;
496 // whitespace = core::stringw(&c, 1) + whitespace;
497 whitespace = cText.substr(i, 1) + whitespace;
499 // compute line break
502 line = whitespace + line;
504 BrokenText.push_back(line);
513 // yippee this is a word..
514 //word = core::stringw(&c, 1) + word;
515 word = cText.substr(i, 1) + word;
519 line = whitespace + line;
521 BrokenText.push_back(line);
526 //! Sets the new caption of this element.
527 void StaticText::setText(const wchar_t* text)
529 setText(EnrichedString(text, getOverrideColor()));
532 void StaticText::setText(const EnrichedString &text)
535 IGUIElement::setText(ColoredText.c_str());
539 void StaticText::updateAbsolutePosition()
541 IGUIElement::updateAbsolutePosition();
546 //! Returns the height of the text in pixels when it is drawn.
547 s32 StaticText::getTextHeight() const
549 IGUIFont* font = getActiveFont();
554 s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
555 return height * BrokenText.size();
557 // There may be intentional new lines without WordWrap
558 return font->getDimension(BrokenText[0].c_str()).Height;
562 s32 StaticText::getTextWidth() const
564 IGUIFont *font = getActiveFont();
570 for (const EnrichedString &line : BrokenText) {
571 s32 width = font->getDimension(line.c_str()).Width;
581 } // end namespace gui
583 } // end namespace irr