FormSpec : Add an auto vertical scrollbar to the textarea
authoradelcoding1 <mustapha.tachouct@actionware.net>
Sat, 18 Feb 2017 19:40:37 +0000 (11:40 -0800)
committerLoic Blot <loic.blot@unix-experience.fr>
Mon, 9 Oct 2017 06:11:00 +0000 (08:11 +0200)
build/android/jni/Android.mk
doc/lua_api.txt
src/CMakeLists.txt
src/guiEditBoxWithScrollbar.cpp [new file with mode: 0644]
src/guiEditBoxWithScrollbar.h [new file with mode: 0644]
src/guiFormSpecMenu.cpp
src/intlGUIEditBox.cpp
src/intlGUIEditBox.h

index 889c24776750c1968dc72eb7ba999bb9fd91218a..854ab75a713f9042e0ad3b55e0b2fd17bcb6c0d6 100644 (file)
@@ -149,6 +149,7 @@ LOCAL_SRC_FILES := \
                jni/src/genericobject.cpp                 \
                jni/src/gettext.cpp                       \
                jni/src/guiChatConsole.cpp                \
+               jni/src/guiEditBoxWithScrollbar.cpp       \
                jni/src/guiEngine.cpp                     \
                jni/src/guiPathSelectMenu.cpp             \
                jni/src/guiFormSpecMenu.cpp               \
index d9e8585299b5d593e4e731ea5d21e9c9b1c7e5d9..c29abdf9c60d07873abc574bc4746ff5c31b5c78 100644 (file)
@@ -1918,8 +1918,9 @@ examples.
 * if <close_on_enter> is false, pressing enter in the field will submit the form but not close it
 * defaults to true when not specified (ie: no tag for a field)
 
-#### `textarea[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]`
+#### `textarea[<X>,<Y>;<W>,<H>;<name>;<label>;<default>;<scrollbar>]`
 * Same as fields above, but with multi-line input
+* if <scrollbar> is true an auto vertical scrollbar is added
 
 #### `label[<X>,<Y>;<label>]`
 * `x` and `y` work as per field
