source: trunk/src/gui/gui_environment.cc @ 269

Last change on this file since 269 was 269, checked in by epyon, 11 years ago
  • 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!)
File size: 8.2 KB
Line 
1// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
2// http://chaosforge.org/
3//
4// This file is part of NV Libraries.
5// For conditions of distribution and use, see copyright notice in nv.hh
6
7#include "nv/gui/gui_environment.hh"
8
9#include "nv/gui/gui_renderer.hh"
10
11
12        /*
13
14        TODO: parse a lua stylesheet as per Trac wiki
15
16        IDEA: Store everything in std::unordered_maps, with lua_value's?
17
18        A lua_value is a variant stores strings as const char* that deletes them on destructor?
19        Question is that there might not be much gained on speed anyway, due to Lua's speed.
20        Special function field allows delayed per parse execution?
21
22        */
23
24#include "nv/gfx/sliced_buffer.hh"
25#include "nv/gfx/texture_atlas.hh"
26
27nv::gui::environment::environment( window* w, const std::string& shader_path )
28        : m_renderer( nullptr ), m_window( w ), m_first_free(-1), m_last_free(-1)
29{
30        m_area.dim( dimension( w->get_width(), w->get_height() ) );
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
37        m_renderer = new renderer( w, shader_path );
38}
39
40void nv::gui::environment::load_style( const std::string& filename )
41{
42        m_renderer->load_style( filename );
43}
44
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;
57        add_child( parent, result );
58        return result;
59}
60
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;
112        destroy_children( e );
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 )
139                {
140                        update( i, elapsed );
141                }
142        }
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 )
159                {
160                        draw(i);
161                }
162        }
163}
164
165void nv::gui::environment::update()
166{
167        update( m_screen, 0 );
168}
169
170void nv::gui::environment::draw()
171{
172        draw( m_screen );
173        m_renderer->draw();
174}
175
176void nv::gui::environment::add_child( handle child )
177{
178        add_child( m_screen, child );
179}
180
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() );
202                }
203        }
204}
205
206
207nv::gui::environment::~environment()
208{
209        destroy_children( handle() );
210        delete m_renderer;
211}
212
213bool nv::gui::environment::process_io_event( const io_event& )
214{
215        return false;
216}
217
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 )
225{
226        return get_deepest_child( m_screen, p );
227}
228
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() )
245        {
246                result = get_deepest_child( *it, p );
247                if ( result.m_index ) return result;
248                ++it;
249        }
250
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 )
260        {
261                auto it = std::find( parent->m_children.begin(), parent->m_children.end(), child );
262                if ( it != parent->m_children.end() )
263                {
264                        parent->m_children.erase( it );
265                        parent->m_children.push_back( child );
266                        parent->m_dirty = true;
267                }       
268        }
269}
270
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 )
276        {
277                auto it = std::find( parent->m_children.begin(), parent->m_children.end(), child );
278                if ( it != parent->m_children.end() )
279                {
280                        parent->m_children.erase( it );
281                        parent->m_children.push_front( child );
282                        parent->m_dirty = true;
283                }
284        }
285}
286
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 )
314        {
315                recalculate_absolute( o );
316        }
317}
318
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
Note: See TracBrowser for help on using the repository browser.