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