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