]> git.lizzy.rs Git - minetest.git/blobdiff - src/intlGUIEditBox.cpp
Profiler: Fix var args not being passed to callback register function
[minetest.git] / src / intlGUIEditBox.cpp
index 33bf8a13cfb22e155cac32ce0e0cea53ac9b4f1c..279e7a48a205e1a022855b965de3ea5f2354b7db 100644 (file)
@@ -29,6 +29,7 @@
 // This file is part of the "Irrlicht Engine".
 // For conditions of distribution and use, see copyright notice in irrlicht.h
 
+#include <util/numeric.h>
 #include "intlGUIEditBox.h"
 
 #if defined(_IRR_COMPILE_WITH_GUI_) && IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9
@@ -60,14 +61,10 @@ namespace gui
 //! constructor
 intlGUIEditBox::intlGUIEditBox(const wchar_t* text, bool border,
                IGUIEnvironment* environment, IGUIElement* parent, s32 id,
-               const core::rect<s32>& rectangle)
-       : IGUIEditBox(environment, parent, id, rectangle), MouseMarking(false),
-       Border(border), OverrideColorEnabled(false), MarkBegin(0), MarkEnd(0),
-       OverrideColor(video::SColor(101,255,255,255)), OverrideFont(0), LastBreakFont(0),
-       Operator(0), BlinkStartTime(0), CursorPos(0), HScrollPos(0), VScrollPos(0), Max(0),
-       WordWrap(false), MultiLine(false), AutoScroll(true), PasswordBox(false),
-       PasswordChar(L'*'), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER),
-       CurrentTextRect(0,0,1,1), FrameRect(rectangle)
+               const core::rect<s32>& rectangle, bool writable, bool has_vscrollbar)
+       : IGUIEditBox(environment, parent, id, rectangle),
+       Border(border), FrameRect(rectangle),
+       m_scrollbar_width(0), m_vscrollbar(NULL), m_writable(writable)
 {
        #ifdef _DEBUG
        setDebugName("intlintlGUIEditBox");
@@ -96,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);
 }
 
 
@@ -271,7 +277,7 @@ bool intlGUIEditBox::OnEvent(const SEvent& event)
                        break;
                case EET_KEY_INPUT_EVENT:
         {
-#if (defined(linux) || defined(__linux) || defined(__FreeBSD__))
+#if (defined(__linux__) || defined(__FreeBSD__))
             // ################################################################
                        // ValkaTR:
             // This part is the difference from the original intlGUIEditBox
@@ -633,8 +639,7 @@ bool intlGUIEditBox::processKey(const SEvent& event)
                if ( !this->IsEnabled )
                        break;
 
-               if (Text.size())
-               {
+               if (!Text.empty()) {
                        core::stringw s;
 
                        if (MarkBegin != MarkEnd)
@@ -673,8 +678,7 @@ bool intlGUIEditBox::processKey(const SEvent& event)
                if ( !this->IsEnabled )
                        break;
 
-               if (Text.size() != 0)
-               {
+               if (!Text.empty()) {
                        core::stringw s;
 
                        if (MarkBegin != MarkEnd)
@@ -776,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);
 
@@ -823,8 +831,7 @@ void intlGUIEditBox::draw()
                const bool prevOver = OverrideColorEnabled;
                const video::SColor prevColor = OverrideColor;
 
-               if (Text.size())
-               {
+               if (!Text.empty()) {
                        if (!IsEnabled && !OverrideColorEnabled)
                        {
                                OverrideColorEnabled = true;
@@ -911,7 +918,7 @@ void intlGUIEditBox::draw()
                                        // draw marked text
                                        s = txtLine->subString(lineStartPos, lineEndPos - lineStartPos);
 
-                                       if (s.size())
+                                       if (!s.empty())
                                                font->draw(s.c_str(), CurrentTextRect,
                                                        OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_HIGH_LIGHT_TEXT),
                                                        false, true, &localClipRect);
@@ -936,14 +943,15 @@ 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);
+                       }
                }
        }
 
@@ -1060,25 +1068,31 @@ bool intlGUIEditBox::processMouse(const SEvent& event)
                else
                {
                        if (!AbsoluteClippingRect.isPointInside(
-                               core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y)))
-                       {
+                               core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y))) {
                                return false;
                        }
-                       else
-                       {
-                               // move cursor
-                               CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
 
-                s32 newMarkBegin = MarkBegin;
-                               if (!MouseMarking)
-                                       newMarkBegin = CursorPos;
 
-                               MouseMarking = true;
-                               setTextMarkers( newMarkBegin, CursorPos);
-                               calculateScrollPos();
-                               return true;
-                       }
+                       // move cursor
+                       CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
+
+                       s32 newMarkBegin = MarkBegin;
+                       if (!MouseMarking)
+                               newMarkBegin = CursorPos;
+
+                       MouseMarking = true;
+                       setTextMarkers( newMarkBegin, CursorPos);
+                       calculateScrollPos();
+                       return true;
                }
+               break;
+       case EMIE_MOUSE_WHEEL:
+               if (m_vscrollbar) {
+                       s32 pos = m_vscrollbar->getPos();
+                       s32 step = m_vscrollbar->getSmallStep();
+                       m_vscrollbar->setPos(pos - event.MouseInput.Wheel * step);
+               }
+               break;
        default:
                break;
        }
