]> git.lizzy.rs Git - dragonfireclient.git/blob - src/intlGUIEditBox.cpp
Fix Android node selection distance (#6187)
[dragonfireclient.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.empty()) {
634                         core::stringw s;
635
636                         if (MarkBegin != MarkEnd)
637                         {
638                                 // delete marked text
639                                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
640                                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
641
642                                 s = Text.subString(0, realmbgn);
643                                 s.append( Text.subString(realmend, Text.size()-realmend) );
644                                 Text = s;
645
646                                 CursorPos = realmbgn;
647                         }
648                         else
649                         {
650                                 // delete text behind cursor
651                                 if (CursorPos>0)
652                                         s = Text.subString(0, CursorPos-1);
653                                 else
654                                         s = L"";
655                                 s.append( Text.subString(CursorPos, Text.size()-CursorPos) );
656                                 Text = s;
657                                 --CursorPos;
658                         }
659
660                         if (CursorPos < 0)
661                                 CursorPos = 0;
662                         BlinkStartTime = porting::getTimeMs();
663                         newMarkBegin = 0;
664                         newMarkEnd = 0;
665                         textChanged = true;
666                 }
667                 break;
668         case KEY_DELETE:
669                 if ( !this->IsEnabled )
670                         break;
671
672                 if (!Text.empty()) {
673                         core::stringw s;
674
675                         if (MarkBegin != MarkEnd)
676                         {
677                                 // delete marked text
678                                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
679                                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
680
681                                 s = Text.subString(0, realmbgn);
682                                 s.append( Text.subString(realmend, Text.size()-realmend) );
683                                 Text = s;
684
685                                 CursorPos = realmbgn;
686                         }
687                         else
688                         {
689                                 // delete text before cursor
690                                 s = Text.subString(0, CursorPos);
691                                 s.append( Text.subString(CursorPos+1, Text.size()-CursorPos-1) );
692                                 Text = s;
693                         }
694
695                         if (CursorPos > (s32)Text.size())
696                                 CursorPos = (s32)Text.size();
697
698                         BlinkStartTime = porting::getTimeMs();
699                         newMarkBegin = 0;
700                         newMarkEnd = 0;
701                         textChanged = true;
702                 }
703                 break;
704
705         case KEY_ESCAPE:
706         case KEY_TAB:
707         case KEY_SHIFT:
708         case KEY_F1:
709         case KEY_F2:
710         case KEY_F3:
711         case KEY_F4:
712         case KEY_F5:
713         case KEY_F6:
714         case KEY_F7:
715         case KEY_F8:
716         case KEY_F9:
717         case KEY_F10:
718         case KEY_F11:
719         case KEY_F12:
720         case KEY_F13:
721         case KEY_F14:
722         case KEY_F15:
723         case KEY_F16:
724         case KEY_F17:
725         case KEY_F18:
726         case KEY_F19:
727         case KEY_F20:
728         case KEY_F21:
729         case KEY_F22:
730         case KEY_F23:
731         case KEY_F24:
732                 // ignore these keys
733                 return false;
734
735         default:
736                 inputChar(event.KeyInput.Char);
737                 return true;
738         }
739
740     // Set new text markers
741     setTextMarkers( newMarkBegin, newMarkEnd );
742
743         // break the text if it has changed
744         if (textChanged)
745         {
746                 breakText();
747                 sendGuiEvent(EGET_EDITBOX_CHANGED);
748         }
749
750         calculateScrollPos();
751
752         return true;
753 }
754
755
756 //! draws the element and its children
757 void intlGUIEditBox::draw()
758 {
759         if (!IsVisible)
760                 return;
761
762         const bool focus = Environment->hasFocus(this);
763
764         IGUISkin* skin = Environment->getSkin();
765         if (!skin)
766                 return;
767
768         FrameRect = AbsoluteRect;
769
770         // draw the border
771
772         if (Border)
773         {
774                 skin->draw3DSunkenPane(this, skin->getColor(EGDC_WINDOW),
775                         false, true, FrameRect, &AbsoluteClippingRect);
776
777                 FrameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
778                 FrameRect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
779                 FrameRect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
780                 FrameRect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
781         }
782         core::rect<s32> localClipRect = FrameRect;
783         localClipRect.clipAgainst(AbsoluteClippingRect);
784
785         // draw the text
786
787         IGUIFont* font = OverrideFont;
788         if (!OverrideFont)
789                 font = skin->getFont();
790
791         s32 cursorLine = 0;
792         s32 charcursorpos = 0;
793
794         if (font)
795         {
796                 if (LastBreakFont != font)
797                 {
798                         breakText();
799                 }
800
801                 // calculate cursor pos
802
803                 core::stringw *txtLine = &Text;
804                 s32 startPos = 0;
805
806                 core::stringw s, s2;
807
808                 // get mark position
809                 const bool ml = (!PasswordBox && (WordWrap || MultiLine));
810                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
811                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
812                 const s32 hlineStart = ml ? getLineFromPos(realmbgn) : 0;
813                 const s32 hlineCount = ml ? getLineFromPos(realmend) - hlineStart + 1 : 1;
814                 const s32 lineCount = ml ? BrokenText.size() : 1;
815
816                 // Save the override color information.
817                 // Then, alter it if the edit box is disabled.
818                 const bool prevOver = OverrideColorEnabled;
819                 const video::SColor prevColor = OverrideColor;
820
821                 if (!Text.empty()) {
822                         if (!IsEnabled && !OverrideColorEnabled)
823                         {
824                                 OverrideColorEnabled = true;
825                                 OverrideColor = skin->getColor(EGDC_GRAY_TEXT);
826                         }
827
828                         for (s32 i=0; i < lineCount; ++i)
829                         {
830                                 setTextRect(i);
831
832                                 // clipping test - don't draw anything outside the visible area
833                                 core::rect<s32> c = localClipRect;
834                                 c.clipAgainst(CurrentTextRect);
835                                 if (!c.isValid())
836                                         continue;
837
838                                 // get current line
839                                 if (PasswordBox)
840                                 {
841                                         if (BrokenText.size() != 1)
842                                         {
843                                                 BrokenText.clear();
844                                                 BrokenText.push_back(core::stringw());
845                                         }
846                                         if (BrokenText[0].size() != Text.size())
847                                         {
848                                                 BrokenText[0] = Text;
849                                                 for (u32 q = 0; q < Text.size(); ++q)
850                                                 {
851                                                         BrokenText[0] [q] = PasswordChar;
852                                                 }
853                                         }
854                                         txtLine = &BrokenText[0];
855                                         startPos = 0;
856                                 }
857                                 else
858                                 {
859                                         txtLine = ml ? &BrokenText[i] : &Text;
860                                         startPos = ml ? BrokenTextPositions[i] : 0;
861                                 }
862
863
864                                 // draw normal text
865                                 font->draw(txtLine->c_str(), CurrentTextRect,
866                                         OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT),
867                                         false, true, &localClipRect);
868
869                                 // draw mark and marked text
870                                 if (focus && MarkBegin != MarkEnd && i >= hlineStart && i < hlineStart + hlineCount)
871                                 {
872
873                                         s32 mbegin = 0, mend = 0;
874                                         s32 lineStartPos = 0, lineEndPos = txtLine->size();
875
876                                         if (i == hlineStart)
877                                         {
878                                                 // highlight start is on this line
879                                                 s = txtLine->subString(0, realmbgn - startPos);
880                                                 mbegin = font->getDimension(s.c_str()).Width;
881
882                                                 // deal with kerning
883                                                 mbegin += font->getKerningWidth(
884                                                         &((*txtLine)[realmbgn - startPos]),
885                                                         realmbgn - startPos > 0 ? &((*txtLine)[realmbgn - startPos - 1]) : 0);
886
887                                                 lineStartPos = realmbgn - startPos;
888                                         }
889                                         if (i == hlineStart + hlineCount - 1)
890                                         {
891                                                 // highlight end is on this line
892                                                 s2 = txtLine->subString(0, realmend - startPos);
893                                                 mend = font->getDimension(s2.c_str()).Width;
894                                                 lineEndPos = (s32)s2.size();
895                                         }
896                                         else
897                                                 mend = font->getDimension(txtLine->c_str()).Width;
898
899                                         CurrentTextRect.UpperLeftCorner.X += mbegin;
900                                         CurrentTextRect.LowerRightCorner.X = CurrentTextRect.UpperLeftCorner.X + mend - mbegin;
901
902                                         // draw mark
903                                         skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), CurrentTextRect, &localClipRect);
904
905                                         // draw marked text
906                                         s = txtLine->subString(lineStartPos, lineEndPos - lineStartPos);
907
908                                         if (!s.empty())
909                                                 font->draw(s.c_str(), CurrentTextRect,
910                                                         OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_HIGH_LIGHT_TEXT),
911                                                         false, true, &localClipRect);
912
913                                 }
914                         }
915
916                         // Return the override color information to its previous settings.
917                         OverrideColorEnabled = prevOver;
918                         OverrideColor = prevColor;
919                 }
920
921                 // draw cursor
922
923                 if (WordWrap || MultiLine)
924                 {
925                         cursorLine = getLineFromPos(CursorPos);
926                         txtLine = &BrokenText[cursorLine];
927                         startPos = BrokenTextPositions[cursorLine];
928                 }
929                 s = txtLine->subString(0,CursorPos-startPos);
930                 charcursorpos = font->getDimension(s.c_str()).Width +
931                         font->getKerningWidth(L"_", CursorPos-startPos > 0 ? &((*txtLine)[CursorPos-startPos-1]) : 0);
932
933                 if (focus && (porting::getTimeMs() - BlinkStartTime) % 700 < 350)
934                 {
935                         setTextRect(cursorLine);
936                         CurrentTextRect.UpperLeftCorner.X += charcursorpos;
937
938                         font->draw(L"_", CurrentTextRect,
939                                 OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT),
940                                 false, true, &localClipRect);
941                 }
942         }
943
944         // draw children
945         IGUIElement::draw();
946 }
947
948
949 //! Sets the new caption of this element.
950 void intlGUIEditBox::setText(const wchar_t* text)
951 {
952         Text = text;
953         if (u32(CursorPos) > Text.size())
954                 CursorPos = Text.size();
955         HScrollPos = 0;
956         breakText();
957 }
958
959
960 //! Enables or disables automatic scrolling with cursor position
961 //! \param enable: If set to true, the text will move around with the cursor position
962 void intlGUIEditBox::setAutoScroll(bool enable)
963 {
964         AutoScroll = enable;
965 }
966
967
968 //! Checks to see if automatic scrolling is enabled
969 //! \return true if automatic scrolling is enabled, false if not
970 bool intlGUIEditBox::isAutoScrollEnabled() const
971 {
972         _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
973         return AutoScroll;
974 }
975
976
977 //! Gets the area of the text in the edit box
978 //! \return Returns the size in pixels of the text
979 core::dimension2du intlGUIEditBox::getTextDimension()
980 {
981         core::rect<s32> ret;
982
983         setTextRect(0);
984         ret = CurrentTextRect;
985
986         for (u32 i=1; i < BrokenText.size(); ++i)
987         {
988                 setTextRect(i);
989                 ret.addInternalPoint(CurrentTextRect.UpperLeftCorner);
990                 ret.addInternalPoint(CurrentTextRect.LowerRightCorner);
991         }
992
993         return core::dimension2du(ret.getSize());
994 }
995
996
997 //! Sets the maximum amount of characters which may be entered in the box.
998 //! \param max: Maximum amount of characters. If 0, the character amount is
999 //! infinity.
1000 void intlGUIEditBox::setMax(u32 max)
1001 {
1002         Max = max;
1003
1004         if (Text.size() > Max && Max != 0)
1005                 Text = Text.subString(0, Max);
1006 }
1007
1008
1009 //! Returns maximum amount of characters, previously set by setMax();
1010 u32 intlGUIEditBox::getMax() const
1011 {
1012         return Max;
1013 }
1014
1015
1016 bool intlGUIEditBox::processMouse(const SEvent& event)
1017 {
1018         switch(event.MouseInput.Event)
1019         {
1020         case irr::EMIE_LMOUSE_LEFT_UP:
1021                 if (Environment->hasFocus(this))
1022                 {
1023                         CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
1024                         if (MouseMarking)
1025                         {
1026                             setTextMarkers( MarkBegin, CursorPos );
1027                         }
1028                         MouseMarking = false;
1029                         calculateScrollPos();
1030                         return true;
1031                 }
1032                 break;
1033         case irr::EMIE_MOUSE_MOVED:
1034                 {
1035                         if (MouseMarking)
1036                         {
1037                                 CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
1038                                 setTextMarkers( MarkBegin, CursorPos );
1039                                 calculateScrollPos();
1040                                 return true;
1041                         }
1042                 }
1043                 break;
1044         case EMIE_LMOUSE_PRESSED_DOWN:
1045                 if (!Environment->hasFocus(this))
1046                 {
1047                         BlinkStartTime = porting::getTimeMs();
1048                         MouseMarking = true;
1049                         CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
1050                         setTextMarkers(CursorPos, CursorPos );
1051                         calculateScrollPos();
1052                         return true;
1053                 }
1054                 else
1055                 {
1056                         if (!AbsoluteClippingRect.isPointInside(
1057                                 core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y))) {
1058                                 return false;
1059                         }
1060
1061
1062                         // move cursor
1063                         CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
1064
1065                         s32 newMarkBegin = MarkBegin;
1066                         if (!MouseMarking)
1067                                 newMarkBegin = CursorPos;
1068
1069                         MouseMarking = true;
1070                         setTextMarkers( newMarkBegin, CursorPos);
1071                         calculateScrollPos();
1072                         return true;
1073                 }
1074         default:
1075                 break;
1076         }
1077
1078         return false;
1079 }
1080
1081
1082 s32 intlGUIEditBox::getCursorPos(s32 x, s32 y)
1083 {
1084         IGUIFont* font = OverrideFont;
1085         IGUISkin* skin = Environment->getSkin();
1086         if (!OverrideFont)
1087                 font = skin->getFont();
1088
1089         const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1;
1090
1091         core::stringw *txtLine = NULL;
1092         s32 startPos = 0;
1093         u32 curr_line_idx = 0;
1094         x += 3;
1095
1096         for (; curr_line_idx < lineCount; ++curr_line_idx) {
1097                 setTextRect(curr_line_idx);
1098                 if (curr_line_idx == 0 && y < CurrentTextRect.UpperLeftCorner.Y)
1099                         y = CurrentTextRect.UpperLeftCorner.Y;
1100                 if (curr_line_idx == lineCount - 1 && y > CurrentTextRect.LowerRightCorner.Y)
1101                         y = CurrentTextRect.LowerRightCorner.Y;
1102
1103                 // is it inside this region?
1104                 if (y >= CurrentTextRect.UpperLeftCorner.Y && y <= CurrentTextRect.LowerRightCorner.Y) {
1105                         // we've found the clicked line
1106                         txtLine = (WordWrap || MultiLine) ? &BrokenText[curr_line_idx] : &Text;
1107                         startPos = (WordWrap || MultiLine) ? BrokenTextPositions[curr_line_idx] : 0;
1108                         break;
1109                 }
1110         }
1111
1112         if (x < CurrentTextRect.UpperLeftCorner.X)
1113                 x = CurrentTextRect.UpperLeftCorner.X;
1114         else if (x > CurrentTextRect.LowerRightCorner.X)
1115                 x = CurrentTextRect.LowerRightCorner.X;
1116
1117         s32 idx = font->getCharacterFromPos(txtLine->c_str(), x - CurrentTextRect.UpperLeftCorner.X);
1118         // Special handling for last line, if we are on limits, add 1 extra shift because idx
1119         // will be the last char, not null char of the wstring
1120         if (curr_line_idx == lineCount - 1 && x == CurrentTextRect.LowerRightCorner.X)
1121                 idx++;
1122
1123         return rangelim(idx + startPos, 0, S32_MAX);
1124 }
1125
1126
1127 //! Breaks the single text line.
1128 void intlGUIEditBox::breakText()
1129 {
1130         IGUISkin* skin = Environment->getSkin();
1131
1132         if ((!WordWrap && !MultiLine) || !skin)
1133                 return;
1134
1135         BrokenText.clear(); // need to reallocate :/
1136         BrokenTextPositions.set_used(0);
1137
1138         IGUIFont* font = OverrideFont;
1139         if (!OverrideFont)
1140                 font = skin->getFont();
1141
1142         if (!font)
1143                 return;
1144
1145         LastBreakFont = font;
1146
1147         core::stringw line;
1148         core::stringw word;
1149         core::stringw whitespace;
1150         s32 lastLineStart = 0;
1151         s32 size = Text.size();
1152         s32 length = 0;
1153         s32 elWidth = RelativeRect.getWidth() - 6;
1154         wchar_t c;
1155
1156         for (s32 i=0; i<size; ++i)
1157         {
1158                 c = Text[i];
1159                 bool lineBreak = false;
1160
1161                 if (c == L'\r') // Mac or Windows breaks
1162                 {
1163                         lineBreak = true;
1164                         c = ' ';
1165                         if (Text[i+1] == L'\n') // Windows breaks
1166                         {
1167                                 Text.erase(i+1);
1168                                 --size;
1169                         }
1170                 }
1171                 else if (c == L'\n') // Unix breaks
1172                 {
1173                         lineBreak = true;
1174                         c = ' ';
1175                 }
1176
1177                 // don't break if we're not a multi-line edit box
1178                 if (!MultiLine)
1179                         lineBreak = false;
1180
1181                 if (c == L' ' || c == 0 || i == (size-1))
1182                 {
1183                         if (!word.empty()) {
1184                                 // here comes the next whitespace, look if
1185                                 // we can break the last word to the next line.
1186                                 s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
1187                                 s32 worldlgth = font->getDimension(word.c_str()).Width;
1188
1189                                 if (WordWrap && length + worldlgth + whitelgth > elWidth)
1190                                 {
1191                                         // break to next line
1192                                         length = worldlgth;
1193                                         BrokenText.push_back(line);
1194                                         BrokenTextPositions.push_back(lastLineStart);
1195                                         lastLineStart = i - (s32)word.size();
1196                                         line = word;
1197                                 }
1198                                 else
1199                                 {
1200                                         // add word to line
1201                                         line += whitespace;
1202                                         line += word;
1203                                         length += whitelgth + worldlgth;
1204                                 }
1205
1206                                 word = L"";
1207                                 whitespace = L"";
1208                         }
1209
1210                         whitespace += c;
1211
1212                         // compute line break
1213                         if (lineBreak)
1214                         {
1215                                 line += whitespace;
1216                                 line += word;
1217                                 BrokenText.push_back(line);
1218                                 BrokenTextPositions.push_back(lastLineStart);
1219                                 lastLineStart = i+1;
1220                                 line = L"";
1221                                 word = L"";
1222                                 whitespace = L"";
1223                                 length = 0;
1224                         }
1225                 }
1226                 else
1227                 {
1228                         // yippee this is a word..
1229                         word += c;
1230                 }
1231         }
1232
1233         line += whitespace;
1234         line += word;
1235         BrokenText.push_back(line);
1236         BrokenTextPositions.push_back(lastLineStart);
1237 }
1238
1239
1240 void intlGUIEditBox::setTextRect(s32 line)
1241 {
1242         core::dimension2du d;
1243
1244         IGUISkin* skin = Environment->getSkin();
1245         if (!skin)
1246                 return;
1247
1248         IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont();
1249
1250         if (!font)
1251                 return;
1252
1253         // get text dimension
1254         const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1;
1255         if (WordWrap || MultiLine)
1256         {
1257                 d = font->getDimension(BrokenText[line].c_str());
1258         }
1259         else
1260         {
1261                 d = font->getDimension(Text.c_str());
1262                 d.Height = AbsoluteRect.getHeight();
1263         }
1264         d.Height += font->getKerningHeight();
1265
1266         // justification
1267         switch (HAlign)
1268         {
1269         case EGUIA_CENTER:
1270                 // align to h centre
1271                 CurrentTextRect.UpperLeftCorner.X = (FrameRect.getWidth()/2) - (d.Width/2);
1272                 CurrentTextRect.LowerRightCorner.X = (FrameRect.getWidth()/2) + (d.Width/2);
1273                 break;
1274         case EGUIA_LOWERRIGHT:
1275                 // align to right edge
1276                 CurrentTextRect.UpperLeftCorner.X = FrameRect.getWidth() - d.Width;
1277                 CurrentTextRect.LowerRightCorner.X = FrameRect.getWidth();
1278                 break;
1279         default:
1280                 // align to left edge
1281                 CurrentTextRect.UpperLeftCorner.X = 0;
1282                 CurrentTextRect.LowerRightCorner.X = d.Width;
1283
1284         }
1285
1286         switch (VAlign)
1287         {
1288         case EGUIA_CENTER:
1289                 // align to v centre
1290                 CurrentTextRect.UpperLeftCorner.Y =
1291                         (FrameRect.getHeight()/2) - (lineCount*d.Height)/2 + d.Height*line;
1292                 break;
1293         case EGUIA_LOWERRIGHT:
1294                 // align to bottom edge
1295                 CurrentTextRect.UpperLeftCorner.Y =
1296                         FrameRect.getHeight() - lineCount*d.Height + d.Height*line;
1297                 break;
1298         default:
1299                 // align to top edge
1300                 CurrentTextRect.UpperLeftCorner.Y = d.Height*line;
1301                 break;
1302         }
1303
1304         CurrentTextRect.UpperLeftCorner.X  -= HScrollPos;
1305         CurrentTextRect.LowerRightCorner.X -= HScrollPos;
1306         CurrentTextRect.UpperLeftCorner.Y  -= VScrollPos;
1307         CurrentTextRect.LowerRightCorner.Y = CurrentTextRect.UpperLeftCorner.Y + d.Height;
1308
1309         CurrentTextRect += FrameRect.UpperLeftCorner;
1310
1311 }
1312
1313
1314 s32 intlGUIEditBox::getLineFromPos(s32 pos)
1315 {
1316         if (!WordWrap && !MultiLine)
1317                 return 0;
1318
1319         s32 i=0;
1320         while (i < (s32)BrokenTextPositions.size())
1321         {
1322                 if (BrokenTextPositions[i] > pos)
1323                         return i-1;
1324                 ++i;
1325         }
1326         return (s32)BrokenTextPositions.size() - 1;
1327 }
1328
1329
1330 void intlGUIEditBox::inputChar(wchar_t c)
1331 {
1332         if (!IsEnabled)
1333                 return;
1334
1335         if (c != 0)
1336         {
1337                 if (Text.size() < Max || Max == 0)
1338                 {
1339                         core::stringw s;
1340
1341                         if (MarkBegin != MarkEnd)
1342                         {
1343                                 // replace marked text
1344                                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
1345                                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
1346
1347                                 s = Text.subString(0, realmbgn);
1348                                 s.append(c);
1349                                 s.append( Text.subString(realmend, Text.size()-realmend) );
1350                                 Text = s;
1351                                 CursorPos = realmbgn+1;
1352                         }
1353                         else
1354                         {
1355                                 // add new character
1356                                 s = Text.subString(0, CursorPos);
1357                                 s.append(c);
1358                                 s.append( Text.subString(CursorPos, Text.size()-CursorPos) );
1359                                 Text = s;
1360                                 ++CursorPos;
1361                         }
1362
1363                         BlinkStartTime = porting::getTimeMs();
1364                         setTextMarkers(0, 0);
1365                 }
1366         }
1367         breakText();
1368         sendGuiEvent(EGET_EDITBOX_CHANGED);
1369         calculateScrollPos();
1370 }
1371
1372
1373 void intlGUIEditBox::calculateScrollPos()
1374 {
1375         if (!AutoScroll)
1376                 return;
1377
1378         // calculate horizontal scroll position
1379         s32 cursLine = getLineFromPos(CursorPos);
1380         setTextRect(cursLine);
1381
1382         // don't do horizontal scrolling when wordwrap is enabled.
1383         if (!WordWrap)
1384         {
1385                 // get cursor position
1386                 IGUISkin* skin = Environment->getSkin();
1387                 if (!skin)
1388                         return;
1389                 IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont();
1390                 if (!font)
1391                         return;
1392
1393                 core::stringw *txtLine = MultiLine ? &BrokenText[cursLine] : &Text;
1394                 s32 cPos = MultiLine ? CursorPos - BrokenTextPositions[cursLine] : CursorPos;
1395
1396                 s32 cStart = CurrentTextRect.UpperLeftCorner.X + HScrollPos +
1397                         font->getDimension(txtLine->subString(0, cPos).c_str()).Width;
1398
1399                 s32 cEnd = cStart + font->getDimension(L"_ ").Width;
1400
1401                 if (FrameRect.LowerRightCorner.X < cEnd)
1402                         HScrollPos = cEnd - FrameRect.LowerRightCorner.X;
1403                 else if (FrameRect.UpperLeftCorner.X > cStart)
1404                         HScrollPos = cStart - FrameRect.UpperLeftCorner.X;
1405                 else
1406                         HScrollPos = 0;
1407
1408                 // todo: adjust scrollbar
1409         }
1410
1411         // vertical scroll position
1412         if (FrameRect.LowerRightCorner.Y < CurrentTextRect.LowerRightCorner.Y + VScrollPos)
1413                 VScrollPos = CurrentTextRect.LowerRightCorner.Y - FrameRect.LowerRightCorner.Y + VScrollPos;
1414
1415         else if (FrameRect.UpperLeftCorner.Y > CurrentTextRect.UpperLeftCorner.Y + VScrollPos)
1416                 VScrollPos = CurrentTextRect.UpperLeftCorner.Y - FrameRect.UpperLeftCorner.Y + VScrollPos;
1417         else
1418                 VScrollPos = 0;
1419
1420         // todo: adjust scrollbar
1421 }
1422
1423 //! set text markers
1424 void intlGUIEditBox::setTextMarkers(s32 begin, s32 end)
1425 {
1426     if ( begin != MarkBegin || end != MarkEnd )
1427     {
1428         MarkBegin = begin;
1429         MarkEnd = end;
1430         sendGuiEvent(EGET_EDITBOX_MARKING_CHANGED);
1431     }
1432 }
1433
1434 //! send some gui event to parent
1435 void intlGUIEditBox::sendGuiEvent(EGUI_EVENT_TYPE type)
1436 {
1437         if ( Parent )
1438         {
1439         SEvent e;
1440         e.EventType = EET_GUI_EVENT;
1441         e.GUIEvent.Caller = this;
1442         e.GUIEvent.Element = 0;
1443         e.GUIEvent.EventType = type;
1444
1445         Parent->OnEvent(e);
1446         }
1447 }
1448
1449 //! Writes attributes of the element.
1450 void intlGUIEditBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
1451 {
1452         // IGUIEditBox::serializeAttributes(out,options);
1453
1454         out->addBool  ("OverrideColorEnabled",OverrideColorEnabled );
1455         out->addColor ("OverrideColor",       OverrideColor);
1456         // out->addFont("OverrideFont",OverrideFont);
1457         out->addInt   ("MaxChars",            Max);
1458         out->addBool  ("WordWrap",            WordWrap);
1459         out->addBool  ("MultiLine",           MultiLine);
1460         out->addBool  ("AutoScroll",          AutoScroll);
1461         out->addBool  ("PasswordBox",         PasswordBox);
1462         core::stringw ch = L" ";
1463         ch[0] = PasswordChar;
1464         out->addString("PasswordChar",        ch.c_str());
1465         out->addEnum  ("HTextAlign",          HAlign, GUIAlignmentNames);
1466         out->addEnum  ("VTextAlign",          VAlign, GUIAlignmentNames);
1467
1468         IGUIEditBox::serializeAttributes(out,options);
1469 }
1470
1471
1472 //! Reads attributes of the element
1473 void intlGUIEditBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
1474 {
1475         IGUIEditBox::deserializeAttributes(in,options);
1476
1477         setOverrideColor(in->getAttributeAsColor("OverrideColor"));
1478         enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled"));
1479         setMax(in->getAttributeAsInt("MaxChars"));
1480         setWordWrap(in->getAttributeAsBool("WordWrap"));
1481         setMultiLine(in->getAttributeAsBool("MultiLine"));
1482         setAutoScroll(in->getAttributeAsBool("AutoScroll"));
1483         core::stringw ch = in->getAttributeAsStringW("PasswordChar");
1484
1485         if (ch.empty())
1486                 setPasswordBox(in->getAttributeAsBool("PasswordBox"));
1487         else
1488                 setPasswordBox(in->getAttributeAsBool("PasswordBox"), ch[0]);
1489
1490         setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
1491                         (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
1492
1493         // setOverrideFont(in->getAttributeAsFont("OverrideFont"));
1494 }
1495
1496
1497 } // end namespace gui
1498 } // end namespace irr
1499
1500 #endif // _IRR_COMPILE_WITH_GUI_