index d82887b380e1b5e4515a9f9a86924a4b1357dc56..f836a9f66f61032e0e33eb4f61b2ed36eaddcad4 100644 (file)
@@ -511,6 +511,7 @@ set(client_SRCS
        fontengine.cpp
        game.cpp
        guiChatConsole.cpp
+       guiEditBoxWithScrollbar.cpp
        guiEngine.cpp
        guiPathSelectMenu.cpp
        guiFormSpecMenu.cpp
diff --git a/src/guiEditBoxWithScrollbar.cpp b/src/guiEditBoxWithScrollbar.cpp
new file mode 100644 (file)
index 0000000..a27a772
--- /dev/null
@@ -0,0 +1,1524 @@
+// Copyright (C) 2002-2012 Nikolaus Gebhardt
+// Modified by Mustapha T.
+// This file is part of the "Irrlicht Engine".
+// For conditions of distribution and use, see copyright notice in irrlicht.h
+
+#include "guiEditBoxWithScrollbar.h"
+
+#include "IGUISkin.h"
+#include "IGUIEnvironment.h"
+#include "IGUIFont.h"
+#include "IVideoDriver.h"
+#include "rect.h"
+#include "porting.h"
+#include "Keycodes.h"
+
+
+/*
+todo:
+optional scrollbars [done]
+ctrl+left/right to select word
+double click/ctrl click: word select + drag to select whole words, triple click to select line
+optional? dragging selected text
+numerical
+*/
+
+
+//! constructor
+GUIEditBoxWithScrollBar::GUIEditBoxWithScrollBar(const wchar_t* text, bool border,
+       IGUIEnvironment* environment, IGUIElement* parent, s32 id,
+       const core::rect<s32>& rectangle, bool writable, bool has_vscrollbar)
+       : IGUIEditBox(environment, parent, id, rectangle), m_mouse_marking(false),
+       m_border(border), m_background(true), m_override_color_enabled(false), m_mark_begin(0), m_mark_end(0),
+       m_override_color(video::SColor(101, 255, 255, 255)), m_override_font(0), m_last_break_font(0),
+       m_operator(0), m_blink_start_time(0), m_cursor_pos(0), m_hscroll_pos(0), m_vscroll_pos(0), m_max(0),
+       m_word_wrap(false), m_multiline(false), m_autoscroll(true), m_passwordbox(false),
+       m_passwordchar(L'*'), m_halign(EGUIA_UPPERLEFT), m_valign(EGUIA_CENTER),
+       m_current_text_rect(0, 0, 1, 1), m_frame_rect(rectangle),
+       m_scrollbar_width(0), m_vscrollbar(NULL), m_writable(writable),
+       m_bg_color_used(false)
+{
+#ifdef _DEBUG
+       setDebugName("GUIEditBoxWithScrollBar");
+#endif
+
+
+       Text = text;
+
+       if (Environment)
+               m_operator = Environment->getOSOperator();
+
+       if (m_operator)
+               m_operator->grab();
+
+       // this element can be tabbed to
+       setTabStop(true);
+       setTabOrder(-1);
+
+       if (has_vscrollbar) {
+               createVScrollBar();
+       }
+
+       calculateFrameRect();
+       breakText();
+
+       calculateScrollPos();
+       setWritable(writable);
+}
+
+
+//! destructor
+GUIEditBoxWithScrollBar::~GUIEditBoxWithScrollBar()
+{
+       if (m_override_font)
+               m_override_font->drop();
+
+       if (m_operator)
+               m_operator->drop();
+
+       m_vscrollbar->remove();
+}
+
+
+//! Sets another skin independent font.
+void GUIEditBoxWithScrollBar::setOverrideFont(IGUIFont* font)
+{
+       if (m_override_font == font)
+               return;
+
+       if (m_override_font)
+               m_override_font->drop();
+
+       m_override_font = font;
+
+       if (m_override_font)
+               m_override_font->grab();
+
+       breakText();
+}
+
+//! Gets the override font (if any)
+IGUIFont * GUIEditBoxWithScrollBar::getOverrideFont() const
+{
+       return m_override_font;
+}
+
+//! Get the font which is used right now for drawing
+IGUIFont* GUIEditBoxWithScrollBar::getActiveFont() const
+{
+       if (m_override_font)
+               return m_override_font;
+       IGUISkin* skin = Environment->getSkin();
+       if (skin)
+               return skin->getFont();
+       return 0;
+}
+
+//! Sets another color for the text.
+void GUIEditBoxWithScrollBar::setOverrideColor(video::SColor color)
+{
+       m_override_color = color;
+       m_override_color_enabled = true;
+}
+
+
+video::SColor GUIEditBoxWithScrollBar::getOverrideColor() const
+{
+       return m_override_color;
+}
+
+
+//! Turns the border on or off
+void GUIEditBoxWithScrollBar::setDrawBorder(bool border)
+{
+       border = border;
+}
+
+//! Sets whether to draw the background
+void GUIEditBoxWithScrollBar::setDrawBackground(bool draw)
+{
+       m_background = draw;
+}
+
+//! Sets if the text should use the overide color or the color in the gui skin.
+void GUIEditBoxWithScrollBar::enableOverrideColor(bool enable)
+{
+       m_override_color_enabled = enable;
+}
+
+bool GUIEditBoxWithScrollBar::isOverrideColorEnabled() const
+{
+       _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
+       return m_override_color_enabled;
+}
+
+//! Enables or disables word wrap
+void GUIEditBoxWithScrollBar::setWordWrap(bool enable)
+{
+       m_word_wrap = enable;
+       breakText();
+}
+
+
+void GUIEditBoxWithScrollBar::updateAbsolutePosition()
+{
+       core::rect<s32> old_absolute_rect(AbsoluteRect);
+       IGUIElement::updateAbsolutePosition();
+       if (old_absolute_rect != AbsoluteRect) {
+               calculateFrameRect();
+               breakText();
+               calculateScrollPos();
+       }
+}
+
+//! Checks if word wrap is enabled
+bool GUIEditBoxWithScrollBar::isWordWrapEnabled() const
+{
+       _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
+       return m_word_wrap;
+}
+
+
+//! Enables or disables newlines.
+void GUIEditBoxWithScrollBar::setMultiLine(bool enable)
+{
+       m_multiline = enable;
+}
+
+
+//! Checks if multi line editing is enabled
+bool GUIEditBoxWithScrollBar::isMultiLineEnabled() const
+{
+       _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
+       return m_multiline;
+}
+
+
+void GUIEditBoxWithScrollBar::setPasswordBox(bool password_box, wchar_t password_char)
+{
+       m_passwordbox = password_box;
+       if (m_passwordbox) {
+               m_passwordchar = password_char;
+               setMultiLine(false);
+               setWordWrap(false);
+               m_broken_text.clear();
+       }
+}
+
+
+bool GUIEditBoxWithScrollBar::isPasswordBox() const
+{
+       _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
+       return m_passwordbox;
+}
+
+
+//! Sets text justification
+void GUIEditBoxWithScrollBar::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
+{
+       m_halign = horizontal;
+       m_valign = vertical;
+}
+
+
+//! called if an event happened.
+bool GUIEditBoxWithScrollBar::OnEvent(const SEvent& event)
+{
+       if (isEnabled()) {
+               switch (event.EventType)
+               {
+               case EET_GUI_EVENT:
+                       if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) {
+                               if (event.GUIEvent.Caller == this) {
+                                       m_mouse_marking = false;
+                                       setTextMarkers(0, 0);
+                               }
+                       }
+                       break;
+               case EET_KEY_INPUT_EVENT:
+                       if (processKey(event))
+                               return true;
+                       break;
+               case EET_MOUSE_INPUT_EVENT:
+                       if (processMouse(event))
+                               return true;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return IGUIElement::OnEvent(event);
+}
+
+
+bool GUIEditBoxWithScrollBar::processKey(const SEvent& event)
+{
+       if (!m_writable) {
+               return false;
+       }
+       
+       if (!event.KeyInput.PressedDown)
+               return false;
+
+       bool text_changed = false;
+       s32 new_mark_begin = m_mark_begin;
+       s32 new_mark_end = m_mark_end;
+
+       // control shortcut handling
+
+       if (event.KeyInput.Control) {
+
+               // german backlash '\' entered with control + '?'
+               if (event.KeyInput.Char == '\\') {
+                       inputChar(event.KeyInput.Char);
+                       return true;
+               }
+
+               switch (event.KeyInput.Key) {
+               case KEY_KEY_A:
+                       // select all
+                       new_mark_begin = 0;
+                       new_mark_end = Text.size();
+                       break;
+               case KEY_KEY_C:
+                       // copy to clipboard
+                       if (!m_passwordbox && m_operator && m_mark_begin != m_mark_end)
+                       {
+                               const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
+                               const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
+
+                               core::stringc s;
+                               s = Text.subString(realmbgn, realmend - realmbgn).c_str();
+                               m_operator->copyToClipboard(s.c_str());
+                       }
+                       break;
+               case KEY_KEY_X:
+                       // cut to the clipboard
+                       if (!m_passwordbox && m_operator && m_mark_begin != m_mark_end) {
+                               const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
+                               const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
+
+                               // copy
+                               core::stringc sc;
+                               sc = Text.subString(realmbgn, realmend - realmbgn).c_str();
+                               m_operator->copyToClipboard(sc.c_str());
+
+                               if (isEnabled())
+                               {
+                                       // delete
+                                       core::stringw s;
+                                       s = Text.subString(0, realmbgn);
+                                       s.append(Text.subString(realmend, Text.size() - realmend));
+                                       Text = s;
+
+                                       m_cursor_pos = realmbgn;
+                                       new_mark_begin = 0;
+                                       new_mark_end = 0;
+                                       text_changed = true;
+                               }
+                       }
+                       break;
+               case KEY_KEY_V:
+                       if (!isEnabled())
+                               break;
+
+                       // paste from the clipboard
+                       if (m_operator) {
+                               const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
+                               const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
+
+                               // add new character
+                               const c8* p = m_operator->getTextFromClipboard();
+                               if (p) {
+                                       if (m_mark_begin == m_mark_end) {
+                                               // insert text
+                                               core::stringw s = Text.subString(0, m_cursor_pos);
+                                               s.append(p);
+                                               s.append(Text.subString(m_cursor_pos, Text.size() - m_cursor_pos));
+
+                                               if (!m_max || s.size() <= m_max) // thx to Fish FH for fix
+                                               {
+                                                       Text = s;
+                                                       s = p;
+                                                       m_cursor_pos += s.size();
+                                               }
+                                       } else {
+                                               // replace text
+
+                                               core::stringw s = Text.subString(0, realmbgn);
+                                               s.append(p);
+                                               s.append(Text.subString(realmend, Text.size() - realmend));
+
+                                               if (!m_max || s.size() <= m_max)  // thx to Fish FH for fix
+                                               {
+                                                       Text = s;
+                                                       s = p;
+                                                       m_cursor_pos = realmbgn + s.size();
+                                               }
+                                       }
+                               }
+
+                               new_mark_begin = 0;
+                               new_mark_end = 0;
+                               text_changed = true;
+                       }
+                       break;
+               case KEY_HOME:
+                       // move/highlight to start of text
+                       if (event.KeyInput.Shift) {
+                               new_mark_end = m_cursor_pos;
+                               new_mark_begin = 0;
+                               m_cursor_pos = 0;
+                       } else {
+                               m_cursor_pos = 0;
+                               new_mark_begin = 0;
+                               new_mark_end = 0;
+                       }
+                       break;
+               case KEY_END:
+                       // move/highlight to end of text
+                       if (event.KeyInput.Shift) {
+                               new_mark_begin = m_cursor_pos;
+                               new_mark_end = Text.size();
+                               m_cursor_pos = 0;
+                       } else {
+                               m_cursor_pos = Text.size();
+                               new_mark_begin = 0;
+                               new_mark_end = 0;
+                       }
+                       break;
+               default:
+                       return false;
+               }
+       }
+       // default keyboard handling
+       else
+               switch (event.KeyInput.Key)     {
+               case KEY_END:
+               {
+                       s32 p = Text.size();
+                       if (m_word_wrap || m_multiline) {
+                               p = getLineFromPos(m_cursor_pos);
+                               p = m_broken_text_positions[p] + (s32)m_broken_text[p].size();
+                               if (p > 0 && (Text[p - 1] == L'\r' || Text[p - 1] == L'\n'))
+                                       p -= 1;
+                       }
+
+                       if (event.KeyInput.Shift) {
+                               if (m_mark_begin == m_mark_end)
+                                       new_mark_begin = m_cursor_pos;
+
+                               new_mark_end = p;
+                       } else {
+                               new_mark_begin = 0;
+                               new_mark_end = 0;
+                       }
+                       m_cursor_pos = p;
+                       m_blink_start_time = porting::getTimeMs();
+               }
+               break;
+               case KEY_HOME:
+               {
+
+                       s32 p = 0;
+                       if (m_word_wrap || m_multiline) {
+                               p = getLineFromPos(m_cursor_pos);
+                               p = m_broken_text_positions[p];
+                       }
+
+                       if (event.KeyInput.Shift) {
+                               if (m_mark_begin == m_mark_end)
+                                       new_mark_begin = m_cursor_pos;
+                               new_mark_end = p;
+                       } else {
+                               new_mark_begin = 0;
+                               new_mark_end = 0;
+                       }
+                       m_cursor_pos = p;
+                       m_blink_start_time = porting::getTimeMs();
+               }
+               break;
+               case KEY_RETURN:
+                       if (m_multiline) {
+                               inputChar(L'\n');
+                       } else {
+                               calculateScrollPos();
+                               sendGuiEvent(EGET_EDITBOX_ENTER);
+                       }
+                       return true;
+               case KEY_LEFT:
+
+                       if (event.KeyInput.Shift) {
+                               if (m_cursor_pos > 0) {
+                                       if (m_mark_begin == m_mark_end)
+                                               new_mark_begin = m_cursor_pos;
+
+                                       new_mark_end = m_cursor_pos - 1;
+                               }
+                       } else {
+                               new_mark_begin = 0;
+                               new_mark_end = 0;
+                       }
+
+                       if (m_cursor_pos > 0)
+                               m_cursor_pos--;
+                       m_blink_start_time = porting::getTimeMs();
+                       break;
+
+               case KEY_RIGHT:
+                       if (event.KeyInput.Shift) {
+                               if (Text.size() > (u32)m_cursor_pos) {
+                                       if (m_mark_begin == m_mark_end)
+                                               new_mark_begin = m_cursor_pos;
+
+                                       new_mark_end = m_cursor_pos + 1;
+                               }
+                       } else {
+                               new_mark_begin = 0;
+                               new_mark_end = 0;
+                       }
+
+                       if (Text.size() > (u32)m_cursor_pos)
+                               m_cursor_pos++;
+                       m_blink_start_time = porting::getTimeMs();
+                       break;
+               case KEY_UP:
+                       if (m_multiline || (m_word_wrap && m_broken_text.size() > 1)) {
+                               s32 lineNo = getLineFromPos(m_cursor_pos);
+                               s32 mb = (m_mark_begin == m_mark_end) ? m_cursor_pos : (m_mark_begin > m_mark_end ? m_mark_begin : m_mark_end);
+                               if (lineNo > 0) {
+                                       s32 cp = m_cursor_pos - m_broken_text_positions[lineNo];
+                                       if ((s32)m_broken_text[lineNo - 1].size() < cp)
+                                               m_cursor_pos = m_broken_text_positions[lineNo - 1] + core::max_((u32)1, m_broken_text[lineNo - 1].size()) - 1;
+                                       else
+                                               m_cursor_pos = m_broken_text_positions[lineNo - 1] + cp;
+                               }
+
+                               if (event.KeyInput.Shift) {
+                                       new_mark_begin = mb;
+                                       new_mark_end = m_cursor_pos;
+                               } else {
+                                       new_mark_begin = 0;
+                                       new_mark_end = 0;
+                               }
+                       } else {
+                               return false;
+                       }
+                       break;
+               case KEY_DOWN:
+                       if (m_multiline || (m_word_wrap && m_broken_text.size() > 1)) {
+                               s32 lineNo = getLineFromPos(m_cursor_pos);
+                               s32 mb = (m_mark_begin == m_mark_end) ? m_cursor_pos : (m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end);
+                               if (lineNo < (s32)m_broken_text.size() - 1)
+                               {
+                                       s32 cp = m_cursor_pos - m_broken_text_positions[lineNo];
+                                       if ((s32)m_broken_text[lineNo + 1].size() < cp)
+                                               m_cursor_pos = m_broken_text_positions[lineNo + 1] + core::max_((u32)1, m_broken_text[lineNo + 1].size()) - 1;
+                                       else
+                                               m_cursor_pos = m_broken_text_positions[lineNo + 1] + cp;
+                               }
+
+                               if (event.KeyInput.Shift) {
+                                       new_mark_begin = mb;
+                                       new_mark_end = m_cursor_pos;
+                               } else {
+                                       new_mark_begin = 0;
+                                       new_mark_end = 0;
+                               }
+
+                       } else {
+                               return false;
+                       }
+                       break;
+
+               case KEY_BACK:
+                       if (!isEnabled())
+                               break;
+
+                       if (Text.size()) {
+                               core::stringw s;
+
+                               if (m_mark_begin != m_mark_end) {
+                                       // delete marked text
+                                       const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
+                                       const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
+
+                                       s = Text.subString(0, realmbgn);
+                                       s.append(Text.subString(realmend, Text.size() - realmend));
+                                       Text = s;
+
+                                       m_cursor_pos = realmbgn;
+                               } else {
+                                       // delete text behind cursor
+                                       if (m_cursor_pos > 0)
+                                               s = Text.subString(0, m_cursor_pos - 1);
+                                       else
+                                               s = L"";
+                                       s.append(Text.subString(m_cursor_pos, Text.size() - m_cursor_pos));
+                                       Text = s;
+                                       --m_cursor_pos;
+                               }
+
+                               if (m_cursor_pos < 0)
+                                       m_cursor_pos = 0;
+                               m_blink_start_time = porting::getTimeMs(); // os::Timer::getTime();
+                               new_mark_begin = 0;
+                               new_mark_end = 0;
+                               text_changed = true;
+                       }
+                       break;
+               case KEY_DELETE:
+                       if (!isEnabled())
+                               break;
+
+                       if (Text.size() != 0) {
+                               core::stringw s;
+
+                               if (m_mark_begin != m_mark_end) {
+                                       // delete marked text
+                                       const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
+                                       const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
+
+                                       s = Text.subString(0, realmbgn);
+                                       s.append(Text.subString(realmend, Text.size() - realmend));
+                                       Text = s;
+
+                                       m_cursor_pos = realmbgn;
+                               } else {
+                                       // delete text before cursor
+                                       s = Text.subString(0, m_cursor_pos);
+                                       s.append(Text.subString(m_cursor_pos + 1, Text.size() - m_cursor_pos - 1));
+                                       Text = s;
+                               }
+
+                               if (m_cursor_pos > (s32)Text.size())
+                                       m_cursor_pos = (s32)Text.size();
+
+                               m_blink_start_time = porting::getTimeMs(); // os::Timer::getTime();
+                               new_mark_begin = 0;
+                               new_mark_end = 0;
+                               text_changed = true;
+                       }
+                       break;
+
+               case KEY_ESCAPE:
+               case KEY_TAB:
+               case KEY_SHIFT:
+               case KEY_F1:
+               case KEY_F2:
+               case KEY_F3:
+               case KEY_F4:
+               case KEY_F5:
+               case KEY_F6:
+               case KEY_F7:
+               case KEY_F8:
+               case KEY_F9:
+               case KEY_F10:
+               case KEY_F11:
+               case KEY_F12:
+               case KEY_F13:
+               case KEY_F14:
+               case KEY_F15:
+               case KEY_F16:
+               case KEY_F17:
+               case KEY_F18:
+               case KEY_F19:
+               case KEY_F20:
+               case KEY_F21:
+               case KEY_F22:
+               case KEY_F23:
+               case KEY_F24:
+                       // ignore these keys
+                       return false;
+
+               default:
+                       inputChar(event.KeyInput.Char);
+                       return true;
+               }
+
+       // Set new text markers
+       setTextMarkers(new_mark_begin, new_mark_end);
+
+       // break the text if it has changed
+       if (text_changed) {
+               breakText();
+               calculateScrollPos();
+               sendGuiEvent(EGET_EDITBOX_CHANGED);
+       }
+       else
+       {
+               calculateScrollPos();
+       }
+
+       return true;
+}
+
+
+//! draws the element and its children
+void GUIEditBoxWithScrollBar::draw()
+{
+       if (!IsVisible)
+               return;
+
+       const bool focus = Environment->hasFocus(this);
+
+       IGUISkin* skin = Environment->getSkin();
+       if (!skin)
+               return;
+
+       video::SColor default_bg_color;
+       video::SColor bg_color;
+
+       default_bg_color = m_writable ? skin->getColor(EGDC_WINDOW) : video::SColor(0);
+       bg_color = m_bg_color_used ? m_bg_color : default_bg_color;
+
+       if (!m_border && m_background) {
+               skin->draw2DRectangle(this, bg_color, AbsoluteRect, &AbsoluteClippingRect);
+       }
+
+       // draw the border
+
+       if (m_border) {
+
+               if (m_writable) {
+                       skin->draw3DSunkenPane(this, bg_color, false, m_background,
+                               AbsoluteRect, &AbsoluteClippingRect);
+               }
+
+               calculateFrameRect();
+       }
+
+       core::rect<s32> local_clip_rect = m_frame_rect;
+       local_clip_rect.clipAgainst(AbsoluteClippingRect);
+
+       // draw the text
+
+       IGUIFont* font = getActiveFont();
+
+       s32 cursor_line = 0;
+       s32 charcursorpos = 0;
+
+       if (font) {
+               if (m_last_break_font != font) {
+                       breakText();
+               }
+
+               // calculate cursor pos
+
+               core::stringw *txt_line = &Text;
+               s32 start_pos = 0;
+
+               core::stringw s, s2;
+
+               // get mark position
+               const bool ml = (!m_passwordbox && (m_word_wrap || m_multiline));
+               const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
+               const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
+               const s32 hline_start = ml ? getLineFromPos(realmbgn) : 0;
+               const s32 hline_count = ml ? getLineFromPos(realmend) - hline_start + 1 : 1;
+               const s32 line_count = ml ? m_broken_text.size() : 1;
+
+               // Save the override color information.
+               // Then, alter it if the edit box is disabled.
+               const bool prevOver = m_override_color_enabled;
+               const video::SColor prevColor = m_override_color;
+
+               if (Text.size()) {
+                       if (!isEnabled() && !m_override_color_enabled) {
+                               m_override_color_enabled = true;
+                               m_override_color = skin->getColor(EGDC_GRAY_TEXT);
+                       }
+
+                       for (s32 i = 0; i < line_count; ++i) {
+                               setTextRect(i);
+
+                               // clipping test - don't draw anything outside the visible area
+                               core::rect<s32> c = local_clip_rect;
+                               c.clipAgainst(m_current_text_rect);
+                               if (!c.isValid())
+                                       continue;
+
+                               // get current line
+                               if (m_passwordbox) {
+                                       if (m_broken_text.size() != 1) {
+                                               m_broken_text.clear();
+                                               m_broken_text.push_back(core::stringw());
+                                       }
+                                       if (m_broken_text[0].size() != Text.size()){
+                                               m_broken_text[0] = Text;
+                                               for (u32 q = 0; q < Text.size(); ++q)
+                                               {
+                                                       m_broken_text[0][q] = m_passwordchar;
+                                               }
+                                       }
+                                       txt_line = &m_broken_text[0];
+                                       start_pos = 0;
+                               } else {
+                                       txt_line = ml ? &m_broken_text[i] : &Text;
+                                       start_pos = ml ? m_broken_text_positions[i] : 0;
+                               }
+
+
+                               // draw normal text
+                               font->draw(txt_line->c_str(), m_current_text_rect,
+                                       m_override_color_enabled ? m_override_color : skin->getColor(EGDC_BUTTON_TEXT),
+                                       false, true, &local_clip_rect);
+
+                               // draw mark and marked text
+                               if (focus && m_mark_begin != m_mark_end && i >= hline_start && i < hline_start + hline_count) {
+
+                                       s32 mbegin = 0, mend = 0;
+                                       s32 lineStartPos = 0, lineEndPos = txt_line->size();
+
+                                       if (i == hline_start) {
+                                               // highlight start is on this line
+                                               s = txt_line->subString(0, realmbgn - start_pos);
+                                               mbegin = font->getDimension(s.c_str()).Width;
+
+                                               // deal with kerning
+                                               mbegin += font->getKerningWidth(
+                                                       &((*txt_line)[realmbgn - start_pos]),
+                                                       realmbgn - start_pos > 0 ? &((*txt_line)[realmbgn - start_pos - 1]) : 0);
+
+                                               lineStartPos = realmbgn - start_pos;
+                                       }
+                                       if (i == hline_start + hline_count - 1) {
+                                               // highlight end is on this line
+                                               s2 = txt_line->subString(0, realmend - start_pos);
+                                               mend = font->getDimension(s2.c_str()).Width;
+                                               lineEndPos = (s32)s2.size();
+                                       } else {
+                                               mend = font->getDimension(txt_line->c_str()).Width;
+                                       }
+                                               
+
+                                       m_current_text_rect.UpperLeftCorner.X += mbegin;
+                                       m_current_text_rect.LowerRightCorner.X = m_current_text_rect.UpperLeftCorner.X + mend - mbegin;
+
+
+                                       // draw mark
+                                       skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), m_current_text_rect, &local_clip_rect);
+
+                                       // draw marked text
+                                       s = txt_line->subString(lineStartPos, lineEndPos - lineStartPos);
+
+                                       if (s.size())
+                                               font->draw(s.c_str(), m_current_text_rect,
+                                                       m_override_color_enabled ? m_override_color : skin->getColor(EGDC_HIGH_LIGHT_TEXT),
+                                                       false, true, &local_clip_rect);
+
+                               }
+                       }
+
+                       // Return the override color information to its previous settings.
+                       m_override_color_enabled = prevOver;
+                       m_override_color = prevColor;
+               }
+
+               // draw cursor
+               if (IsEnabled && m_writable) {
+                       if (m_word_wrap || m_multiline) {
+                               cursor_line = getLineFromPos(m_cursor_pos);
+                               txt_line = &m_broken_text[cursor_line];
+                               start_pos = m_broken_text_positions[cursor_line];
+                       }
+                       s = txt_line->subString(0, m_cursor_pos - start_pos);
+                       charcursorpos = font->getDimension(s.c_str()).Width +
+                               font->getKerningWidth(L"_", m_cursor_pos - start_pos > 0 ? &((*txt_line)[m_cursor_pos - start_pos - 1]) : 0);
+
+                       if (focus && (porting::getTimeMs() - m_blink_start_time) % 700 < 350) {
+                               setTextRect(cursor_line);
+                               m_current_text_rect.UpperLeftCorner.X += charcursorpos;
+
+                               font->draw(L"_", m_current_text_rect,
+                                       m_override_color_enabled ? m_override_color : skin->getColor(EGDC_BUTTON_TEXT),
+                                       false, true, &local_clip_rect);
+                       }
+               }
+       }
+
+       // draw children
+       IGUIElement::draw();
+}
+
+
+//! Sets the new caption of this element.
+void GUIEditBoxWithScrollBar::setText(const wchar_t* text)
+{
+       Text = text;
+       if (u32(m_cursor_pos) > Text.size())
+               m_cursor_pos = Text.size();
+       m_hscroll_pos = 0;
+       breakText();
+}
+
+
+//! Enables or disables automatic scrolling with cursor position
+//! \param enable: If set to true, the text will move around with the cursor position
+void GUIEditBoxWithScrollBar::setAutoScroll(bool enable)
+{
+       m_autoscroll = enable;
+}
+
+
+//! Checks to see if automatic scrolling is enabled
+//! \return true if automatic scrolling is enabled, false if not
+bool GUIEditBoxWithScrollBar::isAutoScrollEnabled() const
+{
+       _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
+       return m_autoscroll;
+}
+
+
+//! Gets the area of the text in the edit box
+//! \return Returns the size in pixels of the text
+core::dimension2du GUIEditBoxWithScrollBar::getTextDimension()
+{
+       core::rect<s32> ret;
+
+       setTextRect(0);
+       ret = m_current_text_rect;
+
+       for (u32 i = 1; i < m_broken_text.size(); ++i) {
+               setTextRect(i);
+               ret.addInternalPoint(m_current_text_rect.UpperLeftCorner);
+               ret.addInternalPoint(m_current_text_rect.LowerRightCorner);
+       }
+
+       return core::dimension2du(ret.getSize());
+}
+
+
+//! Sets the maximum amount of characters which may be entered in the box.
+//! \param max: Maximum amount of characters. If 0, the character amount is
+//! infinity.
+void GUIEditBoxWithScrollBar::setMax(u32 max)
+{
+       m_max = max;
+
+       if (Text.size() > m_max && m_max != 0)
+               Text = Text.subString(0, m_max);
+}
+
+
+//! Returns maximum amount of characters, previously set by setMax();
+u32 GUIEditBoxWithScrollBar::getMax() const
+{
+       return m_max;
+}
+
+
+bool GUIEditBoxWithScrollBar::processMouse(const SEvent& event)
+{
+       switch (event.MouseInput.Event)
+       {
+       case irr::EMIE_LMOUSE_LEFT_UP:
+               if (Environment->hasFocus(this)) {
+                       m_cursor_pos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
+                       if (m_mouse_marking) {
+                               setTextMarkers(m_mark_begin, m_cursor_pos);
+                       }
+                       m_mouse_marking = false;
+                       calculateScrollPos();
+                       return true;
+               }
+               break;
+       case irr::EMIE_MOUSE_MOVED:
+       {
+               if (m_mouse_marking) {
+                       m_cursor_pos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
+                       setTextMarkers(m_mark_begin, m_cursor_pos);
+                       calculateScrollPos();
+                       return true;
+               }
+       }
+       break;
+       case EMIE_LMOUSE_PRESSED_DOWN:
+
+               if (!Environment->hasFocus(this)) {
+                       m_blink_start_time = porting::getTimeMs();
+                       m_mouse_marking = true;
+                       m_cursor_pos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
+                       setTextMarkers(m_cursor_pos, m_cursor_pos);
+                       calculateScrollPos();
+                       return true;
+               } else {
+                       if (!AbsoluteClippingRect.isPointInside(
+                               core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y))) {
+                               return false;
+                       } else {
+                               // move cursor
+                               m_cursor_pos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
+
+                               s32 newMarkBegin = m_mark_begin;
+                               if (!m_mouse_marking)
+                                       newMarkBegin = m_cursor_pos;
+
+                               m_mouse_marking = true;
+                               setTextMarkers(newMarkBegin, m_cursor_pos);
+                               calculateScrollPos();
+                               return true;
+                       }
+               }
+       default:
+               break;
+       }
+
+       return false;
+}
+
+
+s32 GUIEditBoxWithScrollBar::getCursorPos(s32 x, s32 y)
+{
+       IGUIFont* font = getActiveFont();
+
+       const u32 line_count = (m_word_wrap || m_multiline) ? m_broken_text.size() : 1;
+
+       core::stringw *txt_line = 0;
+       s32 start_pos = 0;
+       x += 3;
+
+       for (u32 i = 0; i < line_count; ++i) {
+               setTextRect(i);
+               if (i == 0 && y < m_current_text_rect.UpperLeftCorner.Y)
+                       y = m_current_text_rect.UpperLeftCorner.Y;
+               if (i == line_count - 1 && y > m_current_text_rect.LowerRightCorner.Y)
+                       y = m_current_text_rect.LowerRightCorner.Y;
+
+               // is it inside this region?
+               if (y >= m_current_text_rect.UpperLeftCorner.Y && y <= m_current_text_rect.LowerRightCorner.Y) {
+                       // we've found the clicked line
+                       txt_line = (m_word_wrap || m_multiline) ? &m_broken_text[i] : &Text;
+                       start_pos = (m_word_wrap || m_multiline) ? m_broken_text_positions[i] : 0;
+                       break;
+               }
+       }
+
+       if (x < m_current_text_rect.UpperLeftCorner.X)
+               x = m_current_text_rect.UpperLeftCorner.X;
+
+       if (!txt_line)
+               return 0;
+
+       s32 idx = font->getCharacterFromPos(txt_line->c_str(), x - m_current_text_rect.UpperLeftCorner.X);
+
+       // click was on or left of the line
+       if (idx != -1)
+               return idx + start_pos;
+
+       // click was off the right edge of the line, go to end.
+       return txt_line->size() + start_pos;
+}
+
+
+//! Breaks the single text line.
+void GUIEditBoxWithScrollBar::breakText()
+{
+       if ((!m_word_wrap && !m_multiline))
+               return;
+
+       m_broken_text.clear(); // need to reallocate :/
+       m_broken_text_positions.clear();
+
+       IGUIFont* font = getActiveFont();
+       if (!font)
+               return;
+
+       m_last_break_font = font;
+
+       core::stringw line;
+       core::stringw word;
+       core::stringw whitespace;
+       s32 last_line_start = 0;
+       s32 size = Text.size();
+       s32 length = 0;
+       s32 el_width = RelativeRect.getWidth() - 6;
+       wchar_t c;
+
+       for (s32 i = 0; i < size; ++i) {
+               c = Text[i];
+               bool line_break = false;
+
+               if (c == L'\r') { // Mac or Windows breaks
+               
+                       line_break = true;
+                       c = 0;
+                       if (Text[i + 1] == L'\n') { // Windows breaks
+                               // TODO: I (Michael) think that we shouldn't change the text given by the user for whatever reason.
+                               // Instead rework the cursor positioning to be able to handle this (but not in stable release
+                               // branch as users might already expect this behavior).
+                               Text.erase(i + 1);
+                               --size;
+                               if (m_cursor_pos > i)
+                                       --m_cursor_pos;
+                       }
+               } else if (c == L'\n') { // Unix breaks
+                       line_break = true;
+                       c = 0;
+               }
+
+               // don't break if we're not a multi-line edit box
+               if (!m_multiline)
+                       line_break = false;
+
+               if (c == L' ' || c == 0 || i == (size - 1)) {
+                       // here comes the next whitespace, look if
+                       // we can break the last word to the next line
+                       // We also break whitespace, otherwise cursor would vanish beside the right border.
+                       s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
+                       s32 worldlgth = font->getDimension(word.c_str()).Width;
+
+                       if (m_word_wrap && length + worldlgth + whitelgth > el_width && line.size() > 0) {
+                               // break to next line
+                               length = worldlgth;
+                               m_broken_text.push_back(line);
+                               m_broken_text_positions.push_back(last_line_start);
+                               last_line_start = i - (s32)word.size();
+                               line = word;
+                       } else {
+                               // add word to line
+                               line += whitespace;
+                               line += word;
+                               length += whitelgth + worldlgth;
+                       }
+
+                       word = L"";
+                       whitespace = L"";
+
+
+                       if (c)
+                               whitespace += c;
+
+                       // compute line break
+                       if (line_break) {
+                               line += whitespace;
+                               line += word;
+                               m_broken_text.push_back(line);
+                               m_broken_text_positions.push_back(last_line_start);
+                               last_line_start = i + 1;
+                               line = L"";
+                               word = L"";
+                               whitespace = L"";
+                               length = 0;
+                       }
+               } else {
+                       // yippee this is a word..
+                       word += c;
+               }
+       }
+
+       line += whitespace;
+       line += word;
+       m_broken_text.push_back(line);
+       m_broken_text_positions.push_back(last_line_start);
+}
+
+// TODO: that function does interpret VAlign according to line-index (indexed line is placed on top-center-bottom)
+// but HAlign according to line-width (pixels) and not by row.
+// Intuitively I suppose HAlign handling is better as VScrollPos should handle the line-scrolling.
+// But please no one change this without also rewriting (and this time fucking testing!!!) autoscrolling (I noticed this when fixing the old autoscrolling).
+void GUIEditBoxWithScrollBar::setTextRect(s32 line)
+{
+       if (line < 0)
+               return;
+
+       IGUIFont* font = getActiveFont();
+       if (!font)
+               return;
+
+       core::dimension2du d;
+
+       // get text dimension
+       const u32 line_count = (m_word_wrap || m_multiline) ? m_broken_text.size() : 1;
+       if (m_word_wrap || m_multiline) {
+               d = font->getDimension(m_broken_text[line].c_str());
+       } else {
+               d = font->getDimension(Text.c_str());
+               d.Height = AbsoluteRect.getHeight();
+       }
+       d.Height += font->getKerningHeight();
+
+       // justification
+       switch (m_halign) {
+       case EGUIA_CENTER:
+               // align to h centre
+               m_current_text_rect.UpperLeftCorner.X = (m_frame_rect.getWidth() / 2) - (d.Width / 2);
+               m_current_text_rect.LowerRightCorner.X = (m_frame_rect.getWidth() / 2) + (d.Width / 2);
+               break;
+       case EGUIA_LOWERRIGHT:
+               // align to right edge
+               m_current_text_rect.UpperLeftCorner.X = m_frame_rect.getWidth() - d.Width;
+               m_current_text_rect.LowerRightCorner.X = m_frame_rect.getWidth();
+               break;
+       default:
+               // align to left edge
+               m_current_text_rect.UpperLeftCorner.X = 0;
+               m_current_text_rect.LowerRightCorner.X = d.Width;
+
+       }
+
+       switch (m_valign) {
+       case EGUIA_CENTER:
+               // align to v centre
+               m_current_text_rect.UpperLeftCorner.Y =
+                       (m_frame_rect.getHeight() / 2) - (line_count*d.Height) / 2 + d.Height*line;
+               break;
+       case EGUIA_LOWERRIGHT:
+               // align to bottom edge
+               m_current_text_rect.UpperLeftCorner.Y =
+                       m_frame_rect.getHeight() - line_count*d.Height + d.Height*line;
+               break;
+       default:
+               // align to top edge
+               m_current_text_rect.UpperLeftCorner.Y = d.Height*line;
+               break;
+       }
+
+       m_current_text_rect.UpperLeftCorner.X -= m_hscroll_pos;
+       m_current_text_rect.LowerRightCorner.X -= m_hscroll_pos;
+       m_current_text_rect.UpperLeftCorner.Y -= m_vscroll_pos;
+       m_current_text_rect.LowerRightCorner.Y = m_current_text_rect.UpperLeftCorner.Y + d.Height;
+
+       m_current_text_rect += m_frame_rect.UpperLeftCorner;
+}
+
+
+s32 GUIEditBoxWithScrollBar::getLineFromPos(s32 pos)
+{
+       if (!m_word_wrap && !m_multiline)
+               return 0;
+
+       s32 i = 0;
+       while (i < (s32)m_broken_text_positions.size()) {
+               if (m_broken_text_positions[i] > pos)
+                       return i - 1;
+               ++i;
+       }
+       return (s32)m_broken_text_positions.size() - 1;
+}
+
+
+void GUIEditBoxWithScrollBar::inputChar(wchar_t c)
+{
+       if (!isEnabled())
+               return;
+
+       if (c != 0)     {
+               if (Text.size() < m_max || m_max == 0) {
+                       core::stringw s;
+
+                       if (m_mark_begin != m_mark_end) {
+                               // replace marked text
+                               const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
+                               const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
+
+                               s = Text.subString(0, realmbgn);
+                               s.append(c);
+                               s.append(Text.subString(realmend, Text.size() - realmend));
+                               Text = s;
+                               m_cursor_pos = realmbgn + 1;
+                       } else {
+                               // add new character
+                               s = Text.subString(0, m_cursor_pos);
+                               s.append(c);
+                               s.append(Text.subString(m_cursor_pos, Text.size() - m_cursor_pos));
+                               Text = s;
+                               ++m_cursor_pos;
+                       }
+
+                       m_blink_start_time = porting::getTimeMs();
+                       setTextMarkers(0, 0);
+               }
+       }
+       breakText();
+       calculateScrollPos();
+       sendGuiEvent(EGET_EDITBOX_CHANGED);
+}
+
+// calculate autoscroll
+void GUIEditBoxWithScrollBar::calculateScrollPos()
+{
+       if (!m_autoscroll)
+               return;
+
+       IGUISkin* skin = Environment->getSkin();
+       if (!skin)
+               return;
+       IGUIFont* font = m_override_font ? m_override_font : skin->getFont();
+       if (!font)
+               return;
+
+       s32 curs_line = getLineFromPos(m_cursor_pos);
+       if (curs_line < 0)
+               return;
+       setTextRect(curs_line);
+       const bool has_broken_text = m_multiline || m_word_wrap;
+
+       // Check horizonal scrolling
+       // NOTE: Calculations different to vertical scrolling because setTextRect interprets VAlign relative to line but HAlign not relative to row
+       {
+               // get cursor position
+               IGUIFont* font = getActiveFont();
+               if (!font)
+                       return;
+
+               // get cursor area
+               irr::u32 cursor_width = font->getDimension(L"_").Width;
+               core::stringw *txt_line = has_broken_text ? &m_broken_text[curs_line] : &Text;
+               s32 cpos = has_broken_text ? m_cursor_pos - m_broken_text_positions[curs_line] : m_cursor_pos;  // column
+               s32 cstart = font->getDimension(txt_line->subString(0, cpos).c_str()).Width;            // pixels from text-start
+               s32 cend = cstart + cursor_width;
+               s32 txt_width = font->getDimension(txt_line->c_str()).Width;
+
+               if (txt_width < m_frame_rect.getWidth()) {
+                       // TODO: Needs a clean left and right gap removal depending on HAlign, similar to vertical scrolling tests for top/bottom.
+                       // This check just fixes the case where it was most noticable (text smaller than clipping area).
+
+                       m_hscroll_pos = 0;
+                       setTextRect(curs_line);
+               }
+
+               if (m_current_text_rect.UpperLeftCorner.X + cstart < m_frame_rect.UpperLeftCorner.X) {
+                       // cursor to the left of the clipping area
+                       m_hscroll_pos -= m_frame_rect.UpperLeftCorner.X - (m_current_text_rect.UpperLeftCorner.X + cstart);
+                       setTextRect(curs_line);
+
+                       // TODO: should show more characters to the left when we're scrolling left
+                       //      and the cursor reaches the border.
+               } else if (m_current_text_rect.UpperLeftCorner.X + cend > m_frame_rect.LowerRightCorner.X)      {
+                       // cursor to the right of the clipping area
+                       m_hscroll_pos += (m_current_text_rect.UpperLeftCorner.X + cend) - m_frame_rect.LowerRightCorner.X;
+                       setTextRect(curs_line);
+               }
+       }
+
+       // calculate vertical scrolling
+       if (has_broken_text) {
+               irr::u32 line_height = font->getDimension(L"A").Height + font->getKerningHeight();
+               // only up to 1 line fits?
+               if (line_height >= (irr::u32)m_frame_rect.getHeight()) {
+                       m_vscroll_pos = 0;
+                       setTextRect(curs_line);
+                       s32 unscrolledPos = m_current_text_rect.UpperLeftCorner.Y;
+                       s32 pivot = m_frame_rect.UpperLeftCorner.Y;
+                       switch (m_valign) {
+                       case EGUIA_CENTER:
+                               pivot += m_frame_rect.getHeight() / 2;
+                               unscrolledPos += line_height / 2;
+                               break;
+                       case EGUIA_LOWERRIGHT:
+                               pivot += m_frame_rect.getHeight();
+                               unscrolledPos += line_height;
+                               break;
+                       default:
+                               break;
+                       }
+                       m_vscroll_pos = unscrolledPos - pivot;
+                       setTextRect(curs_line);
+               } else {
+                       // First 2 checks are necessary when people delete lines
+                       setTextRect(0);
+                       if (m_current_text_rect.UpperLeftCorner.Y > m_frame_rect.UpperLeftCorner.Y && m_valign != EGUIA_LOWERRIGHT) {
+                               // first line is leaving a gap on top
+                               m_vscroll_pos = 0;
+                       } else if (m_valign != EGUIA_UPPERLEFT) {
+                               u32 lastLine = m_broken_text_positions.empty() ? 0 : m_broken_text_positions.size() - 1;
+                               setTextRect(lastLine);
+                               if (m_current_text_rect.LowerRightCorner.Y < m_frame_rect.LowerRightCorner.Y)
+                               {
+                                       // last line is leaving a gap on bottom
+                                       m_vscroll_pos -= m_frame_rect.LowerRightCorner.Y - m_current_text_rect.LowerRightCorner.Y;
+                               }
+                       }
+
+                       setTextRect(curs_line);
+                       if (m_current_text_rect.UpperLeftCorner.Y < m_frame_rect.UpperLeftCorner.Y) {
+                               // text above valid area
+                               m_vscroll_pos -= m_frame_rect.UpperLeftCorner.Y - m_current_text_rect.UpperLeftCorner.Y;
+                               setTextRect(curs_line);
+                       } else if (m_current_text_rect.LowerRightCorner.Y > m_frame_rect.LowerRightCorner.Y){
+                               // text below valid area
+                               m_vscroll_pos += m_current_text_rect.LowerRightCorner.Y - m_frame_rect.LowerRightCorner.Y;
+                               setTextRect(curs_line);
+                       }
+               }
+       }
+
+       if (m_vscrollbar) {
+               m_vscrollbar->setPos(m_vscroll_pos);
+       }
+}
+
+void GUIEditBoxWithScrollBar::calculateFrameRect()
+{
+       m_frame_rect = AbsoluteRect;
+
+
+       IGUISkin *skin = 0;
+       if (Environment)
+               skin = Environment->getSkin();
+       if (m_border && skin) {
+               m_frame_rect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X) + 1;
+               m_frame_rect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y) + 1;
+               m_frame_rect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X) + 1;
+               m_frame_rect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y) + 1;
+       }
+
+       updateVScrollBar();
+}
+
+//! set text markers
+void GUIEditBoxWithScrollBar::setTextMarkers(s32 begin, s32 end)
+{
+       if (begin != m_mark_begin || end != m_mark_end) {
+               m_mark_begin = begin;
+               m_mark_end = end;
+               sendGuiEvent(EGET_EDITBOX_MARKING_CHANGED);
+       }
+}
+
+//! send some gui event to parent
+void GUIEditBoxWithScrollBar::sendGuiEvent(EGUI_EVENT_TYPE type)
+{
+       if (Parent) {
+               SEvent e;
+               e.EventType = EET_GUI_EVENT;
+               e.GUIEvent.Caller = this;
+               e.GUIEvent.Element = 0;
+               e.GUIEvent.EventType = type;
+
+               Parent->OnEvent(e);
+       }
+}
+
+//! create a vertical scroll bar
+void GUIEditBoxWithScrollBar::createVScrollBar()
+{
+       IGUISkin *skin = 0;
+       if (Environment)
+               skin = Environment->getSkin();
+
+       m_scrollbar_width = skin ? skin->getSize(gui::EGDS_SCROLLBAR_SIZE) : 16;
+
+       irr::core::rect<s32> scrollbarrect = m_frame_rect;
+       scrollbarrect.UpperLeftCorner.X += m_frame_rect.getWidth() - m_scrollbar_width;
+       m_vscrollbar = Environment->addScrollBar(false, scrollbarrect, getParent(), getID());
+       m_vscrollbar->setVisible(false);
+       m_vscrollbar->setSmallStep(1);
+       m_vscrollbar->setLargeStep(1);
+}
+
+void GUIEditBoxWithScrollBar::updateVScrollBar()
+{
+       if (!m_vscrollbar) {
+               return;
+       }
+
+       // OnScrollBarChanged(...)
+       if (m_vscrollbar->getPos() != m_vscroll_pos) {
+               s32 deltaScrollY = m_vscrollbar->getPos() - m_vscroll_pos;
+               m_current_text_rect.UpperLeftCorner.Y -= deltaScrollY;
+               m_current_text_rect.LowerRightCorner.Y -= deltaScrollY;
+
+               s32 scrollymax = getTextDimension().Height - m_frame_rect.getHeight();
+               if (scrollymax != m_vscrollbar->getMax()) {
+                       // manage a newline or a deleted line
+                       m_vscrollbar->setMax(scrollymax);
+                       calculateScrollPos();
+               } else {
+                       // manage a newline or a deleted line
+                       m_vscroll_pos = m_vscrollbar->getPos();
+               }
+       }
+
+       // check if a vertical scrollbar is needed ?
+       if (getTextDimension().Height > m_frame_rect.getHeight()) {
+               m_frame_rect.LowerRightCorner.X -= m_scrollbar_width;
+
+               s32 scrollymax = getTextDimension().Height - m_frame_rect.getHeight();
+               if (scrollymax != m_vscrollbar->getMax()) {
+                       m_vscrollbar->setMax(scrollymax);
+               }
+
+               if (!m_vscrollbar->isVisible()) {
+                       m_vscrollbar->setVisible(true);
+               }
+       } else {
+               if (m_vscrollbar->isVisible())
+               {
+                       m_vscrollbar->setVisible(false);
+                       m_vscroll_pos = 0;
+                       m_vscrollbar->setPos(0);
+                       m_vscrollbar->setMax(1);
+               }
+       }
+
+
+}
+
+//! set true if this editbox is writable
+void GUIEditBoxWithScrollBar::setWritable(bool writable)
+{
+       m_writable = writable;
+}
+
+//! Change the background color
+void GUIEditBoxWithScrollBar::setBackgroundColor(const video::SColor &bg_color)
+{
+       m_bg_color = bg_color;
+       m_bg_color_used = true;
+}
+
+//! Writes attributes of the element.
+void GUIEditBoxWithScrollBar::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options = 0) const
+{
+       // IGUIEditBox::serializeAttributes(out,options);
+
+       out->addBool("Border", m_border);
+       out->addBool("Background", m_background);
+       out->addBool("OverrideColorEnabled", m_override_color_enabled);
+       out->addColor("OverrideColor", m_override_color);
+       // out->addFont("OverrideFont", OverrideFont);
+       out->addInt("MaxChars", m_max);
+       out->addBool("WordWrap", m_word_wrap);
+       out->addBool("MultiLine", m_multiline);
+       out->addBool("AutoScroll", m_autoscroll);
+       out->addBool("PasswordBox", m_passwordbox);
+       core::stringw ch = L" ";
+       ch[0] = m_passwordchar;
+       out->addString("PasswordChar", ch.c_str());
+       out->addEnum("HTextAlign", m_halign, GUIAlignmentNames);
+       out->addEnum("VTextAlign", m_valign, GUIAlignmentNames);
+       out->addBool("Writable", m_writable);
+
+       IGUIEditBox::serializeAttributes(out, options);
+}
+
+
+//! Reads attributes of the element
+void GUIEditBoxWithScrollBar::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options = 0)
+{
+       IGUIEditBox::deserializeAttributes(in, options);
+
+       setDrawBorder(in->getAttributeAsBool("Border"));
+       setDrawBackground(in->getAttributeAsBool("Background"));
+       setOverrideColor(in->getAttributeAsColor("OverrideColor"));
+       enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled"));
+       setMax(in->getAttributeAsInt("MaxChars"));
+       setWordWrap(in->getAttributeAsBool("WordWrap"));
+       setMultiLine(in->getAttributeAsBool("MultiLine"));
+       setAutoScroll(in->getAttributeAsBool("AutoScroll"));
+       core::stringw ch = in->getAttributeAsStringW("PasswordChar");
+
+       if (!ch.size())
+               setPasswordBox(in->getAttributeAsBool("PasswordBox"));
+       else
+               setPasswordBox(in->getAttributeAsBool("PasswordBox"), ch[0]);
+
+       setTextAlignment((EGUI_ALIGNMENT)in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
+               (EGUI_ALIGNMENT)in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
+
+       // setOverrideFont(in->getAttributeAsFont("OverrideFont"));
+       setWritable(in->getAttributeAsBool("Writable"));
+}
diff --git a/src/guiEditBoxWithScrollbar.h b/src/guiEditBoxWithScrollbar.h
new file mode 100644 (file)
index 0000000..cca2f65
--- /dev/null
@@ -0,0 +1,192 @@
+// Copyright (C) 2002-2012 Nikolaus Gebhardt, Modified by Mustapha Tachouct
+// This file is part of the "Irrlicht Engine".
+// For conditions of distribution and use, see copyright notice in irrlicht.h
+
+#ifndef GUIEDITBOXWITHSCROLLBAR_HEADER
+#define GUIEDITBOXWITHSCROLLBAR_HEADER
+
+#include "IGUIEditBox.h"
+#include "IOSOperator.h"
+#include "IGUIScrollBar.h"
+#include <vector>
+
+using namespace irr;
+using namespace irr::gui;
+
+class GUIEditBoxWithScrollBar : public IGUIEditBox
+{
+public:
+
+       //! constructor
+       GUIEditBoxWithScrollBar(const wchar_t* text, bool border, IGUIEnvironment* environment,
+               IGUIElement* parent, s32 id, const core::rect<s32>& rectangle,
+               bool writable = true, bool has_vscrollbar = true);
+
+       //! destructor
+       virtual ~GUIEditBoxWithScrollBar();
+
+       //! Sets another skin independent font.
+       virtual void setOverrideFont(IGUIFont* font = 0);
+
+       //! Gets the override font (if any)
+       /** \return The override font (may be 0) */
+       virtual IGUIFont* getOverrideFont() const;
+
+       //! Get the font which is used right now for drawing
+       /** Currently this is the override font when one is set and the
+       font of the active skin otherwise */
+       virtual IGUIFont* getActiveFont() const;
+
+       //! Sets another color for the text.
+       virtual void setOverrideColor(video::SColor color);
+
+       //! Gets the override color
+       virtual video::SColor getOverrideColor() const;
+
+       //! Sets if the text should use the overide color or the
+       //! color in the gui skin.
+       virtual void enableOverrideColor(bool enable);
+
+       //! Checks if an override color is enabled
+       /** \return true if the override color is enabled, false otherwise */
+       virtual bool isOverrideColorEnabled(void) const;
+
+       //! Sets whether to draw the background
+       virtual void setDrawBackground(bool draw);
+
+       //! Turns the border on or off
+       virtual void setDrawBorder(bool border);
+
+       //! Enables or disables word wrap for using the edit box as multiline text editor.
+       virtual void setWordWrap(bool enable);
+
+       //! Checks if word wrap is enabled
+       //! \return true if word wrap is enabled, false otherwise
+       virtual bool isWordWrapEnabled() const;
+
+       //! Enables or disables newlines.
+       /** \param enable: If set to true, the EGET_EDITBOX_ENTER event will not be fired,
+       instead a newline character will be inserted. */
+       virtual void setMultiLine(bool enable);
+
+       //! Checks if multi line editing is enabled
+       //! \return true if mult-line is enabled, false otherwise
+       virtual bool isMultiLineEnabled() const;
+
+       //! Enables or disables automatic scrolling with cursor position
+       //! \param enable: If set to true, the text will move around with the cursor position
+       virtual void setAutoScroll(bool enable);
+
+       //! Checks to see if automatic scrolling is enabled
+       //! \return true if automatic scrolling is enabled, false if not
+       virtual bool isAutoScrollEnabled() const;
+
+       //! Gets the size area of the text in the edit box
+       //! \return Returns the size in pixels of the text
+       virtual core::dimension2du getTextDimension();
+
+       //! Sets text justification
+       virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical);
+
+       //! called if an event happened.
+       virtual bool OnEvent(const SEvent& event);
+
+       //! draws the element and its children
+       virtual void draw();
+
+       //! Sets the new caption of this element.
+       virtual void setText(const wchar_t* text);
+
+       //! Sets the maximum amount of characters which may be entered in the box.
+       //! \param max: Maximum amount of characters. If 0, the character amount is
+       //! infinity.
+       virtual void setMax(u32 max);
+
+       //! Returns maximum amount of characters, previously set by setMax();
+       virtual u32 getMax() const;
+
+       //! Sets whether the edit box is a password box. Setting this to true will
+       /** disable MultiLine, WordWrap and the ability to copy with ctrl+c or ctrl+x
+       \param passwordBox: true to enable password, false to disable
+       \param passwordChar: the character that is displayed instead of letters */
+       virtual void setPasswordBox(bool passwordBox, wchar_t passwordChar = L'*');
+
+       //! Returns true if the edit box is currently a password box.
+       virtual bool isPasswordBox() const;
+
+       //! Updates the absolute position, splits text if required
+       virtual void updateAbsolutePosition();
+       
+       virtual void setWritable(bool writable);
+
+       //! Change the background color
+       virtual void setBackgroundColor(const video::SColor &bg_color);
+
+       //! Writes attributes of the element.
+       virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
+
+       //! Reads attributes of the element
+       virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options);
+
+protected:
+       //! Breaks the single text line.
+       void breakText();
+       //! sets the area of the given line
+       void setTextRect(s32 line);
+       //! returns the line number that the cursor is on
+       s32 getLineFromPos(s32 pos);
+       //! adds a letter to the edit box
+       void inputChar(wchar_t c);
+       //! calculates the current scroll position
+       void calculateScrollPos();
+       //! calculated the FrameRect
+       void calculateFrameRect();
+       //! send some gui event to parent
+       void sendGuiEvent(EGUI_EVENT_TYPE type);
+       //! set text markers
+       void setTextMarkers(s32 begin, s32 end);
+       //! create a Vertical ScrollBar
+       void createVScrollBar();
+       //! update the vertical scrollBar (visibilty & position)
+       void updateVScrollBar();
+
+       bool processKey(const SEvent& event);
+       bool processMouse(const SEvent& event);
+       s32 getCursorPos(s32 x, s32 y);
+
+       bool m_mouse_marking;
+       bool m_border;
+       bool m_background;
+       bool m_override_color_enabled;
+       s32 m_mark_begin;
+       s32 m_mark_end;
+
+       video::SColor m_override_color;
+       gui::IGUIFont *m_override_font, *m_last_break_font;
+       IOSOperator* m_operator;
+
+       u32 m_blink_start_time;
+       s32 m_cursor_pos;
+       s32 m_hscroll_pos, m_vscroll_pos; // scroll position in characters
+       u32 m_max;
+
+       bool m_word_wrap, m_multiline, m_autoscroll, m_passwordbox;
+       wchar_t m_passwordchar;
+       EGUI_ALIGNMENT m_halign, m_valign;
+
+       std::vector<core::stringw> m_broken_text;
+       std::vector<s32> m_broken_text_positions;
+
+       core::rect<s32> m_current_text_rect, m_frame_rect; // temporary values
+
+       u32 m_scrollbar_width;
+       IGUIScrollBar *m_vscrollbar;
+       bool m_writable;
+
+       bool m_bg_color_used;
+       video::SColor m_bg_color;
+};
+
+
+#endif // GUIEDITBOXWITHSCROLLBAR_HEADER
+
index 9d97821f02ea1569311d06757ab1e5562e026be8..f62b6e3deae4015900abf9a5aff1d7e225db74a9 100644 (file)
@@ -53,6 +53,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "util/string.h" // for parseColorString()
 #include "irrlicht_changes/static_text.h"
 #include "guiscalingfilter.h"
