Hi Robert,

this is an update of the input control. It now has selection of text as well
work with the clipboard (Windows only implemented now)

Nick

http://www.linkedin.com/in/tnick


On Tue, Jan 26, 2010 at 7:03 PM, Trajce Nikolov <[email protected]>wrote:

> I might have updates these days to work with text selection and work with
> the clipboard .. Then it will be 100% . Will keep you posted
>
> Nick
>
> http://www.linkedin.com/in/tnick
>
>
> On Tue, Jan 26, 2010 at 6:59 PM, Robert Osfield 
> <[email protected]>wrote:
>
>> Hi Nick, Just merged and tested your changes, very cool indeed :-)
>> Changes now merged and submitted to svn/trunk.
>>
>> On Sun, Jan 17, 2010 at 1:17 PM, Trajce Nikolov
>> <[email protected]> wrote:
>> > Hi,
>> > didnt wanned to get more into, but I had some time. Now implements
>> CTRL+DEL
>> > for word deleting. Dont know what more to add....
>> > Nick
>> >
>> > http://www.linkedin.com/in/tnick
>> > Sent from Izmit, 41, Turkey
>> >
>> > On Sun, Jan 17, 2010 at 2:36 PM, Trajce Nikolov <
>> [email protected]>
>> > wrote:
>> >>
>> >> this is fix for backspace delete
>> >> Nick
>> >>
>> >> http://www.linkedin.com/in/tnick
>> >> Sent from Izmit, 41, Turkey
>> >>
>> >> On Sun, Jan 17, 2010 at 2:32 PM, Trajce Nikolov <
>> [email protected]>
>> >> wrote:
>> >>>
>> >>> ok .. once again. Here is CTRL-LEFT/RIGHT goes thru words, also some
>> >>> fixes
>> >>> Nick
>> >>>
>> >>> http://www.linkedin.com/in/tnick
>> >>> Sent from Izmit, 41, Turkey
>> >>>
>> >>> On Sun, Jan 17, 2010 at 1:48 PM, Trajce Nikolov
>> >>> <[email protected]> wrote:
>> >>>>
>> >>>> Hi,
>> >>>> once again. now handles empty spaces. This one should be final
>> >>>> Nick
>> >>>>
>> >>>> http://www.linkedin.com/in/tnick
>> >>>> Sent from Izmit, 41, Turkey
>> >>>>
>> >>>> On Sun, Jan 17, 2010 at 1:08 PM, Trajce Nikolov
>> >>>> <[email protected]> wrote:
>> >>>>>
>> >>>>> small cursor position fix
>> >>>>> Nick
>> >>>>>
>> >>>>> http://www.linkedin.com/in/tnick
>> >>>>> Sent from Izmit, 41, Turkey
>> >>>>>
>> >>>>> On Sun, Jan 17, 2010 at 1:00 PM, Trajce Nikolov
>> >>>>> <[email protected]> wrote:
>> >>>>>>
>> >>>>>> Hi,
>> >>>>>> implemented cursor size based on the character. Looks much better.
>> >>>>>> Nick
>> >>>>>>
>> >>>>>> http://www.linkedin.com/in/tnick
>> >>>>>> Sent from Izmit, 41, Turkey
>> >>>>
>> >>>
>> >>
>> >
>> >
>> > _______________________________________________
>> > osg-submissions mailing list
>> > [email protected]
>> >
>> http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
>> >
>> >
>> _______________________________________________
>> osg-submissions mailing list
>> [email protected]
>>
>> http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
>>
>
>
// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008

#include <osg/io_utils>
#include <osgWidget/WindowManager>
#include <osgWidget/Input>

#ifdef WIN32
#include <windows.h>
#endif

namespace osgWidget {

class BlinkCursorCallback: public osg::Drawable::DrawCallback
{
public:
    BlinkCursorCallback(const bool& insertMode)
                : _insertMode(insertMode)
    {
    }

