3
3
#include <osg/io_utils>
4
4
#include <osgWidget/WindowManager>
5
5
#include <osgWidget/Input>
7
12
namespace osgWidget {
14
class BlinkCursorCallback: public osg::Drawable::DrawCallback
17
BlinkCursorCallback(const bool& insertMode)
18
: _insertMode(insertMode)
22
virtual void drawImplementation( osg::RenderInfo & ri,const osg::Drawable* drawable ) const
24
static bool on = true;
25
static osg::Timer_t startTime = osg::Timer::instance()->tick();
26
osg::Timer_t now = osg::Timer::instance()->tick();
28
if (osg::Timer::instance()->delta_s(startTime,now)>(_insertMode?0.125:0.25))
34
drawable->drawImplementation(ri);
37
const bool& _insertMode;
9
40
Input::Input(const std::string& name, const std::string& label, unsigned int size):
17
_cursor (new Widget("cursor")) {
18
_text->setAlignment(osgText::Text::LEFT_BOTTOM_BASE_LINE);
19
_text->setKerningType(osgText::KERNING_NONE);
21
// Make the cursor un-copyable.
22
_cursor->setCanClone(false);
23
_cursor->setDataVariance(osg::Object::DYNAMIC);
24
_cursor->setColor(0.0f, 0.0f, 0.0f, 1.0f);
27
// For showing/hiding the "cursor."
29
// For keypresses, obviously.
31
// For "click" focusing.
35
_offsets.resize(size, 0.0f);
37
_text->getText().resize(size, ' ');
48
_cursor(new Widget("cursor")),
50
_selection(new Widget("selection")),
51
_selectionStartIndex(0),
52
_selectionEndIndex(0),
56
_text->setAlignment(osgText::Text::LEFT_BOTTOM_BASE_LINE);
57
_text->setKerningType(osgText::KERNING_NONE);
59
// Make the cursor un-copyable.
60
_cursor->setCanClone(false);
61
_cursor->setDataVariance(osg::Object::DYNAMIC);
62
_cursor->setColor(0.0f, 0.0f, 0.0f, 1.0f);
64
_selection->setCanClone(false);
65
_selection->setDataVariance(osg::Object::DYNAMIC);
68
// For showing/hiding the "cursor."
70
// For keypresses, obviously.
72
// For "click" focusing.
77
_offsets.resize(_text->getText().size()+1, 0.0f);
78
_widths.resize(_text->getText().size()+1, 1.0f);
82
_cursor->setDrawCallback( new BlinkCursorCallback(_insertMode) );
41
85
void Input::_calculateSize(const XYCoord& size) {
42
// An Input cannot currently set it's own size RELIABLY until the osgText implementation
43
// is dratiscally improved. I'm getting wildly crazy results. :(
44
// point_type height = size.y() > _cursor->getHeight() ? size.y() : _cursor->getHeight();
86
// An Input cannot currently set it's own size RELIABLY until the osgText implementation
87
// is dratiscally improved. I'm getting wildly crazy results. :(
88
// point_type height = size.y() > _cursor->getHeight() ? size.y() : _cursor->getHeight();
47
point_type width = size.x() + _cursor->getWidth();
48
point_type height = _cursor->getHeight();
50
if(width > getWidth()) setWidth(osg::round(width));
52
if(height > getHeight()) setHeight(osg::round(height));
91
point_type width = size.x() + _cursor->getWidth();
92
point_type height = _cursor->getHeight();
94
if(width > getWidth()) setWidth(osg::round(width));
96
if(height > getHeight()) setHeight(osg::round(height));
56
100
void Input::_calculateCursorOffsets() {
57
// Determine the "offset"
58
const osgText::Text::TextureGlyphQuadMap& tgqm = _text->getTextureGlyphQuadMap();
60
const osgText::Text::TextureGlyphQuadMap::const_iterator tgqmi = tgqm.begin();
62
const osgText::Text::GlyphQuads& gq = tgqmi->second;
101
// Determine the "offset"
103
_offsets.resize(_text->getText().size()+1, 0.0f);
104
_widths.resize(_text->getText().size()+1, 1.0f);
106
if (_text->getText().size()==0)
64
113
osg::Vec3 pos = _text->getPosition();
66
for(unsigned int i = 0; i < _maxSize; i++) {
67
osg::Vec3 ul = gq.getTransformedCoords(0)[0 + (i * 4)];
68
osg::Vec3 ll = gq.getTransformedCoords(0)[1 + (i * 4)];
69
osg::Vec3 lr = gq.getTransformedCoords(0)[2 + (i * 4)];
70
osg::Vec3 ur = gq.getTransformedCoords(0)[3 + (i * 4)];
72
_offsets[i] = lr.x() - pos.x();
74
// warn() << "vb: " << gq.getGlyphs()[i]->getHorizontalBearing() << std::endl;
78
bool Input::focus(WindowManager*) {
79
_cursor->setColor(0.0f, 0.0f, 0.0f, 1.0f);
84
bool Input::unfocus(WindowManager*) {
85
_cursor->setColor(0.0f, 0.0f, 0.0f, 0.0f);
115
osgText::Text::TextureGlyphQuadMap& tgqm = const_cast<osgText::Text::TextureGlyphQuadMap&>(_text->getTextureGlyphQuadMap());
116
osgText::Text::TextureGlyphQuadMap::iterator tgqmi = tgqm.begin();
118
std::vector<osg::Vec2> coords;
119
std::vector<osgText::Glyph*> glyphs;
120
for ( ; tgqmi != tgqm.end(); tgqmi++ )
122
const osgText::Text::GlyphQuads& gq = tgqmi->second;
124
//coords.insert(coords.end(),gq.getTransformedCoords(0).begin(),gq.getTransformedCoords(0).end());
125
coords.insert(coords.end(),gq.getCoords().begin(),gq.getCoords().end());
126
for (unsigned int i=0; i<gq.getGlyphs().size(); ++i)
128
glyphs.push_back(gq.getGlyphs().at(i));
132
std::list<unsigned int> keys;
133
for (unsigned int i=0; i<_text->getText().size(); ++i)
135
keys.push_back(_text->getText().at(i));
140
while (!keys.empty())
142
unsigned int key = keys.front();
143
for (unsigned int i=0; i<glyphs.size(); ++i)
145
static osgText::Glyph* previous_g = 0;
147
osgText::Glyph* g = glyphs.at(i);
148
if (g->getGlyphCode()==key)
150
lr = coords[2 + (i * 4)];
151
ll = coords[1 + (i * 4)];
153
point_type width = lr.x() - ll.x();
154
_widths[idx] = width == 0 ? g->getHorizontalAdvance() : width;
156
_offsets[idx] = lr.x() + pos.x();
159
_offsets[idx] += g->getHorizontalAdvance();
165
point_type& ref = _offsets[idx];
166
ref += previous_g->getHorizontalAdvance();
169
point_type& ref = _widths[idx];
170
ref += previous_g->getHorizontalAdvance();
175
glyphs.erase(glyphs.begin()+i);
176
coords.erase(coords.begin()+i*4);
177
coords.erase(coords.begin()+i*4);
178
coords.erase(coords.begin()+i*4);
179
coords.erase(coords.begin()+i*4);
186
_offsets[idx] = lr.x() + pos.x();
189
_wordsOffsets.clear();
190
for ( unsigned int i=0; i<_text->getText().size(); ++i )
192
while (i<_text->getText().size() && _text->getText().at(i)==' ') ++i;
193
if (i<_text->getText().size())_wordsOffsets.push_back(i);
194
while (i<_text->getText().size() && _text->getText().at(i)!=' ') ++i;
200
bool Input::focus(const WindowManager*) {
201
_cursor->setColor(0.5f, 0.5f, 0.6f, 1.0f);
202
_selection->setColor(0.8f, 0.8f, 0.9f, 1.0f);
207
bool Input::unfocus(const WindowManager*) {
208
_cursor->setColor(0.0f, 0.0f, 0.0f, 0.0f);
209
_selection->setColor(0.0f, 0.0f, 0.0f, 0.0f);
90
214
void Input::parented(Window* parent) {
91
Label::parented(parent);
93
_cursor->setSize(2.0f, _text->getCharacterHeight());
95
if(_cursorIndex) parent->getGeode()->setDrawable(_cursorIndex, _cursor.get());
97
else _cursorIndex = parent->addDrawableAndGetIndex(_cursor.get());
215
Label::parented(parent);
217
_cursor->setSize(_widths[_index], getHeight());
219
if(_cursorIndex) parent->getGeode()->setDrawable(_cursorIndex, _cursor.get());
220
else _cursorIndex = parent->addDrawableAndGetIndex(_cursor.get());
222
if(_selectionIndex) parent->getGeode()->setDrawable(_selectionIndex, _selection.get());
223
else _selectionIndex = parent->addDrawableAndGetIndex(_selection.get());
100
void Input::positioned() {
226
void Input::positioned()
101
228
point_type ln = static_cast<point_type>(_text->getLineCount());
103
230
ln = ln == 0.0f ? 1.0f : ln;
110
237
// XYCoord size = getTextSize();
112
239
_text->setPosition(osg::Vec3(x, y, _calculateZ(LAYER_MIDDLE)));
114
241
point_type xoffset = _index > 0 ? _offsets[_index - 1] : 0.0f;
116
_cursor->setOrigin(x + xoffset + 1.0f, y + 1.0f);
117
_cursor->setZ(_calculateZ(LAYER_MIDDLE));
120
bool Input::keyUp(int key, int mask, WindowManager*) {
124
bool Input::keyDown(int key, int mask, WindowManager*) {
125
osgText::String& s = _text->getText();
127
if(key == osgGA::GUIEventAdapter::KEY_BackSpace) {
129
// s.erase(s.begin() + (_index - 1));
135
_calculateCursorOffsets();
245
if (_index < _text->getText().size())
247
_cursor->setSize(_widths[_index], getHeight());
251
// We're at the end of the string, perhaps the string is empty,
252
// so get the advance for any character, perhaps a large one, I chose 'A'.
253
osgText::Glyph* glyph = const_cast<osgText::Font*>(_text->getFont())->getGlyph(osgText::FontResolution(_text->getFontWidth(), _text->getFontHeight()), 'A');
254
_cursor->setSize(glyph->getHorizontalAdvance(), getHeight());
259
_cursor->setSize(1.f, getHeight());
262
_cursor->setOrigin(getX() + xoffset, getY() );
263
_cursor->setZ(_calculateZ(LAYER_MIDDLE-1));
266
unsigned int selectionMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
267
unsigned int selectionMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
269
if (selectionMax - selectionMin > 0)
271
point_type xstart = selectionMin > 0 ? _offsets[selectionMin - 1] : 0.0f;
272
point_type xend = selectionMax > 0 ? _offsets[selectionMax - 1] : 0.0f;
274
_selection->setSize(xend-xstart, getHeight());
275
_selection->setOrigin(getX() + xstart, getY());
276
_selection->setZ(_calculateZ(LAYER_MIDDLE-2));
280
_selection->setSize(0, getHeight());
284
bool Input::keyUp(int key, int mask, const WindowManager*) {
288
bool Input::mouseDrag (double x, double y, const WindowManager*)
293
for ( unsigned int i = 0; i < _offsets.size(); ++i )
295
point_type offset1 = i > 0 ? _offsets.at(i-1) : 0;
296
point_type offset2 = _offsets.at(i);
297
if ((x >= offset1 && x <= offset2) ||
298
i == _offsets.size() - 1) // If we're at the last one, obviously it will be there.
300
_selectionEndIndex = _index = i;
309
bool Input::mousePush (double x, double y, const WindowManager* wm)
311
double offset = getOrigin().x();
312
Window* window = getParent();
315
offset += window->getOrigin().x();
321
for ( unsigned int i = 0; i < _offsets.size(); ++i )
323
point_type offset1 = i > 0 ? _offsets.at(i-1) : 0;
324
point_type offset2 = _offsets.at(i);
325
if ((x >= offset1 && x <= offset2) ||
326
i == _offsets.size() - 1) // If we're at the last one, obviously it will be there.
328
_selectionStartIndex = _selectionEndIndex = _index = i;
336
bool Input::mouseRelease(double, double, const WindowManager*)
341
bool Input::keyDown(int key, int mask, const WindowManager*)
343
osgText::String& s = _text->getText();
347
case osgGA::GUIEventAdapter::KEY_Left:
348
if (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)
351
for (unsigned int i = 0; i < _wordsOffsets.size() - 1; ++i)
353
if (_wordsOffsets.at(i) < _index && _index <= _wordsOffsets.at(i+1))
356
_index = _wordsOffsets.at(i);
360
if (!found && _wordsOffsets.size())
362
_index = _wordsOffsets.at(_wordsOffsets.size()-1);
370
if (mask & osgGA::GUIEventAdapter::MODKEY_SHIFT)
372
_selectionEndIndex = _index;
376
_selectionStartIndex = _selectionEndIndex = _index;
379
case osgGA::GUIEventAdapter::KEY_Right:
380
if (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)
383
for (unsigned int i = 0; i < _wordsOffsets.size() - 1; ++i)
385
if (_wordsOffsets.at(i) <= _index && _index < _wordsOffsets.at(i+1))
388
_index = _wordsOffsets.at(i+1);
392
if (!found && _wordsOffsets.size())
394
_index = _wordsOffsets.at(_wordsOffsets.size()-1);
398
if (_index < s.size())
403
if (mask & osgGA::GUIEventAdapter::MODKEY_SHIFT)
405
_selectionEndIndex = _index;
409
_selectionStartIndex = _selectionEndIndex = _index;
412
case osgGA::GUIEventAdapter::KEY_Home:
414
if (mask & osgGA::GUIEventAdapter::MODKEY_SHIFT)
416
_selectionEndIndex = _index;
420
_selectionStartIndex = _selectionEndIndex = _index;
423
case osgGA::GUIEventAdapter::KEY_End:
425
if (mask & osgGA::GUIEventAdapter::MODKEY_SHIFT)
427
_selectionEndIndex = _index;
431
_selectionStartIndex = _selectionEndIndex = _index;
434
case osgGA::GUIEventAdapter::KEY_Insert:
435
_insertMode = !_insertMode;
437
case osgGA::GUIEventAdapter::KEY_Delete:
439
unsigned int deleteMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
440
unsigned int deleteMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
442
if (deleteMax - deleteMin > 0)
445
else if (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)
449
for (unsigned int i =0; i < _wordsOffsets.size() - 1; ++i)
451
if (_wordsOffsets.at(i) <= _index && _index < _wordsOffsets.at(i+1))
453
deleteMin = _wordsOffsets.at(i);
454
deleteMax = _wordsOffsets.at(i+1);
459
else if (_index < s.size())
462
deleteMax = _index + 1;
465
if (deleteMin != deleteMax)
466
s.erase(s.begin() + deleteMin, s.begin() + deleteMax);
470
_calculateCursorOffsets();
473
_selectionStartIndex = _selectionEndIndex = _index;
476
case osgGA::GUIEventAdapter::KEY_BackSpace:
478
unsigned int deleteMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
479
unsigned int deleteMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
481
if (deleteMax - deleteMin > 0)
486
deleteMin = _index - 1;
490
if (deleteMin != deleteMax)
491
s.erase(s.begin() + deleteMin, s.begin() + deleteMax);
495
_calculateCursorOffsets();
498
_selectionStartIndex = _selectionEndIndex = _index;
142
502
if(key > 255 || _index >= _maxSize) return false;
144
// else if(_index < s.size()) s.insert(s.begin() + _index, key);
145
// else if(_index == s.size()) s.push_back(key);
504
if (((key=='v' || key=='V') && (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)) || (key==22))
507
// Data from clipboard
509
if (::OpenClipboard(NULL))
511
HANDLE hData = ::GetClipboardData( CF_TEXT );
512
char* buff = (char*)::GlobalLock( hData );
513
if (buff) data = buff;
514
::GlobalUnlock( hData );
520
unsigned int deleteMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
521
unsigned int deleteMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
523
if (deleteMax - deleteMin > 0)
525
data = data.substr(0, _maxSize-s.size()-(deleteMax - deleteMin));
527
s.erase(s.begin() + deleteMin, s.begin() + deleteMax);
528
std::copy(data.begin(), data.end(), std::inserter(s, s.begin() + deleteMin));
530
_index = deleteMin + data.size();
534
data = data.substr(0, _maxSize-s.size());
536
std::copy(data.begin(), data.end(), std::inserter(s, s.begin() + _index));
537
_index += data.length();
540
_selectionStartIndex = _selectionEndIndex = _index;
544
_calculateCursorOffsets();
546
_calculateSize(getTextSize());
548
getParent()->resize();
554
if (((key=='c' || key=='C' || key=='x' || key=='X') && (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)) || (key==3) || (key==24))
556
unsigned int selectionMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
557
unsigned int selectionMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
559
if (selectionMax - selectionMin > 0)
562
std::copy(s.begin() + selectionMin, s.begin() + selectionMax, std::inserter(data, data.begin()));
566
if(::OpenClipboard(NULL))
569
HGLOBAL clipbuffer = ::GlobalAlloc(GMEM_DDESHARE, data.length()+1);
570
char* buffer = (char*)::GlobalLock(clipbuffer);
571
strcpy(buffer, data.c_str());
572
::GlobalUnlock(clipbuffer);
573
::SetClipboardData(CF_TEXT,clipbuffer);
578
if (key=='x' || key=='X' || key == 24)
580
s.erase(s.begin() + selectionMin, s.begin() + selectionMax);
582
_index = selectionMin;
584
_selectionStartIndex = _selectionEndIndex = _index;
588
_calculateCursorOffsets();
590
_calculateSize(getTextSize());
592
getParent()->resize();
599
// If something is selected, we need to delete it and insert the character there.
600
unsigned int deleteMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
601
unsigned int deleteMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
603
if (deleteMax - deleteMin > 0)
605
s.erase(s.begin() + deleteMin, s.begin() + deleteMax);
609
_calculateCursorOffsets();
612
_selectionStartIndex = _selectionEndIndex = _index;
616
if (_insertMode && _index < s.size())
622
if (_index < _maxSize)
623
s.insert(s.begin() + _index, key);
151
628
_calculateCursorOffsets();
632
_selectionStartIndex = _selectionEndIndex = _index;
158
635
_calculateSize(getTextSize());
160
637
getParent()->resize();
165
642
void Input::setCursor(Widget*) {