X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2FintlGUIEditBox.cpp;h=279e7a48a205e1a022855b965de3ea5f2354b7db;hb=9f3a5859378ac01648ca0caf01b04ad57c871baa;hp=32cca48667ada6956e5e48e053d6f345f32e1ce3;hpb=979ca23f1eae1adeb8b0083dffe7203c54d87395;p=minetest.git diff --git a/src/intlGUIEditBox.cpp b/src/intlGUIEditBox.cpp index 32cca4866..279e7a48a 100644 --- a/src/intlGUIEditBox.cpp +++ b/src/intlGUIEditBox.cpp @@ -29,9 +29,10 @@ // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h +#include #include "intlGUIEditBox.h" -#ifdef _IRR_COMPILE_WITH_GUI_ +#if defined(_IRR_COMPILE_WITH_GUI_) && IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9 #include "IGUISkin.h" #include "IGUIEnvironment.h" @@ -41,6 +42,7 @@ //#include "irrlicht/os.cpp" #include "porting.h" //#include "Keycodes.h" +#include "log.h" /* todo: @@ -59,14 +61,10 @@ namespace gui //! constructor intlGUIEditBox::intlGUIEditBox(const wchar_t* text, bool border, IGUIEnvironment* environment, IGUIElement* parent, s32 id, - const core::rect& 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& 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"); @@ -95,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); } @@ -270,7 +277,7 @@ bool intlGUIEditBox::OnEvent(const SEvent& event) break; case EET_KEY_INPUT_EVENT: { -#if defined(linux) +#if (defined(__linux__) || defined(__FreeBSD__)) // ################################################################ // ValkaTR: // This part is the difference from the original intlGUIEditBox @@ -632,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) @@ -672,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) @@ -775,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 localClipRect = FrameRect; localClipRect.clipAgainst(AbsoluteClippingRect); @@ -822,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; @@ -910,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); @@ -935,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); + } } } @@ -1059,25 +1068,31 @@ bool intlGUIEditBox::processMouse(const SEvent& event) else { if (!AbsoluteClippingRect.isPointInside( - core::position2d(event.MouseInput.X, event.MouseInput.Y))) - { + core::position2d(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; } @@ -1095,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); } @@ -1187,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; @@ -1426,6 +1440,8 @@ void intlGUIEditBox::calculateScrollPos() VScrollPos = 0; // todo: adjust scrollbar + if (m_vscrollbar) + m_vscrollbar->setPos(VScrollPos); } //! set text markers @@ -1454,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 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 { @@ -1472,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); } @@ -1490,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]); @@ -1498,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")); }