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
;
111 //str = colorizeText(BrokenText[i].c_str(), colors, previous_color);
112 //if (!colors.empty())
113 // previous_color = colors[colors.size() - 1];
116 if (font
->getType() == irr::gui::EGFT_CUSTOM
) {
117 irr::gui::CGUITTFont
*tmp
= static_cast<irr::gui::CGUITTFont
*>(font
);
119 r
, previous_color
, // FIXME
120 HAlign
== EGUIA_CENTER
, VAlign
== EGUIA_CENTER
,
121 (RestrainTextInside
? &AbsoluteClippingRect
: NULL
));
125 // Draw non-colored text
126 font
->draw(str
.c_str(),
127 r
, str
.getDefaultColor(), // TODO: Implement colorization
128 HAlign
== EGUIA_CENTER
, VAlign
== EGUIA_CENTER
,
129 (RestrainTextInside
? &AbsoluteClippingRect
: NULL
));
133 r
.LowerRightCorner
.Y
+= height_line
;
134 r
.UpperLeftCorner
.Y
+= height_line
;
142 //! Sets another skin independent font.
143 void StaticText::setOverrideFont(IGUIFont
* font
)
145 if (OverrideFont
== font
)
149 OverrideFont
->drop();
154 OverrideFont
->grab();
159 //! Gets the override font (if any)
160 IGUIFont
* StaticText::getOverrideFont() const
165 //! Get the font which is used right now for drawing
166 IGUIFont
* StaticText::getActiveFont() const
170 IGUISkin
* skin
= Environment
->getSkin();
172 return skin
->getFont();
176 //! Sets another color for the text.
177 void StaticText::setOverrideColor(video::SColor color
)
179 ColoredText
.setDefaultColor(color
);
184 //! Sets another color for the text.
185 void StaticText::setBackgroundColor(video::SColor color
)
187 ColoredText
.setBackground(color
);
192 //! Sets whether to draw the background
193 void StaticText::setDrawBackground(bool draw
)
199 //! Gets the background color
200 video::SColor
StaticText::getBackgroundColor() const
202 IGUISkin
*skin
= Environment
->getSkin();
204 return (ColoredText
.hasBackground() || !skin
) ?
205 ColoredText
.getBackground() : skin
->getColor(gui::EGDC_3D_FACE
);
209 //! Checks if background drawing is enabled
210 bool StaticText::isDrawBackgroundEnabled() const
216 //! Sets whether to draw the border
217 void StaticText::setDrawBorder(bool draw
)
223 //! Checks if border drawing is enabled
224 bool StaticText::isDrawBorderEnabled() const
230 void StaticText::setTextRestrainedInside(bool restrainTextInside
)
232 RestrainTextInside
= restrainTextInside
;
236 bool StaticText::isTextRestrainedInside() const
238 return RestrainTextInside
;
242 void StaticText::setTextAlignment(EGUI_ALIGNMENT horizontal
, EGUI_ALIGNMENT vertical
)
249 #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
250 const video::SColor
& StaticText::getOverrideColor() const
252 video::SColor
StaticText::getOverrideColor() const
255 return ColoredText
.getDefaultColor();
259 //! Sets if the static text should use the overide color or the
260 //! color in the gui skin.
261 void StaticText::enableOverrideColor(bool enable
)
267 bool StaticText::isOverrideColorEnabled() const
273 //! Enables or disables word wrap for using the static text as
274 //! multiline text control.
275 void StaticText::setWordWrap(bool enable
)
282 bool StaticText::isWordWrapEnabled() const
288 void StaticText::setRightToLeft(bool rtl
)
290 if (RightToLeft
!= rtl
)
298 bool StaticText::isRightToLeft() const
304 //! Breaks the single text line.
305 // Updates the font colors
306 void StaticText::updateText()
308 const EnrichedString
&cText
= ColoredText
;
311 if (cText
.hasBackground())
312 setBackgroundColor(cText
.getBackground());
314 setDrawBackground(false);
317 BrokenText
.push_back(cText
);
323 IGUISkin
* skin
= Environment
->getSkin();
324 IGUIFont
* font
= getActiveFont();
328 LastBreakFont
= font
;
332 EnrichedString whitespace
;
333 s32 size
= cText
.size();
335 s32 elWidth
= RelativeRect
.getWidth();
337 elWidth
-= 2*skin
->getSize(EGDS_TEXT_DISTANCE_X
);
340 //std::vector<irr::video::SColor> colors;
342 // We have to deal with right-to-left and left-to-right differently
343 // However, most parts of the following code is the same, it's just
344 // some order and boundaries which change.
347 // regular (left-to-right)
348 for (s32 i
=0; i
<size
; ++i
)
350 c
= cText
.getString()[i
];
351 bool lineBreak
= false;
353 if (c
== L
'\r') // Mac or Windows breaks
356 //if (Text[i+1] == L'\n') // Windows breaks
363 else if (c
== L
'\n') // Unix breaks
369 bool isWhitespace
= (c
== L
' ' || c
== 0);
374 word
.addChar(cText
, i
);
377 if ( isWhitespace
|| i
== (size
-1))
381 // here comes the next whitespace, look if
382 // we must break the last word to the next line.
383 const s32 whitelgth
= font
->getDimension(whitespace
.c_str()).Width
;
384 //const std::wstring sanitized = removeEscapes(word.c_str());
385 const s32 wordlgth
= font
->getDimension(word
.c_str()).Width
;
387 if (wordlgth
> elWidth
)
389 // This word is too long to fit in the available space, look for
390 // the Unicode Soft HYphen (SHY / 00AD) character for a place to
392 int where
= core::stringw(word
.c_str()).findFirst( wchar_t(0x00AD) );
395 EnrichedString first
= word
.substr(0, where
);
396 EnrichedString second
= word
.substr(where
, word
.size() - where
);
397 first
.addCharNoColor(L
'-');
398 BrokenText
.push_back(line
+ first
);
399 const s32 secondLength
= font
->getDimension(second
.c_str()).Width
;
401 length
= secondLength
;
406 // No soft hyphen found, so there's nothing more we can do
407 // break to next line
409 BrokenText
.push_back(line
);
414 else if (length
&& (length
+ wordlgth
+ whitelgth
> elWidth
))
416 // break to next line
417 BrokenText
.push_back(line
);
426 length
+= whitelgth
+ wordlgth
;
433 if ( isWhitespace
&& c
!= 0)
435 whitespace
.addChar(cText
, i
);
438 // compute line break
443 BrokenText
.push_back(line
);
454 BrokenText
.push_back(line
);
459 for (s32 i
=size
; i
>=0; --i
)
461 c
= cText
.getString()[i
];
462 bool lineBreak
= false;
464 if (c
== L
'\r') // Mac or Windows breaks
467 //if ((i>0) && Text[i-1] == L'\n') // Windows breaks
474 else if (c
== L
'\n') // Unix breaks
480 if (c
==L
' ' || c
==0 || i
==0)
484 // here comes the next whitespace, look if
485 // we must break the last word to the next line.
486 const s32 whitelgth
= font
->getDimension(whitespace
.c_str()).Width
;
487 const s32 wordlgth
= font
->getDimension(word
.c_str()).Width
;
489 if (length
&& (length
+ wordlgth
+ whitelgth
> elWidth
))
491 // break to next line
492 BrokenText
.push_back(line
);
499 line
= whitespace
+ line
;
501 length
+= whitelgth
+ wordlgth
;
509 // whitespace = core::stringw(&c, 1) + whitespace;
510 whitespace
= cText
.substr(i
, 1) + whitespace
;
512 // compute line break
515 line
= whitespace
+ line
;
517 BrokenText
.push_back(line
);
526 // yippee this is a word..
527 //word = core::stringw(&c, 1) + word;
528 word
= cText
.substr(i
, 1) + word
;
532 line
= whitespace
+ line
;
534 BrokenText
.push_back(line
);
539 //! Sets the new caption of this element.
540 void StaticText::setText(const wchar_t* text
)
542 setText(EnrichedString(text
, getOverrideColor()));
545 void StaticText::setText(const EnrichedString
&text
)
548 IGUIElement::setText(ColoredText
.c_str());
552 void StaticText::updateAbsolutePosition()
554 IGUIElement::updateAbsolutePosition();
559 //! Returns the height of the text in pixels when it is drawn.
560 s32
StaticText::getTextHeight() const
562 IGUIFont
* font
= getActiveFont();
567 s32 height
= font
->getDimension(L
"A").Height
+ font
->getKerningHeight();
568 return height
* BrokenText
.size();
570 // There may be intentional new lines without WordWrap
571 return font
->getDimension(BrokenText
[0].c_str()).Height
;
575 s32
StaticText::getTextWidth() const
577 IGUIFont
*font
= getActiveFont();
583 for (const EnrichedString
&line
: BrokenText
) {
584 s32 width
= font
->getDimension(line
.c_str()).Width
;
594 //! Writes attributes of the element.
595 //! Implement this to expose the attributes of your element for
596 //! scripting languages, editors, debuggers or xml serialization purposes.
597 void StaticText::serializeAttributes(io::IAttributes
* out
, io::SAttributeReadWriteOptions
* options
=0) const
599 IGUIStaticText::serializeAttributes(out
,options
);
601 out
->addBool ("Border", Border
);
602 out
->addBool ("OverrideColorEnabled",true);
603 out
->addBool ("OverrideBGColorEnabled",ColoredText
.hasBackground());
604 out
->addBool ("WordWrap", WordWrap
);
605 out
->addBool ("Background", Background
);
606 out
->addBool ("RightToLeft", RightToLeft
);
607 out
->addBool ("RestrainTextInside", RestrainTextInside
);
608 out
->addColor ("OverrideColor", ColoredText
.getDefaultColor());
609 out
->addColor ("BGColor", ColoredText
.getBackground());
610 out
->addEnum ("HTextAlign", HAlign
, GUIAlignmentNames
);
611 out
->addEnum ("VTextAlign", VAlign
, GUIAlignmentNames
);
613 // out->addFont ("OverrideFont", OverrideFont);
617 //! Reads attributes of the element
618 void StaticText::deserializeAttributes(io::IAttributes
* in
, io::SAttributeReadWriteOptions
* options
=0)
620 IGUIStaticText::deserializeAttributes(in
,options
);
622 Border
= in
->getAttributeAsBool("Border");
623 setWordWrap(in
->getAttributeAsBool("WordWrap"));
624 Background
= in
->getAttributeAsBool("Background");
625 RightToLeft
= in
->getAttributeAsBool("RightToLeft");
626 RestrainTextInside
= in
->getAttributeAsBool("RestrainTextInside");
627 if (in
->getAttributeAsBool("OverrideColorEnabled"))
628 ColoredText
.setDefaultColor(in
->getAttributeAsColor("OverrideColor"));
629 if (in
->getAttributeAsBool("OverrideBGColorEnabled"))
630 ColoredText
.setBackground(in
->getAttributeAsColor("BGColor"));
632 setTextAlignment( (EGUI_ALIGNMENT
) in
->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames
),
633 (EGUI_ALIGNMENT
) in
->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames
));
635 // OverrideFont = in->getAttributeAsFont("OverrideFont");
638 } // end namespace gui
640 #endif // USE_FREETYPE
642 } // end namespace irr
645 #endif // _IRR_COMPILE_WITH_GUI_