@@ -1096,39 +1110,39 @@ s32 intlGUIEditBox::getCursorPos(s32 x, s32 y)
 
        const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1;
 
-       core::stringw *txtLine=0;
-       s32 startPos=0;
-       x+=3;
+       core::stringw *txtLine = NULL;
+       s32 startPos = 0;
+       u32 curr_line_idx = 0;
+       x += 3;
 
-       for (u32 i=0; i < lineCount; ++i)
-       {
-               setTextRect(i);
-               if (i == 0 && y < CurrentTextRect.UpperLeftCorner.Y)
+       for (; curr_line_idx < lineCount; ++curr_line_idx) {
+               setTextRect(curr_line_idx);
+               if (curr_line_idx == 0 && y < CurrentTextRect.UpperLeftCorner.Y)
                        y = CurrentTextRect.UpperLeftCorner.Y;
-               if (i == lineCount - 1 && y > CurrentTextRect.LowerRightCorner.Y )
+               if (curr_line_idx == lineCount - 1 && y > CurrentTextRect.LowerRightCorner.Y)
                        y = CurrentTextRect.LowerRightCorner.Y;
 
                // is it inside this region?
-               if (y >= CurrentTextRect.UpperLeftCorner.Y && y <= CurrentTextRect.LowerRightCorner.Y)
-               {
+               if (y >= CurrentTextRect.UpperLeftCorner.Y && y <= CurrentTextRect.LowerRightCorner.Y) {
                        // we've found the clicked line
-                       txtLine = (WordWrap || MultiLine) ? &BrokenText[i] : &Text;
-                       startPos = (WordWrap || MultiLine) ? BrokenTextPositions[i] : 0;
+                       txtLine = (WordWrap || MultiLine) ? &BrokenText[curr_line_idx] : &Text;
+                       startPos = (WordWrap || MultiLine) ? BrokenTextPositions[curr_line_idx] : 0;
                        break;
                }
        }
 
        if (x < CurrentTextRect.UpperLeftCorner.X)
                x = CurrentTextRect.UpperLeftCorner.X;
+       else if (x > CurrentTextRect.LowerRightCorner.X)
+               x = CurrentTextRect.LowerRightCorner.X;
 
-       s32 idx = font->getCharacterFromPos(Text.c_str(), x - CurrentTextRect.UpperLeftCorner.X);
-
-       // click was on or left of the line
-       if (idx != -1)
-               return idx + startPos;
+       s32 idx = font->getCharacterFromPos(txtLine->c_str(), x - CurrentTextRect.UpperLeftCorner.X);
+       // Special handling for last line, if we are on limits, add 1 extra shift because idx
+       // will be the last char, not null char of the wstring
+       if (curr_line_idx == lineCount - 1 && x == CurrentTextRect.LowerRightCorner.X)
+               idx++;
 
-       // click was off the right edge of the line, go to end.
-       return txtLine->size() + startPos;
+       return rangelim(idx + startPos, 0, S32_MAX);
 }
 
 
@@ -1188,8 +1202,7 @@ void intlGUIEditBox::breakText()
 
                if (c == L' ' || c == 0 || i == (size-1))
                {
-                       if (word.size())
-                       {
+                       if (!word.empty()) {
                                // here comes the next whitespace, look if
                                // we can break the last word to the next line.
                                s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
@@ -1427,6 +1440,8 @@ void intlGUIEditBox::calculateScrollPos()
                VScrollPos = 0;
 
        // todo: adjust scrollbar
+       if (m_vscrollbar)
+               m_vscrollbar->setPos(VScrollPos);
 }
 
 //! set text markers
@@ -1455,6 +1470,81 @@ void intlGUIEditBox::sendGuiEvent(EGUI_EVENT_TYPE type)
        }
 }
 
+//! Create a vertical scrollbar
+void intlGUIEditBox::createVScrollBar()
+{
+       s32 fontHeight = 1;
+
+       if (OverrideFont) {
+               fontHeight = OverrideFont->getDimension(L"").Height;
+       } else {
+               if (IGUISkin* skin = Environment->getSkin()) {
+                       if (IGUIFont* font = skin->getFont()) {
+                               fontHeight = font->getDimension(L"").Height;
+                       }
+               }
+       }
+
+       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(3 * fontHeight);
+       m_vscrollbar->setLargeStep(10 * fontHeight);
+}
+
+//! 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 > (u32) 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
 {
@@ -1473,6 +1563,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);
 }
@@ -1491,7 +1582,7 @@ void intlGUIEditBox::deserializeAttributes(io::IAttributes* in, io::SAttributeRe
        setAutoScroll(in->getAttributeAsBool("AutoScroll"));
        core::stringw ch = in->getAttributeAsStringW("PasswordChar");
 
-       if (!ch.size())
+       if (ch.empty())
                setPasswordBox(in->getAttributeAsBool("PasswordBox"));
        else
                setPasswordBox(in->getAttributeAsBool("PasswordBox"), ch[0]);
@@ -1499,6 +1590,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"));
 }