StyleManager 5.75 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield 
 *
 * This library is open source and may be redistributed and/or modified under  
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * OpenSceneGraph Public License for more details.
*/

// Code by: Jeremy Moles (cubicool) 2007-2008

#ifndef OSGWIDGET_STYLE_MANAGER
#define OSGWIDGET_STYLE_MANAGER

#include <map>
#include <osgDB/Input>
#include <osgWidget/Box>
#include <osgWidget/Frame>
#include <osgWidget/Input>
#include <osgWidget/Canvas>

namespace osgWidget {

typedef osgDB::FieldReaderIterator& Reader;

class OSGWIDGET_EXPORT Style: public osg::Object
{
    public:
        META_Object(osgWidget, Style);

        // Class and contents...
        Style (const std::string& = "", const std::string& = "");
        Style (const Style&, const osg::CopyOp&);

        virtual bool applyStyle (Widget*, Reader);
        virtual bool applyStyle (Label*, Reader);
        virtual bool applyStyle (Input*, Reader);
        virtual bool applyStyle (Window*, Reader);
        virtual bool applyStyle (Window::EmbeddedWindow*, Reader);
        virtual bool applyStyle (Box*, Reader);
        virtual bool applyStyle (Frame::Corner*, Reader);
        virtual bool applyStyle (Frame::Border*, Reader);
        virtual bool applyStyle (Canvas*, Reader);



        void setStyle(const std::string& style) {
            _style = style;
        }

        std::string& getStyle() {
            return _style;
        }

        const std::string& getStyle() const {
            return _style;
        }

        static Widget::Layer                strToLayer     (const std::string&);
        static Widget::VerticalAlignment    strToVAlign    (const std::string&);
        static Widget::HorizontalAlignment  strToHAlign    (const std::string&);
        static Widget::CoordinateMode       strToCoordMode (const std::string&);
        static bool                         strToFill      (const std::string&);

    protected:

        std::string _style;

        bool _match(const char* seq, Reader r) {
            if(r.matchSequence(seq)) {
                ++r;

                return true;
            }

            return false;
        }
};

class OSGWIDGET_EXPORT StyleManager: public osg::Object
{
    public:
        typedef std::map<std::string, osg::ref_ptr<Style> > Styles;
        typedef Styles::iterator                            Iterator;
        typedef Styles::const_iterator                      ConstIterator;

        META_Object(osgWidget, StyleManager);

        StyleManager ();
        StyleManager (const StyleManager&, const osg::CopyOp&);

        bool addStyle(Style*);

        bool applyStyles(Widget* widget) {
            return _applyStyles(widget);
        }

        bool applyStyles(Window* window) {
            return _applyStyles(window);
        }

    private:
        Styles _styles;

        template<typename T>
        bool _applySpecificStyle(T* t, const std::string& style)
        {
            osgDB::FieldReaderIterator r;

            std::istringstream input(_styles[style]->getStyle());

            r.attach(&input);

            bool inc = false;

            while(!r.eof()) 
            {
                if(_styles[style]->applyStyle(t, r)) 
                    inc = true;
                else
                    r.advanceOverCurrentFieldOrBlock();
            }



            return inc;
        }

        template<typename T>
        bool _coerceAndApply(
            osg::Object*       obj,
            const std::string& style,
            const std::string& className
        ) {
            T* t = dynamic_cast<T*>(obj);

            if(!t) {
                warn()
                    << "An attempt was made to coerce Object [" << obj->getName()
                    << "] into a " << className << " but failed." << std::endl
                ;

                return 0;
            }

            return _applySpecificStyle(t, style);
        }


        bool _applyStyleToObject(osg::Object*, const std::string&);

        // 1. Check and see if the explicit FULL path is available.
        // 2. Check and see if each component working backward--minus the last--is available.
        // 3. Check to see if just the className() is available.
        template<typename T>
        bool _applyStyles(T* t)
        {
            if(!t)
            {
                warn()
                    << "Cannot call StyleManager::applyStyle with a NULL object."
                    << std::endl
                ;

                return false;
            }

            osg::Object* obj = dynamic_cast<osg::Object*>(t);

            if(!obj)
            {
                warn() 
                    << "Cannot coerce object into osg::Object in StyleManager:::applyStyle"
                    << std::endl
                ;

                return false;
            }

            std::string c = obj->className();

            // Case 3; there's no explicit Style set, so see if there's one for the class.
            if(t->getStyle().empty())
            {
                // Couldn't find the className, so we exit.
                if(_styles.find(c) == _styles.end()) return false;

                return _applyStyleToObject(obj, c);
            }

            // Case 1...
            if(_styles.find(t->getStyle()) != _styles.end()) return _applyStyleToObject(
                obj,
                t->getStyle()
            );

            return false;
        }

};

}

#endif