LineEdit copy-paste & selection by shift-cursor.

This commit is contained in:
Lasse Öörni 2011-02-08 11:06:12 +00:00
parent 5d5cf9e0e0
commit 6d22d95d97
6 changed files with 158 additions and 22 deletions

View File

@ -75,6 +75,5 @@
</element>
<element type="Text">
<font name="Cour.ttf" size="10" />
<selectioncolor value="1.0 0.5 0.5" />
</element>
</elements>

View File

@ -172,12 +172,18 @@ static void registerLineEdit(asIScriptEngine* engine)
engine->RegisterObjectMethod("LineEdit", "void setMaxLength(uint)", asMETHOD(LineEdit, setMaxLength), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "void setEchoCharacter(uint8)", asMETHOD(LineEdit, setEchoCharacter), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "void setDefocusable(bool)", asMETHOD(LineEdit, setDefocusable), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "void setCursorMovable(bool)", asMETHOD(LineEdit, setCursorMovable), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "void setTextSelectable(bool)", asMETHOD(LineEdit, setTextSelectable), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "void setTextCopyable(bool)", asMETHOD(LineEdit, setTextCopyable), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "const string& getText() const", asMETHOD(LineEdit, getText), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "uint getCursorPosition() const", asMETHOD(LineEdit, getCursorPosition), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "float getCursorBlinkRate() const", asMETHOD(LineEdit, getCursorBlinkRate), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "uint getMaxLength() const", asMETHOD(LineEdit, getMaxLength), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "uint8 getEchoCharacter() const", asMETHOD(LineEdit, getEchoCharacter), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "bool isDefocusable() const", asMETHOD(LineEdit, isDefocusable), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "bool isCursorMovable() const", asMETHOD(LineEdit, isCursorMovable), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "bool isTextSelectable() const", asMETHOD(LineEdit, isTextSelectable), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "bool isTextCopyable() const", asMETHOD(LineEdit, isTextCopyable), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "Text@+ getTextElement() const", asMETHOD(LineEdit, getTextElement), asCALL_THISCALL);
engine->RegisterObjectMethod("LineEdit", "BorderImage@+ getCursorElement() const", asMETHOD(LineEdit, getCursorElement), asCALL_THISCALL);
registerRefCasts<UIElement, LineEdit>(engine, "UIElement", "LineEdit");

View File

