LCOV - code coverage report
Current view: top level - src - intlGUIEditBox.cpp (source / functions) Hit Total Coverage
Test: report Lines: 157 723 21.7 %
Date: 2015-07-11 18:23:49 Functions: 11 44 25.0 %

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

Generated by: LCOV version 1.11