// 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
//! 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");
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);
}
if ( !this->IsEnabled )
break;
- if (Text.size())
- {
+ if (!Text.empty()) {
core::stringw s;
if (MarkBegin != MarkEnd)
if ( !this->IsEnabled )
break;
- if (Text.size() != 0)
- {
+ if (!Text.empty()) {
core::stringw s;
if (MarkBegin != MarkEnd)
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);
const bool prevOver = OverrideColorEnabled;
const video::SColor prevColor = OverrideColor;
- if (Text.size())
- {
+ if (!Text.empty()) {
if (!IsEnabled && !OverrideColorEnabled)
{
OverrideColorEnabled = true;
// 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);
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);
+ }
}
}
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;
}
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);
}
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;
VScrollPos = 0;
// todo: adjust scrollbar
+ if (m_vscrollbar)
+ m_vscrollbar->setPos(VScrollPos);
}
//! set text markers
}
}
+//! 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
{
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);
}
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]);
setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
(EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
+ setWritable(in->getAttributeAsBool("Writable"));
// setOverrideFont(in->getAttributeAsFont("OverrideFont"));
}