From Trajce Nikolov, improvements to osgWidget::Input including selection support

This commit is contained in:
Robert Osfield 2010-01-27 16:31:34 +00:00
parent 18fc63a263
commit 00c17c6cff
2 changed files with 332 additions and 69 deletions

View File

@ -38,6 +38,8 @@ class OSGWIDGET_EXPORT Input: public Label
virtual bool unfocus (const WindowManager*);
virtual bool keyUp (int, int, const WindowManager*);
virtual bool keyDown (int, int, const WindowManager*);
virtual bool mouseDrag (double, double, const WindowManager*);
virtual bool mousePush (double x, double y, const WindowManager*);
void setCursor (Widget*);
unsigned int calculateBestYOffset (const std::string& = "qgl");
@ -80,21 +82,28 @@ class OSGWIDGET_EXPORT Input: public Label
void _calculateCursorOffsets();
point_type _xoff;
point_type _yoff;
point_type _xoff;
point_type _yoff;
unsigned int _index;
unsigned int _size;
unsigned int _cursorIndex;
unsigned int _maxSize;
unsigned int _textLength;
unsigned int _index;
unsigned int _size;
unsigned int _cursorIndex;
unsigned int _maxSize;
unsigned int _textLength;
std::vector<point_type> _offsets;
std::vector<point_type> _wordsOffsets;
std::vector<point_type> _widths;
osg::ref_ptr<Widget> _cursor;
bool _insertMode;
std::vector<point_type> _offsets;
std::vector<point_type> _wordsOffsets;
std::vector<point_type> _widths;
osg::ref_ptr<Widget> _cursor;
bool _insertMode;
osg::ref_ptr<Widget> _selection;
unsigned int _selectionStartIndex;
unsigned int _selectionEndIndex;
unsigned int _selectionIndex;
point_type _mouseClickX;
};
}

View File