+#include "guiEditBoxWithScrollbar.h"
 
 #if USE_FREETYPE && IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9
 #include "intlGUIEditBox.h"
@@ -1072,6 +1073,7 @@ void GUIFormSpecMenu::parseTextArea(parserData* data, std::vector<std::string>&
        std::string name = parts[2];
        std::string label = parts[3];
        std::string default_val = parts[4];
+       bool has_vscrollbar = parts.size() > 5 ? is_yes(parts[5]) : false;
 
        MY_CHECKPOS(type,0);
        MY_CHECKGEOM(type,1);
@@ -1114,29 +1116,31 @@ void GUIFormSpecMenu::parseTextArea(parserData* data, std::vector<std::string>&
                258+m_fields.size()
        );
 
-       if (name.empty()) {
-               // spec field id to 0, this stops submit searching for a value that isn't there
-               addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, spec.fid);
-       } else {
-               spec.send = true;
+       bool is_editable = !name.empty();
 
+       if (is_editable) {
+               spec.send = true;
+       }
+       
                gui::IGUIEditBox *e;
 #if USE_FREETYPE && IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9
-               if (g_settings->getBool("freetype")) {
-                       e = (gui::IGUIEditBox *) new gui::intlGUIEditBox(spec.fdefault.c_str(),
-                               true, Environment, this, spec.fid, rect);
-                       e->drop();
-               } else {
+       if (g_settings->getBool("freetype")) {
+               e = (gui::IGUIEditBox *) new gui::intlGUIEditBox(spec.flabel.c_str(),
+                       true, Environment, this, spec.fid, rect, is_editable, has_vscrollbar);
+               e->drop();
+       } else {
 #else
-               {
+       {
 #endif
-                       e = Environment->addEditBox(spec.fdefault.c_str(), rect, true, this, spec.fid);
-               }
+               e = new GUIEditBoxWithScrollBar(spec.flabel.c_str(), true,
+                       Environment, this, spec.fid, rect, is_editable, has_vscrollbar);
+       }
 
-               if (spec.fname == data->focused_fieldname) {
-                       Environment->setFocus(e);
-               }
+       if (is_editable && spec.fname == data->focused_fieldname) {
+               Environment->setFocus(e);
+       }
 
+       if (e) {
                if (type == "textarea")
                {
                        e->setMultiLine(true);
@@ -1152,9 +1156,9 @@ void GUIFormSpecMenu::parseTextArea(parserData* data, std::vector<std::string>&
                        evt.KeyInput.PressedDown = true;
                        e->OnEvent(evt);
                }
-
-               if (label.length() >= 1)
-               {
+       }
+       if (is_editable) {
+               if (label.length() >= 1) {
                        int font_height = g_fontengine->getTextHeight();
                        rect.UpperLeftCorner.Y -= font_height;
                        rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height;
index 671b37c5d3b591a2d4766fe7cb3a559eee3817c5..a6175231fedfb68172f94a5235d341985d087770 100644 (file)
@@ -61,10 +61,10 @@ namespace gui
 //! constructor
 intlGUIEditBox::intlGUIEditBox(const wchar_t* text, bool border,
                IGUIEnvironment* environment, IGUIElement* parent, s32 id,
-               const core::rect<s32>& rectangle)
+               const core::rect<s32>& rectangle, bool writable, bool has_vscrollbar)
        : IGUIEditBox(environment, parent, id, rectangle),
-       Border(border),
-       FrameRect(rectangle)
+       Border(border), FrameRect(rectangle),
+       m_scrollbar_width(0), m_vscrollbar(NULL), m_writable(writable)
 {
        #ifdef _DEBUG
        setDebugName("intlintlGUIEditBox");
@@ -93,9 +93,18 @@ intlGUIEditBox::intlGUIEditBox(const wchar_t* text, bool border,
                FrameRect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
        }
 
+       if (skin && has_vscrollbar) {
+               m_scrollbar_width = skin->getSize(gui::EGDS_SCROLLBAR_SIZE);
+
+               if (m_scrollbar_width > 0) {
+                       createVScrollBar();
+               }
+       }
+
        breakText();
 
        calculateScrollPos();
+       setWritable(writable);
 }
 
 
@@ -251,7 +260,7 @@ void intlGUIEditBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT
 //! called if an event happened.
 bool intlGUIEditBox::OnEvent(const SEvent& event)
 {
-       if (IsEnabled)
+       if (IsEnabled && m_writable)
        {
 
                switch(event.EventType)
@@ -771,14 +780,18 @@ void intlGUIEditBox::draw()
 
        if (Border)
        {
-               skin->draw3DSunkenPane(this, skin->getColor(EGDC_WINDOW),
-                       false, true, FrameRect, &AbsoluteClippingRect);
+               if (m_writable) {
+                       skin->draw3DSunkenPane(this, skin->getColor(EGDC_WINDOW),
+                               false, true, FrameRect, &AbsoluteClippingRect);
+               }
 
                FrameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
                FrameRect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
                FrameRect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
                FrameRect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
        }
+
+       updateVScrollBar();
        core::rect<s32> localClipRect = FrameRect;
        localClipRect.clipAgainst(AbsoluteClippingRect);
 
@@ -930,14 +943,16 @@ void intlGUIEditBox::draw()
                charcursorpos = font->getDimension(s.c_str()).Width +
                        font->getKerningWidth(L"_", CursorPos-startPos > 0 ? &((*txtLine)[CursorPos-startPos-1]) : 0);
 
-               if (focus && (porting::getTimeMs() - BlinkStartTime) % 700 < 350)
-               {
-                       setTextRect(cursorLine);
-                       CurrentTextRect.UpperLeftCorner.X += charcursorpos;
+               if (m_writable) {
+                       if (focus && (porting::getTimeMs() - BlinkStartTime) % 700 < 350)
+                       {
+                               setTextRect(cursorLine);
+                               CurrentTextRect.UpperLeftCorner.X += charcursorpos;
 
-                       font->draw(L"_", CurrentTextRect,
-                               OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT),
-                               false, true, &localClipRect);
+                               font->draw(L"_", CurrentTextRect,
+                                       OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT),
+                                       false, true, &localClipRect);
+                       }
                }
        }
 
@@ -1418,6 +1433,9 @@ void intlGUIEditBox::calculateScrollPos()
                VScrollPos = 0;
 
        // todo: adjust scrollbar
+       if (m_vscrollbar) {
+               m_vscrollbar->setPos(VScrollPos);
+       }       
 }
 
 //! set text markers
@@ -1446,6 +1464,70 @@ void intlGUIEditBox::sendGuiEvent(EGUI_EVENT_TYPE type)
        }
 }
 
+//! Create a vertical scrollbar
+void intlGUIEditBox::createVScrollBar()
+{
+       irr::core::rect<s32> scrollbarrect = FrameRect;
+       scrollbarrect.UpperLeftCorner.X += FrameRect.getWidth() - m_scrollbar_width;
+       m_vscrollbar = Environment->addScrollBar(false, scrollbarrect, getParent(), getID());
+       m_vscrollbar->setVisible(false);
+       m_vscrollbar->setSmallStep(1);
+       m_vscrollbar->setLargeStep(1);
+}
+
+//! Update the vertical scrollbar (visibilty & scroll position)
+void intlGUIEditBox::updateVScrollBar()
+{
+       if (!m_vscrollbar) {
+               return;
+       }
+
+       // OnScrollBarChanged(...)
+       if (m_vscrollbar->getPos() != VScrollPos) {
+               s32 deltaScrollY = m_vscrollbar->getPos() - VScrollPos;
+               CurrentTextRect.UpperLeftCorner.Y -= deltaScrollY;
+               CurrentTextRect.LowerRightCorner.Y -= deltaScrollY;
+
+               s32 scrollymax = getTextDimension().Height - FrameRect.getHeight();
+               if (scrollymax != m_vscrollbar->getMax()) {
+                       // manage a newline or a deleted line
+                       m_vscrollbar->setMax(scrollymax);
+                       calculateScrollPos();
+               } else {
+                       // manage a newline or a deleted line
+                       VScrollPos = m_vscrollbar->getPos();
+               }
+       }
+
+       // check if a vertical scrollbar is needed ?
+       if (getTextDimension().Height > FrameRect.getHeight()) {
+               s32 scrollymax = getTextDimension().Height - FrameRect.getHeight();
+               if (scrollymax != m_vscrollbar->getMax()) {
+                       m_vscrollbar->setMax(scrollymax);
+               }
+
+               if (!m_vscrollbar->isVisible() && MultiLine) {
+                       AbsoluteRect.LowerRightCorner.X -= m_scrollbar_width;
+
+                       m_vscrollbar->setVisible(true);
+               }
+       } else {
+               if (m_vscrollbar->isVisible()) {
+                       AbsoluteRect.LowerRightCorner.X += m_scrollbar_width;
+
+                       VScrollPos = 0;
+                       m_vscrollbar->setPos(0);
+                       m_vscrollbar->setMax(1);
+                       m_vscrollbar->setVisible(false);
+               }
+       }
+}
+
+void intlGUIEditBox::setWritable(bool can_write_text)
+{
+       m_writable = can_write_text;
+}
+
 //! Writes attributes of the element.
 void intlGUIEditBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
 {
@@ -1464,6 +1546,7 @@ void intlGUIEditBox::serializeAttributes(io::IAttributes* out, io::SAttributeRea
        out->addString("PasswordChar",        ch.c_str());
        out->addEnum  ("HTextAlign",          HAlign, GUIAlignmentNames);
        out->addEnum  ("VTextAlign",          VAlign, GUIAlignmentNames);
+       out->addBool  ("Writable",            m_writable);
 
        IGUIEditBox::serializeAttributes(out,options);
 }
@@ -1490,6 +1573,7 @@ void intlGUIEditBox::deserializeAttributes(io::IAttributes* in, io::SAttributeRe
        setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
                        (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
 
+       setWritable(in->getAttributeAsBool("Writable"));
        // setOverrideFont(in->getAttributeAsFont("OverrideFont"));
 }
 
index 941d83c1c9d3658ebf7fbcbdbb1814a61ac4d690..aa35e2e71d119128a794c5edb913f42f972373aa 100644 (file)
@@ -10,6 +10,7 @@
 #include "IGUIEditBox.h"
 #include "irrArray.h"
 #include "IOSOperator.h"
+#include "IGUIScrollBar.h"
 
 namespace irr
 {
@@ -21,7 +22,8 @@ namespace gui
 
                //! constructor
                intlGUIEditBox(const wchar_t* text, bool border, IGUIEnvironment* environment,
-                       IGUIElement* parent, s32 id, const core::rect<s32>& rectangle);
+                       IGUIElement* parent, s32 id, const core::rect<s32>& rectangle,
+                       bool writable = true, bool has_vscrollbar = false);
 
                //! destructor
                virtual ~intlGUIEditBox();
@@ -118,6 +120,9 @@ namespace gui
                //! Updates the absolute position, splits text if required
                virtual void updateAbsolutePosition();
 
+               //! set true if this EditBox is writable
+               virtual void setWritable(bool can_write_text);
+
                //! Writes attributes of the element.
                virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const;
 
@@ -144,6 +149,12 @@ namespace gui
                bool processMouse(const SEvent& event);
                s32 getCursorPos(s32 x, s32 y);
 
+               //! Create a vertical scrollbar
+               void createVScrollBar();
+
+               //! Update the vertical scrollbar (visibilty & scroll position)
+               void updateVScrollBar();
+
                bool MouseMarking = false;
                bool Border;
                bool OverrideColorEnabled = false;
@@ -174,6 +185,10 @@ namespace gui
 
                core::rect<s32> CurrentTextRect = core::rect<s32>(0,0,1,1);
                core::rect<s32> FrameRect; // temporary values
+               u32 m_scrollbar_width;
+               IGUIScrollBar *m_vscrollbar;
+               bool m_writable;
+
        };