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"
8 #ifdef _IRR_COMPILE_WITH_GUI_
11 #include <IVideoDriver.h>
15 #include "CGUITTFont.h"
16 #include "util/string.h"
24 StaticText::StaticText(const EnrichedString &text, bool border,
25 IGUIEnvironment* environment, IGUIElement* parent,
26 s32 id, const core::rect<s32>& rectangle,
28 : IGUIStaticText(environment, parent, id, rectangle),
29 HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_UPPERLEFT),
30 Border(border), WordWrap(false), Background(background),
31 RestrainTextInside(true), RightToLeft(false),
32 OverrideFont(0), LastBreakFont(0)
35 setDebugName("StaticText");
43 StaticText::~StaticText()
49 //! draws the element and its children
50 void StaticText::draw()
55 IGUISkin* skin = Environment->getSkin();
58 video::IVideoDriver* driver = Environment->getVideoDriver();
60 core::rect<s32> frameRect(AbsoluteRect);
65 driver->draw2DRectangle(getBackgroundColor(), frameRect, &AbsoluteClippingRect);
71 skin->draw3DSunkenPane(this, 0, true, false, frameRect, &AbsoluteClippingRect);
72 frameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X);
76 IGUIFont *font = getActiveFont();
77 if (font && BrokenText.size()) {
78 if (font != LastBreakFont)
81 core::rect<s32> r = frameRect;
82 s32 height_line = font->getDimension(L"A").Height + font->getKerningHeight();
83 s32 height_total = height_line * BrokenText.size();
84 if (VAlign == EGUIA_CENTER && WordWrap)
86 r.UpperLeftCorner.Y = r.getCenter().Y - (height_total / 2);
88 else if (VAlign == EGUIA_LOWERRIGHT)
90 r.UpperLeftCorner.Y = r.LowerRightCorner.Y - height_total;
92 if (HAlign == EGUIA_LOWERRIGHT)
94 r.UpperLeftCorner.X = r.LowerRightCorner.X -
98 irr::video::SColor previous_color(255, 255, 255, 255);
99 for (const EnrichedString &str : BrokenText) {
100 if (HAlign == EGUIA_LOWERRIGHT)
102 r.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
103 font->getDimension(str.c_str()).Width;
106 if (font->getType() == irr::gui::EGFT_CUSTOM) {
107 CGUITTFont *tmp = static_cast<CGUITTFont*>(font);
109 r, HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER,
110 (RestrainTextInside ? &AbsoluteClippingRect : NULL));
113 // Draw non-colored text
114 font->draw(str.c_str(),
115 r, str.getDefaultColor(), // TODO: Implement colorization
116 HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER,
117 (RestrainTextInside ? &AbsoluteClippingRect : NULL));
121 r.LowerRightCorner.Y += height_line;
122 r.UpperLeftCorner.Y += height_line;
130 //! Sets another skin independent font.
131 void StaticText::setOverrideFont(IGUIFont* font)
133 if (OverrideFont == font)
137 OverrideFont->drop();
142 OverrideFont->grab();
147 //! Gets the override font (if any)
148 IGUIFont * StaticText::getOverrideFont() const
153 //! Get the font which is used right now for drawing
154 IGUIFont* StaticText::getActiveFont() const
158 IGUISkin* skin = Environment->getSkin();
160 return skin->getFont();
164 //! Sets another color for the text.
165 void StaticText::setOverrideColor(video::SColor color)
167 ColoredText.setDefaultColor(color);
172 //! Sets another color for the text.
173 void StaticText::setBackgroundColor(video::SColor color)
175 ColoredText.setBackground(color);
180 //! Sets whether to draw the background
181 void StaticText::setDrawBackground(bool draw)
187 //! Gets the background color
188 video::SColor StaticText::getBackgroundColor() const
190 IGUISkin *skin = Environment->getSkin();
192 return (ColoredText.hasBackground() || !skin) ?
193 ColoredText.getBackground() : skin->getColor(gui::EGDC_3D_FACE);
197 //! Checks if background drawing is enabled
198 bool StaticText::isDrawBackgroundEnabled() const
204 //! Sets whether to draw the border
205 void StaticText::setDrawBorder(bool draw)
211 //! Checks if border drawing is enabled
212 bool StaticText::isDrawBorderEnabled() const
218 void StaticText::setTextRestrainedInside(bool restrainTextInside)
220 RestrainTextInside = restrainTextInside;
224 bool StaticText::isTextRestrainedInside() const
226 return RestrainTextInside;
230 void StaticText::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
237 video::SColor StaticText::getOverrideColor() const
239 return ColoredText.getDefaultColor();
242 #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8
243 video::SColor StaticText::getActiveColor() const
245 return getOverrideColor();
249 //! Sets if the static text should use the overide color or the
250 //! color in the gui skin.
251 void StaticText::enableOverrideColor(bool enable)
257 bool StaticText::isOverrideColorEnabled() const
263 //! Enables or disables word wrap for using the static text as
264 //! multiline text control.
265 void StaticText::setWordWrap(bool enable)
272 bool StaticText::isWordWrapEnabled() const
278 void StaticText::setRightToLeft(bool rtl)
280 if (RightToLeft != rtl)
288 bool StaticText::isRightToLeft() const
294 //! Breaks the single text line.
295 // Updates the font colors
296 void StaticText::updateText()
298 const EnrichedString &cText = ColoredText;
301 if (cText.hasBackground())
302 setBackgroundColor(cText.getBackground());
304 setDrawBackground(false);
307 BrokenText.push_back(cText);
313 IGUISkin* skin = Environment->getSkin();
314 IGUIFont* font = getActiveFont();
318 LastBreakFont = font;
322 EnrichedString whitespace;
323 s32 size = cText.size();
325 s32 elWidth = RelativeRect.getWidth();
327 elWidth -= 2*skin->getSize(EGDS_TEXT_DISTANCE_X);
330 //std::vector<irr::video::SColor> colors;
332 // We have to deal with right-to-left and left-to-right differently
333 // However, most parts of the following code is the same, it's just
334 // some order and boundaries which change.
337 // regular (left-to-right)
338 for (s32 i=0; i<size; ++i)
340 c = cText.getString()[i];
341 bool lineBreak = false;
343 if (c == L'\r') // Mac or Windows breaks
346 //if (Text[i+1] == L'\n') // Windows breaks
353 else if (c == L'\n') // Unix breaks
359 bool isWhitespace = (c == L' ' || c == 0);
364 word.addChar(cText, i);
367 if ( isWhitespace || i == (size-1))
371 // here comes the next whitespace, look if
372 // we must break the last word to the next line.
373 const s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
374 //const std::wstring sanitized = removeEscapes(word.c_str());
375 const s32 wordlgth = font->getDimension(word.c_str()).Width;
377 if (wordlgth > elWidth)
379 // This word is too long to fit in the available space, look for
380 // the Unicode Soft HYphen (SHY / 00AD) character for a place to
382 int where = core::stringw(word.c_str()).findFirst( wchar_t(0x00AD) );
385 EnrichedString first = word.substr(0, where);
386 EnrichedString second = word.substr(where, word.size() - where);
387 first.addCharNoColor(L'-');
388 BrokenText.push_back(line + first);
389 const s32 secondLength = font->getDimension(second.c_str()).Width;
391 length = secondLength;
396 // No soft hyphen found, so there's nothing more we can do
397 // break to next line
399 BrokenText.push_back(line);
404 else if (length && (length + wordlgth + whitelgth > elWidth))
406 // break to next line
407 BrokenText.push_back(line);
416 length += whitelgth + wordlgth;
423 if ( isWhitespace && c != 0)
425 whitespace.addChar(cText, i);
428 // compute line break
433 BrokenText.push_back(line);
444 BrokenText.push_back(line);
449 for (s32 i=size; i>=0; --i)
451 c = cText.getString()[i];
452 bool lineBreak = false;
454 if (c == L'\r') // Mac or Windows breaks
457 //if ((i>0) && Text[i-1] == L'\n') // Windows breaks
464 else if (c == L'\n') // Unix breaks
470 if (c==L' ' || c==0 || i==0)
474 // here comes the next whitespace, look if
475 // we must break the last word to the next line.
476 const s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
477 const s32 wordlgth = font->getDimension(word.c_str()).Width;
479 if (length && (length + wordlgth + whitelgth > elWidth))
481 // break to next line
482 BrokenText.push_back(line);
489 line = whitespace + line;
491 length += whitelgth + wordlgth;
499 // whitespace = core::stringw(&c, 1) + whitespace;
500 whitespace = cText.substr(i, 1) + whitespace;
502 // compute line break
505 line = whitespace + line;
507 BrokenText.push_back(line);
516 // yippee this is a word..
517 //word = core::stringw(&c, 1) + word;
518 word = cText.substr(i, 1) + word;
522 line = whitespace + line;
524 BrokenText.push_back(line);
529 //! Sets the new caption of this element.
530 void StaticText::setText(const wchar_t* text)
532 setText(EnrichedString(text, getOverrideColor()));
535 void StaticText::setText(const EnrichedString &text)
538 IGUIElement::setText(ColoredText.c_str());
542 void StaticText::updateAbsolutePosition()
544 IGUIElement::updateAbsolutePosition();
549 //! Returns the height of the text in pixels when it is drawn.
550 s32 StaticText::getTextHeight() const
552 IGUIFont* font = getActiveFont();
557 s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
558 return height * BrokenText.size();
560 // There may be intentional new lines without WordWrap
561 return font->getDimension(BrokenText[0].c_str()).Height;
565 s32 StaticText::getTextWidth() const
567 IGUIFont *font = getActiveFont();
573 for (const EnrichedString &line : BrokenText) {
574 s32 width = font->getDimension(line.c_str()).Width;
584 } // end namespace gui
586 } // end namespace irr
589 #endif // _IRR_COMPILE_WITH_GUI_