Changeset 269


Ignore:
Timestamp:
06/21/14 19:38:56 (11 years ago)
Author:
epyon
Message:
  • gui::environment uses a single vector of static elements
  • gui::environment operates on gui::handle's explicitly
  • indexes via gui::handle are reusable, but counted!
  • full DOD achieved (making a note here, huge success!)
Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/nv/gui/gui_element.hh

    r268 r269  
    2323        namespace gui
    2424        {
     25
     26                class handle
     27                {
     28                public:
     29                        handle() : m_index(0), m_counter(0) {}
     30
     31                        inline bool operator==(const handle& rhs){return m_index == rhs.m_index && m_counter == rhs.m_counter; }
     32                        inline bool operator!=(const handle& rhs){return !(*this == rhs);}
     33
     34                        bool is_nil() { return m_index == 0 && m_counter == 0; }
     35                        bool is_valid() { return !is_nil(); }
     36                private:
     37                        friend class environment;
     38
     39                        explicit handle( uint16 a_index, uint16 a_counter ) : m_index( a_index ), m_counter(a_counter) {}
     40
     41                        uint16 m_index;
     42                        uint16 m_counter;
     43                };
     44
     45
    2546                class element
    2647                {
    27                 protected:
     48                public:
    2849                        /// List type
    29                         typedef std::list<element*> list;
     50                        typedef std::list<handle> list;
    3051
    3152
    32                         explicit element( const rectangle& r )
     53                        element()
    3354                                : m_id( "" )
    34                                 , m_parent( nullptr )
     55                                , m_this()
     56                                , m_parent()
    3557                                , m_children()
    3658                                , m_child_count(0)
    3759                                , m_class("")
    38                                 , m_relative( r )
    39                                 , m_absolute( r )
     60                                , m_relative()
     61                                , m_absolute()
    4062                                , m_enabled( true )
    4163                                , m_visible( true )
     
    4365                                , m_render_data( nullptr ) {}
    4466
    45                 protected:
    46                         virtual ~element() { delete m_render_data; }
    47                 protected:
    4867                        friend class environment;
    4968                        friend class renderer;
     
    5170
    5271                        string    m_id;              ///< id type of the object
    53                         element*  m_parent;          ///< pointer to parent
     72                        handle    m_this;            ///< pointer to parent
     73                        handle    m_parent;          ///< pointer to parent
    5474                        list      m_children;        ///< children objects
    5575                        size_t    m_child_count;     ///< number of children
  • trunk/nv/gui/gui_environment.hh

    r268 r269  
    2626        namespace gui
    2727        {
    28                 class handle
    29                 {
    30 
    31                 };
    32 
    3328                class environment
    3429                {
     
    3732                        // temporary
    3833                        void load_style( const std::string& filename );
    39                         element* create_element( element* parent, const rectangle& r );
    40                         void set_text( element* e, const string& text );
    41                         void set_class( element* e, const string& text );
     34                        handle create_element( const rectangle& r );
     35                        handle create_element( handle parent, const rectangle& r );
     36                        void set_text( handle e, const string& text );
     37                        void set_class( handle  e, const string& text );
    4238                        void update();
    4339                        void draw();
    44                         void destroy_element( element* e );
     40                        void destroy_element( handle e );
    4541                        bool process_io_event( const io_event& ev );
    4642                        virtual ~environment();
    4743                protected:
    48                         element* get_element( const position& p );
    49                         void add_child( element* child );
    50                         void add_child( element* parent, element* child );
    51                         void remove_child( element* parent, element* child );
    52                         void destroy_children( element* e );
    53                         void update( element* e, uint32 elapsed );
    54                         void draw( element* e );
    55                         bool process_io_event( element* e, const io_event& ev );
    56                         element* get_deepest_child( element* e, const position& p );
    57                         void move_to_top( element* child );
    58                         void move_to_bottom( element* child );
    59                         void set_relative( element* e, const rectangle& r );
    60                         void set_relative( element* e, const position& p );
    61                         void recalculate_absolute( element* e );
     44                        handle create_handle();
     45                        handle create_index( sint16 element_id );
     46                        element* get_element( handle h );
     47                        handle get_element( const position& p );
     48                        void add_child( handle child );
     49                        void add_child( handle parent, handle child );
     50                        void remove_child( handle parent, handle child );
     51                        void destroy_children( handle e );
     52                        void update( handle e, uint32 elapsed );
     53                        void draw( handle e );
     54                        bool process_io_event( handle e, const io_event& ev );
     55                        handle get_deepest_child( handle e, const position& p );
     56                        void move_to_top( handle child );
     57                        void move_to_bottom( handle child );
     58                        void set_relative( handle e, const rectangle& r );
     59                        void set_relative( handle e, const position& p );
     60                        void recalculate_absolute( handle e );
    6261                       
     62                        struct index
     63                        {
     64                                sint16 element_id;
     65                                uint16 counter;
     66                                sint32 next_free;
     67
     68                                index() : element_id(0), counter(0), next_free(-1) {}
     69                        };
     70                        uint16 get_free_index();
     71                        void free_index( uint16 idx_index );
     72
     73                        sint32 m_first_free;
     74                        sint32 m_last_free;
     75
     76                        std::vector< element > m_elements;
     77                        std::vector< index >   m_indices;
     78
    6379                        renderer*    m_renderer;
    6480                        window*      m_window;
    65                         element*     m_screen;
     81                        handle       m_screen;
    6682                        rectangle    m_area;
    6783                };
  • trunk/src/gui/gui_environment.cc

    r268 r269  
    2626
    2727nv::gui::environment::environment( window* w, const std::string& shader_path )
    28         : m_renderer( nullptr ), m_window( w ), m_screen( nullptr )
     28        : m_renderer( nullptr ), m_window( w ), m_first_free(-1), m_last_free(-1)
    2929{
    3030        m_area.dim( dimension( w->get_width(), w->get_height() ) );
    31         m_screen = new element( m_area );
     31       
     32        m_screen           = create_handle();
     33        element* screen    = get_element( m_screen );
     34        screen->m_absolute = m_area;
     35        screen->m_relative = m_area;
     36
    3237        m_renderer = new renderer( w, shader_path );
    3338}
     
    3843}
    3944
    40 nv::gui::element* nv::gui::environment::create_element( element* parent, const rectangle& r )
    41 {
    42         element* result = new element( r );
    43         if ( parent == nullptr ) parent = m_screen;
     45nv::gui::handle nv::gui::environment::create_element( const rectangle& r )
     46{
     47        return create_element( m_screen, r );
     48}
     49
     50nv::gui::handle nv::gui::environment::create_element( handle parent, const rectangle& r )
     51{
     52        if ( parent.is_nil() ) parent = m_screen;
     53        handle result = create_handle();
     54        element* e    = get_element( result );
     55        e->m_absolute = r;
     56        e->m_relative = r;
    4457        add_child( parent, result );
    4558        return result;
    4659}
    4760
    48 void nv::gui::environment::destroy_element( element* e )
    49 {
     61nv::gui::handle nv::gui::environment::create_handle()
     62{
     63        m_elements.emplace_back();
     64        m_elements.back().m_this = create_index( uint16( m_elements.size() - 1 ) );
     65        return m_elements.back().m_this;
     66}
     67
     68nv::gui::handle nv::gui::environment::create_index( sint16 element_id )
     69{
     70        uint16 i   = get_free_index();
     71        index& idx = m_indices[i];
     72        idx.element_id = element_id;
     73        idx.counter++;
     74        return handle( i, idx.counter );
     75}
     76
     77nv::uint16 nv::gui::environment::get_free_index()
     78{
     79        if ( m_first_free != -1 )
     80        {
     81                uint16 result = (uint16)m_first_free;
     82                m_first_free = m_indices[result].next_free;
     83                m_indices[result].next_free = -1;
     84                if ( m_first_free == -1 ) m_last_free = -1;
     85                return result;
     86        }
     87        m_indices.emplace_back();
     88        return uint16( m_indices.size() - 1 );
     89}
     90
     91void nv::gui::environment::free_index( uint16 idx_index )
     92{
     93        // TODO: reuse
     94        index& idx = m_indices[ idx_index ];
     95        idx.element_id = -1;
     96        idx.next_free  = -1;
     97        if ( m_last_free == -1 )
     98        {
     99                m_first_free = m_last_free = idx_index;
     100        }
     101        else
     102        {
     103                m_indices[ m_last_free ].next_free = idx_index;
     104                m_last_free = idx_index;
     105        }
     106}
     107
     108void nv::gui::environment::destroy_element( handle e )
     109{
     110        element* dead_element = get_element( e );
     111        if ( dead_element == nullptr ) return;
    50112        destroy_children( e );
    51         if ( e->m_parent )
    52         {
    53                 remove_child( e->m_parent, e );
    54         }
    55         delete e;
    56 }
    57 
    58 void nv::gui::environment::update( element* e, uint32 elapsed )
    59 {
    60 //      e->on_update( elapsed );
    61         if ( e->m_visible )
    62         {
    63                 for ( element* i : e->m_children )
     113        remove_child( dead_element->m_parent, e );
     114
     115        delete dead_element->m_render_data;
     116        dead_element->m_render_data = nullptr;
     117        dead_element->m_parent = handle();
     118
     119        uint16 dead_index    = m_indices[ e.m_index ].element_id;
     120        if ( dead_index != m_elements.size()-1 )
     121        {
     122                m_elements[ dead_index ] = m_elements.back();
     123                m_elements.pop_back();
     124                m_indices[ m_elements[ dead_index ].m_this.m_index ].element_id = dead_index;
     125        }
     126        else
     127                m_elements.pop_back();
     128        free_index( e.m_index );
     129}
     130
     131void nv::gui::environment::update( handle e, uint32 elapsed )
     132{
     133        element* el = get_element( e );
     134        if ( !el ) return;
     135        //      el->on_update( elapsed );
     136        if ( el->m_visible )
     137        {
     138                for ( handle i : el->m_children )
    64139                {
    65140                        update( i, elapsed );
    66141                }
    67142        }
    68         if ( e->m_dirty || e->m_render_data == nullptr )
    69         {
    70                 m_renderer->redraw( e, elapsed );
    71                 e->m_dirty = false;
    72         }
    73 }
    74 
    75 void nv::gui::environment::draw( element* e )
    76 {
    77         if ( e->m_visible )
    78         {
    79 //              e->on_draw();
    80                 m_renderer->draw( e );
    81                 for ( element* i : e->m_children )
     143        if ( el->m_dirty || el->m_render_data == nullptr )
     144        {
     145                m_renderer->redraw( el, elapsed );
     146                el->m_dirty = false;
     147        }
     148}
     149
     150void nv::gui::environment::draw( handle e )
     151{
     152        element* el = get_element( e );
     153        if ( !el ) return;
     154        if ( el->m_visible )
     155        {
     156//              el->on_draw();
     157                m_renderer->draw( el );
     158                for ( handle i : el->m_children )
    82159                {
    83160                        draw(i);
     
    97174}
    98175
    99 void nv::gui::environment::add_child( element* child )
     176void nv::gui::environment::add_child( handle child )
    100177{
    101178        add_child( m_screen, child );
    102179}
    103180
    104 void nv::gui::environment::add_child( element* parent, element* child )
    105 {
    106         if ( child )
    107         {
    108                 if ( child->m_parent )
    109                 {
    110                         remove_child( child->m_parent, child );
     181void nv::gui::environment::add_child( handle parent, handle child )
     182{
     183        element* e = get_element( child );
     184        element* p = get_element( parent );
     185        if ( e && p )
     186        {
     187                remove_child( e->m_parent, child );
     188                e->m_parent = parent;
     189                p->m_children.push_back( child );
     190                p->m_child_count++;
     191        }
     192}
     193
     194void nv::gui::environment::destroy_children( handle e )
     195{
     196        element* parent = get_element(e);
     197        if ( parent )
     198        {
     199                while ( !parent->m_children.empty() )
     200                {
     201                        destroy_element( parent->m_children.front() );
    111202                }
    112                 child->m_parent = parent;
    113                 parent->m_children.push_back( child );
    114                 parent->m_child_count++;
    115         }
    116 }
    117 
    118 void nv::gui::environment::destroy_children( element* e )
    119 {
    120         while ( !e->m_children.empty() )
    121         {
    122                 destroy_element( e->m_children.front() );
    123203        }
    124204}
     
    127207nv::gui::environment::~environment()
    128208{
    129         destroy_element( m_screen );
     209        destroy_children( handle() );
    130210        delete m_renderer;
    131211}
     
    136216}
    137217
    138 bool nv::gui::environment::process_io_event( element* e, const io_event& ev )
    139 {
    140         return e->m_parent ? process_io_event( e->m_parent, ev ) : false;
    141 }
    142 
    143 nv::gui::element* nv::gui::environment::get_element( const position& p )
     218bool nv::gui::environment::process_io_event( handle e, const io_event& ev )
     219{
     220        element* el = get_element( e );
     221        return el && el->m_parent.m_index ? process_io_event( el->m_parent, ev ) : false;
     222}
     223
     224nv::gui::handle nv::gui::environment::get_element( const position& p )
    144225{
    145226        return get_deepest_child( m_screen, p );
    146227}
    147228
    148 nv::gui::element* nv::gui::environment::get_deepest_child( element* e, const position& p )
    149 {
    150         if ( !e->m_visible ) return nullptr;
    151 
    152         element* result = nullptr;
    153         element::list::reverse_iterator it = e->m_children.rbegin();
    154 
    155         while ( it != e->m_children.rend() )
     229nv::gui::element* nv::gui::environment::get_element( handle h )
     230{
     231        if ( h.is_nil() ) return nullptr;
     232        const index& idx = m_indices[ h.m_index ];
     233        return idx.counter == h.m_counter && idx.element_id >= 0 ? &m_elements[ idx.element_id ] : nullptr;
     234}
     235
     236nv::gui::handle nv::gui::environment::get_deepest_child( handle e, const position& p )
     237{
     238        element* el = get_element(e);
     239        if ( !el && !el->m_visible ) return handle();
     240
     241        handle result;
     242        element::list::reverse_iterator it = el->m_children.rbegin();
     243
     244        while ( it != el->m_children.rend() )
    156245        {
    157246                result = get_deepest_child( *it, p );
    158                 if ( result ) return result;
     247                if ( result.m_index ) return result;
    159248                ++it;
    160249        }
    161250
    162         if ( e->m_absolute.contains(p) ) return e;
    163         return nullptr;
    164 }
    165 
    166 void nv::gui::environment::move_to_top( element* child )
    167 {
    168         element* parent = child->m_parent;
    169         if ( parent )
     251        if ( el->m_absolute.contains(p) ) return e;
     252        return handle();
     253}
     254
     255void nv::gui::environment::move_to_top( handle child )
     256{
     257        element* e      = get_element( child );
     258        element* parent = get_element( e->m_parent );
     259        if ( e && parent )
    170260        {
    171261                auto it = std::find( parent->m_children.begin(), parent->m_children.end(), child );
     
    179269}
    180270
    181 void nv::gui::environment::move_to_bottom( element* child )
    182 {
    183         element* parent = child->m_parent;
    184         if ( parent )
     271void nv::gui::environment::move_to_bottom( handle child )
     272{
     273        element* e      = get_element( child );
     274        element* parent = get_element( e->m_parent );
     275        if ( e && parent )
    185276        {
    186277                auto it = std::find( parent->m_children.begin(), parent->m_children.end(), child );
     
    194285}
    195286
    196 void nv::gui::environment::set_relative( element* e, const rectangle& r )
    197 {
    198         e->m_dirty    = true;
    199         e->m_relative = r;
    200         recalculate_absolute( e );
    201 }
    202 
    203 void nv::gui::environment::set_relative( element* e, const position& p )
    204 {
    205         set_relative( e, rectangle( p, p + e->m_relative.get_size() ) );
    206 }
    207 
    208 void nv::gui::environment::recalculate_absolute( element* e )
    209 {
    210         rectangle pabsolute;
    211 
    212         if ( e->m_parent )
    213         {
    214                 pabsolute = e->m_parent->m_absolute;
    215         }
    216 
    217         e->m_absolute = e->m_relative + pabsolute.ul;
    218 
    219         for ( element* o : e->m_children )
     287void nv::gui::environment::set_relative( handle e, const rectangle& r )
     288{
     289        element* el = get_element(e);
     290        if ( el )
     291        {
     292                el->m_dirty    = true;
     293                el->m_relative = r;
     294                recalculate_absolute( e );
     295        }
     296}
     297
     298void nv::gui::environment::set_relative( handle e, const position& p )
     299{
     300        element* el = get_element(e);
     301        if ( el )
     302        {
     303                set_relative( e, rectangle( p, p + el->m_relative.get_size() ) );
     304        }
     305}
     306
     307void nv::gui::environment::recalculate_absolute( handle e )
     308{
     309        element* el = get_element(e);
     310        rectangle pabsolute = get_element( el->m_parent )->m_absolute;
     311        el->m_absolute = el->m_relative + pabsolute.ul;
     312
     313        for ( handle o : el->m_children )
    220314        {
    221315                recalculate_absolute( o );
     
    223317}
    224318
    225 void nv::gui::environment::set_class( element* e, const string& text )
    226 {
    227         e->m_class = text;
    228         e->m_dirty = true;
    229 }
    230 
    231 void nv::gui::environment::set_text( element* e, const string& text )
    232 {
    233         e->m_text = text;
    234         e->m_dirty = true;
    235 }
    236 
    237 void nv::gui::environment::remove_child( element* parent, element* child )
    238 {
    239         if ( child->m_parent != parent )
    240         {
    241                 return; // signal error?
    242         }
    243         auto it = std::find( parent->m_children.begin(), parent->m_children.end(), child );
    244         if ( it != parent->m_children.end() )
    245         {
    246                 (*it)->m_parent = nullptr;
    247                 parent->m_children.erase(it);
    248         }       
    249 
    250 }
    251 
     319void nv::gui::environment::set_class( handle e, const string& text )
     320{
     321        element* ep = get_element(e);
     322        if ( ep != nullptr )
     323        {
     324                ep->m_class = text;
     325                ep->m_dirty = true;
     326        }
     327}
     328
     329void nv::gui::environment::set_text( handle e, const string& text )
     330{
     331        element* ep = get_element(e);
     332        if ( ep != nullptr )
     333        {
     334                ep->m_text = text;
     335                ep->m_dirty = true;
     336        }
     337}
     338
     339void nv::gui::environment::remove_child( handle parent, handle child )
     340{
     341        element* p = get_element( parent );
     342        if ( p )
     343        {
     344                auto it = std::find( p->m_children.begin(), p->m_children.end(), child );
     345                if ( it != p->m_children.end() )
     346                {
     347                        element* e = get_element( *it );
     348                        e->m_parent = handle();
     349                        p->m_children.erase(it);
     350                }       
     351        }
     352}
     353
  • trunk/tests/gui_test/nv_gui_test.cc

    r268 r269  
    2323        nv::clear_state m_clear_state;
    2424        nv::gui::environment* m_guienv;
    25         std::vector<nv::gui::element*>   m_windows;
     25        std::vector<nv::gui::handle>   m_windows;
    2626};
    2727
     
    8686        glm::ivec2 a( std::rand() % 600, std::rand() % 400 );
    8787        glm::ivec2 b( std::rand() % 200 + 40, std::rand() % 200 + 40 );
    88         nv::gui::element* e = m_guienv->create_element( nullptr, nv::rectangle(a).dim(b) );
     88        nv::gui::handle e = m_guienv->create_element( nv::rectangle(a).dim(b) );
    8989        m_guienv->set_class( e, "window" );
    9090        m_guienv->set_text( e, "Window "+nv::to_string(m_windows.size()+1) );
Note: See TracChangeset for help on using the changeset viewer.