    virtual void drawImplementation( osg::RenderInfo & ri,const osg::Drawable* 
drawable ) const
    {
                static bool on = true;
                static osg::Timer_t startTime = osg::Timer::instance()->tick();
                osg::Timer_t now = osg::Timer::instance()->tick();

                if 
(osg::Timer::instance()->delta_s(startTime,now)>(_insertMode?0.125:0.25))
                {
                        on = !on;
                        startTime = now;
                }
                if (on)
                        drawable->drawImplementation(ri);
    }
protected:
        const bool&     _insertMode;
};

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),       
_selection      (new Widget("selection")),
_selectionStartIndex(0),
_selectionEndIndex(0),
_selectionIndex(0),
_cursor      (new Widget("cursor")) {
   _text->setAlignment(osgText::Text::LEFT_BOTTOM_BASE_LINE);
   _text->setKerningType(osgText::KERNING_NONE);

   // Make the cursor un-copyable.
   _cursor->setCanClone(false);
   _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
   );

   _offsets.resize(size+1, 0.0f);
   _widths.resize(size+1, 1.0f);

   _text->getText().resize(size, ' ');
   _text->update();

   _cursor->setDrawCallback( new BlinkCursorCallback(_insertMode) );
}

void Input::_calculateSize(const XYCoord& size) {
   // An Input cannot currently set it's own size RELIABLY until the osgText 
implementation
   // is dratiscally improved. I'm getting wildly crazy results. :(
   // point_type height = size.y() > _cursor->getHeight() ? size.y() : 
_cursor->getHeight();

#if 0
   point_type width  = size.x() + _cursor->getWidth();
   point_type height = _cursor->getHeight();

   if(width > getWidth()) setWidth(osg::round(width));

   if(height > getHeight()) setHeight(osg::round(height));
#endif
}

