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_
14 #include <IGUIEnvironment.h>
16 #include <IVideoDriver.h>
21 #include "cguittfont/xCGUITTFont.h"
23 #ifndef _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX
24 // newer Irrlicht versions no longer have this
25 #define _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX
28 #include "util/string.h"
38 StaticText::StaticText(const EnrichedString &text, bool border,
39 IGUIEnvironment* environment, IGUIElement* parent,
40 s32 id, const core::rect<s32>& rectangle,
42 : IGUIStaticText(environment, parent, id, rectangle),
43 HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_UPPERLEFT),
44 Border(border), OverrideColorEnabled(false), OverrideBGColorEnabled(false), WordWrap(false), Background(background),
45 RestrainTextInside(true), RightToLeft(false),
46 OverrideColor(video::SColor(101,255,255,255)), BGColor(video::SColor(101,210,210,210)),
47 OverrideFont(0), LastBreakFont(0)
50 setDebugName("StaticText");
55 if (environment && environment->getSkin())
57 BGColor = environment->getSkin()->getColor(gui::EGDC_3D_FACE);
63 StaticText::~StaticText()
69 //! draws the element and its children
70 void StaticText::draw()
75 IGUISkin* skin = Environment->getSkin();
78 video::IVideoDriver* driver = Environment->getVideoDriver();
80 core::rect<s32> frameRect(AbsoluteRect);
86 if ( !OverrideBGColorEnabled ) // skin-colors can change
87 BGColor = skin->getColor(gui::EGDC_3D_FACE);
89 driver->draw2DRectangle(BGColor, frameRect, &AbsoluteClippingRect);
96 skin->draw3DSunkenPane(this, 0, true, false, frameRect, &AbsoluteClippingRect);
97 frameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X);
103 IGUIFont* font = getActiveFont();
109 // TODO: add colors here
110 if (VAlign == EGUIA_LOWERRIGHT)
112 frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y -
113 font->getDimension(L"A").Height - font->getKerningHeight();
115 if (HAlign == EGUIA_LOWERRIGHT)
117 frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
118 font->getDimension(cText.c_str()).Width;
121 irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(font);
122 tmp->draw(cText, frameRect,
123 OverrideColorEnabled ? OverrideColor : skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT),
124 HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER, (RestrainTextInside ? &AbsoluteClippingRect : NULL));
128 if (font != LastBreakFont)
131 core::rect<s32> r = frameRect;
132 s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
133 s32 totalHeight = height * BrokenText.size();
134 if (VAlign == EGUIA_CENTER)
136 r.UpperLeftCorner.Y = r.getCenter().Y - (totalHeight / 2);
138 else if (VAlign == EGUIA_LOWERRIGHT)
140 r.UpperLeftCorner.Y = r.LowerRightCorner.Y - totalHeight;
143 irr::video::SColor previous_color(255, 255, 255, 255);
144 for (u32 i=0; i<BrokenText.size(); ++i)
146 if (HAlign == EGUIA_LOWERRIGHT)
148 r.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
149 font->getDimension(BrokenText[i].c_str()).Width;
152 //std::vector<irr::video::SColor> colors;
154 EnrichedString str = BrokenText[i];
156 //str = colorizeText(BrokenText[i].c_str(), colors, previous_color);
157 //if (!colors.empty())
158 // previous_color = colors[colors.size() - 1];
160 irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(font);
162 previous_color, // FIXME
163 HAlign == EGUIA_CENTER, false, (RestrainTextInside ? &AbsoluteClippingRect : NULL));
165 r.LowerRightCorner.Y += height;
166 r.UpperLeftCorner.Y += height;
176 //! Sets another skin independent font.
177 void StaticText::setOverrideFont(IGUIFont* font)
179 if (OverrideFont == font)
183 OverrideFont->drop();
188 OverrideFont->grab();
193 //! Gets the override font (if any)
194 IGUIFont * StaticText::getOverrideFont() const
199 //! Get the font which is used right now for drawing
200 IGUIFont* StaticText::getActiveFont() const
204 IGUISkin* skin = Environment->getSkin();
206 return skin->getFont();
210 //! Sets another color for the text.
211 void StaticText::setOverrideColor(video::SColor color)
213 OverrideColor = color;
214 OverrideColorEnabled = true;
218 //! Sets another color for the text.
219 void StaticText::setBackgroundColor(video::SColor color)
222 OverrideBGColorEnabled = true;
227 //! Sets whether to draw the background
228 void StaticText::setDrawBackground(bool draw)
234 //! Gets the background color
235 video::SColor StaticText::getBackgroundColor() const
241 //! Checks if background drawing is enabled
242 bool StaticText::isDrawBackgroundEnabled() const
244 _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
249 //! Sets whether to draw the border
250 void StaticText::setDrawBorder(bool draw)
256 //! Checks if border drawing is enabled
257 bool StaticText::isDrawBorderEnabled() const
259 _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
264 void StaticText::setTextRestrainedInside(bool restrainTextInside)
266 RestrainTextInside = restrainTextInside;
270 bool StaticText::isTextRestrainedInside() const
272 return RestrainTextInside;
276 void StaticText::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
283 #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
284 const video::SColor& StaticText::getOverrideColor() const
286 video::SColor StaticText::getOverrideColor() const
289 return OverrideColor;
293 //! Sets if the static text should use the overide color or the
294 //! color in the gui skin.
295 void StaticText::enableOverrideColor(bool enable)
297 OverrideColorEnabled = enable;
301 bool StaticText::isOverrideColorEnabled() const
303 _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
304 return OverrideColorEnabled;
308 //! Enables or disables word wrap for using the static text as
309 //! multiline text control.
310 void StaticText::setWordWrap(bool enable)
317 bool StaticText::isWordWrapEnabled() const
319 _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
324 void StaticText::setRightToLeft(bool rtl)
326 if (RightToLeft != rtl)
334 bool StaticText::isRightToLeft() const
340 //! Breaks the single text line.
341 void StaticText::breakText()
348 IGUISkin* skin = Environment->getSkin();
349 IGUIFont* font = getActiveFont();
353 LastBreakFont = font;
357 EnrichedString whitespace;
358 s32 size = cText.size();
360 s32 elWidth = RelativeRect.getWidth();
362 elWidth -= 2*skin->getSize(EGDS_TEXT_DISTANCE_X);
365 //std::vector<irr::video::SColor> colors;
367 // We have to deal with right-to-left and left-to-right differently
368 // However, most parts of the following code is the same, it's just
369 // some order and boundaries which change.
372 // regular (left-to-right)
373 for (s32 i=0; i<size; ++i)
375 c = cText.getString()[i];
376 bool lineBreak = false;
378 if (c == L'\r') // Mac or Windows breaks
381 //if (Text[i+1] == L'\n') // Windows breaks
388 else if (c == L'\n') // Unix breaks
394 bool isWhitespace = (c == L' ' || c == 0);
399 word.addChar(cText, i);
402 if ( isWhitespace || i == (size-1))
406 // here comes the next whitespace, look if
407 // we must break the last word to the next line.
408 const s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
409 //const std::wstring sanitized = removeEscapes(word.c_str());
410 const s32 wordlgth = font->getDimension(word.c_str()).Width;
412 if (wordlgth > elWidth)
414 // This word is too long to fit in the available space, look for
415 // the Unicode Soft HYphen (SHY / 00AD) character for a place to
417 int where = core::stringw(word.c_str()).findFirst( wchar_t(0x00AD) );
420 EnrichedString first = word.substr(0, where);
421 EnrichedString second = word.substr(where, word.size() - where);
422 first.addCharNoColor(L'-');
423 BrokenText.push_back(line + first);
424 const s32 secondLength = font->getDimension(second.c_str()).Width;
426 length = secondLength;
431 // No soft hyphen found, so there's nothing more we can do
432 // break to next line
434 BrokenText.push_back(line);
439 else if (length && (length + wordlgth + whitelgth > elWidth))
441 // break to next line
442 BrokenText.push_back(line);
451 length += whitelgth + wordlgth;
458 if ( isWhitespace && c != 0)
460 whitespace.addChar(cText, i);
463 // compute line break
468 BrokenText.push_back(line);
479 BrokenText.push_back(line);
484 for (s32 i=size; i>=0; --i)
486 c = cText.getString()[i];
487 bool lineBreak = false;
489 if (c == L'\r') // Mac or Windows breaks
492 //if ((i>0) && Text[i-1] == L'\n') // Windows breaks
499 else if (c == L'\n') // Unix breaks
505 if (c==L' ' || c==0 || i==0)
509 // here comes the next whitespace, look if
510 // we must break the last word to the next line.
511 const s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
512 const s32 wordlgth = font->getDimension(word.c_str()).Width;
514 if (length && (length + wordlgth + whitelgth > elWidth))
516 // break to next line
517 BrokenText.push_back(line);
524 line = whitespace + line;
526 length += whitelgth + wordlgth;
534 // whitespace = core::stringw(&c, 1) + whitespace;
535 whitespace = cText.substr(i, 1) + whitespace;
537 // compute line break
540 line = whitespace + line;
542 BrokenText.push_back(line);
551 // yippee this is a word..
552 //word = core::stringw(&c, 1) + word;
553 word = cText.substr(i, 1) + word;
557 line = whitespace + line;
559 BrokenText.push_back(line);
564 //! Sets the new caption of this element.
565 void StaticText::setText(const wchar_t* text)
567 setText(EnrichedString(text));
570 //! Sets the new caption of this element.
571 void StaticText::setText(const EnrichedString &text)
573 IGUIElement::setText(text.c_str());
575 if (text.hasBackground()) {
576 setBackgroundColor(text.getBackground());
582 void StaticText::updateAbsolutePosition()
584 IGUIElement::updateAbsolutePosition();
589 //! Returns the height of the text in pixels when it is drawn.
590 s32 StaticText::getTextHeight() const
592 IGUIFont* font = getActiveFont();
596 s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
599 height *= BrokenText.size();
605 s32 StaticText::getTextWidth() const
607 IGUIFont * font = getActiveFont();
615 for(u32 line = 0; line < BrokenText.size(); ++line)
617 s32 width = font->getDimension(BrokenText[line].c_str()).Width;
627 return font->getDimension(cText.c_str()).Width;
632 //! Writes attributes of the element.
633 //! Implement this to expose the attributes of your element for
634 //! scripting languages, editors, debuggers or xml serialization purposes.
635 void StaticText::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
637 IGUIStaticText::serializeAttributes(out,options);
639 out->addBool ("Border", Border);
640 out->addBool ("OverrideColorEnabled",OverrideColorEnabled);
641 out->addBool ("OverrideBGColorEnabled",OverrideBGColorEnabled);
642 out->addBool ("WordWrap", WordWrap);
643 out->addBool ("Background", Background);
644 out->addBool ("RightToLeft", RightToLeft);
645 out->addBool ("RestrainTextInside", RestrainTextInside);
646 out->addColor ("OverrideColor", OverrideColor);
647 out->addColor ("BGColor", BGColor);
648 out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames);
649 out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames);
651 // out->addFont ("OverrideFont", OverrideFont);
655 //! Reads attributes of the element
656 void StaticText::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
658 IGUIStaticText::deserializeAttributes(in,options);
660 Border = in->getAttributeAsBool("Border");
661 enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled"));
662 OverrideBGColorEnabled = in->getAttributeAsBool("OverrideBGColorEnabled");
663 setWordWrap(in->getAttributeAsBool("WordWrap"));
664 Background = in->getAttributeAsBool("Background");
665 RightToLeft = in->getAttributeAsBool("RightToLeft");
666 RestrainTextInside = in->getAttributeAsBool("RestrainTextInside");
667 OverrideColor = in->getAttributeAsColor("OverrideColor");
668 BGColor = in->getAttributeAsColor("BGColor");
670 setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
671 (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
673 // OverrideFont = in->getAttributeAsFont("OverrideFont");
676 } // end namespace gui
678 #endif // USE_FREETYPE
680 } // end namespace irr
683 #endif // _IRR_COMPILE_WITH_GUI_