]> git.lizzy.rs Git - dragonfireclient.git/blob - src/irrlicht_changes/static_text.cpp
Drop .NET-specific workaround: _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX
[dragonfireclient.git] / src / irrlicht_changes / static_text.cpp
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
6
7 #include "static_text.h"
8 #ifdef _IRR_COMPILE_WITH_GUI_
9
10 #include <IGUIFont.h>
11 #include <IVideoDriver.h>
12 #include <rect.h>
13 #include <SColor.h>
14
15 #if USE_FREETYPE
16         #include "CGUITTFont.h"
17 #endif
18
19 #include "util/string.h"
20
21 namespace irr
22 {
23
24 #if USE_FREETYPE
25
26 namespace gui
27 {
28 //! constructor
29 StaticText::StaticText(const EnrichedString &text, bool border,
30                         IGUIEnvironment* environment, IGUIElement* parent,
31                         s32 id, const core::rect<s32>& rectangle,
32                         bool background)
33 : IGUIStaticText(environment, parent, id, rectangle),
34         HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_UPPERLEFT),
35         Border(border), OverrideColorEnabled(false), OverrideBGColorEnabled(false), WordWrap(false), Background(background),
36         RestrainTextInside(true), RightToLeft(false),
37         OverrideColor(video::SColor(101,255,255,255)), BGColor(video::SColor(101,210,210,210)),
38         OverrideFont(0), LastBreakFont(0)
39 {
40         #ifdef _DEBUG
41         setDebugName("StaticText");
42         #endif
43
44         Text = text.c_str();
45         cText = text;
46         if (environment && environment->getSkin())
47         {
48                 BGColor = environment->getSkin()->getColor(gui::EGDC_3D_FACE);
49         }
50 }
51
52
53 //! destructor
54 StaticText::~StaticText()
55 {
56         if (OverrideFont)
57                 OverrideFont->drop();
58 }
59
60 //! draws the element and its children
61 void StaticText::draw()
62 {
63         if (!IsVisible)
64                 return;
65
66         IGUISkin* skin = Environment->getSkin();
67         if (!skin)
68                 return;
69         video::IVideoDriver* driver = Environment->getVideoDriver();
70
71         core::rect<s32> frameRect(AbsoluteRect);
72
73         // draw background
74
75         if (Background)
76         {
77                 if ( !OverrideBGColorEnabled )  // skin-colors can change
78                         BGColor = skin->getColor(gui::EGDC_3D_FACE);
79
80                 driver->draw2DRectangle(BGColor, frameRect, &AbsoluteClippingRect);
81         }
82
83         // draw the border
84
85         if (Border)
86         {
87                 skin->draw3DSunkenPane(this, 0, true, false, frameRect, &AbsoluteClippingRect);
88                 frameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X);
89         }
90
91         // draw the text
92         if (cText.size())
93         {
94                 IGUIFont* font = getActiveFont();
95
96                 if (font)
97                 {
98                         if (!WordWrap)
99                         {
100                                 // TODO: add colors here
101                                 if (VAlign == EGUIA_LOWERRIGHT)
102                                 {
103                                         frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y -
104                                                 font->getDimension(L"A").Height - font->getKerningHeight();
105                                 }
106                                 if (HAlign == EGUIA_LOWERRIGHT)
107                                 {
108                                         frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
109                                                 font->getDimension(cText.c_str()).Width;
110                                 }
111
112                                 irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(font);
113                                 tmp->draw(cText, frameRect,
114                                         OverrideColorEnabled ? OverrideColor : skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT),
115                                         HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER, (RestrainTextInside ? &AbsoluteClippingRect : NULL));
116                         }
117                         else
118                         {
119                                 if (font != LastBreakFont)
120                                         breakText();
121
122                                 core::rect<s32> r = frameRect;
123                                 s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
124                                 s32 totalHeight = height * BrokenText.size();
125                                 if (VAlign == EGUIA_CENTER)
126                                 {
127                                         r.UpperLeftCorner.Y = r.getCenter().Y - (totalHeight / 2);
128                                 }
129                                 else if (VAlign == EGUIA_LOWERRIGHT)
130                                 {
131                                         r.UpperLeftCorner.Y = r.LowerRightCorner.Y - totalHeight;
132                                 }
133
134                                 irr::video::SColor previous_color(255, 255, 255, 255);
135                                 for (u32 i=0; i<BrokenText.size(); ++i)
136                                 {
137                                         if (HAlign == EGUIA_LOWERRIGHT)
138                                         {
139                                                 r.UpperLeftCorner.X = frameRect.LowerRightCorner.X -
140                                                         font->getDimension(BrokenText[i].c_str()).Width;
141                                         }
142
143                                         //std::vector<irr::video::SColor> colors;
144                                         //std::wstring str;
145                                         EnrichedString str = BrokenText[i];
146
147                                         //str = colorizeText(BrokenText[i].c_str(), colors, previous_color);
148                                         //if (!colors.empty())
149                                         //      previous_color = colors[colors.size() - 1];
150
151                                         irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(font);
152                                         tmp->draw(str, r,
153                                                 previous_color, // FIXME
154                                                 HAlign == EGUIA_CENTER, false, (RestrainTextInside ? &AbsoluteClippingRect : NULL));
155
156                                         r.LowerRightCorner.Y += height;
157                                         r.UpperLeftCorner.Y += height;
158                                 }
159                         }
160                 }
161         }
162
163         IGUIElement::draw();
164 }
165
166
167 //! Sets another skin independent font.
168 void StaticText::setOverrideFont(IGUIFont* font)
169 {
170         if (OverrideFont == font)
171                 return;
172
173         if (OverrideFont)
174                 OverrideFont->drop();
175
176         OverrideFont = font;
177
178         if (OverrideFont)
179                 OverrideFont->grab();
180
181         breakText();
182 }
183
184 //! Gets the override font (if any)
185 IGUIFont * StaticText::getOverrideFont() const
186 {
187         return OverrideFont;
188 }
189
190 //! Get the font which is used right now for drawing
191 IGUIFont* StaticText::getActiveFont() const
192 {
193         if ( OverrideFont )
194                 return OverrideFont;
195         IGUISkin* skin = Environment->getSkin();
196         if (skin)
197                 return skin->getFont();
198         return 0;
199 }
200
201 //! Sets another color for the text.
202 void StaticText::setOverrideColor(video::SColor color)
203 {
204         OverrideColor = color;
205         OverrideColorEnabled = true;
206 }
207
208
209 //! Sets another color for the text.
210 void StaticText::setBackgroundColor(video::SColor color)
211 {
212         BGColor = color;
213         OverrideBGColorEnabled = true;
214         Background = true;
215 }
216
217
218 //! Sets whether to draw the background
219 void StaticText::setDrawBackground(bool draw)
220 {
221         Background = draw;
222 }
223
224
225 //! Gets the background color
226 video::SColor StaticText::getBackgroundColor() const
227 {
228         return BGColor;
229 }
230
231
232 //! Checks if background drawing is enabled
233 bool StaticText::isDrawBackgroundEnabled() const
234 {
235         return Background;
236 }
237
238
239 //! Sets whether to draw the border
240 void StaticText::setDrawBorder(bool draw)
241 {
242         Border = draw;
243 }
244
245
246 //! Checks if border drawing is enabled
247 bool StaticText::isDrawBorderEnabled() const
248 {
249         return Border;
250 }
251
252
253 void StaticText::setTextRestrainedInside(bool restrainTextInside)
254 {
255         RestrainTextInside = restrainTextInside;
256 }
257
258
259 bool StaticText::isTextRestrainedInside() const
260 {
261         return RestrainTextInside;
262 }
263
264
265 void StaticText::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
266 {
267         HAlign = horizontal;
268         VAlign = vertical;
269 }
270
271
272 #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
273 const video::SColor& StaticText::getOverrideColor() const
274 #else
275 video::SColor StaticText::getOverrideColor() const
276 #endif
277 {
278         return OverrideColor;
279 }
280
281
282 //! Sets if the static text should use the overide color or the
283 //! color in the gui skin.
284 void StaticText::enableOverrideColor(bool enable)
285 {
286         OverrideColorEnabled = enable;
287 }
288
289
290 bool StaticText::isOverrideColorEnabled() const
291 {
292         return OverrideColorEnabled;
293 }
294
295
296 //! Enables or disables word wrap for using the static text as
297 //! multiline text control.
298 void StaticText::setWordWrap(bool enable)
299 {
300         WordWrap = enable;
301         breakText();
302 }
303
304
305 bool StaticText::isWordWrapEnabled() const
306 {
307         return WordWrap;
308 }
309
310
311 void StaticText::setRightToLeft(bool rtl)
312 {
313         if (RightToLeft != rtl)
314         {
315                 RightToLeft = rtl;
316                 breakText();
317         }
318 }
319
320
321 bool StaticText::isRightToLeft() const
322 {
323         return RightToLeft;
324 }
325
326
327 //! Breaks the single text line.
328 void StaticText::breakText()
329 {
330         if (!WordWrap)
331                 return;
332
333         BrokenText.clear();
334
335         IGUISkin* skin = Environment->getSkin();
336         IGUIFont* font = getActiveFont();
337         if (!font)
338                 return;
339
340         LastBreakFont = font;
341
342         EnrichedString line;
343         EnrichedString word;
344         EnrichedString whitespace;
345         s32 size = cText.size();
346         s32 length = 0;
347         s32 elWidth = RelativeRect.getWidth();
348         if (Border)
349                 elWidth -= 2*skin->getSize(EGDS_TEXT_DISTANCE_X);
350         wchar_t c;
351
352         //std::vector<irr::video::SColor> colors;
353
354         // We have to deal with right-to-left and left-to-right differently
355         // However, most parts of the following code is the same, it's just
356         // some order and boundaries which change.
357         if (!RightToLeft)
358         {
359                 // regular (left-to-right)
360                 for (s32 i=0; i<size; ++i)
361                 {
362                         c = cText.getString()[i];
363                         bool lineBreak = false;
364
365                         if (c == L'\r') // Mac or Windows breaks
366                         {
367                                 lineBreak = true;
368                                 //if (Text[i+1] == L'\n') // Windows breaks
369                                 //{
370                                 //      Text.erase(i+1);
371                                 //      --size;
372                                 //}
373                                 c = '\0';
374                         }
375                         else if (c == L'\n') // Unix breaks
376                         {
377                                 lineBreak = true;
378                                 c = '\0';
379                         }
380
381                         bool isWhitespace = (c == L' ' || c == 0);
382                         if ( !isWhitespace )
383                         {
384                                 // part of a word
385                                 //word += c;
386                                 word.addChar(cText, i);
387                         }
388
389                         if ( isWhitespace || i == (size-1))
390                         {
391                                 if (word.size())
392                                 {
393                                         // here comes the next whitespace, look if
394                                         // we must break the last word to the next line.
395                                         const s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
396                                         //const std::wstring sanitized = removeEscapes(word.c_str());
397                                         const s32 wordlgth = font->getDimension(word.c_str()).Width;
398
399                                         if (wordlgth > elWidth)
400                                         {
401                                                 // This word is too long to fit in the available space, look for
402                                                 // the Unicode Soft HYphen (SHY / 00AD) character for a place to
403                                                 // break the word at
404                                                 int where = core::stringw(word.c_str()).findFirst( wchar_t(0x00AD) );
405                                                 if (where != -1)
406                                                 {
407                                                         EnrichedString first = word.substr(0, where);
408                                                         EnrichedString second = word.substr(where, word.size() - where);
409                                                         first.addCharNoColor(L'-');
410                                                         BrokenText.push_back(line + first);
411                                                         const s32 secondLength = font->getDimension(second.c_str()).Width;
412
413                                                         length = secondLength;
414                                                         line = second;
415                                                 }
416                                                 else
417                                                 {
418                                                         // No soft hyphen found, so there's nothing more we can do
419                                                         // break to next line
420                                                         if (length)
421                                                                 BrokenText.push_back(line);
422                                                         length = wordlgth;
423                                                         line = word;
424                                                 }
425                                         }
426                                         else if (length && (length + wordlgth + whitelgth > elWidth))
427                                         {
428                                                 // break to next line
429                                                 BrokenText.push_back(line);
430                                                 length = wordlgth;
431                                                 line = word;
432                                         }
433                                         else
434                                         {
435                                                 // add word to line
436                                                 line += whitespace;
437                                                 line += word;
438                                                 length += whitelgth + wordlgth;
439                                         }
440
441                                         word.clear();
442                                         whitespace.clear();
443                                 }
444
445                                 if ( isWhitespace && c != 0)
446                                 {
447                                         whitespace.addChar(cText, i);
448                                 }
449
450                                 // compute line break
451                                 if (lineBreak)
452                                 {
453                                         line += whitespace;
454                                         line += word;
455                                         BrokenText.push_back(line);
456                                         line.clear();
457                                         word.clear();
458                                         whitespace.clear();
459                                         length = 0;
460                                 }
461                         }
462                 }
463
464                 line += whitespace;
465                 line += word;
466                 BrokenText.push_back(line);
467         }
468         else
469         {
470                 // right-to-left
471                 for (s32 i=size; i>=0; --i)
472                 {
473                         c = cText.getString()[i];
474                         bool lineBreak = false;
475
476                         if (c == L'\r') // Mac or Windows breaks
477                         {
478                                 lineBreak = true;
479                                 //if ((i>0) && Text[i-1] == L'\n') // Windows breaks
480                                 //{
481                                 //      Text.erase(i-1);
482                                 //      --size;
483                                 //}
484                                 c = '\0';
485                         }
486                         else if (c == L'\n') // Unix breaks
487                         {
488                                 lineBreak = true;
489                                 c = '\0';
490                         }
491
492                         if (c==L' ' || c==0 || i==0)
493                         {
494                                 if (word.size())
495                                 {
496                                         // here comes the next whitespace, look if
497                                         // we must break the last word to the next line.
498                                         const s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
499                                         const s32 wordlgth = font->getDimension(word.c_str()).Width;
500
501                                         if (length && (length + wordlgth + whitelgth > elWidth))
502                                         {
503                                                 // break to next line
504                                                 BrokenText.push_back(line);
505                                                 length = wordlgth;
506                                                 line = word;
507                                         }
508                                         else
509                                         {
510                                                 // add word to line
511                                                 line = whitespace + line;
512                                                 line = word + line;
513                                                 length += whitelgth + wordlgth;
514                                         }
515
516                                         word.clear();
517                                         whitespace.clear();
518                                 }
519
520                                 if (c != 0)
521                                 //      whitespace = core::stringw(&c, 1) + whitespace;
522                                 whitespace = cText.substr(i, 1) + whitespace;
523
524                                 // compute line break
525                                 if (lineBreak)
526                                 {
527                                         line = whitespace + line;
528                                         line = word + line;
529                                         BrokenText.push_back(line);
530                                         line.clear();
531                                         word.clear();
532                                         whitespace.clear();
533                                         length = 0;
534                                 }
535                         }
536                         else
537                         {
538                                 // yippee this is a word..
539                                 //word = core::stringw(&c, 1) + word;
540                                 word = cText.substr(i, 1) + word;
541                         }
542                 }
543
544                 line = whitespace + line;
545                 line = word + line;
546                 BrokenText.push_back(line);
547         }
548 }
549
550
551 //! Sets the new caption of this element.
552 void StaticText::setText(const wchar_t* text)
553 {
554         setText(EnrichedString(text));
555 }
556
557 //! Sets the new caption of this element.
558 void StaticText::setText(const EnrichedString &text)
559 {
560         IGUIElement::setText(text.c_str());
561         cText = text;
562         if (text.hasBackground()) {
563                 setBackgroundColor(text.getBackground());
564         }
565         breakText();
566 }
567
568
569 void StaticText::updateAbsolutePosition()
570 {
571         IGUIElement::updateAbsolutePosition();
572         breakText();
573 }
574
575
576 //! Returns the height of the text in pixels when it is drawn.
577 s32 StaticText::getTextHeight() const
578 {
579         IGUIFont* font = getActiveFont();
580         if (!font)
581                 return 0;
582
583         s32 height = font->getDimension(L"A").Height + font->getKerningHeight();
584
585         if (WordWrap)
586                 height *= BrokenText.size();
587
588         return height;
589 }
590
591
592 s32 StaticText::getTextWidth() const
593 {
594         IGUIFont * font = getActiveFont();
595         if(!font)
596                 return 0;
597
598         if(WordWrap)
599         {
600                 s32 widest = 0;
601
602                 for(u32 line = 0; line < BrokenText.size(); ++line)
603                 {
604                         s32 width = font->getDimension(BrokenText[line].c_str()).Width;
605
606                         if(width > widest)
607                                 widest = width;
608                 }
609
610                 return widest;
611         }
612         else
613         {
614                 return font->getDimension(cText.c_str()).Width;
615         }
616 }
617
618
619 //! Writes attributes of the element.
620 //! Implement this to expose the attributes of your element for
621 //! scripting languages, editors, debuggers or xml serialization purposes.
622 void StaticText::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
623 {
624         IGUIStaticText::serializeAttributes(out,options);
625
626         out->addBool    ("Border",              Border);
627         out->addBool    ("OverrideColorEnabled",OverrideColorEnabled);
628         out->addBool    ("OverrideBGColorEnabled",OverrideBGColorEnabled);
629         out->addBool    ("WordWrap",            WordWrap);
630         out->addBool    ("Background",          Background);
631         out->addBool    ("RightToLeft",         RightToLeft);
632         out->addBool    ("RestrainTextInside",  RestrainTextInside);
633         out->addColor   ("OverrideColor",       OverrideColor);
634         out->addColor   ("BGColor",             BGColor);
635         out->addEnum    ("HTextAlign",          HAlign, GUIAlignmentNames);
636         out->addEnum    ("VTextAlign",          VAlign, GUIAlignmentNames);
637
638         // out->addFont ("OverrideFont",        OverrideFont);
639 }
640
641
642 //! Reads attributes of the element
643 void StaticText::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
644 {
645         IGUIStaticText::deserializeAttributes(in,options);
646
647         Border = in->getAttributeAsBool("Border");
648         enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled"));
649         OverrideBGColorEnabled = in->getAttributeAsBool("OverrideBGColorEnabled");
650         setWordWrap(in->getAttributeAsBool("WordWrap"));
651         Background = in->getAttributeAsBool("Background");
652         RightToLeft = in->getAttributeAsBool("RightToLeft");
653         RestrainTextInside = in->getAttributeAsBool("RestrainTextInside");
654         OverrideColor = in->getAttributeAsColor("OverrideColor");
655         BGColor = in->getAttributeAsColor("BGColor");
656
657         setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
658                       (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
659
660         // OverrideFont = in->getAttributeAsFont("OverrideFont");
661 }
662
663 } // end namespace gui
664
665 #endif // USE_FREETYPE
666
667 } // end namespace irr
668
669
670 #endif // _IRR_COMPILE_WITH_GUI_