@ -24,6 +24,7 @@
#include "Precompiled.h"
#include "Input.h"
#include "LineEdit.h"
#include "Log.h"
#include "Text.h"
#include "UIEvents.h"
@ -34,12 +35,15 @@ LineEdit::LineEdit(const std::string& name, const std::string& text) :
mLastFont(0),
mLastFontSize(0),
mCursorPosition(0),
mDragStartPosition(0),
mDragStartPosition(M_MAX_UNSIGNED),
mCursorBlinkRate(1.0f),
mCursorBlinkTimer(0.0f),
mMaxLength(0),
mEchoCharacter(0),
mDefocusable(true),
mCursorMovable(true),
mTextSelectable(true),
mTextCopyable(true),
mDefocus(false)
{
mClipChildren = true;
@ -65,6 +69,14 @@ void LineEdit::setStyle(const XMLElement& element, ResourceCache* cache)
if (element.hasChildElement("maxlength"))
setMaxLength(element.getChildElement("maxlength").getInt("value"));
if (element.hasChildElement("defocusable"))
setDefocusable(element.getChildElement("defocusable").getBool("enable"));
if (element.hasChildElement("cursormovable"))
setCursorMovable(element.getChildElement("cursormovable").getBool("enable"));
if (element.hasChildElement("textselectable"))
setTextSelectable(element.getChildElement("textselectable").getBool("enable"));
if (element.hasChildElement("textcopyable"))
setTextCopyable(element.getChildElement("textcopyable").getBool("enable"));
XMLElement textElem = element.getChildElement("text");
if (textElem)
@ -119,7 +131,7 @@ void LineEdit::update(float timeStep)
void LineEdit::onClick(const IntVector2& position, const IntVector2& screenPosition, int buttons, int qualifiers)
{
if (buttons & MOUSEB_LEFT)
if ((buttons & MOUSEB_LEFT) && (mCursorMovable))
{
unsigned pos = getCharIndex(position);
if (pos != M_MAX_UNSIGNED)
@ -137,20 +149,18 @@ void LineEdit::onDragStart(const IntVector2& position, const IntVector2& screenP
void LineEdit::onDragMove(const IntVector2& position, const IntVector2& screenPosition, int buttons, int qualifiers)
{
unsigned start = mDragStartPosition;
unsigned current = getCharIndex(position);
if ((start != M_MAX_UNSIGNED) && (current != M_MAX_UNSIGNED))
if ((mCursorMovable) && (mTextSelectable))
{
if (start < current)
unsigned start = mDragStartPosition;
unsigned current = getCharIndex(position);
if ((start != M_MAX_UNSIGNED) && (current != M_MAX_UNSIGNED))
{
mText->setSelection(start, current - start);
if (start < current)
mText->setSelection(start, current - start);
else
mText->setSelection(current, start - current);
setCursorPosition(current);
}
else
{
mText->setSelection(current, start - current);
setCursorPosition(start);
}
}
}
@ -161,21 +171,93 @@ void LineEdit::onKey(int key, int buttons, int qualifiers)
switch (key)
{
case KEY_LEFT:
mText->setSelection(0, 0);
if (mCursorPosition > 0)
case 'X':
case 'C':
if ((mTextCopyable) && (qualifiers & QUAL_CTRL))
{
--mCursorPosition;
unsigned start = mText->getSelectionStart();
unsigned length = mText->getSelectionLength();
if (mText->getSelectionLength())
sClipBoard = mLine.substr(start, length);
if (key == 'X')
{
if (start + length < mLine.length())
mLine = mLine.substr(0, start) + mLine.substr(start + length);
else
mLine = mLine.substr(0, start);
mText->setSelection(0, 0);
mCursorPosition = start;
changed = true;
}
}
break;
case 'V':
if ((mTextCopyable) && (qualifiers & QUAL_CTRL))
{
if (sClipBoard.length())
{
if (mCursorPosition < mLine.length())
mLine = mLine.substr(0, mCursorPosition) + sClipBoard + mLine.substr(mCursorPosition);
else
mLine += sClipBoard;
mCursorPosition += sClipBoard.length();
changed = true;
}
}
break;
case KEY_LEFT:
if (!(qualifiers & QUAL_SHIFT))
mText->setSelection(0, 0);
if ((mCursorMovable) && (mCursorPosition > 0))
{
if ((mTextSelectable) && (qualifiers & QUAL_SHIFT) && (!mText->getSelectionLength()))
mDragStartPosition = mCursorPosition;
if (qualifiers & QUAL_CTRL)
mCursorPosition = 0;
else
--mCursorPosition;
cursorMoved = true;
if ((mTextSelectable) && (qualifiers & QUAL_SHIFT))
{
unsigned start = mDragStartPosition;
unsigned current = mCursorPosition;
if (start < current)
mText->setSelection(start, current - start);
else
mText->setSelection(current, start - current);
}
}
break;
case KEY_RIGHT:
mText->setSelection(0, 0);
if (mCursorPosition < mLine.length())
if (!(qualifiers & QUAL_SHIFT))
mText->setSelection(0, 0);
if ((mCursorMovable) && (mCursorPosition < mLine.length()))
{
++mCursorPosition;
if ((mTextSelectable) && (qualifiers & QUAL_SHIFT) && (!mText->getSelectionLength()))
mDragStartPosition = mCursorPosition;
if (qualifiers & QUAL_CTRL)
mCursorPosition = mLine.length();
else
++mCursorPosition;
cursorMoved = true;
if ((mTextSelectable) && (qualifiers & QUAL_SHIFT))
{
unsigned start = mDragStartPosition;
unsigned current = mCursorPosition;
if (start < current)
mText->setSelection(start, current - start);
else
mText->setSelection(current, start - current);
}
}
break;
@ -223,6 +305,9 @@ void LineEdit::onChar(unsigned char c, int buttons, int qualifiers)
{
bool changed = false;
if (qualifiers & QUAL_CTRL)
return;
if (c == '\b')
{
if ((mLine.length()) && (mCursorPosition))
@ -242,11 +327,16 @@ void LineEdit::onChar(unsigned char c, int buttons, int qualifiers)
VariantMap eventData;
eventData[P_ELEMENT] = (void*)this;
sendEvent(EVENT_TEXTFINISHED, eventData);
mText->setSelection(0, 0);
}
else if (c == 27)
{
if (mDefocusable)
{
mText->setSelection(0, 0);
mDefocus = true;
}
}
else if ((c >= 0x20) && ((!mMaxLength) || (mLine.length() < mMaxLength)))
{
@ -271,7 +361,6 @@ void LineEdit::onChar(unsigned char c, int buttons, int qualifiers)
mLine = mLine.substr(0, start) + charStr + mLine.substr(start + length);
else
mLine = mLine.substr(0, start) + charStr;
mText->setSelection(0, 0);
mCursorPosition = start + 1;
}
changed = true;
@ -279,6 +368,7 @@ void LineEdit::onChar(unsigned char c, int buttons, int qualifiers)
if (changed)
{
mText->setSelection(0, 0);
updateText();
updateCursor();
@ -295,12 +385,15 @@ void LineEdit::setText(const std::string& text)
{
mLine = text;
mText->setText(text);
// If cursor is not movable, make sure it's at the text end
if (!mCursorMovable)
setCursorPosition(mLine.length());
updateText();
}
void LineEdit::setCursorPosition(unsigned position)
{
if (position > mLine.length())
if ((position > mLine.length()) || (!mCursorMovable))
position = mLine.length();
if (position != mCursorPosition)
@ -331,6 +424,21 @@ void LineEdit::setDefocusable(bool enable)
mDefocusable = enable;
}
void LineEdit::setCursorMovable(bool enable)
{
mCursorMovable = enable;
}
void LineEdit::setTextSelectable(bool enable)
{
mTextSelectable = enable;
}
void LineEdit::setTextCopyable(bool enable)
{
mTextCopyable = enable;
}
void LineEdit::updateText()
{
if (!mEchoCharacter)

View File

@ -67,6 +67,12 @@ public:
void setEchoCharacter(char c);
//! Set whether can defocus with ESC, default true
void setDefocusable(bool enable);
//! Set whether can move cursor with arrows or mouse, default true
void setCursorMovable(bool enable);
//! Set whether selections are allowed, default true
void setTextSelectable(bool enable);
//! Set whether copy-paste operations are allowed, default true
void setTextCopyable(bool enable);
//! Return text
const std::string& getText() const { return mLine; }
@ -80,6 +86,12 @@ public:
char getEchoCharacter() const { return mEchoCharacter; }
//! Return whether can defocus with ESC
bool isDefocusable() const { return mDefocusable; }
//! Return whether can move cursor with arrows or mouse
bool isCursorMovable() const { return mCursorMovable; }
//! Return whether selections are allowed
bool isTextSelectable() const { return mTextSelectable; }
//! Return whether copy-paste operations are allowed
bool isTextCopyable() const { return mTextCopyable; }
//! Return text element
Text* getTextElement() const { return mText; }
//! Return cursor element
@ -117,6 +129,12 @@ protected:
char mEchoCharacter;
//! ESC defocus flag
bool mDefocusable;
//! Cursor movable flag
bool mCursorMovable;
//! Text selectable flag
bool mTextSelectable;
//! Copy-paste enable flag
bool mTextCopyable;
//! Defocus flag (defocus on next update)
bool mDefocus;
};

View File

@ -29,6 +29,8 @@
#include "DebugNew.h"
std::string UIElement::sClipBoard;
UIElement::UIElement(const std::string& name) :
mName(name),
mParent(0),

View File

@ -293,6 +293,9 @@ protected:
//! Userdata
Variant mUserData;
//! Clipboard data
static std::string sClipBoard;
private:
//! Return child elements recursively
void getChildrenRecursive(std::vector<UIElement*>& dest) const;