void Input::_calculateCursorOffsets() {
   // Determine the "offset"

        if (_text->getText().size()==0) 
        {
                _offsets[0] = 0;
                _widths[0] = 0;
                return;
        }

        osg::Vec3 pos = _text->getPosition();

        osgText::Text::TextureGlyphQuadMap& tgqm = 
const_cast<osgText::Text::TextureGlyphQuadMap&>(_text->getTextureGlyphQuadMap());
        osgText::Text::TextureGlyphQuadMap::iterator tgqmi = tgqm.begin();

        std::vector<osg::Vec2>                          coords;
        std::vector<osgText::Font::Glyph*>      glyphs;
        for ( ; tgqmi != tgqm.end(); tgqmi++ )
        {
                const osgText::Text::GlyphQuads& gq = tgqmi->second;

                
//coords.insert(coords.end(),gq.getTransformedCoords(0).begin(),gq.getTransformedCoords(0).end());
                
coords.insert(coords.end(),gq.getCoords().begin(),gq.getCoords().end());
                for (unsigned int i=0; i<gq.getGlyphs().size(); ++i)
                {
                        glyphs.push_back(gq.getGlyphs().at(i));
                }
        }
        
        std::list<unsigned int> keys;
        for (unsigned int i=0; i<_text->getText().size(); ++i)
        {
                keys.push_back(_text->getText().at(i));
        }
        unsigned int idx=0;
        osg::Vec2 lr;
        osg::Vec2 ll;
        while (!keys.empty())
        {
                unsigned int key = keys.front();
                for (unsigned int i=0; i<glyphs.size(); ++i)
                {
                        osgText::Font::Glyph* g = glyphs.at(i);
                        if (g->getGlyphCode()==key)
                        {
                                lr = coords[2 + (i * 4)];
                                ll = coords[1 + (i * 4)];

                                point_type width = lr.x() - ll.x();
                                _widths[idx] = width == 0 ? 
g->getHorizontalAdvance() : width;

                                _offsets[idx] = lr.x() + pos.x();

                                if (width == 0)
                                        _offsets[idx] += 
g->getHorizontalAdvance();
                                ++idx;

                                glyphs.erase(glyphs.begin()+i);
                                coords.erase(coords.begin()+i*4);
                                coords.erase(coords.begin()+i*4);
                                coords.erase(coords.begin()+i*4);
                                coords.erase(coords.begin()+i*4);
                                break;
                        }
                }
                keys.pop_front();
        }

        _offsets[idx] = lr.x() + pos.x();
        _widths[idx]= 1.f;

        _wordsOffsets.clear();
        for ( unsigned int i=0; i<_text->getText().size(); ++i )
        {
                while (i<_text->getText().size() && _text->getText().at(i)==' 
') ++i;
                if (i<_text->getText().size())_wordsOffsets.push_back(i);
                while (i<_text->getText().size() && _text->getText().at(i)!=' 
') ++i;
        }

        positioned();
}

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;
}

void Input::parented(Window* parent) {
   Label::parented(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() {
   point_type ln = static_cast<point_type>(_text->getLineCount());

   ln = ln == 0.0f ? 1.0f : ln;

   // point_type th = (_text->getCharacterHeight() * ln) + 
(_text->getLineSpacing() * (ln - 1.0f));

   point_type x = getX() + _xoff;
   point_type y = getY() + _yoff;

   // XYCoord size = getTextSize();

   _text->setPosition(osg::Vec3(x, y, _calculateZ(LAYER_MIDDLE)));

   point_type xoffset = _index > 0 ? _offsets[_index - 1] : 0.0f;

   _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::keyDown(int key, int mask, const WindowManager*) {
   osgText::String& s = _text->getText();

   switch (key)
   {
        case osgGA::GUIEventAdapter::KEY_Left:
                if (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)
                {
                        bool found = false;
                        for (unsigned int i=0; i<_wordsOffsets.size()-1; ++i)
                        {
                                if (_wordsOffsets.at(i) < _index && _index <= 
_wordsOffsets.at(i+1))
                                {
                                        found = true;
                                        _index = _wordsOffsets.at(i);
                                        break;
                                }
                        }
                        if (!found && _wordsOffsets.size())
                        {
                                _index = 
_wordsOffsets.at(_wordsOffsets.size()-1);
                        }
                }
                else
                if (_index>0)
                {
                        --_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)
                {
                        bool found = false;
                        for (unsigned int i=0; i<_wordsOffsets.size()-1; ++i)
                        {
                                if (_wordsOffsets.at(i) <= _index && _index < 
_wordsOffsets.at(i+1))
                                {
                                        found = true;
                                        _index = _wordsOffsets.at(i+1);
                                        break;
                                }
                        }
                        if (!found && _wordsOffsets.size())
                        {
                                _index = 
_wordsOffsets.at(_wordsOffsets.size()-1);
                        }
                }
                else
                if (_index<_textLength)
                {
                        ++_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:
                {
                        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
                        if (mask & osgGA::GUIEventAdapter::MODKEY_CTRL)
                        {
                                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;
                        }
                        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:
                {
                        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
                   if(_index >= 1) {

                           _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] = ' ';
                                }

                           _text->update();

                           _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)
                        {
                                s[i] = s[i-1];
                        }
                }

           s[_index] = key;

           _text->update();

           _calculateCursorOffsets();

           _index++;

           if (!_insertMode) ++_textLength;
   }

   // _text->update();

   _calculateSize(getTextSize());

   getParent()->resize();

   return false;
}

void Input::setCursor(Widget*) {
}

unsigned int Input::calculateBestYOffset(const std::string& s)
{
#if 0
   const osgText::FontResolution fr(static_cast<unsigned 
int>(_text->getCharacterHeight()),
                                    static_cast<unsigned 
int>(_text->getCharacterHeight()));

   osgText::String utf(s);

   unsigned int descent = 0;

   for(osgText::String::iterator i = utf.begin(); i != utf.end(); i++) {
       osgText::Font*        font  = 
const_cast<osgText::Font*>(_text->getFont());
       osgText::Font::Glyph* glyph = font->getGlyph(fr, *i);
       unsigned int          d     = 
abs((int)glyph->getHorizontalBearing().y());

       if(d > descent) descent = d;
   }

   return descent;
#else
        return 0;
#endif
}

}

Attachment: Input
Description: Binary data

_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to