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