]> git.lizzy.rs Git - minetest.git/blob - src/intlGUIEditBox.cpp
Isolate irrlicht references and use a singleton (#6041)
[minetest.git] / src / intlGUIEditBox.cpp
1 // 11.11.2011 11:11 ValkaTR
2 //
3 // This is a copy of intlGUIEditBox from the irrlicht, but with a
4 // fix in the OnEvent function, which doesn't allowed input of
5 // other keyboard layouts than latin-1
6 //
7 // Characters like: ä ö ü õ ы й ю я ъ № € ° ...
8 //
9 // This fix is only needed for linux, because of a bug
10 // in the CIrrDeviceLinux.cpp:1014-1015 of the irrlicht
11 //
12 // Also locale in the programm should not be changed to
13 // a "C", "POSIX" or whatever, it should be set to "",
14 // or XLookupString will return nothing for the international
15 // characters.
16 //
17 // From the "man setlocale":
18 //
19 // On startup of the main program, the portable "C" locale
20 // is selected as default.  A  program  may  be  made
21 // portable to all locales by calling:
22 //
23 //           setlocale(LC_ALL, "");
24 //
25 //       after  program initialization....
26 //
27
28 // Copyright (C) 2002-2013 Nikolaus Gebhardt
29 // This file is part of the "Irrlicht Engine".
30 // For conditions of distribution and use, see copyright notice in irrlicht.h
31
32 #include <util/numeric.h>
33 #include "intlGUIEditBox.h"
34
35 #if defined(_IRR_COMPILE_WITH_GUI_) && IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9
36
37 #include "IGUISkin.h"
38 #include "IGUIEnvironment.h"
39 #include "IGUIFont.h"
40 #include "IVideoDriver.h"
41 //#include "rect.h"
42 //#include "irrlicht/os.cpp"
43 #include "porting.h"
44 //#include "Keycodes.h"
45 #include "log.h"
46
47 /*
48         todo:
49         optional scrollbars
50         ctrl+left/right to select word
51         double click/ctrl click: word select + drag to select whole words, triple click to select line
52         optional? dragging selected text
53         numerical
54 */
55
56 namespace irr
57 {
58 namespace gui
59 {
60
61 //! constructor
62 intlGUIEditBox::intlGUIEditBox(const wchar_t* text, bool border,
63                 IGUIEnvironment* environment, IGUIElement* parent, s32 id,
64                 const core::rect<s32>& rectangle)
65         : IGUIEditBox(environment, parent, id, rectangle),
66         Border(border),
67         FrameRect(rectangle)
68 {
69         #ifdef _DEBUG
70         setDebugName("intlintlGUIEditBox");
71         #endif
72
73         Text = text;
74
75         if (Environment)
76                 Operator = Environment->getOSOperator();
77
78         if (Operator)
79                 Operator->grab();
80
81         // this element can be tabbed to
82         setTabStop(true);
83         setTabOrder(-1);
84
85         IGUISkin *skin = 0;
86         if (Environment)
87                 skin = Environment->getSkin();
88         if (Border && skin)
89         {
90                 FrameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
91                 FrameRect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
92                 FrameRect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
93                 FrameRect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
94         }
95
96         breakText();
97
98         calculateScrollPos();
99 }
100
101
102 //! destructor
103 intlGUIEditBox::~intlGUIEditBox()
104 {
105         if (OverrideFont)
106                 OverrideFont->drop();
107
108         if (Operator)
109                 Operator->drop();
110 }
111
112
113 //! Sets another skin independent font.
114 void intlGUIEditBox::setOverrideFont(IGUIFont* font)
115 {
116         if (OverrideFont == font)
117                 return;
118
119         if (OverrideFont)
120                 OverrideFont->drop();
121
122         OverrideFont = font;
123
124         if (OverrideFont)
125                 OverrideFont->grab();
126
127         breakText();
128 }
129
130 IGUIFont * intlGUIEditBox::getOverrideFont() const
131 {
132         return OverrideFont;
133 }
134
135 //! Get the font which is used right now for drawing
136 IGUIFont* intlGUIEditBox::getActiveFont() const
137 {
138         if ( OverrideFont )
139                 return OverrideFont;
140         IGUISkin* skin = Environment->getSkin();
141         if (skin)
142                 return skin->getFont();
143         return 0;
144 }
145
146 //! Sets another color for the text.
147 void intlGUIEditBox::setOverrideColor(video::SColor color)
148 {
149         OverrideColor = color;
150         OverrideColorEnabled = true;
151 }
152
153 video::SColor intlGUIEditBox::getOverrideColor() const
154 {
155         return OverrideColor;
156 }
157
158 //! Turns the border on or off
159 void intlGUIEditBox::setDrawBorder(bool border)
160 {
161         Border = border;
162 }
163
164 //! Sets whether to draw the background
165 void intlGUIEditBox::setDrawBackground(bool draw)
166 {
167 }
168
169 //! Sets if the text should use the overide color or the color in the gui skin.
170 void intlGUIEditBox::enableOverrideColor(bool enable)
171 {
172         OverrideColorEnabled = enable;
173 }
174
175 bool intlGUIEditBox::isOverrideColorEnabled() const
176 {
177         _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
178         return OverrideColorEnabled;
179 }
180
181 //! Enables or disables word wrap
182 void intlGUIEditBox::setWordWrap(bool enable)
183 {
184         WordWrap = enable;
185         breakText();
186 }
187
188
189 void intlGUIEditBox::updateAbsolutePosition()
190 {
191     core::rect<s32> oldAbsoluteRect(AbsoluteRect);
192         IGUIElement::updateAbsolutePosition();
193         if ( oldAbsoluteRect != AbsoluteRect )
194         {
195         breakText();
196         }
197 }
198
199
200 //! Checks if word wrap is enabled
201 bool intlGUIEditBox::isWordWrapEnabled() const
202 {
203         _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
204         return WordWrap;
205 }
206
207
208 //! Enables or disables newlines.
209 void intlGUIEditBox::setMultiLine(bool enable)
210 {
211         MultiLine = enable;
212 }
213
214
215 //! Checks if multi line editing is enabled
216 bool intlGUIEditBox::isMultiLineEnabled() const
217 {
218         _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
219         return MultiLine;
220 }
221
222
223 void intlGUIEditBox::setPasswordBox(bool passwordBox, wchar_t passwordChar)
224 {
225         PasswordBox = passwordBox;
226         if (PasswordBox)
227         {
228                 PasswordChar = passwordChar;
229                 setMultiLine(false);
230                 setWordWrap(false);
231                 BrokenText.clear();
232         }
233 }
234
235
236 bool intlGUIEditBox::isPasswordBox() const
237 {
238         _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
239         return PasswordBox;
240 }
241
242
243 //! Sets text justification
244 void intlGUIEditBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
245 {
246         HAlign = horizontal;
247         VAlign = vertical;
248 }
249
250
251 //! called if an event happened.
252 bool intlGUIEditBox::OnEvent(const SEvent& event)
253 {
254         if (IsEnabled)
255         {
256
257                 switch(event.EventType)
258                 {
259                 case EET_GUI_EVENT:
260                         if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
261                         {
262                                 if (event.GUIEvent.Caller == this)
263                                 {
264                                         MouseMarking = false;
265                                         setTextMarkers(0,0);
266                                 }
267                         }
268                         break;
269                 case EET_KEY_INPUT_EVENT:
270         {
271 #if (defined(__linux__) || defined(__FreeBSD__))
272             // ################################################################
273                         // ValkaTR:
274             // This part is the difference from the original intlGUIEditBox
275             // It converts UTF-8 character into a UCS-2 (wchar_t)
276             wchar_t wc = L'_';
277             mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) );
278
279             //printf( "char: %lc (%u)  \r\n", wc, wc );
280
281             SEvent irrevent(event);
282             irrevent.KeyInput.Char = wc;
283             // ################################################################
284
285                         if (processKey(irrevent))
286                                 return true;
287 #else
288                         if (processKey(event))
289                                 return true;
290 #endif // defined(linux)
291
292                         break;
293         }
294                 case EET_MOUSE_INPUT_EVENT:
295                         if (processMouse(event))
296                                 return true;
297                         break;
298                 default:
299                         break;
300                 }
301         }
302
303         return IGUIElement::OnEvent(event);
304 }
305
306
307 bool intlGUIEditBox::processKey(const SEvent& event)
308 {
309         if (!event.KeyInput.PressedDown)
310                 return false;
311
312         bool textChanged = false;
313         s32 newMarkBegin = MarkBegin;
314         s32 newMarkEnd = MarkEnd;
315
316         // control shortcut handling
317
318         if (event.KeyInput.Control)
319         {
320                 // german backlash '\' entered with control + '?'
321                 if ( event.KeyInput.Char == '\\' )
322                 {
323                         inputChar(event.KeyInput.Char);
324                         return true;
325                 }
326
327                 switch(event.KeyInput.Key)
328                 {
329                 case KEY_KEY_A:
330                         // select all
331                         newMarkBegin = 0;
332                         newMarkEnd = Text.size();
333                         break;
334                 case KEY_KEY_C:
335                         // copy to clipboard
336                         if (!PasswordBox && Operator && MarkBegin != MarkEnd)
337                         {
338                                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
339                                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
340
341                                 core::stringc s;
342                                 s = Text.subString(realmbgn, realmend - realmbgn).c_str();
343                                 Operator->copyToClipboard(s.c_str());
344                         }
345                         break;
346                 case KEY_KEY_X:
347                         // cut to the clipboard
348                         if (!PasswordBox && Operator && MarkBegin != MarkEnd)
349                         {
350                                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
351                                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
352
353                                 // copy
354                                 core::stringc sc;
355                                 sc = Text.subString(realmbgn, realmend - realmbgn).c_str();
356                                 Operator->copyToClipboard(sc.c_str());
357
358                                 if (IsEnabled)
359                                 {
360                                         // delete
361                                         core::stringw s;
362                                         s = Text.subString(0, realmbgn);
363                                         s.append( Text.subString(realmend, Text.size()-realmend) );
364                                         Text = s;
365
366                                         CursorPos = realmbgn;
367                                         newMarkBegin = 0;
368                                         newMarkEnd = 0;
369                                         textChanged = true;
370                                 }
371                         }
372                         break;
373                 case KEY_KEY_V:
374                         if ( !IsEnabled )
375                                 break;
376
377                         // paste from the clipboard
378                         if (Operator)
379                         {
380                                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
381                                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
382
383                                 // add new character
384                                 const c8* p = Operator->getTextFromClipboard();
385                                 if (p)
386                                 {
387                                         if (MarkBegin == MarkEnd)
388                                         {
389                                                 // insert text
390                                                 core::stringw s = Text.subString(0, CursorPos);
391                                                 s.append(p);
392                                                 s.append( Text.subString(CursorPos, Text.size()-CursorPos) );
393
394                                                 if (!Max || s.size()<=Max) // thx to Fish FH for fix
395                                                 {
396                                                         Text = s;
397                                                         s = p;
398                                                         CursorPos += s.size();
399                                                 }
400                                         }
401                                         else
402                                         {
403                                                 // replace text
404
405                                                 core::stringw s = Text.subString(0, realmbgn);
406                                                 s.append(p);
407                                                 s.append( Text.subString(realmend, Text.size()-realmend) );
408
409                                                 if (!Max || s.size()<=Max)  // thx to Fish FH for fix
410                                                 {
411                                                         Text = s;
412                                                         s = p;
413                                                         CursorPos = realmbgn + s.size();
414                                                 }
415                                         }
416                                 }
417
418                                 newMarkBegin = 0;
419                                 newMarkEnd = 0;
420                                 textChanged = true;
421                         }
422                         break;
423                 case KEY_HOME:
424                         // move/highlight to start of text
425                         if (event.KeyInput.Shift)
426                         {
427                                 newMarkEnd = CursorPos;
428                                 newMarkBegin = 0;
429                                 CursorPos = 0;
430                         }
431                         else
432                         {
433                                 CursorPos = 0;
434                                 newMarkBegin = 0;
435                                 newMarkEnd = 0;
436                         }
437                         break;
438                 case KEY_END:
439                         // move/highlight to end of text
440                         if (event.KeyInput.Shift)
441                         {
442                                 newMarkBegin = CursorPos;
443                                 newMarkEnd = Text.size();
444                                 CursorPos = 0;
445                         }
446                         else
447                         {
448                                 CursorPos = Text.size();
449                                 newMarkBegin = 0;
450                                 newMarkEnd = 0;
451                         }
452                         break;
453                 default:
454                         return false;
455                 }
456         }
457         // default keyboard handling
458         else
459         switch(event.KeyInput.Key)
460         {
461         case KEY_END:
462                 {
463                         s32 p = Text.size();
464                         if (WordWrap || MultiLine)
465                         {
466                                 p = getLineFromPos(CursorPos);
467                                 p = BrokenTextPositions[p] + (s32)BrokenText[p].size();
468                                 if (p > 0 && (Text[p-1] == L'\r' || Text[p-1] == L'\n' ))
469                                         p-=1;
470                         }
471
472                         if (event.KeyInput.Shift)
473                         {
474                                 if (MarkBegin == MarkEnd)
475                                         newMarkBegin = CursorPos;
476
477                                 newMarkEnd = p;
478                         }
479                         else
480                         {
481                                 newMarkBegin = 0;
482                                 newMarkEnd = 0;
483                         }
484                         CursorPos = p;
485                         BlinkStartTime = porting::getTimeMs();
486                 }
487                 break;
488         case KEY_HOME:
489                 {
490
491                         s32 p = 0;
492                         if (WordWrap || MultiLine)
493                         {
494                                 p = getLineFromPos(CursorPos);
495                                 p = BrokenTextPositions[p];
496                         }
497
498                         if (event.KeyInput.Shift)
499                         {
500                                 if (MarkBegin == MarkEnd)
501                                         newMarkBegin = CursorPos;
502                                 newMarkEnd = p;
503                         }
504                         else
505                         {
506                                 newMarkBegin = 0;
507                                 newMarkEnd = 0;
508                         }
509                         CursorPos = p;
510                         BlinkStartTime = porting::getTimeMs();
511                 }
512                 break;
513         case KEY_RETURN:
514                 if (MultiLine)
515                 {
516                         inputChar(L'\n');
517                         return true;
518                 }
519                 else
520                 {
521                     sendGuiEvent( EGET_EDITBOX_ENTER );
522                 }
523                 break;
524         case KEY_LEFT:
525
526                 if (event.KeyInput.Shift)
527                 {
528                         if (CursorPos > 0)
529                         {
530                                 if (MarkBegin == MarkEnd)
531                                         newMarkBegin = CursorPos;
532
533                                 newMarkEnd = CursorPos-1;
534                         }
535                 }
536                 else
537                 {
538                         newMarkBegin = 0;
539                         newMarkEnd = 0;
540                 }
541
542                 if (CursorPos > 0) CursorPos--;
543                 BlinkStartTime = porting::getTimeMs();
544                 break;
545
546         case KEY_RIGHT:
547                 if (event.KeyInput.Shift)
548                 {
549                         if (Text.size() > (u32)CursorPos)
550                         {
551                                 if (MarkBegin == MarkEnd)
552                                         newMarkBegin = CursorPos;
553
554                                 newMarkEnd = CursorPos+1;
555                         }
556                 }
557                 else
558                 {
559                         newMarkBegin = 0;
560                         newMarkEnd = 0;
561                 }
562
563                 if (Text.size() > (u32)CursorPos) CursorPos++;
564                 BlinkStartTime = porting::getTimeMs();
565                 break;
566         case KEY_UP:
567                 if (MultiLine || (WordWrap && BrokenText.size() > 1) )
568                 {
569                         s32 lineNo = getLineFromPos(CursorPos);
570                         s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin > MarkEnd ? MarkBegin : MarkEnd);
571                         if (lineNo > 0)
572                         {
573                                 s32 cp = CursorPos - BrokenTextPositions[lineNo];
574                                 if ((s32)BrokenText[lineNo-1].size() < cp)
575                                         CursorPos = BrokenTextPositions[lineNo-1] + (s32)BrokenText[lineNo-1].size()-1;
576                                 else
577                                         CursorPos = BrokenTextPositions[lineNo-1] + cp;
578                         }
579
580                         if (event.KeyInput.Shift)
581                         {
582                                 newMarkBegin = mb;
583                                 newMarkEnd = CursorPos;
584                         }
585                         else
586                         {
587                                 newMarkBegin = 0;
588                                 newMarkEnd = 0;
589                         }
590
591                 }
592                 else
593                 {
594                         return false;
595                 }
596                 break;
597         case KEY_DOWN:
598                 if (MultiLine || (WordWrap && BrokenText.size() > 1) )
599                 {
600                         s32 lineNo = getLineFromPos(CursorPos);
601                         s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin < MarkEnd ? MarkBegin : MarkEnd);
602                         if (lineNo < (s32)BrokenText.size()-1)
603                         {
604                                 s32 cp = CursorPos - BrokenTextPositions[lineNo];
605                                 if ((s32)BrokenText[lineNo+1].size() < cp)
606                                         CursorPos = BrokenTextPositions[lineNo+1] + BrokenText[lineNo+1].size()-1;
607                                 else
608                                         CursorPos = BrokenTextPositions[lineNo+1] + cp;
609                         }
610
611                         if (event.KeyInput.Shift)
612                         {
613                                 newMarkBegin = mb;
614                                 newMarkEnd = CursorPos;
615                         }
616                         else
617                         {
618                                 newMarkBegin = 0;
619                                 newMarkEnd = 0;
620                         }
621
622                 }
623                 else
624                 {
625                         return false;
626                 }
627                 break;
628
629         case KEY_BACK:
630                 if ( !this->IsEnabled )
631                         break;
632
633                 if (Text.size())
634                 {
635                         core::stringw s;
636
637                         if (MarkBegin != MarkEnd)
638                         {
639                                 // delete marked text
640                                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
641                                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
642
643                                 s = Text.subString(0, realmbgn);
644                                 s.append( Text.subString(realmend, Text.size()-realmend) );
645                                 Text = s;
646
647                                 CursorPos = realmbgn;
648                         }
649                         else
650                         {
651                                 // delete text behind cursor
652                                 if (CursorPos>0)
653                                         s = Text.subString(0, CursorPos-1);
654                                 else
655                                         s = L"";
656                                 s.append( Text.subString(CursorPos, Text.size()-CursorPos) );
657                                 Text = s;
658                                 --CursorPos;
659                         }
660
661                         if (CursorPos < 0)
662                                 CursorPos = 0;
663                         BlinkStartTime = porting::getTimeMs();
664                         newMarkBegin = 0;
665                         newMarkEnd = 0;
666                         textChanged = true;
667                 }
668                 break;
669         case KEY_DELETE:
670                 if ( !this->IsEnabled )
671                         break;
672
673                 if (Text.size() != 0)
674                 {
675                         core::stringw s;
676
677                         if (MarkBegin != MarkEnd)
678                         {
679                                 // delete marked text
680                                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
681                                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
682
683                                 s = Text.subString(0, realmbgn);
684                                 s.append( Text.subString(realmend, Text.size()-realmend) );
685                                 Text = s;
686
687                                 CursorPos = realmbgn;
688                         }
689                         else
690                         {
691                                 // delete text before cursor
692                                 s = Text.subString(0, CursorPos);
693                                 s.append( Text.subString(CursorPos+1, Text.size()-CursorPos-1) );
694                                 Text = s;
695                         }
696
697                         if (CursorPos > (s32)Text.size())
698                                 CursorPos = (s32)Text.size();
699
700                         BlinkStartTime = porting::getTimeMs();
701                         newMarkBegin = 0;
702                         newMarkEnd = 0;
703                         textChanged = true;
704                 }
705                 break;
706
707         case KEY_ESCAPE:
708         case KEY_TAB:
709         case KEY_SHIFT:
710         case KEY_F1:
711         case KEY_F2:
712         case KEY_F3:
713         case KEY_F4:
714         case KEY_F5:
715         case KEY_F6:
716         case KEY_F7:
717         case KEY_F8:
718         case KEY_F9:
719         case KEY_F10:
720         case KEY_F11:
721         case KEY_F12:
722         case KEY_F13:
723         case KEY_F14:
724         case KEY_F15:
725         case KEY_F16:
726         case KEY_F17:
727         case KEY_F18:
728         case KEY_F19:
729         case KEY_F20:
730         case KEY_F21:
731         case KEY_F22:
732         case KEY_F23:
733         case KEY_F24:
734                 // ignore these keys
735                 return false;
736
737         default:
738                 inputChar(event.KeyInput.Char);
739                 return true;
740         }
741
742     // Set new text markers
743     setTextMarkers( newMarkBegin, newMarkEnd );
744
745         // break the text if it has changed
746         if (textChanged)
747         {
748                 breakText();
749                 sendGuiEvent(EGET_EDITBOX_CHANGED);
750         }
751
752         calculateScrollPos();
753
754         return true;
755 }
756
757
758 //! draws the element and its children
759 void intlGUIEditBox::draw()
760 {
761         if (!IsVisible)
762                 return;
763
764         const bool focus = Environment->hasFocus(this);
765
766         IGUISkin* skin = Environment->getSkin();
767         if (!skin)
768                 return;
769
770         FrameRect = AbsoluteRect;
771
772         // draw the border
773
774         if (Border)
775         {
776                 skin->draw3DSunkenPane(this, skin->getColor(EGDC_WINDOW),
777                         false, true, FrameRect, &AbsoluteClippingRect);
778
779                 FrameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
780                 FrameRect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
781                 FrameRect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
782                 FrameRect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
783         }
784         core::rect<s32> localClipRect = FrameRect;
785         localClipRect.clipAgainst(AbsoluteClippingRect);
786
787         // draw the text
788
789         IGUIFont* font = OverrideFont;
790         if (!OverrideFont)
791                 font = skin->getFont();
792
793         s32 cursorLine = 0;
794         s32 charcursorpos = 0;
795
796         if (font)
797         {
798                 if (LastBreakFont != font)
799                 {
800                         breakText();
801                 }
802
803                 // calculate cursor pos
804
805                 core::stringw *txtLine = &Text;
806                 s32 startPos = 0;
807
808                 core::stringw s, s2;
809
810                 // get mark position
811                 const bool ml = (!PasswordBox && (WordWrap || MultiLine));
812                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
813                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
814                 const s32 hlineStart = ml ? getLineFromPos(realmbgn) : 0;
815                 const s32 hlineCount = ml ? getLineFromPos(realmend) - hlineStart + 1 : 1;
816                 const s32 lineCount = ml ? BrokenText.size() : 1;
817
818                 // Save the override color information.
819                 // Then, alter it if the edit box is disabled.
820                 const bool prevOver = OverrideColorEnabled;
821                 const video::SColor prevColor = OverrideColor;
822
823                 if (Text.size())
824                 {
825                         if (!IsEnabled && !OverrideColorEnabled)
826                         {
827                                 OverrideColorEnabled = true;
828                                 OverrideColor = skin->getColor(EGDC_GRAY_TEXT);
829                         }
830
831                         for (s32 i=0; i < lineCount; ++i)
832                         {
833                                 setTextRect(i);
834
835                                 // clipping test - don't draw anything outside the visible area
836                                 core::rect<s32> c = localClipRect;
837                                 c.clipAgainst(CurrentTextRect);
838                                 if (!c.isValid())
839                                         continue;
840
841                                 // get current line
842                                 if (PasswordBox)
843                                 {
844                                         if (BrokenText.size() != 1)
845                                         {
846                                                 BrokenText.clear();
847                                                 BrokenText.push_back(core::stringw());
848                                         }
849                                         if (BrokenText[0].size() != Text.size())
850                                         {
851                                                 BrokenText[0] = Text;
852                                                 for (u32 q = 0; q < Text.size(); ++q)
853                                                 {
854                                                         BrokenText[0] [q] = PasswordChar;
855                                                 }
856                                         }
857                                         txtLine = &BrokenText[0];
858                                         startPos = 0;
859                                 }
860                                 else
861                                 {
862                                         txtLine = ml ? &BrokenText[i] : &Text;
863                                         startPos = ml ? BrokenTextPositions[i] : 0;
864                                 }
865
866
867                                 // draw normal text
868                                 font->draw(txtLine->c_str(), CurrentTextRect,
869                                         OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT),
870                                         false, true, &localClipRect);
871
872                                 // draw mark and marked text
873                                 if (focus && MarkBegin != MarkEnd && i >= hlineStart && i < hlineStart + hlineCount)
874                                 {
875
876                                         s32 mbegin = 0, mend = 0;
877                                         s32 lineStartPos = 0, lineEndPos = txtLine->size();
878
879                                         if (i == hlineStart)
880                                         {
881                                                 // highlight start is on this line
882                                                 s = txtLine->subString(0, realmbgn - startPos);
883                                                 mbegin = font->getDimension(s.c_str()).Width;
884
885                                                 // deal with kerning
886                                                 mbegin += font->getKerningWidth(
887                                                         &((*txtLine)[realmbgn - startPos]),
888                                                         realmbgn - startPos > 0 ? &((*txtLine)[realmbgn - startPos - 1]) : 0);
889
890                                                 lineStartPos = realmbgn - startPos;
891                                         }
892                                         if (i == hlineStart + hlineCount - 1)
893                                         {
894                                                 // highlight end is on this line
895                                                 s2 = txtLine->subString(0, realmend - startPos);
896                                                 mend = font->getDimension(s2.c_str()).Width;
897                                                 lineEndPos = (s32)s2.size();
898                                         }
899                                         else
900                                                 mend = font->getDimension(txtLine->c_str()).Width;
901
902                                         CurrentTextRect.UpperLeftCorner.X += mbegin;
903                                         CurrentTextRect.LowerRightCorner.X = CurrentTextRect.UpperLeftCorner.X + mend - mbegin;
904
905                                         // draw mark
906                                         skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), CurrentTextRect, &localClipRect);
907
908                                         // draw marked text
909                                         s = txtLine->subString(lineStartPos, lineEndPos - lineStartPos);
910
911                                         if (s.size())
912                                                 font->draw(s.c_str(), CurrentTextRect,
913                                                         OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_HIGH_LIGHT_TEXT),
914                                                         false, true, &localClipRect);
915
916                                 }
917                         }
918
919                         // Return the override color information to its previous settings.
920                         OverrideColorEnabled = prevOver;
921                         OverrideColor = prevColor;
922                 }
923
924                 // draw cursor
925
926                 if (WordWrap || MultiLine)
927                 {
928                         cursorLine = getLineFromPos(CursorPos);
929                         txtLine = &BrokenText[cursorLine];
930                         startPos = BrokenTextPositions[cursorLine];
931                 }
932                 s = txtLine->subString(0,CursorPos-startPos);
933                 charcursorpos = font->getDimension(s.c_str()).Width +
934                         font->getKerningWidth(L"_", CursorPos-startPos > 0 ? &((*txtLine)[CursorPos-startPos-1]) : 0);
935
936                 if (focus && (porting::getTimeMs() - BlinkStartTime) % 700 < 350)
937                 {
938                         setTextRect(cursorLine);
939                         CurrentTextRect.UpperLeftCorner.X += charcursorpos;
940
941                         font->draw(L"_", CurrentTextRect,
942                                 OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT),
943                                 false, true, &localClipRect);
944                 }
945         }
946
947         // draw children
948         IGUIElement::draw();
949 }
950
951
952 //! Sets the new caption of this element.
953 void intlGUIEditBox::setText(const wchar_t* text)
954 {
955         Text = text;
956         if (u32(CursorPos) > Text.size())
957                 CursorPos = Text.size();
958         HScrollPos = 0;
959         breakText();
960 }
961
962
963 //! Enables or disables automatic scrolling with cursor position
964 //! \param enable: If set to true, the text will move around with the cursor position
965 void intlGUIEditBox::setAutoScroll(bool enable)
966 {
967         AutoScroll = enable;
968 }
969
970
971 //! Checks to see if automatic scrolling is enabled
972 //! \return true if automatic scrolling is enabled, false if not
973 bool intlGUIEditBox::isAutoScrollEnabled() const
974 {
975         _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
976         return AutoScroll;
977 }
978
979
980 //! Gets the area of the text in the edit box
981 //! \return Returns the size in pixels of the text
982 core::dimension2du intlGUIEditBox::getTextDimension()
983 {
984         core::rect<s32> ret;
985
986         setTextRect(0);
987         ret = CurrentTextRect;
988
989         for (u32 i=1; i < BrokenText.size(); ++i)
990         {
991                 setTextRect(i);
992                 ret.addInternalPoint(CurrentTextRect.UpperLeftCorner);
993                 ret.addInternalPoint(CurrentTextRect.LowerRightCorner);
994         }
995
996         return core::dimension2du(ret.getSize());
997 }
998
999
1000 //! Sets the maximum amount of characters which may be entered in the box.
1001 //! \param max: Maximum amount of characters. If 0, the character amount is
1002 //! infinity.
1003 void intlGUIEditBox::setMax(u32 max)
1004 {
1005         Max = max;
1006
1007         if (Text.size() > Max && Max != 0)
1008                 Text = Text.subString(0, Max);
1009 }
1010
1011
1012 //! Returns maximum amount of characters, previously set by setMax();
1013 u32 intlGUIEditBox::getMax() const
1014 {
1015         return Max;
1016 }
1017
1018
1019 bool intlGUIEditBox::processMouse(const SEvent& event)
1020 {
1021         switch(event.MouseInput.Event)
1022         {
1023         case irr::EMIE_LMOUSE_LEFT_UP:
1024                 if (Environment->hasFocus(this))
1025                 {
1026                         CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
1027                         if (MouseMarking)
1028                         {
1029                             setTextMarkers( MarkBegin, CursorPos );
1030                         }
1031                         MouseMarking = false;
1032                         calculateScrollPos();
1033                         return true;
1034                 }
1035                 break;
1036         case irr::EMIE_MOUSE_MOVED:
1037                 {
1038                         if (MouseMarking)
1039                         {
1040                                 CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
1041                                 setTextMarkers( MarkBegin, CursorPos );
1042                                 calculateScrollPos();
1043                                 return true;
1044                         }
1045                 }
1046                 break;
1047         case EMIE_LMOUSE_PRESSED_DOWN:
1048                 if (!Environment->hasFocus(this))
1049                 {
1050                         BlinkStartTime = porting::getTimeMs();
1051                         MouseMarking = true;
1052                         CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
1053                         setTextMarkers(CursorPos, CursorPos );
1054                         calculateScrollPos();
1055                         return true;
1056                 }
1057                 else
1058                 {
1059                         if (!AbsoluteClippingRect.isPointInside(
1060                                 core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y)))
1061                         {
1062                                 return false;
1063                         }
1064                         else
1065                         {
1066                                 // move cursor
1067                                 CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
1068
1069                 s32 newMarkBegin = MarkBegin;
1070                                 if (!MouseMarking)
1071                                         newMarkBegin = CursorPos;
1072
1073                                 MouseMarking = true;
1074                                 setTextMarkers( newMarkBegin, CursorPos);
1075                                 calculateScrollPos();
1076                                 return true;
1077                         }
1078                 }
1079         default:
1080                 break;
1081         }
1082
1083         return false;
1084 }
1085
1086
1087 s32 intlGUIEditBox::getCursorPos(s32 x, s32 y)
1088 {
1089         IGUIFont* font = OverrideFont;
1090         IGUISkin* skin = Environment->getSkin();
1091         if (!OverrideFont)
1092                 font = skin->getFont();
1093
1094         const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1;
1095
1096         core::stringw *txtLine = NULL;
1097         s32 startPos = 0;
1098         u32 curr_line_idx = 0;
1099         x += 3;
1100
1101         for (; curr_line_idx < lineCount; ++curr_line_idx) {
1102                 setTextRect(curr_line_idx);
1103                 if (curr_line_idx == 0 && y < CurrentTextRect.UpperLeftCorner.Y)
1104                         y = CurrentTextRect.UpperLeftCorner.Y;
1105                 if (curr_line_idx == lineCount - 1 && y > CurrentTextRect.LowerRightCorner.Y)
1106                         y = CurrentTextRect.LowerRightCorner.Y;
1107
1108                 // is it inside this region?
1109                 if (y >= CurrentTextRect.UpperLeftCorner.Y && y <= CurrentTextRect.LowerRightCorner.Y) {
1110                         // we've found the clicked line
1111                         txtLine = (WordWrap || MultiLine) ? &BrokenText[curr_line_idx] : &Text;
1112                         startPos = (WordWrap || MultiLine) ? BrokenTextPositions[curr_line_idx] : 0;
1113                         break;
1114                 }
1115         }
1116
1117         if (x < CurrentTextRect.UpperLeftCorner.X)
1118                 x = CurrentTextRect.UpperLeftCorner.X;
1119         else if (x > CurrentTextRect.LowerRightCorner.X)
1120                 x = CurrentTextRect.LowerRightCorner.X;
1121
1122         s32 idx = font->getCharacterFromPos(txtLine->c_str(), x - CurrentTextRect.UpperLeftCorner.X);
1123         // Special handling for last line, if we are on limits, add 1 extra shift because idx
1124         // will be the last char, not null char of the wstring
1125         if (curr_line_idx == lineCount - 1 && x == CurrentTextRect.LowerRightCorner.X)
1126                 idx++;
1127
1128         return rangelim(idx + startPos, 0, S32_MAX);
1129 }
1130
1131
1132 //! Breaks the single text line.
1133 void intlGUIEditBox::breakText()
1134 {
1135         IGUISkin* skin = Environment->getSkin();
1136
1137         if ((!WordWrap && !MultiLine) || !skin)
1138                 return;
1139
1140         BrokenText.clear(); // need to reallocate :/
1141         BrokenTextPositions.set_used(0);
1142
1143         IGUIFont* font = OverrideFont;
1144         if (!OverrideFont)
1145                 font = skin->getFont();
1146
1147         if (!font)
1148                 return;
1149
1150         LastBreakFont = font;
1151
1152         core::stringw line;
1153         core::stringw word;
1154         core::stringw whitespace;
1155         s32 lastLineStart = 0;
1156         s32 size = Text.size();
1157         s32 length = 0;
1158         s32 elWidth = RelativeRect.getWidth() - 6;
1159         wchar_t c;
1160
1161         for (s32 i=0; i<size; ++i)
1162         {
1163                 c = Text[i];
1164                 bool lineBreak = false;
1165
1166                 if (c == L'\r') // Mac or Windows breaks
1167                 {
1168                         lineBreak = true;
1169                         c = ' ';
1170                         if (Text[i+1] == L'\n') // Windows breaks
1171                         {
1172                                 Text.erase(i+1);
1173                                 --size;
1174                         }
1175                 }
1176                 else if (c == L'\n') // Unix breaks
1177                 {
1178                         lineBreak = true;
1179                         c = ' ';
1180                 }
1181
1182                 // don't break if we're not a multi-line edit box
1183                 if (!MultiLine)
1184                         lineBreak = false;
1185
1186                 if (c == L' ' || c == 0 || i == (size-1))
1187                 {
1188                         if (word.size())
1189                         {
1190                                 // here comes the next whitespace, look if
1191                                 // we can break the last word to the next line.
1192                                 s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
1193                                 s32 worldlgth = font->getDimension(word.c_str()).Width;
1194
1195                                 if (WordWrap && length + worldlgth + whitelgth > elWidth)
1196                                 {
1197                                         // break to next line
1198                                         length = worldlgth;
1199                                         BrokenText.push_back(line);
1200                                         BrokenTextPositions.push_back(lastLineStart);
1201                                         lastLineStart = i - (s32)word.size();
1202                                         line = word;
1203                                 }
1204                                 else
1205                                 {
1206                                         // add word to line
1207                                         line += whitespace;
1208                                         line += word;
1209                                         length += whitelgth + worldlgth;
1210                                 }
1211
1212                                 word = L"";
1213                                 whitespace = L"";
1214                         }
1215
1216                         whitespace += c;
1217
1218                         // compute line break
1219                         if (lineBreak)
1220                         {
1221                                 line += whitespace;
1222                                 line += word;
1223                                 BrokenText.push_back(line);
1224                                 BrokenTextPositions.push_back(lastLineStart);
1225                                 lastLineStart = i+1;
1226                                 line = L"";
1227                                 word = L"";
1228                                 whitespace = L"";
1229                                 length = 0;
1230                         }
1231                 }
1232                 else
1233                 {
1234                         // yippee this is a word..
1235                         word += c;
1236                 }
1237         }
1238
1239         line += whitespace;
1240         line += word;
1241         BrokenText.push_back(line);
1242         BrokenTextPositions.push_back(lastLineStart);
1243 }
1244
1245
1246 void intlGUIEditBox::setTextRect(s32 line)
1247 {
1248         core::dimension2du d;
1249
1250         IGUISkin* skin = Environment->getSkin();
1251         if (!skin)
1252                 return;
1253
1254         IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont();
1255
1256         if (!font)
1257                 return;
1258
1259         // get text dimension
1260         const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1;
1261         if (WordWrap || MultiLine)
1262         {
1263                 d = font->getDimension(BrokenText[line].c_str());
1264         }
1265         else
1266         {
1267                 d = font->getDimension(Text.c_str());
1268                 d.Height = AbsoluteRect.getHeight();
1269         }
1270         d.Height += font->getKerningHeight();
1271
1272         // justification
1273         switch (HAlign)
1274         {
1275         case EGUIA_CENTER:
1276                 // align to h centre
1277                 CurrentTextRect.UpperLeftCorner.X = (FrameRect.getWidth()/2) - (d.Width/2);
1278                 CurrentTextRect.LowerRightCorner.X = (FrameRect.getWidth()/2) + (d.Width/2);
1279                 break;
1280         case EGUIA_LOWERRIGHT:
1281                 // align to right edge
1282                 CurrentTextRect.UpperLeftCorner.X = FrameRect.getWidth() - d.Width;
1283                 CurrentTextRect.LowerRightCorner.X = FrameRect.getWidth();
1284                 break;
1285         default:
1286                 // align to left edge
1287                 CurrentTextRect.UpperLeftCorner.X = 0;
1288                 CurrentTextRect.LowerRightCorner.X = d.Width;
1289
1290         }
1291
1292         switch (VAlign)
1293         {
1294         case EGUIA_CENTER:
1295                 // align to v centre
1296                 CurrentTextRect.UpperLeftCorner.Y =
1297                         (FrameRect.getHeight()/2) - (lineCount*d.Height)/2 + d.Height*line;
1298                 break;
1299         case EGUIA_LOWERRIGHT:
1300                 // align to bottom edge
1301                 CurrentTextRect.UpperLeftCorner.Y =
1302                         FrameRect.getHeight() - lineCount*d.Height + d.Height*line;
1303                 break;
1304         default:
1305                 // align to top edge
1306                 CurrentTextRect.UpperLeftCorner.Y = d.Height*line;
1307                 break;
1308         }
1309
1310         CurrentTextRect.UpperLeftCorner.X  -= HScrollPos;
1311         CurrentTextRect.LowerRightCorner.X -= HScrollPos;
1312         CurrentTextRect.UpperLeftCorner.Y  -= VScrollPos;
1313         CurrentTextRect.LowerRightCorner.Y = CurrentTextRect.UpperLeftCorner.Y + d.Height;
1314
1315         CurrentTextRect += FrameRect.UpperLeftCorner;
1316
1317 }
1318
1319
1320 s32 intlGUIEditBox::getLineFromPos(s32 pos)
1321 {
1322         if (!WordWrap && !MultiLine)
1323                 return 0;
1324
1325         s32 i=0;
1326         while (i < (s32)BrokenTextPositions.size())
1327         {
1328                 if (BrokenTextPositions[i] > pos)
1329                         return i-1;
1330                 ++i;
1331         }
1332         return (s32)BrokenTextPositions.size() - 1;
1333 }
1334
1335
1336 void intlGUIEditBox::inputChar(wchar_t c)
1337 {
1338         if (!IsEnabled)
1339                 return;
1340
1341         if (c != 0)
1342         {
1343                 if (Text.size() < Max || Max == 0)
1344                 {
1345                         core::stringw s;
1346
1347                         if (MarkBegin != MarkEnd)
1348                         {
1349                                 // replace marked text
1350                                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
1351                                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
1352
1353                                 s = Text.subString(0, realmbgn);
1354                                 s.append(c);
1355                                 s.append( Text.subString(realmend, Text.size()-realmend) );
1356                                 Text = s;
1357                                 CursorPos = realmbgn+1;
1358                         }
1359                         else
1360                         {
1361                                 // add new character
1362                                 s = Text.subString(0, CursorPos);
1363                                 s.append(c);
1364                                 s.append( Text.subString(CursorPos, Text.size()-CursorPos) );
1365                                 Text = s;
1366                                 ++CursorPos;
1367                         }
1368
1369                         BlinkStartTime = porting::getTimeMs();
1370                         setTextMarkers(0, 0);
1371                 }
1372         }
1373         breakText();
1374         sendGuiEvent(EGET_EDITBOX_CHANGED);
1375         calculateScrollPos();
1376 }
1377
1378
1379 void intlGUIEditBox::calculateScrollPos()
1380 {
1381         if (!AutoScroll)
1382                 return;
1383
1384         // calculate horizontal scroll position
1385         s32 cursLine = getLineFromPos(CursorPos);
1386         setTextRect(cursLine);
1387
1388         // don't do horizontal scrolling when wordwrap is enabled.
1389         if (!WordWrap)
1390         {
1391                 // get cursor position
1392                 IGUISkin* skin = Environment->getSkin();
1393                 if (!skin)
1394                         return;
1395                 IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont();
1396                 if (!font)
1397                         return;
1398
1399                 core::stringw *txtLine = MultiLine ? &BrokenText[cursLine] : &Text;
1400                 s32 cPos = MultiLine ? CursorPos - BrokenTextPositions[cursLine] : CursorPos;
1401
1402                 s32 cStart = CurrentTextRect.UpperLeftCorner.X + HScrollPos +
1403                         font->getDimension(txtLine->subString(0, cPos).c_str()).Width;
1404
1405                 s32 cEnd = cStart + font->getDimension(L"_ ").Width;
1406
1407                 if (FrameRect.LowerRightCorner.X < cEnd)
1408                         HScrollPos = cEnd - FrameRect.LowerRightCorner.X;
1409                 else if (FrameRect.UpperLeftCorner.X > cStart)
1410                         HScrollPos = cStart - FrameRect.UpperLeftCorner.X;
1411                 else
1412                         HScrollPos = 0;
1413
1414                 // todo: adjust scrollbar
1415         }
1416
1417         // vertical scroll position
1418         if (FrameRect.LowerRightCorner.Y < CurrentTextRect.LowerRightCorner.Y + VScrollPos)
1419                 VScrollPos = CurrentTextRect.LowerRightCorner.Y - FrameRect.LowerRightCorner.Y + VScrollPos;
1420
1421         else if (FrameRect.UpperLeftCorner.Y > CurrentTextRect.UpperLeftCorner.Y + VScrollPos)
1422                 VScrollPos = CurrentTextRect.UpperLeftCorner.Y - FrameRect.UpperLeftCorner.Y + VScrollPos;
1423         else
1424                 VScrollPos = 0;
1425
1426         // todo: adjust scrollbar
1427 }
1428
1429 //! set text markers
1430 void intlGUIEditBox::setTextMarkers(s32 begin, s32 end)
1431 {
1432     if ( begin != MarkBegin || end != MarkEnd )
1433     {
1434         MarkBegin = begin;
1435         MarkEnd = end;
1436         sendGuiEvent(EGET_EDITBOX_MARKING_CHANGED);
1437     }
1438 }
1439
1440 //! send some gui event to parent
1441 void intlGUIEditBox::sendGuiEvent(EGUI_EVENT_TYPE type)
1442 {
1443         if ( Parent )
1444         {
1445         SEvent e;
1446         e.EventType = EET_GUI_EVENT;
1447         e.GUIEvent.Caller = this;
1448         e.GUIEvent.Element = 0;
1449         e.GUIEvent.EventType = type;
1450
1451         Parent->OnEvent(e);
1452         }
1453 }
1454
1455 //! Writes attributes of the element.
1456 void intlGUIEditBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
1457 {
1458         // IGUIEditBox::serializeAttributes(out,options);
1459
1460         out->addBool  ("OverrideColorEnabled",OverrideColorEnabled );
1461         out->addColor ("OverrideColor",       OverrideColor);
1462         // out->addFont("OverrideFont",OverrideFont);
1463         out->addInt   ("MaxChars",            Max);
1464         out->addBool  ("WordWrap",            WordWrap);
1465         out->addBool  ("MultiLine",           MultiLine);
1466         out->addBool  ("AutoScroll",          AutoScroll);
1467         out->addBool  ("PasswordBox",         PasswordBox);
1468         core::stringw ch = L" ";
1469         ch[0] = PasswordChar;
1470         out->addString("PasswordChar",        ch.c_str());
1471         out->addEnum  ("HTextAlign",          HAlign, GUIAlignmentNames);
1472         out->addEnum  ("VTextAlign",          VAlign, GUIAlignmentNames);
1473
1474         IGUIEditBox::serializeAttributes(out,options);
1475 }
1476
1477
1478 //! Reads attributes of the element
1479 void intlGUIEditBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
1480 {
1481         IGUIEditBox::deserializeAttributes(in,options);
1482
1483         setOverrideColor(in->getAttributeAsColor("OverrideColor"));
1484         enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled"));
1485         setMax(in->getAttributeAsInt("MaxChars"));
1486         setWordWrap(in->getAttributeAsBool("WordWrap"));
1487         setMultiLine(in->getAttributeAsBool("MultiLine"));
1488         setAutoScroll(in->getAttributeAsBool("AutoScroll"));
1489         core::stringw ch = in->getAttributeAsStringW("PasswordChar");
1490
1491         if (!ch.size())
1492                 setPasswordBox(in->getAttributeAsBool("PasswordBox"));
1493         else
1494                 setPasswordBox(in->getAttributeAsBool("PasswordBox"), ch[0]);
1495
1496         setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
1497                         (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
1498
1499         // setOverrideFont(in->getAttributeAsFont("OverrideFont"));
1500 }
1501
1502
1503 } // end namespace gui
1504 } // end namespace irr
1505
1506 #endif // _IRR_COMPILE_WITH_GUI_