1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // Copyright (C) 2016 Nathanaƫl 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>
16 #include "CGUITTFont.h"
19 #include "util/string.h"
29 StaticText::StaticText(const EnrichedString &text, bool border,
30 IGUIEnvironment* environment, IGUIElement* parent,
31 s32 id, const core::rect<s32>& rectangle,
33 : IGUIStaticText(environment, parent, id, rectangle),
34 HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_UPPERLEFT),
35 Border(border), WordWrap(false), Background(background),
36 RestrainTextInside(true), RightToLeft(false),
37 OverrideFont(0), LastBreakFont(0)
40 setDebugName("StaticText");
48 StaticText::~StaticText()
54 //! draws the element and its children
55 void StaticText::draw()
60 IGUISkin* skin = Environment->getSkin();
63 video::IVideoDriver* driver = Environment->getVideoDriver();
65 core::rect<s32> frameRect(AbsoluteRect);
70 driver->draw2DRectangle(getBackgroundColor(), frameRect, &AbsoluteClippingRect);
76 skin->draw3DSunkenPane(this, 0, true, false, frameRect, &AbsoluteClippingRect);
77 frameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X);
81 IGUIFont *font = getActiveFont();
82 if (font && BrokenText.size()) {
83 if (font != LastBreakFont)
86 core::rect<s32> r = frameRect;
87 s32 height_line = font->getDimension(L"A").Height + font->getKerningHeight();
88 s32 height_total = height_line * BrokenText.size();
89 if (VAlign == EGUIA_CENTER && WordWrap)
91 r.UpperLeftCorner.Y = r.getCenter().Y - (height_total / 2);
93 else if (VAlign == EGUIA_LOWERRIGHT)
95 r.UpperLeftCorner.Y = r.LowerRightCorner.Y - height_total;
97 if (HAlign == EGUIA_LOWERRIGHT)
99 r.UpperLeftCorner.X = r.LowerRightCorner.X -
103 irr::video::SColor previous_color(255, 255, 255, 255);
104 for (const EnrichedString &str : BrokenText) {
105 if (HAlign == EGUIA_LOWERRIGHT)
107 r.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
108 font->getDimension(str.c_str()).Width;
112 if (font->getType() == irr::gui::EGFT_CUSTOM) {
113 irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(font);
115 r, HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER,
116 (RestrainTextInside ? &AbsoluteClippingRect : NULL));
120 // Draw non-colored text
121 font->draw(str.c_str(),
122 r, str.getDefaultColor(), // TODO: Implement colorization
123 HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER,
124 (RestrainTextInside ? &AbsoluteClippingRect : NULL));
128 r.LowerRightCorner.Y += height_line;
129 r.UpperLeftCorner.Y += height_line;
137 //! Sets another skin independent font.
138 void StaticText::setOverrideFont(IGUIFont* font)
140 if (OverrideFont == font)
144 OverrideFont->drop();
149 OverrideFont->grab();
154 //! Gets the override font (if any)
155 IGUIFont * StaticText::getOverrideFont() const
160 //! Get the font which is used right now for drawing
161 IGUIFont* StaticText::getActiveFont() const
165 IGUISkin* skin = Environment->getSkin();
167 return skin->getFont();
171 //! Sets another color for the text.
172 void StaticText::setOverrideColor(video::SColor color)
174 ColoredText.setDefaultColor(color);
179 //! Sets another color for the text.
180 void StaticText::setBackgroundColor(video::SColor color)
182 ColoredText.setBackground(color);
187 //! Sets whether to draw the background
188 void StaticText::setDrawBackground(bool draw)
194 //! Gets the background color
195 video::SColor StaticText::getBackgroundColor() const
197 IGUISkin *skin = Environment->getSkin();
199 return (ColoredText.hasBackground() || !skin) ?
200 ColoredText.getBackground() : skin->getColor(gui::EGDC_3D_FACE);
204 //! Checks if background drawing is enabled
205 bool StaticText::isDrawBackgroundEnabled() const
211 //! Sets whether to draw the border
212 void StaticText::setDrawBorder(bool draw)
218 //! Checks if border drawing is enabled
219 bool StaticText::isDrawBorderEnabled() const
225 void StaticText::setTextRestrainedInside(bool restrainTextInside)
227 RestrainTextInside = restrainTextInside;
231 bool StaticText::isTextRestrainedInside() const
233 return RestrainTextInside;
237 void StaticText::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
244 video::SColor StaticText::getOverrideColor() const
246 return ColoredText.getDefaultColor();
249 #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8
250 video::SColor StaticText::getActiveColor() const
252 return getOverrideColor();
256 //! Sets if the static text should use the overide color or the
257 //! color in the gui skin.
258 void StaticText::enableOverrideColor(bool enable)
264 bool StaticText::isOverrideColorEnabled() const
270 //! Enables or disables word wrap for using the static text as
271 //! multiline text control.
272 void StaticText::setWordWrap(bool enable)
279 bool StaticText::isWordWrapEnabled() const
285 void StaticText::setRightToLeft(bool rtl)
287 if (RightToLeft != rtl)
295 bool StaticText::isRightToLeft() const
301 //! Breaks the single text line.
302 // Updates the font colors
303 void StaticText::updateText()
305 const EnrichedString &cText = ColoredText;
308 if (cText.hasBackground())
309 setBackgroundColor(cText.getBackground());
311 setDrawBackground(false);
314 BrokenText.push_back(cText);
320 IGUISkin* skin = Environment->getSkin();
321 IGUIFont* font = getActiveFont();
325 LastBreakFont = font;
329 EnrichedString whitespace;
330 s32 size = cText.size();
332 s32 elWidth = RelativeRect.getWidth();
334 elWidth -= 2*skin->getSize(EGDS_TEXT_DISTANCE_X);
337 //std::vector<irr::video::SColor> colors;
339 // We have to deal with right-to-left and left-to-right differently
340 // However, most parts of the following code is the same, it's just
341 // some order and boundaries which change.
344 // regular (left-to-right)
345 for (s32 i=0; i<size; ++i)
347 c = cText.getString()[i];
348 bool lineBreak = false;
350 if (c == L'\r') // Mac or Windows breaks
353 //if (Text[i+1] == L'\n') // Windows breaks
360 else if (c == L'\n') // Unix breaks
366 bool isWhitespace = (c == L' ' || c == 0);
371 word.addChar(cText, i);
374 if ( isWhitespace || i == (size-1))
378 // here comes the next whitespace, look if
379 // we must break the last word to the next line.
380 const s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
381 //const std::wstring sanitized = removeEscapes(word.c_str());
382 const s32 wordlgth = font->getDimension(word.c_str()).Width;
384 if (wordlgth > elWidth)
386 // This word is too long to fit in the available space, look for
387 // the Unicode Soft HYphen (SHY / 00AD) character for a place to
389 int where = core::stringw(word.c_str()).findFirst( wchar_t(0x00AD) );
392 EnrichedString first = word.substr(0, where);
393 EnrichedString second = word.substr(where, word.size() - where);
394 first.addCharNoColor(L'-');
395 BrokenText.push_back(line + first);
396 const s32 secondLength = font->getDimension(second.c_str()).Width;
398 length = secondLength;
403 // No soft hyphen found, so there's nothing more we can do
404 // break to next line
406 BrokenText.push_back(line);
411 else if (length && (length + wordlgth + whitelgth > elWidth))
413 // break to next line
414 BrokenText.push_back(line);
423 length += whitelgth + wordlgth;
430 if ( isWhitespace && c != 0)
432 whitespace.addChar(cText, i);
435 // compute line break
440 BrokenText.push_back(line);
451 BrokenText.push_back(line);
456 for (s32 i=size; i>=0; --i)
458 c = cText.getString()[i];
459 bool lineBreak = false;
461 if (c == L'\r') // Mac or Windows breaks
464 //if ((i>0) && Text[i-1] == L'\n') // Windows breaks
471 else if (c == L'\n') // Unix breaks
477 if (c==L' ' || c==0 || i==0)
481 // here comes the next whitespace, look if
482 // we must break the last word to the next line.
483 const s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
484 const s32 wordlgth = font->getDimension(word.c_str()).Width;
486 if (length && (length + wordlgth + whitelgth > elWidth))
488 // break to next line
489 BrokenText.push_back(line);
496 line = whitespace + line;
498 length += whitelgth + wordlgth;
506 // whitespace = core::stringw(&c, 1) + whitespace;
507 whitespace = cText.substr(i, 1) + whitespace;
509 // compute line break
512 line = whitespace + line;
514 BrokenText.push_back(line);
523 // yippee this is a word..
524 //word = core::stringw(&c, 1) + word;
525 word = cText.substr(i, 1) + word;
529 line = whitespace + line;
531 BrokenText.push_back(line);
536 //! Sets the new caption of this element.
537 void StaticText::setText(const wchar_t* text)
539 setText(EnrichedString(text, getOverrideColor()));
542 void StaticText::setText(const EnrichedString &text)
545 IGUIElement::setText(ColoredText.c_str());
549 void StaticText::updateAbsolutePosition()
551 IGUIElement::updateAbsolutePosition();
556 //! Returns the height of the text in pixels when it is drawn.
557 s32 StaticText::getTextHeight() const
559 IGUIFont* font = getActiveFont();
564 s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
565 return height * BrokenText.size();
567 // There may be intentional new lines without WordWrap
568 return font->getDimension(BrokenText[0].c_str()).Height;
572 s32 StaticText::getTextWidth() const
574 IGUIFont *font = getActiveFont();
580 for (const EnrichedString &line : BrokenText) {
581 s32 width = font->getDimension(line.c_str()).Width;
591 //! Writes attributes of the element.
592 //! Implement this to expose the attributes of your element for
593 //! scripting languages, editors, debuggers or xml serialization purposes.
594 void StaticText::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
596 IGUIStaticText::serializeAttributes(out,options);
598 out->addBool ("Border", Border);
599 out->addBool ("OverrideColorEnabled",true);
600 out->addBool ("OverrideBGColorEnabled",ColoredText.hasBackground());
601 out->addBool ("WordWrap", WordWrap);
602 out->addBool ("Background", Background);
603 out->addBool ("RightToLeft", RightToLeft);
604 out->addBool ("RestrainTextInside", RestrainTextInside);
605 out->addColor ("OverrideColor", ColoredText.getDefaultColor());
606 out->addColor ("BGColor", ColoredText.getBackground());
607 out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames);
608 out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames);
610 // out->addFont ("OverrideFont", OverrideFont);
614 //! Reads attributes of the element
615 void StaticText::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
617 IGUIStaticText::deserializeAttributes(in,options);
619 Border = in->getAttributeAsBool("Border");
620 setWordWrap(in->getAttributeAsBool("WordWrap"));
621 Background = in->getAttributeAsBool("Background");
622 RightToLeft = in->getAttributeAsBool("RightToLeft");
623 RestrainTextInside = in->getAttributeAsBool("RestrainTextInside");
624 if (in->getAttributeAsBool("OverrideColorEnabled"))
625 ColoredText.setDefaultColor(in->getAttributeAsColor("OverrideColor"));
626 if (in->getAttributeAsBool("OverrideBGColorEnabled"))
627 ColoredText.setBackground(in->getAttributeAsColor("BGColor"));
629 setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
630 (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
632 // OverrideFont = in->getAttributeAsFont("OverrideFont");
635 } // end namespace gui
637 #endif // USE_FREETYPE
639 } // end namespace irr
642 #endif // _IRR_COMPILE_WITH_GUI_