Translated using Weblate (Lithuanian)
[oweals/minetest.git] / src / gui / 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 #include "IGUISkin.h"
36 #include "IGUIEnvironment.h"
37 #include "IGUIFont.h"
38 #include "IVideoDriver.h"
39 //#include "irrlicht/os.cpp"
40 #include "porting.h"
41 //#include "Keycodes.h"
42 #include "log.h"
43
44 /*
45         todo:
46         optional scrollbars
47         ctrl+left/right to select word
48         double click/ctrl click: word select + drag to select whole words, triple click to select line
49         optional? dragging selected text
50         numerical
51 */
52
53 namespace irr
54 {
55 namespace gui
56 {
57
58 //! constructor
59 intlGUIEditBox::intlGUIEditBox(const wchar_t* text, bool border,
60                 IGUIEnvironment* environment, IGUIElement* parent, s32 id,
61                 const core::rect<s32>& rectangle, bool writable, bool has_vscrollbar)
62         : IGUIEditBox(environment, parent, id, rectangle),
63         Border(border), FrameRect(rectangle),
64         m_scrollbar_width(0), m_vscrollbar(NULL), m_writable(writable)
65 {
66         #ifdef _DEBUG
67         setDebugName("intlintlGUIEditBox");
68         #endif
69
70         Text = text;
71
72         if (Environment)
73                 Operator = Environment->getOSOperator();
74
75         if (Operator)
76                 Operator->grab();
77
78         // this element can be tabbed to
79         setTabStop(true);
80         setTabOrder(-1);
81
82         IGUISkin *skin = 0;
83         if (Environment)
84                 skin = Environment->getSkin();
85         if (Border && skin)
86         {
87                 FrameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
88                 FrameRect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
89                 FrameRect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
90                 FrameRect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
91         }
92
93         if (skin && has_vscrollbar) {
94                 m_scrollbar_width = skin->getSize(gui::EGDS_SCROLLBAR_SIZE);
95
96                 if (m_scrollbar_width > 0) {
97                         createVScrollBar();
98                 }
99         }
100
101         breakText();
102
103         calculateScrollPos();
104         setWritable(writable);
105 }
106
107
108 //! destructor
109 intlGUIEditBox::~intlGUIEditBox()
110 {
111         if (OverrideFont)
112                 OverrideFont->drop();
113
114         if (Operator)
115                 Operator->drop();
116
117         if (m_vscrollbar)
118                 m_vscrollbar->drop();
119 }
120
121
122 //! Sets another skin independent font.
123 void intlGUIEditBox::setOverrideFont(IGUIFont* font)
124 {
125         if (OverrideFont == font)
126                 return;
127
128         if (OverrideFont)
129                 OverrideFont->drop();
130
131         OverrideFont = font;
132
133         if (OverrideFont)
134                 OverrideFont->grab();
135
136         breakText();
137 }
138
139 IGUIFont * intlGUIEditBox::getOverrideFont() const
140 {
141         return OverrideFont;
142 }
143
144 //! Get the font which is used right now for drawing
145 IGUIFont* intlGUIEditBox::getActiveFont() const
146 {
147         if ( OverrideFont )
148                 return OverrideFont;
149         IGUISkin* skin = Environment->getSkin();
150         if (skin)
151                 return skin->getFont();
152         return 0;
153 }
154
155 //! Sets another color for the text.
156 void intlGUIEditBox::setOverrideColor(video::SColor color)
157 {
158         OverrideColor = color;
159         OverrideColorEnabled = true;
160 }
161
162 video::SColor intlGUIEditBox::getOverrideColor() const
163 {
164         return OverrideColor;
165 }
166
167 //! Turns the border on or off
168 void intlGUIEditBox::setDrawBorder(bool border)
169 {
170         Border = border;
171 }
172
173 //! Sets whether to draw the background
174 void intlGUIEditBox::setDrawBackground(bool draw)
175 {
176 }
177
178 //! Sets if the text should use the overide color or the color in the gui skin.
179 void intlGUIEditBox::enableOverrideColor(bool enable)
180 {
181         OverrideColorEnabled = enable;
182 }
183
184 bool intlGUIEditBox::isOverrideColorEnabled() const
185 {
186         return OverrideColorEnabled;
187 }
188
189 //! Enables or disables word wrap
190 void intlGUIEditBox::setWordWrap(bool enable)
191 {
192         WordWrap = enable;
193         breakText();
194 }
195
196
197 void intlGUIEditBox::updateAbsolutePosition()
198 {
199     core::rect<s32> oldAbsoluteRect(AbsoluteRect);
200         IGUIElement::updateAbsolutePosition();
201         if ( oldAbsoluteRect != AbsoluteRect )
202         {
203         breakText();
204         }
205 }
206
207
208 //! Checks if word wrap is enabled
209 bool intlGUIEditBox::isWordWrapEnabled() const
210 {
211         return WordWrap;
212 }
213
214
215 //! Enables or disables newlines.
216 void intlGUIEditBox::setMultiLine(bool enable)
217 {
218         MultiLine = enable;
219 }
220
221
222 //! Checks if multi line editing is enabled
223 bool intlGUIEditBox::isMultiLineEnabled() const
224 {
225         return MultiLine;
226 }
227
228
229 void intlGUIEditBox::setPasswordBox(bool passwordBox, wchar_t passwordChar)
230 {
231         PasswordBox = passwordBox;
232         if (PasswordBox)
233         {
234                 PasswordChar = passwordChar;
235                 setMultiLine(false);
236                 setWordWrap(false);
237                 BrokenText.clear();
238         }
239 }
240
241
242 bool intlGUIEditBox::isPasswordBox() const
243 {
244         return PasswordBox;
245 }
246
247
248 //! Sets text justification
249 void intlGUIEditBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
250 {
251         HAlign = horizontal;
252         VAlign = vertical;
253 }
254
255
256 //! called if an event happened.
257 bool intlGUIEditBox::OnEvent(const SEvent& event)
258 {
259         if (IsEnabled)
260         {
261
262                 switch(event.EventType)
263                 {
264                 case EET_GUI_EVENT:
265                         if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
266                         {
267                                 if (event.GUIEvent.Caller == this)
268                                 {
269                                         MouseMarking = false;
270                                         setTextMarkers(0,0);
271                                 }
272                         }
273                         break;
274                 case EET_KEY_INPUT_EVENT:
275         {
276 #if (defined(__linux__) || defined(__FreeBSD__)) || defined(__DragonFly__)
277             // ################################################################
278                         // ValkaTR:
279             // This part is the difference from the original intlGUIEditBox
280             // It converts UTF-8 character into a UCS-2 (wchar_t)
281             wchar_t wc = L'_';
282             mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) );
283
284             //printf( "char: %lc (%u)  \r\n", wc, wc );
285
286             SEvent irrevent(event);
287             irrevent.KeyInput.Char = wc;
288             // ################################################################
289
290                         if (processKey(irrevent))
291                                 return true;
292 #else
293                         if (processKey(event))
294                                 return true;
295 #endif // defined(linux)
296
297                         break;
298         }
299                 case EET_MOUSE_INPUT_EVENT:
300                         if (processMouse(event))
301                                 return true;
302                         break;
303                 default:
304                         break;
305                 }
306         }
307
308         return IGUIElement::OnEvent(event);
309 }
310
311
312 bool intlGUIEditBox::processKey(const SEvent& event)
313 {
314         if (!event.KeyInput.PressedDown)
315                 return false;
316
317         bool textChanged = false;
318         s32 newMarkBegin = MarkBegin;
319         s32 newMarkEnd = MarkEnd;
320
321         // control shortcut handling
322
323         if (event.KeyInput.Control)
324         {
325                 // german backlash '\' entered with control + '?'
326                 if ( event.KeyInput.Char == '\\' )
327                 {
328                         inputChar(event.KeyInput.Char);
329                         return true;
330                 }
331
332                 switch(event.KeyInput.Key)
333                 {
334                 case KEY_KEY_A:
335                         // select all
336                         newMarkBegin = 0;
337                         newMarkEnd = Text.size();
338                         break;
339                 case KEY_KEY_C:
340                         // copy to clipboard
341                         if (!PasswordBox && Operator && MarkBegin != MarkEnd)
342                         {
343                                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
344                                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
345
346                                 core::stringc s;
347                                 s = Text.subString(realmbgn, realmend - realmbgn).c_str();
348                                 Operator->copyToClipboard(s.c_str());
349                         }
350                         break;
351                 case KEY_KEY_X:
352                         // cut to the clipboard
353                         if (!PasswordBox && Operator && MarkBegin != MarkEnd) {
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 && m_writable) {
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 || !m_writable)
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 || !m_writable)
634                         break;
635
636                 if (!Text.empty()) {
637                         core::stringw s;
638
639                         if (MarkBegin != MarkEnd)
640                         {
641                                 // delete marked text
642                                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
643                                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
644
645                                 s = Text.subString(0, realmbgn);
646                                 s.append( Text.subString(realmend, Text.size()-realmend) );
647                                 Text = s;
648
649                                 CursorPos = realmbgn;
650                         }
651                         else
652                         {
653                                 // delete text behind cursor
654                                 if (CursorPos>0)
655                                         s = Text.subString(0, CursorPos-1);
656                                 else
657                                         s = L"";
658                                 s.append( Text.subString(CursorPos, Text.size()-CursorPos) );
659                                 Text = s;
660                                 --CursorPos;
661                         }
662
663                         if (CursorPos < 0)
664                                 CursorPos = 0;
665                         BlinkStartTime = porting::getTimeMs();
666                         newMarkBegin = 0;
667                         newMarkEnd = 0;
668                         textChanged = true;
669                 }
670                 break;
671         case KEY_DELETE:
672                 if (!this->IsEnabled || !m_writable)
673                         break;
674
675                 if (!Text.empty()) {
676                         core::stringw s;
677
678                         if (MarkBegin != MarkEnd)
679                         {
680                                 // delete marked text
681                                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
682                                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
683
684                                 s = Text.subString(0, realmbgn);
685                                 s.append( Text.subString(realmend, Text.size()-realmend) );
686                                 Text = s;
687
688                                 CursorPos = realmbgn;
689                         }
690                         else
691                         {
692                                 // delete text before cursor
693                                 s = Text.subString(0, CursorPos);
694                                 s.append( Text.subString(CursorPos+1, Text.size()-CursorPos-1) );
695                                 Text = s;
696                         }
697
698                         if (CursorPos > (s32)Text.size())
699                                 CursorPos = (s32)Text.size();
700
701                         BlinkStartTime = porting::getTimeMs();
702                         newMarkBegin = 0;
703                         newMarkEnd = 0;
704                         textChanged = true;
705                 }
706                 break;
707
708         case KEY_ESCAPE:
709         case KEY_TAB:
710         case KEY_SHIFT:
711         case KEY_F1:
712         case KEY_F2:
713         case KEY_F3:
714         case KEY_F4:
715         case KEY_F5:
716         case KEY_F6:
717         case KEY_F7:
718         case KEY_F8:
719         case KEY_F9:
720         case KEY_F10:
721         case KEY_F11:
722         case KEY_F12:
723         case KEY_F13:
724         case KEY_F14:
725         case KEY_F15:
726         case KEY_F16:
727         case KEY_F17:
728         case KEY_F18:
729         case KEY_F19:
730         case KEY_F20:
731         case KEY_F21:
732         case KEY_F22:
733         case KEY_F23:
734         case KEY_F24:
735                 // ignore these keys
736                 return false;
737
738         default:
739                 inputChar(event.KeyInput.Char);
740                 return true;
741         }
742
743     // Set new text markers
744     setTextMarkers( newMarkBegin, newMarkEnd );
745
746         // break the text if it has changed
747         if (textChanged)
748         {
749                 breakText();
750                 sendGuiEvent(EGET_EDITBOX_CHANGED);
751         }
752
753         calculateScrollPos();
754
755         return true;
756 }
757
758
759 //! draws the element and its children
760 void intlGUIEditBox::draw()
761 {
762         if (!IsVisible)
763                 return;
764
765         const bool focus = Environment->hasFocus(this);
766
767         IGUISkin* skin = Environment->getSkin();
768         if (!skin)
769                 return;
770
771         FrameRect = AbsoluteRect;
772
773         // draw the border
774
775         if (Border)
776         {
777                 if (m_writable) {
778                         skin->draw3DSunkenPane(this, skin->getColor(EGDC_WINDOW),
779                                 false, true, FrameRect, &AbsoluteClippingRect);
780                 }
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
788         updateVScrollBar();
789         core::rect<s32> localClipRect = FrameRect;
790         localClipRect.clipAgainst(AbsoluteClippingRect);
791
792         // draw the text
793
794         IGUIFont* font = OverrideFont;
795         if (!OverrideFont)
796                 font = skin->getFont();
797
798         s32 cursorLine = 0;
799         s32 charcursorpos = 0;
800
801         if (font)
802         {
803                 if (LastBreakFont != font)
804                 {
805                         breakText();
806                 }
807
808                 // calculate cursor pos
809
810                 core::stringw *txtLine = &Text;
811                 s32 startPos = 0;
812
813                 core::stringw s, s2;
814
815                 // get mark position
816                 const bool ml = (!PasswordBox && (WordWrap || MultiLine));
817                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
818                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
819                 const s32 hlineStart = ml ? getLineFromPos(realmbgn) : 0;
820                 const s32 hlineCount = ml ? getLineFromPos(realmend) - hlineStart + 1 : 1;
821                 const s32 lineCount = ml ? BrokenText.size() : 1;
822
823                 // Save the override color information.
824                 // Then, alter it if the edit box is disabled.
825                 const bool prevOver = OverrideColorEnabled;
826                 const video::SColor prevColor = OverrideColor;
827
828                 if (!Text.empty()) {
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.empty())
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 (m_writable) {
941                         if (focus && (porting::getTimeMs() - BlinkStartTime) % 700 < 350) {
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
952         // draw children
953         IGUIElement::draw();
954 }
955
956
957 //! Sets the new caption of this element.
958 void intlGUIEditBox::setText(const wchar_t* text)
959 {
960         Text = text;
961         if (u32(CursorPos) > Text.size())
962                 CursorPos = Text.size();
963         HScrollPos = 0;
964         breakText();
965 }
966
967
968 //! Enables or disables automatic scrolling with cursor position
969 //! \param enable: If set to true, the text will move around with the cursor position
970 void intlGUIEditBox::setAutoScroll(bool enable)
971 {
972         AutoScroll = enable;
973 }
974
975
976 //! Checks to see if automatic scrolling is enabled
977 //! \return true if automatic scrolling is enabled, false if not
978 bool intlGUIEditBox::isAutoScrollEnabled() const
979 {
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                                 return false;
1066                         }
1067
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                 break;
1082         case EMIE_MOUSE_WHEEL:
1083                 if (m_vscrollbar && m_vscrollbar->isVisible()) {
1084                         s32 pos = m_vscrollbar->getPos();
1085                         s32 step = m_vscrollbar->getSmallStep();
1086                         m_vscrollbar->setPos(pos - event.MouseInput.Wheel * step);
1087                 }
1088                 break;
1089         default:
1090                 break;
1091         }
1092
1093         return false;
1094 }
1095
1096
1097 s32 intlGUIEditBox::getCursorPos(s32 x, s32 y)
1098 {
1099         IGUIFont* font = OverrideFont;
1100         IGUISkin* skin = Environment->getSkin();
1101         if (!OverrideFont)
1102                 font = skin->getFont();
1103
1104         const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1;
1105
1106         core::stringw *txtLine = NULL;
1107         s32 startPos = 0;
1108         u32 curr_line_idx = 0;
1109         x += 3;
1110
1111         for (; curr_line_idx < lineCount; ++curr_line_idx) {
1112                 setTextRect(curr_line_idx);
1113                 if (curr_line_idx == 0 && y < CurrentTextRect.UpperLeftCorner.Y)
1114                         y = CurrentTextRect.UpperLeftCorner.Y;
1115                 if (curr_line_idx == lineCount - 1 && y > CurrentTextRect.LowerRightCorner.Y)
1116                         y = CurrentTextRect.LowerRightCorner.Y;
1117
1118                 // is it inside this region?
1119                 if (y >= CurrentTextRect.UpperLeftCorner.Y && y <= CurrentTextRect.LowerRightCorner.Y) {
1120                         // we've found the clicked line
1121                         txtLine = (WordWrap || MultiLine) ? &BrokenText[curr_line_idx] : &Text;
1122                         startPos = (WordWrap || MultiLine) ? BrokenTextPositions[curr_line_idx] : 0;
1123                         break;
1124                 }
1125         }
1126
1127         if (x < CurrentTextRect.UpperLeftCorner.X)
1128                 x = CurrentTextRect.UpperLeftCorner.X;
1129         else if (x > CurrentTextRect.LowerRightCorner.X)
1130                 x = CurrentTextRect.LowerRightCorner.X;
1131
1132         s32 idx = font->getCharacterFromPos(txtLine->c_str(), x - CurrentTextRect.UpperLeftCorner.X);
1133         // Special handling for last line, if we are on limits, add 1 extra shift because idx
1134         // will be the last char, not null char of the wstring
1135         if (curr_line_idx == lineCount - 1 && x == CurrentTextRect.LowerRightCorner.X)
1136                 idx++;
1137
1138         return rangelim(idx + startPos, 0, S32_MAX);
1139 }
1140
1141
1142 //! Breaks the single text line.
1143 void intlGUIEditBox::breakText()
1144 {
1145         IGUISkin* skin = Environment->getSkin();
1146
1147         if ((!WordWrap && !MultiLine) || !skin)
1148                 return;
1149
1150         BrokenText.clear(); // need to reallocate :/
1151         BrokenTextPositions.set_used(0);
1152
1153         IGUIFont* font = OverrideFont;
1154         if (!OverrideFont)
1155                 font = skin->getFont();
1156
1157         if (!font)
1158                 return;
1159
1160         LastBreakFont = font;
1161
1162         core::stringw line;
1163         core::stringw word;
1164         core::stringw whitespace;
1165         s32 lastLineStart = 0;
1166         s32 size = Text.size();
1167         s32 length = 0;
1168         s32 elWidth = RelativeRect.getWidth() - 6;
1169         wchar_t c;
1170
1171         for (s32 i=0; i<size; ++i)
1172         {
1173                 c = Text[i];
1174                 bool lineBreak = false;
1175
1176                 if (c == L'\r') // Mac or Windows breaks
1177                 {
1178                         lineBreak = true;
1179                         c = ' ';
1180                         if (Text[i+1] == L'\n') // Windows breaks
1181                         {
1182                                 Text.erase(i+1);
1183                                 --size;
1184                         }
1185                 }
1186                 else if (c == L'\n') // Unix breaks
1187                 {
1188                         lineBreak = true;
1189                         c = ' ';
1190                 }
1191
1192                 // don't break if we're not a multi-line edit box
1193                 if (!MultiLine)
1194                         lineBreak = false;
1195
1196                 if (c == L' ' || c == 0 || i == (size-1))
1197                 {
1198                         if (!word.empty()) {
1199                                 // here comes the next whitespace, look if
1200                                 // we can break the last word to the next line.
1201                                 s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
1202                                 s32 worldlgth = font->getDimension(word.c_str()).Width;
1203
1204                                 if (WordWrap && length + worldlgth + whitelgth > elWidth)
1205                                 {
1206                                         // break to next line
1207                                         length = worldlgth;
1208                                         BrokenText.push_back(line);
1209                                         BrokenTextPositions.push_back(lastLineStart);
1210                                         lastLineStart = i - (s32)word.size();
1211                                         line = word;
1212                                 }
1213                                 else
1214                                 {
1215                                         // add word to line
1216                                         line += whitespace;
1217                                         line += word;
1218                                         length += whitelgth + worldlgth;
1219                                 }
1220
1221                                 word = L"";
1222                                 whitespace = L"";
1223                         }
1224
1225                         whitespace += c;
1226
1227                         // compute line break
1228                         if (lineBreak)
1229                         {
1230                                 line += whitespace;
1231                                 line += word;
1232                                 BrokenText.push_back(line);
1233                                 BrokenTextPositions.push_back(lastLineStart);
1234                                 lastLineStart = i+1;
1235                                 line = L"";
1236                                 word = L"";
1237                                 whitespace = L"";
1238                                 length = 0;
1239                         }
1240                 }
1241                 else
1242                 {
1243                         // yippee this is a word..
1244                         word += c;
1245                 }
1246         }
1247
1248         line += whitespace;
1249         line += word;
1250         BrokenText.push_back(line);
1251         BrokenTextPositions.push_back(lastLineStart);
1252 }
1253
1254
1255 void intlGUIEditBox::setTextRect(s32 line)
1256 {
1257         core::dimension2du d;
1258
1259         IGUISkin* skin = Environment->getSkin();
1260         if (!skin)
1261                 return;
1262
1263         IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont();
1264
1265         if (!font)
1266                 return;
1267
1268         // get text dimension
1269         const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1;
1270         if (WordWrap || MultiLine)
1271         {
1272                 d = font->getDimension(BrokenText[line].c_str());
1273         }
1274         else
1275         {
1276                 d = font->getDimension(Text.c_str());
1277                 d.Height = AbsoluteRect.getHeight();
1278         }
1279         d.Height += font->getKerningHeight();
1280
1281         // justification
1282         switch (HAlign)
1283         {
1284         case EGUIA_CENTER:
1285                 // align to h centre
1286                 CurrentTextRect.UpperLeftCorner.X = (FrameRect.getWidth()/2) - (d.Width/2);
1287                 CurrentTextRect.LowerRightCorner.X = (FrameRect.getWidth()/2) + (d.Width/2);
1288                 break;
1289         case EGUIA_LOWERRIGHT:
1290                 // align to right edge
1291                 CurrentTextRect.UpperLeftCorner.X = FrameRect.getWidth() - d.Width;
1292                 CurrentTextRect.LowerRightCorner.X = FrameRect.getWidth();
1293                 break;
1294         default:
1295                 // align to left edge
1296                 CurrentTextRect.UpperLeftCorner.X = 0;
1297                 CurrentTextRect.LowerRightCorner.X = d.Width;
1298
1299         }
1300
1301         switch (VAlign)
1302         {
1303         case EGUIA_CENTER:
1304                 // align to v centre
1305                 CurrentTextRect.UpperLeftCorner.Y =
1306                         (FrameRect.getHeight()/2) - (lineCount*d.Height)/2 + d.Height*line;
1307                 break;
1308         case EGUIA_LOWERRIGHT:
1309                 // align to bottom edge
1310                 CurrentTextRect.UpperLeftCorner.Y =
1311                         FrameRect.getHeight() - lineCount*d.Height + d.Height*line;
1312                 break;
1313         default:
1314                 // align to top edge
1315                 CurrentTextRect.UpperLeftCorner.Y = d.Height*line;
1316                 break;
1317         }
1318
1319         CurrentTextRect.UpperLeftCorner.X  -= HScrollPos;
1320         CurrentTextRect.LowerRightCorner.X -= HScrollPos;
1321         CurrentTextRect.UpperLeftCorner.Y  -= VScrollPos;
1322         CurrentTextRect.LowerRightCorner.Y = CurrentTextRect.UpperLeftCorner.Y + d.Height;
1323
1324         CurrentTextRect += FrameRect.UpperLeftCorner;
1325
1326 }
1327
1328
1329 s32 intlGUIEditBox::getLineFromPos(s32 pos)
1330 {
1331         if (!WordWrap && !MultiLine)
1332                 return 0;
1333
1334         s32 i=0;
1335         while (i < (s32)BrokenTextPositions.size())
1336         {
1337                 if (BrokenTextPositions[i] > pos)
1338                         return i-1;
1339                 ++i;
1340         }
1341         return (s32)BrokenTextPositions.size() - 1;
1342 }
1343
1344
1345 void intlGUIEditBox::inputChar(wchar_t c)
1346 {
1347         if (!IsEnabled || !m_writable)
1348                 return;
1349
1350         if (c != 0)
1351         {
1352                 if (Text.size() < Max || Max == 0)
1353                 {
1354                         core::stringw s;
1355
1356                         if (MarkBegin != MarkEnd)
1357                         {
1358                                 // replace marked text
1359                                 const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
1360                                 const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
1361
1362                                 s = Text.subString(0, realmbgn);
1363                                 s.append(c);
1364                                 s.append( Text.subString(realmend, Text.size()-realmend) );
1365                                 Text = s;
1366                                 CursorPos = realmbgn+1;
1367                         }
1368                         else
1369                         {
1370                                 // add new character
1371                                 s = Text.subString(0, CursorPos);
1372                                 s.append(c);
1373                                 s.append( Text.subString(CursorPos, Text.size()-CursorPos) );
1374                                 Text = s;
1375                                 ++CursorPos;
1376                         }
1377
1378                         BlinkStartTime = porting::getTimeMs();
1379                         setTextMarkers(0, 0);
1380                 }
1381         }
1382         breakText();
1383         sendGuiEvent(EGET_EDITBOX_CHANGED);
1384         calculateScrollPos();
1385 }
1386
1387
1388 void intlGUIEditBox::calculateScrollPos()
1389 {
1390         if (!AutoScroll)
1391                 return;
1392
1393         // calculate horizontal scroll position
1394         s32 cursLine = getLineFromPos(CursorPos);
1395         setTextRect(cursLine);
1396
1397         // don't do horizontal scrolling when wordwrap is enabled.
1398         if (!WordWrap)
1399         {
1400                 // get cursor position
1401                 IGUISkin* skin = Environment->getSkin();
1402                 if (!skin)
1403                         return;
1404                 IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont();
1405                 if (!font)
1406                         return;
1407
1408                 core::stringw *txtLine = MultiLine ? &BrokenText[cursLine] : &Text;
1409                 s32 cPos = MultiLine ? CursorPos - BrokenTextPositions[cursLine] : CursorPos;
1410
1411                 s32 cStart = CurrentTextRect.UpperLeftCorner.X + HScrollPos +
1412                         font->getDimension(txtLine->subString(0, cPos).c_str()).Width;
1413
1414                 s32 cEnd = cStart + font->getDimension(L"_ ").Width;
1415
1416                 if (FrameRect.LowerRightCorner.X < cEnd)
1417                         HScrollPos = cEnd - FrameRect.LowerRightCorner.X;
1418                 else if (FrameRect.UpperLeftCorner.X > cStart)
1419                         HScrollPos = cStart - FrameRect.UpperLeftCorner.X;
1420                 else
1421                         HScrollPos = 0;
1422
1423                 // todo: adjust scrollbar
1424         }
1425
1426         if (!WordWrap && !MultiLine)
1427                 return;
1428
1429         // vertical scroll position
1430         if (FrameRect.LowerRightCorner.Y < CurrentTextRect.LowerRightCorner.Y)
1431                 VScrollPos += CurrentTextRect.LowerRightCorner.Y - FrameRect.LowerRightCorner.Y; // scrolling downwards
1432         else if (FrameRect.UpperLeftCorner.Y > CurrentTextRect.UpperLeftCorner.Y)
1433                 VScrollPos += CurrentTextRect.UpperLeftCorner.Y - FrameRect.UpperLeftCorner.Y; // scrolling upwards
1434
1435         // todo: adjust scrollbar
1436         if (m_vscrollbar)
1437                 m_vscrollbar->setPos(VScrollPos);
1438 }
1439
1440 //! set text markers
1441 void intlGUIEditBox::setTextMarkers(s32 begin, s32 end)
1442 {
1443     if ( begin != MarkBegin || end != MarkEnd )
1444     {
1445         MarkBegin = begin;
1446         MarkEnd = end;
1447         sendGuiEvent(EGET_EDITBOX_MARKING_CHANGED);
1448     }
1449 }
1450
1451 //! send some gui event to parent
1452 void intlGUIEditBox::sendGuiEvent(EGUI_EVENT_TYPE type)
1453 {
1454         if ( Parent )
1455         {
1456         SEvent e;
1457         e.EventType = EET_GUI_EVENT;
1458         e.GUIEvent.Caller = this;
1459         e.GUIEvent.Element = 0;
1460         e.GUIEvent.EventType = type;
1461
1462         Parent->OnEvent(e);
1463         }
1464 }
1465
1466 //! Create a vertical scrollbar
1467 void intlGUIEditBox::createVScrollBar()
1468 {
1469         s32 fontHeight = 1;
1470
1471         if (OverrideFont) {
1472                 fontHeight = OverrideFont->getDimension(L"").Height;
1473         } else {
1474                 if (IGUISkin* skin = Environment->getSkin()) {
1475                         if (IGUIFont* font = skin->getFont()) {
1476                                 fontHeight = font->getDimension(L"").Height;
1477                         }
1478                 }
1479         }
1480
1481         RelativeRect.LowerRightCorner.X -= m_scrollbar_width + 4;
1482
1483         irr::core::rect<s32> scrollbarrect = FrameRect;
1484         scrollbarrect.UpperLeftCorner.X += FrameRect.getWidth() - m_scrollbar_width;
1485         m_vscrollbar = new GUIScrollBar(Environment, getParent(), -1,
1486                         scrollbarrect, false, true);
1487
1488         m_vscrollbar->setVisible(false);
1489         m_vscrollbar->setSmallStep(3 * fontHeight);
1490         m_vscrollbar->setLargeStep(10 * fontHeight);
1491 }
1492
1493 //! Update the vertical scrollbar (visibilty & scroll position)
1494 void intlGUIEditBox::updateVScrollBar()
1495 {
1496         if (!m_vscrollbar)
1497                 return;
1498
1499         // OnScrollBarChanged(...)
1500         if (m_vscrollbar->getPos() != VScrollPos) {
1501                 s32 deltaScrollY = m_vscrollbar->getPos() - VScrollPos;
1502                 CurrentTextRect.UpperLeftCorner.Y -= deltaScrollY;
1503                 CurrentTextRect.LowerRightCorner.Y -= deltaScrollY;
1504
1505                 s32 scrollymax = getTextDimension().Height - FrameRect.getHeight();
1506                 if (scrollymax != m_vscrollbar->getMax()) {
1507                         // manage a newline or a deleted line
1508                         m_vscrollbar->setMax(scrollymax);
1509                         m_vscrollbar->setPageSize(s32(getTextDimension().Height));
1510                         calculateScrollPos();
1511                 } else {
1512                         // manage a newline or a deleted line
1513                         VScrollPos = m_vscrollbar->getPos();
1514                 }
1515         }
1516
1517         // check if a vertical scrollbar is needed ?
1518         if (getTextDimension().Height > (u32) FrameRect.getHeight()) {
1519                 s32 scrollymax = getTextDimension().Height - FrameRect.getHeight();
1520                 if (scrollymax != m_vscrollbar->getMax()) {
1521                         m_vscrollbar->setMax(scrollymax);
1522                         m_vscrollbar->setPageSize(s32(getTextDimension().Height));
1523                 }
1524
1525                 if (!m_vscrollbar->isVisible() && MultiLine) {
1526                         AbsoluteRect.LowerRightCorner.X -= m_scrollbar_width;
1527
1528                         m_vscrollbar->setVisible(true);
1529                 }
1530         } else {
1531                 if (m_vscrollbar->isVisible()) {
1532                         AbsoluteRect.LowerRightCorner.X += m_scrollbar_width;
1533
1534                         VScrollPos = 0;
1535                         m_vscrollbar->setPos(0);
1536                         m_vscrollbar->setMax(1);
1537                         m_vscrollbar->setPageSize(s32(getTextDimension().Height));
1538                         m_vscrollbar->setVisible(false);
1539                 }
1540         }
1541 }
1542
1543 void intlGUIEditBox::setWritable(bool can_write_text)
1544 {
1545         m_writable = can_write_text;
1546 }
1547
1548 //! Writes attributes of the element.
1549 void intlGUIEditBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
1550 {
1551         // IGUIEditBox::serializeAttributes(out,options);
1552
1553         out->addBool  ("OverrideColorEnabled",OverrideColorEnabled );
1554         out->addColor ("OverrideColor",       OverrideColor);
1555         // out->addFont("OverrideFont",OverrideFont);
1556         out->addInt   ("MaxChars",            Max);
1557         out->addBool  ("WordWrap",            WordWrap);
1558         out->addBool  ("MultiLine",           MultiLine);
1559         out->addBool  ("AutoScroll",          AutoScroll);
1560         out->addBool  ("PasswordBox",         PasswordBox);
1561         core::stringw ch = L" ";
1562         ch[0] = PasswordChar;
1563         out->addString("PasswordChar",        ch.c_str());
1564         out->addEnum  ("HTextAlign",          HAlign, GUIAlignmentNames);
1565         out->addEnum  ("VTextAlign",          VAlign, GUIAlignmentNames);
1566         out->addBool  ("Writable",            m_writable);
1567
1568         IGUIEditBox::serializeAttributes(out,options);
1569 }
1570
1571
1572 //! Reads attributes of the element
1573 void intlGUIEditBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
1574 {
1575         IGUIEditBox::deserializeAttributes(in,options);
1576
1577         setOverrideColor(in->getAttributeAsColor("OverrideColor"));
1578         enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled"));
1579         setMax(in->getAttributeAsInt("MaxChars"));
1580         setWordWrap(in->getAttributeAsBool("WordWrap"));
1581         setMultiLine(in->getAttributeAsBool("MultiLine"));
1582         setAutoScroll(in->getAttributeAsBool("AutoScroll"));
1583         core::stringw ch = in->getAttributeAsStringW("PasswordChar");
1584
1585         if (ch.empty())
1586                 setPasswordBox(in->getAttributeAsBool("PasswordBox"));
1587         else
1588                 setPasswordBox(in->getAttributeAsBool("PasswordBox"), ch[0]);
1589
1590         setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
1591                         (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
1592
1593         setWritable(in->getAttributeAsBool("Writable"));
1594         // setOverrideFont(in->getAttributeAsFont("OverrideFont"));
1595 }
1596
1597
1598 } // end namespace gui
1599 } // end namespace irr