root/OpenSceneGraph/trunk/src/osgWidget/Input.cpp @ 11101

Revision 11101, 19.0 kB (checked in by robert, 5 years ago)

From Trajce Nicklov, fixes to warnings

Line 
1// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008
2
3#include <osg/io_utils>
4#include <osgWidget/WindowManager>
5#include <osgWidget/Input>
6
7#ifdef WIN32
8#include <windows.h>
9#endif
10
11namespace osgWidget {
12
13class BlinkCursorCallback: public osg::Drawable::DrawCallback
14{
15public:
16    BlinkCursorCallback(const bool& insertMode)
17        : _insertMode(insertMode)
18    {
19    }
20
21    virtual void drawImplementation( osg::RenderInfo & ri,const osg::Drawable* drawable ) const
22    {
23        static bool on = true;
24        static osg::Timer_t startTime = osg::Timer::instance()->tick();
25        osg::Timer_t now = osg::Timer::instance()->tick();
26
27        if (osg::Timer::instance()->delta_s(startTime,now)>(_insertMode?0.125:0.25))
28        {
29            on = !on;
30            startTime = now;
31        }
32        if (on)
33            drawable->drawImplementation(ri);
34    }
35protected:
36    const bool&    _insertMode;
37};
38
39Input::Input(const std::string& name, const std::string& label, unsigned int size):
40    Label(name, label),
41    _xoff(0.0f),
42    _yoff(0.0f),
43    _index(0),
44    _size(0),
45    _cursorIndex(0),
46    _maxSize(size),
47    _textLength(0),
48    _cursor(new Widget("cursor")),
49    _insertMode(false),
50    _selection(new Widget("selection")),
51    _selectionStartIndex(0),
52    _selectionEndIndex(0),
53    _selectionIndex(0),
54    _mouseClickX(0)
55{
56   _text->setAlignment(osgText::Text::LEFT_BOTTOM_BASE_LINE);
57   _text->setKerningType(osgText::KERNING_NONE);
58
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);
63
64   _selection->setCanClone(false);
65   _selection->setDataVariance(osg::Object::DYNAMIC);
66
67   setEventMask(
68       // For showing/hiding the "cursor."
69       EVENT_MASK_FOCUS |
70       // For keypresses, obviously.
71       EVENT_MASK_KEY |
72       // For "click" focusing.
73       EVENT_MOUSE_PUSH |
74       EVENT_MASK_MOUSE_DRAG
75   );
76
77   _offsets.resize(size+1, 0.0f);
78   _widths.resize(size+1, 1.0f);
79
80   _text->getText().resize(size, ' ');
81   _text->update();
82
83   _cursor->setDrawCallback( new BlinkCursorCallback(_insertMode) );
84}
85
86void Input::_calculateSize(const XYCoord& size) {
87   // An Input cannot currently set it's own size RELIABLY until the osgText implementation
88   // is dratiscally improved. I'm getting wildly crazy results. :(
89   // point_type height = size.y() > _cursor->getHeight() ? size.y() : _cursor->getHeight();
90
91#if 0
92   point_type width  = size.x() + _cursor->getWidth();
93   point_type height = _cursor->getHeight();
94
95   if(width > getWidth()) setWidth(osg::round(width));
96
97   if(height > getHeight()) setHeight(osg::round(height));
98#endif
99}
100
101void Input::_calculateCursorOffsets() {
102   // Determine the "offset"
103
104    if (_text->getText().size()==0)
105    {
106        _offsets[0] = 0;
107        _widths[0] = 0;
108        return;
109    }
110
111    osg::Vec3 pos = _text->getPosition();
112
113    osgText::Text::TextureGlyphQuadMap& tgqm = const_cast<osgText::Text::TextureGlyphQuadMap&>(_text->getTextureGlyphQuadMap());
114    osgText::Text::TextureGlyphQuadMap::iterator tgqmi = tgqm.begin();
115
116    std::vector<osg::Vec2>                coords;
117    std::vector<osgText::Font::Glyph*>    glyphs;
118    for ( ; tgqmi != tgqm.end(); tgqmi++ )
119    {
120        const osgText::Text::GlyphQuads& gq = tgqmi->second;
121
122        //coords.insert(coords.end(),gq.getTransformedCoords(0).begin(),gq.getTransformedCoords(0).end());
123        coords.insert(coords.end(),gq.getCoords().begin(),gq.getCoords().end());
124        for (unsigned int i=0; i<gq.getGlyphs().size(); ++i)
125        {
126            glyphs.push_back(gq.getGlyphs().at(i));
127        }
128    }
129   
130    std::list<unsigned int> keys;
131    for (unsigned int i=0; i<_text->getText().size(); ++i)
132    {
133        keys.push_back(_text->getText().at(i));
134    }
135    unsigned int idx=0;
136    osg::Vec2 lr;
137    osg::Vec2 ll;
138    while (!keys.empty())
139    {
140        unsigned int key = keys.front();
141        for (unsigned int i=0; i<glyphs.size(); ++i)
142        {
143            static osgText::Font::Glyph* previous_g = 0;
144
145            osgText::Font::Glyph* g = glyphs.at(i);
146            if (g->getGlyphCode()==key)
147            {
148                lr = coords[2 + (i * 4)];
149                ll = coords[1 + (i * 4)];
150
151                point_type width = lr.x() - ll.x();
152                _widths[idx] = width == 0 ? g->getHorizontalAdvance() : width;
153
154                _offsets[idx] = lr.x() + pos.x();
155
156                if (width == 0)
157                    _offsets[idx] += g->getHorizontalAdvance();
158                ++idx;
159
160                if (previous_g)
161                {
162                    {
163                        point_type& ref = _offsets[idx];
164                        ref += previous_g->getHorizontalAdvance();
165                    }
166                    {
167                        point_type& ref = _widths[idx];
168                        ref += previous_g->getHorizontalAdvance();
169                    }
170                }
171                previous_g = g;
172
173                glyphs.erase(glyphs.begin()+i);
174                coords.erase(coords.begin()+i*4);
175                coords.erase(coords.begin()+i*4);
176                coords.erase(coords.begin()+i*4);
177                coords.erase(coords.begin()+i*4);
178                break;
179            }
180        }
181        keys.pop_front();
182    }
183
184    _offsets[idx] = lr.x() + pos.x();
185    _widths[idx]= 1.f;
186
187    _wordsOffsets.clear();
188    for ( unsigned int i=0; i<_text->getText().size(); ++i )
189    {
190        while (i<_text->getText().size() && _text->getText().at(i)==' ') ++i;
191        if (i<_text->getText().size())_wordsOffsets.push_back(i);
192        while (i<_text->getText().size() && _text->getText().at(i)!=' ') ++i;
193    }
194
195    positioned();
196}
197
198bool Input::focus(const WindowManager*) {
199   _cursor->setColor(0.5f, 0.5f, 0.6f, 1.0f);
200   _selection->setColor(0.8f, 0.8f, 0.9f, 1.0f);
201
202   return true;
203}
204
205bool Input::unfocus(const WindowManager*) {
206   _cursor->setColor(0.0f, 0.0f, 0.0f, 0.0f);
207   _selection->setColor(0.0f, 0.0f, 0.0f, 0.0f);
208
209   return true;
210}
211
212void Input::parented(Window* parent) {
213   Label::parented(parent);
214
215   _cursor->setSize(_widths[_index], getHeight());
216
217   if(_cursorIndex) parent->getGeode()->setDrawable(_cursorIndex, _cursor.get());
218   else _cursorIndex = parent->addDrawableAndGetIndex(_cursor.get());
219
220   if(_selectionIndex) parent->getGeode()->setDrawable(_selectionIndex, _selection.get());
221   else _selectionIndex = parent->addDrawableAndGetIndex(_selection.get());
222}
223
224void Input::positioned() {
225   point_type ln = static_cast<point_type>(_text->getLineCount());
226
227   ln = ln == 0.0f ? 1.0f : ln;
228
229   // point_type th = (_text->getCharacterHeight() * ln) + (_text->getLineSpacing() * (ln - 1.0f));
230
231   point_type x = getX() + _xoff;
232   point_type y = getY() + _yoff;
233
234   // XYCoord size = getTextSize();
235
236   _text->setPosition(osg::Vec3(x, y, _calculateZ(LAYER_MIDDLE)));
237
238   point_type xoffset = _index > 0 ? _offsets[_index - 1] : 0.0f;
239
240   _cursor->setSize(_widths[_index], getHeight());
241   _cursor->setOrigin(getX() + xoffset, getY() );
242   _cursor->setZ(_calculateZ(LAYER_MIDDLE-1));
243
244
245    unsigned int _selectionMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
246    unsigned int _selectionMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
247
248   if (_selectionMax-_selectionMin>0)
249   {
250       point_type xstart = _selectionMin > 0 ? _offsets[_selectionMin - 1] : 0.0f;
251       point_type xend = (_selectionMax > 0 ? _offsets[_selectionMax - 1] : 0.0f) + _widths[_selectionMax];
252
253       _selection->setSize(xend-xstart, getHeight());
254       _selection->setOrigin(getX() + xstart, getY());
255       _selection->setZ(_calculateZ(LAYER_MIDDLE-2));
256   }
257   else
258   {
259       _selection->setSize(0, getHeight());
260   }
261}
262
263bool Input::keyUp(int key, int mask, const WindowManager*) {
264   return false;
265}
266
267bool Input::mouseDrag (double x, double y, const WindowManager*)
268{
269    _mouseClickX += x;
270    x = _mouseClickX;
271
272    for ( unsigned int i=0; i< _offsets.size()-1; ++i )
273    {
274        point_type offset1 = i > 0 ? _offsets.at(i-1) : 0;
275        point_type offset2 = _offsets.at(i);
276        if (x >= offset1 && x <= offset2)
277        {
278            _selectionEndIndex = _index = i;
279            positioned();
280            break;
281        }
282    }
283
284    return false;
285}
286
287bool Input::mousePush (double x, double y, const WindowManager* wm)
288{
289    double offset = getOrigin().x();
290    Window* window = getParent();
291    if (window)
292    {
293        offset += window->getOrigin().x();
294    }
295
296    x -= offset;
297    _mouseClickX = x;
298
299    for ( unsigned int i=0; i< _offsets.size()-1; ++i )
300    {
301        point_type offset1 = i > 0 ? _offsets.at(i-1) : 0;
302        point_type offset2 = i == 0 ? _offsets.at(1) : _offsets.at(i);
303        if (x >= offset1 && x <= offset2)
304        {
305            _selectionStartIndex = _selectionEndIndex = _index = i;
306            positioned();
307            break;
308        }
309    }
310    return false;
311}
312
313bool Input::keyDown(int key, int mask, const WindowManager*) {
314   osgText::String& s = _text->getText();
315
316   switch (key)
317   {
318    case osgGA::GUIEventAdapter::KEY_Left:
319        if (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)
320        {
321            bool found = false;
322            for (unsigned int i=0; i<_wordsOffsets.size()-1; ++i)
323            {
324                if (_wordsOffsets.at(i) < _index && _index <= _wordsOffsets.at(i+1))
325                {
326                    found = true;
327                    _index = _wordsOffsets.at(i);
328                    break;
329                }
330            }
331            if (!found && _wordsOffsets.size())
332            {
333                _index = _wordsOffsets.at(_wordsOffsets.size()-1);
334            }
335        }
336        else
337        if (_index>0)
338        {
339            --_index;
340        }
341        if (mask & osgGA::GUIEventAdapter::MODKEY_SHIFT)
342        {
343            _selectionEndIndex = _index;
344        }
345        else
346        {
347            _selectionStartIndex = _selectionEndIndex = _index;
348        }
349        break;
350    case osgGA::GUIEventAdapter::KEY_Right:
351        if (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)
352        {
353            bool found = false;
354            for (unsigned int i=0; i<_wordsOffsets.size()-1; ++i)
355            {
356                if (_wordsOffsets.at(i) <= _index && _index < _wordsOffsets.at(i+1))
357                {
358                    found = true;
359                    _index = _wordsOffsets.at(i+1);
360                    break;
361                }
362            }
363            if (!found && _wordsOffsets.size())
364            {
365                _index = _wordsOffsets.at(_wordsOffsets.size()-1);
366            }
367        }
368        else
369        if (_index<_textLength)
370        {
371            ++_index;
372        }
373
374        if (mask & osgGA::GUIEventAdapter::MODKEY_SHIFT)
375        {
376            _selectionEndIndex = _index;
377        }
378        else
379        {
380            _selectionStartIndex = _selectionEndIndex = _index;
381        }
382        break;
383    case osgGA::GUIEventAdapter::KEY_Home:
384        _index = 0;
385        if (mask & osgGA::GUIEventAdapter::MODKEY_SHIFT)
386        {
387            _selectionEndIndex = _index;
388        }
389        else
390        {
391            _selectionStartIndex = _selectionEndIndex = _index;
392        }
393        break;
394    case osgGA::GUIEventAdapter::KEY_End:
395        _index = _textLength;
396        if (mask & osgGA::GUIEventAdapter::MODKEY_SHIFT)
397        {
398            _selectionEndIndex = _index;
399        }
400        else
401        {
402            _selectionStartIndex = _selectionEndIndex = _index;
403        }
404        break;
405    case osgGA::GUIEventAdapter::KEY_Insert:
406        _insertMode = !_insertMode;
407        break;
408    case osgGA::GUIEventAdapter::KEY_Delete:
409        {
410            unsigned int _selectionMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
411            unsigned int _selectionMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
412
413            if (_selectionMax-_selectionMin>0)
414            {
415                unsigned int    deleteToIdx = _selectionMax;
416                for (unsigned int i=0; i < s.size()-_selectionMin; ++i)
417                {
418                    s[_selectionMin+i] = deleteToIdx+i+1 < s.size() ? s[deleteToIdx+i+1] : ' ';
419                }
420
421                _text->update();
422
423                _calculateCursorOffsets();
424
425                _textLength -= deleteToIdx-_selectionMin;
426                _index = _selectionMin;
427                _selectionStartIndex = _selectionEndIndex = _index;
428            }
429            else
430            if (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)
431            {
432                unsigned int    deleteToIdx = _textLength;
433                for (unsigned int i=0; i<_wordsOffsets.size()-1; ++i)
434                {
435                    if (_wordsOffsets.at(i) <= _index && _index < _wordsOffsets.at(i+1))
436                    {
437                        deleteToIdx = _wordsOffsets.at(i+1);
438                        break;
439                    }
440                }
441                for (unsigned int i=0; i < s.size()-_index; ++i)
442                {
443                    s[_index+i] = deleteToIdx+i < s.size() ? s[deleteToIdx+i] : ' ';
444                }
445
446                _text->update();
447
448                _calculateCursorOffsets();
449
450                _textLength -= deleteToIdx-_index;
451            }
452            else
453            if (_index < s.size()-1)
454            {
455                for (unsigned int i=_index; i < s.size()-1; ++i)
456                {
457                    s[i] = s[i+1];
458                }
459
460                _text->update();
461
462                _calculateCursorOffsets();
463
464                --_textLength;
465            }
466        }
467        break;
468    case osgGA::GUIEventAdapter::KEY_BackSpace:
469        {
470            unsigned int _selectionMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
471            unsigned int _selectionMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
472
473            if (_selectionMax-_selectionMin>0)
474            {
475                unsigned int    deleteToIdx = _selectionMax;
476                for (unsigned int i=0; i < s.size()-_selectionMin; ++i)
477                {
478                    s[_selectionMin+i] = deleteToIdx+i+1 < s.size() ? s[deleteToIdx+i+1] : ' ';
479                }
480
481                _text->update();
482
483                _calculateCursorOffsets();
484
485                _textLength -= deleteToIdx-_selectionMin;
486                _index = _selectionMin;
487                _selectionStartIndex = _selectionEndIndex = _index;
488            }
489            else
490           if(_index >= 1) {
491
492               _index--;
493                if (_index< s.size()-1)
494                {
495                    for (unsigned int i=_index; i < s.size()-1; ++i)
496                    {
497                        s[i] = s[i+1];
498                        s[i+1] = ' ';
499                    }
500                }
501                else
502                {
503                    s[s.size()-1] = ' ';
504                }
505
506               _text->update();
507
508               _calculateCursorOffsets();
509
510               --_textLength;
511           }
512        }
513       break;
514   default:
515        if(key > 255 || _index >= _maxSize) return false;
516
517        if (((key=='v' || key=='V') && (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)) || (key==22))
518        {
519            _selectionStartIndex = _selectionEndIndex = _index;
520            std::string data;
521// Data from clipboard
522#ifdef WIN32
523            if (::OpenClipboard(NULL))
524            {
525                HANDLE hData = ::GetClipboardData( CF_TEXT );
526                char* buff = (char*)::GlobalLock( hData );
527                if (buff) data = buff;
528                ::GlobalUnlock( hData );
529                ::CloseClipboard();
530            }
531#endif
532            if (!data.empty())
533            {
534                data = data.substr(0,_maxSize-_index);
535                _textLength += data.size();
536                _selectionEndIndex = _textLength;
537
538                std::string::iterator itr = data.begin();
539                for ( ; itr != data.end(); ++itr )
540                {
541                    s[_index++] = *itr;
542                }
543
544                _text->update();
545
546                _calculateCursorOffsets();
547
548                _calculateSize(getTextSize());
549
550                getParent()->resize();
551
552                return false;
553
554            }
555
556        }
557        else
558        if (((key=='c' || key=='C') && (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)) || (key==3))
559        {
560            unsigned int _selectionMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
561            unsigned int _selectionMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
562
563            if (_selectionMax-_selectionMin>0)
564            {
565                std::string data;
566                for (unsigned int i=_selectionMin; i<=_selectionMax; ++i)
567                {
568                    data.push_back(s[i]);
569                }
570// Data to clipboard
571#ifdef WIN32
572                if(::OpenClipboard(NULL))
573                {
574                    ::EmptyClipboard();
575                    HGLOBAL clipbuffer = ::GlobalAlloc(GMEM_DDESHARE, data.length()+1);
576                    char* buffer = (char*)::GlobalLock(clipbuffer);
577                    strcpy(buffer, data.c_str());
578                    ::GlobalUnlock(clipbuffer);
579                    ::SetClipboardData(CF_TEXT,clipbuffer);
580                    ::CloseClipboard();
581                }
582#endif
583               
584            }
585            return false;
586        }
587        {
588            unsigned int _selectionMin = osg::minimum(_selectionStartIndex,_selectionEndIndex);
589            unsigned int _selectionMax = osg::maximum(_selectionStartIndex,_selectionEndIndex);
590
591            if (_selectionMax-_selectionMin>0)
592            {
593                point_type    deleteToIdx = _selectionMax;
594                for (unsigned int i=0; i < s.size()-_selectionMin; ++i)
595                {
596                    s[_selectionMin+i] = deleteToIdx+i+1 < s.size() ? s[deleteToIdx+i+1] : ' ';
597                }
598
599                _text->update();
600
601                _calculateCursorOffsets();
602
603                _textLength -= deleteToIdx-_selectionMin;
604                _index = _selectionMin;
605                _selectionStartIndex = _selectionEndIndex = _index;
606            }
607        }
608       
609       
610        if (!_insertMode)
611        {
612            for (unsigned int i=s.size()-1; i>_index; --i)
613            {
614                s[i] = s[i-1];
615            }
616        }
617
618       s[_index] = key;
619
620       _text->update();
621
622       _calculateCursorOffsets();
623
624       _index++;
625
626       if (!_insertMode) ++_textLength;
627
628       _selectionStartIndex = _selectionEndIndex = _index;
629   }
630
631   // _text->update();
632
633   _calculateSize(getTextSize());
634
635   getParent()->resize();
636
637   return false;
638}
639
640void Input::setCursor(Widget*) {
641}
642
643unsigned int Input::calculateBestYOffset(const std::string& s)
644{
645    if (!_text->getFont()) return 0;
646
647   const osgText::FontResolution fr(static_cast<unsigned int>(_text->getCharacterHeight()),
648                                    static_cast<unsigned int>(_text->getCharacterHeight()));
649
650   osgText::String utf(s);
651
652   unsigned int descent = 0;
653
654   for(osgText::String::iterator i = utf.begin(); i != utf.end(); i++) {
655       osgText::Font*        font  = const_cast<osgText::Font*>(_text->getFont());
656       osgText::Font::Glyph* glyph = font->getGlyph(fr, *i);
657       unsigned int          d     = abs((int)glyph->getHorizontalBearing().y());
658
659       if(d > descent) descent = d;
660   }
661
662   return descent;
663}
664
665}
Note: See TracBrowser for help on using the browser.