@ -4,6 +4,10 @@
#include <osgWidget/WindowManager>
#include <osgWidget/Input>
#ifdef WIN32
#include <windows.h>
#endif
namespace osgWidget {
class BlinkCursorCallback: public osg::Drawable::DrawCallback
@ -33,16 +37,22 @@ protected:
};
Input::Input(const std::string& name, const std::string& label, unsigned int size):
Label (name, label),
_xoff (0.0f),
_yoff (0.0f),
_index (0),
_size (0),
_cursorIndex (0),
_textLength (0),
_maxSize (size),
_insertMode (false),
_cursor (new Widget("cursor")) {
Label(name, label),
_xoff(0.0f),
_yoff(0.0f),
_index(0),
_size(0),
_cursorIndex(0),
_maxSize(size),
_textLength(0),
_cursor(new Widget("cursor")),
_insertMode(false),
_selection(new Widget("selection")),
_selectionStartIndex(0),
_selectionEndIndex(0),
_selectionIndex(0),
_mouseClickX(0)
{
_text->setAlignment(osgText::Text::LEFT_BOTTOM_BASE_LINE);
_text->setKerningType(osgText::KERNING_NONE);
@ -51,13 +61,17 @@ _cursor (new Widget("cursor")) {
_cursor->setDataVariance(osg::Object::DYNAMIC);
_cursor->setColor(0.0f, 0.0f, 0.0f, 1.0f);
_selection->setCanClone(false);
_selection->setDataVariance(osg::Object::DYNAMIC);
setEventMask(
// For showing/hiding the "cursor."
EVENT_MASK_FOCUS |
// For keypresses, obviously.
EVENT_MASK_KEY |
// For "click" focusing.
EVENT_MOUSE_PUSH
EVENT_MOUSE_PUSH |
EVENT_MASK_MOUSE_DRAG
);
_offsets.resize(size+1, 0.0f);
@ -168,12 +182,14 @@ void Input::_calculateCursorOffsets() {
bool Input::focus(const WindowManager*) {
_cursor->setColor(0.5f, 0.5f, 0.6f, 1.0f);
_selection->setColor(0.8f, 0.8f, 0.9f, 1.0f);
return true;
}
bool Input::unfocus(const WindowManager*) {
_cursor->setColor(0.0f, 0.0f, 0.0f, 0.0f);
_selection->setColor(0.0f, 0.0f, 0.0f, 0.0f);
return true;
}
@ -184,8 +200,10 @@ void Input::parented(Window* parent) {
_cursor->setSize(_widths[_index], getHeight());
if(_cursorIndex) parent->getGeode()->setDrawable(_cursorIndex, _cursor.get());
else _cursorIndex = parent->addDrawableAndGetIndex(_cursor.get());
if(_selectionIndex) parent->getGeode()->setDrawable(_selectionIndex, _selection.get());
else _selectionIndex = parent->addDrawableAndGetIndex(_selection.get());
}
void Input::positioned() {
@ -207,12 +225,77 @@ void Input::positioned() {
_cursor->setSize(_widths[_index], getHeight());
_cursor->setOrigin(getX() + xoffset, getY() );
_cursor->setZ(_calculateZ(LAYER_MIDDLE-1));
unsigned int _selectionMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
unsigned int _selectionMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
if (_selectionMax-_selectionMin>0)
{
unsigned int size = 0;
for (unsigned int i=_selectionMin; i<_selectionMax; ++i)
{
size += _widths[i];
}
point_type xoffset = _selectionMin > 0 ? _offsets[_selectionMin - 1] : 0.0f;
_selection->setSize(size, getHeight());
_selection->setOrigin(getX() + xoffset, getY());
_selection->setZ(_calculateZ(LAYER_MIDDLE-2));
}
else
{
_selection->setSize(0, getHeight());
}
}
bool Input::keyUp(int key, int mask, const WindowManager*) {
return false;
}
bool Input::mouseDrag (double x, double y, const WindowManager*)
{
_mouseClickX += x;
x = _mouseClickX;
unsigned int size = 0;
for ( unsigned int i=0; i< _widths.size(); ++i )
{
if (x > size && x < size+_widths.at(i))
{
_selectionEndIndex = _index = i;
positioned();
break;
}
size += _widths.at(i);
}
return false;
}
bool Input::mousePush (double x, double y, const WindowManager*)
{
double offset = getOrigin().x();
Window* window = getParent();
while (window) { offset += window->getOrigin().x(); window = window->getParent(); }
x -= offset;
_mouseClickX = x;
unsigned int size = 0;
for ( unsigned int i=0; i< _widths.size(); ++i )
{
if (x > size && x < size+_widths.at(i))
{
_selectionStartIndex = _selectionEndIndex = _index = i;
positioned();
break;
}
size += _widths.at(i);
}
return false;
}
bool Input::keyDown(int key, int mask, const WindowManager*) {
osgText::String& s = _text->getText();
@ -241,6 +324,14 @@ bool Input::keyDown(int key, int mask, const WindowManager*) {
{
--_index;
}
if (mask & osgGA::GUIEventAdapter::MODKEY_SHIFT)
{
_selectionEndIndex = _index;
}
else
{
_selectionStartIndex = _selectionEndIndex = _index;
}
break;
case osgGA::GUIEventAdapter::KEY_Right:
if (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)
@ -265,81 +356,243 @@ bool Input::keyDown(int key, int mask, const WindowManager*) {
{
++_index;
}
if (mask & osgGA::GUIEventAdapter::MODKEY_SHIFT)
{
_selectionEndIndex = _index;
}
else
{
_selectionStartIndex = _selectionEndIndex = _index;
}
break;
case osgGA::GUIEventAdapter::KEY_Home:
_index = 0;
if (mask & osgGA::GUIEventAdapter::MODKEY_SHIFT)
{
_selectionEndIndex = _index;
}
else
{
_selectionStartIndex = _selectionEndIndex = _index;
}
break;
case osgGA::GUIEventAdapter::KEY_End:
_index = _textLength;
if (mask & osgGA::GUIEventAdapter::MODKEY_SHIFT)
{
_selectionEndIndex = _index;
}
else
{
_selectionStartIndex = _selectionEndIndex = _index;
}
break;
case osgGA::GUIEventAdapter::KEY_Insert:
_insertMode = !_insertMode;
break;
case osgGA::GUIEventAdapter::KEY_Delete:
if (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)
{
point_type deleteToIdx = _textLength;
for (unsigned int i=0; i<_wordsOffsets.size()-1; ++i)
unsigned int _selectionMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
unsigned int _selectionMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
if (_selectionMax-_selectionMin>0)
{
if (_wordsOffsets.at(i) <= _index && _index < _wordsOffsets.at(i+1))
point_type deleteToIdx = _selectionMax;
for (unsigned int i=0; i < s.size()-_selectionMin; ++i)
{
deleteToIdx = _wordsOffsets.at(i+1);
break;
s[_selectionMin+i] = deleteToIdx+i < s.size() ? s[deleteToIdx+i] : ' ';
}
_text->update();
_calculateCursorOffsets();
_textLength -= deleteToIdx-_selectionMin;
_index = _selectionMin;
_selectionStartIndex = _selectionEndIndex = _index;
}
for (unsigned int i=0; i < s.size()-_index; ++i)
else
if (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)
{
s[_index+i] = deleteToIdx+i < s.size() ? s[deleteToIdx+i] : ' ';
point_type deleteToIdx = _textLength;
for (unsigned int i=0; i<_wordsOffsets.size()-1; ++i)
{
if (_wordsOffsets.at(i) <= _index && _index < _wordsOffsets.at(i+1))
{
deleteToIdx = _wordsOffsets.at(i+1);
break;
}
}
for (unsigned int i=0; i < s.size()-_index; ++i)
{
s[_index+i] = deleteToIdx+i < s.size() ? s[deleteToIdx+i] : ' ';
}
_text->update();
_calculateCursorOffsets();
_textLength -= deleteToIdx-_index;
}
_text->update();
_calculateCursorOffsets();
_textLength -= deleteToIdx-_index;
}
else
if (_index < s.size()-1)
{
for (unsigned int i=_index; i < s.size()-1; ++i)
{
s[i] = s[i+1];
}
_text->update();
_calculateCursorOffsets();
--_textLength;
}
break;
case osgGA::GUIEventAdapter::KEY_BackSpace:
if(_index >= 1) {
_index--;
if (_index< s.size()-1)
else
if (_index < s.size()-1)
{
for (unsigned int i=_index; i < s.size()-1; ++i)
{
s[i] = s[i+1];
s[i+1] = ' ';
}
_text->update();
_calculateCursorOffsets();
--_textLength;
}
}
break;
case osgGA::GUIEventAdapter::KEY_BackSpace:
{
unsigned int _selectionMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
unsigned int _selectionMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
if (_selectionMax-_selectionMin>0)
{
point_type deleteToIdx = _selectionMax;
for (unsigned int i=0; i < s.size()-_selectionMin; ++i)
{
s[_selectionMin+i] = deleteToIdx+i < s.size() ? s[deleteToIdx+i] : ' ';
}
_text->update();
_calculateCursorOffsets();
_textLength -= deleteToIdx-_selectionMin;
_index = _selectionMin;
_selectionStartIndex = _selectionEndIndex = _index;
}
else
{
s[s.size()-1] = ' ';
}
if(_index >= 1) {
_text->update();
_index--;
if (_index< s.size()-1)
{
for (unsigned int i=_index; i < s.size()-1; ++i)
{
s[i] = s[i+1];
s[i+1] = ' ';
}
}
else
{
s[s.size()-1] = ' ';
}
_calculateCursorOffsets();
_text->update();
--_textLength;
}
_calculateCursorOffsets();
--_textLength;
}
}
break;
default:
if(key > 255 || _index >= _maxSize) return false;
if (((key=='v' || key=='V') && (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)) || (key==22))
{
_selectionStartIndex = _selectionEndIndex = _index;
std::string data;
// Data from clipboard
#ifdef WIN32
if (::OpenClipboard(NULL))
{
HANDLE hData = ::GetClipboardData( CF_TEXT );
char* buff = (char*)::GlobalLock( hData );
if (buff) data = buff;
::GlobalUnlock( hData );
::CloseClipboard();
}
#endif
if (!data.empty())
{
data = data.substr(0,_maxSize-_index);
_textLength += data.size();
_selectionEndIndex = _textLength;
std::string::iterator itr = data.begin();
for ( ; itr != data.end(); ++itr )
{
s[_index++] = *itr;
}
_text->update();
_calculateCursorOffsets();
_calculateSize(getTextSize());
getParent()->resize();
return false;
}
}
else
if (((key=='c' || key=='C') && (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)) || (key==3))
{
unsigned int _selectionMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
unsigned int _selectionMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
if (_selectionMax-_selectionMin>0)
{
std::string data;
for (unsigned int i=_selectionMin; i<_selectionMax; ++i)
{
data.push_back(s[i]);
}
// Data to clipboard
#ifdef WIN32
if(::OpenClipboard(NULL))
{
::EmptyClipboard();
HGLOBAL clipbuffer = ::GlobalAlloc(GMEM_DDESHARE, data.length()+1);
char* buffer = (char*)::GlobalLock(clipbuffer);
strcpy(buffer, data.c_str());
::GlobalUnlock(clipbuffer);
::SetClipboardData(CF_TEXT,clipbuffer);
::CloseClipboard();
}
#endif
}
return false;
}
{
unsigned int _selectionMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
unsigned int _selectionMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
if (_selectionMax-_selectionMin>0)
{
point_type deleteToIdx = _selectionMax;
for (unsigned int i=0; i < s.size()-_selectionMin; ++i)
{
s[_selectionMin+i] = deleteToIdx+i < s.size() ? s[deleteToIdx+i] : ' ';
}
_text->update();
_calculateCursorOffsets();
_textLength -= deleteToIdx-_selectionMin;
_index = _selectionMin;
_selectionStartIndex = _selectionEndIndex = _index;
}
}
if (!_insertMode)
{
for (unsigned int i=s.size()-1; i>_index; --i)
@ -357,6 +610,8 @@ bool Input::keyDown(int key, int mask, const WindowManager*) {
_index++;
if (!_insertMode) ++_textLength;
_selectionStartIndex = _selectionEndIndex = _index;
}
// _text->update();
@ -373,7 +628,6 @@ void Input::setCursor(Widget*) {
unsigned int Input::calculateBestYOffset(const std::string& s)
{
const osgText::FontResolution fr(static_cast<unsigned int>(_text->getCharacterHeight()),
static_cast<unsigned int>(_text->getCharacterHeight()));