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

Last change on this file since 456 was 444, checked in by epyon, 10 years ago
  • slowly fixing up gui
File size: 7.7 KB
Line 
1// Copyright (C) 2012-2015 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
6
7#include "nv/gui/gui_environment.hh"
8
9#include "nv/gui/gui_renderer.hh"
10
11        /*
12
13        TODO: parse a lua stylesheet as per Trac wiki
14
15        IDEA: Store everything in unordered_maps, with lua_value's?
16
17        A lua_value is a variant stores strings as const char* that deletes them on destructor?
18        Question is that there might not be much gained on speed anyway, due to Lua's speed.
19        Special function field allows delayed per parse execution?
20
21        */
22
23
24nv::gui::environment::environment( renderer* r )
25        : m_renderer( r )
26{
27        r->set_environment( this );
28        m_screen   = create_element( handle(), m_renderer->get_area() );
29}
30
31void nv::gui::environment::load_style( const string_view& filename )
32{
33        m_renderer->load_style( filename );
34}
35
36nv::gui::handle nv::gui::environment::create_element( const rectangle& r )
37{
38        return create_element( m_screen, r );
39}
40
41nv::gui::handle nv::gui::environment::create_element( handle parent, const rectangle& r )
42{
43        if ( parent.is_nil() ) parent = m_screen;
44
45        handle result  = m_elements.create();
46        element* e     = m_elements.get( result );
47        rectangle ar   = r;
48        rectangle full = m_renderer->get_area();
49
50        if ( ar.ul.x < 0 ) { ar.ul.x += full.lr.x; ar.lr.x += full.lr.x; }
51        if ( ar.ul.y < 0 ) { ar.ul.y += full.lr.y; ar.lr.y += full.lr.y; }
52
53        e->m_child_count = 0;
54        e->m_flags[ENABLED] = true;
55        e->m_flags[VISIBLE] = true;
56        e->m_flags[DIRTY]   = true;
57        e->m_render_data    = nullptr;
58        e->m_absolute = ar;
59        e->m_relative = ar;
60
61        if ( !parent.is_nil() ) // screen creation
62                add_child( parent, result );
63
64        return result;
65}
66
67void nv::gui::environment::destroy_element( handle e )
68{
69        element* dead_element = m_elements.get( e );
70        if ( dead_element == nullptr ) return;
71        destroy_children( e );
72        remove_child( dead_element->m_parent, e );
73
74        delete dead_element->m_render_data;
75        dead_element->m_render_data = nullptr;
76        dead_element->m_parent = handle();
77
78        m_elements.destroy( e );
79}
80
81void nv::gui::environment::update( handle e, uint32 elapsed )
82{
83        element* el = m_elements.get( e );
84        if ( !el ) return;
85        //      el->on_update( elapsed );
86        if ( el->m_flags[ENABLED] )
87        {
88                bool hover     = el->m_flags[HOVER];
89                bool new_hover = el->m_absolute.contains( m_mouse_position );
90                if ( hover != new_hover )
91                {
92                        el->m_flags[HOVER] = new_hover;
93                        // gain lose hover event
94                        m_renderer->on_hover_change( el );
95                }
96        }
97
98        if ( el->m_flags[VISIBLE] )
99        {
100                for ( handle i : el->m_children )
101                {
102                        update( i, elapsed );
103                }
104        }
105        if ( el->m_flags[DIRTY] || el->m_render_data == nullptr )
106        {
107                m_renderer->redraw( el, elapsed );
108                el->m_flags[DIRTY] = false;
109        }
110}
111
112void nv::gui::environment::draw( handle e )
113{
114        element* el = m_elements.get( e );
115        if ( !el ) return;
116        if ( el->m_flags[VISIBLE] )
117        {
118//              el->on_draw();
119                m_renderer->draw( el );
120                for ( handle i : el->m_children )
121                {
122                        draw(i);
123                }
124        }
125}
126
127void nv::gui::environment::update()
128{
129        update( m_screen, 0 );
130}
131
132void nv::gui::environment::draw()
133{
134        draw( m_screen );
135        m_renderer->draw();
136}
137
138void nv::gui::environment::add_child( handle child )
139{
140        add_child( m_screen, child );
141}
142
143void nv::gui::environment::add_child( handle parent, handle child )
144{
145        element* e = m_elements.get( child );
146        element* p = m_elements.get( parent );
147        if ( e && p )
148        {
149                remove_child( e->m_parent, child );
150                e->m_parent = parent;
151                p->m_children.push_back( child );
152                p->m_child_count++;
153        }
154}
155
156void nv::gui::environment::destroy_children( handle e )
157{
158        element* parent = m_elements.get(e);
159        if ( parent )
160        {
161                while ( !parent->m_children.empty() )
162                {
163                        destroy_element( parent->m_children.back() );
164                }
165        }
166}
167
168
169nv::gui::environment::~environment()
170{
171        destroy_children( handle() );
172        delete m_renderer;
173}
174
175bool nv::gui::environment::process_io_event( const io_event& ev )
176{
177        switch ( ev.type )
178        {
179//      case EV_KEY          :
180        case EV_MOUSE_BUTTON :
181                if ( ev.mbutton.pressed && ev.mbutton.button == MOUSE_LEFT )
182                {
183                        handle h = get_element( position( ev.mbutton.x, ev.mbutton.y ) );
184                        set_selected( h );
185                        return true;
186                }
187                return false;
188        case EV_MOUSE_MOVE:
189                m_mouse_position = position( ev.mmove.x, ev.mmove.y );
190                return false;
191//      case EV_MOUSE_WHEEL  :
192        default:
193                break;
194        }
195        return false;
196}
197
198nv::string_view nv::gui::environment::get_string( shash64 h )
199{
200        return m_strings[h];
201}
202
203bool nv::gui::environment::set_selected( handle e )
204{
205        if ( e != m_selected )
206        {
207                element* eold = m_elements.get( m_selected );
208                element* el   = m_elements.get( e );
209                if ( eold )
210                {
211                        eold->m_flags[SELECTED] = false;
212                        m_renderer->on_select_change( eold );
213                }
214                if ( el )
215                {
216                        el->m_flags[SELECTED] = true;
217                        m_renderer->on_select_change( el );
218                }
219                m_selected = e;
220                return true;
221        }
222        return false;
223}
224
225bool nv::gui::environment::process_io_event( handle e, const io_event& ev )
226{
227        element* el = m_elements.get( e );
228        return el && el->m_parent.is_valid() ? process_io_event( el->m_parent, ev ) : false;
229}
230
231nv::gui::handle nv::gui::environment::get_element( const position& p )
232{
233        return get_deepest_child( m_screen, p );
234}
235
236nv::gui::handle nv::gui::environment::get_deepest_child( handle e, const position& p )
237{
238        element* el = m_elements.get(e);
239        if ( !el && !el->m_flags[VISIBLE] ) return handle();
240
241        handle result;
242        auto it = el->m_children.rbegin();
243
244        while ( it != el->m_children.rend() )
245        {
246                result = get_deepest_child( *it, p );
247                if ( result.is_valid() ) 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      = m_elements.get( child );
258        element* parent = m_elements.get( e->m_parent );
259        if ( e && parent )
260        {
261                auto it = 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_flags[DIRTY] = true;
267                }       
268        }
269}
270
271void nv::gui::environment::set_relative( handle e, const rectangle& r )
272{
273        element* el = m_elements.get(e);
274        if ( el )
275        {
276                el->m_flags[DIRTY] = true;
277                el->m_relative     = r;
278                recalculate_absolute( e );
279        }
280}
281
282void nv::gui::environment::set_relative( handle e, const position& p )
283{
284        element* el = m_elements.get(e);
285        if ( el )
286        {
287                set_relative( e, rectangle( p, p + el->m_relative.get_size() ) );
288        }
289}
290
291void nv::gui::environment::recalculate_absolute( handle e )
292{
293        element* el = m_elements.get(e);
294        rectangle pabsolute = m_elements.get( el->m_parent )->m_absolute;
295        el->m_absolute = el->m_relative + pabsolute.ul;
296
297        for ( handle o : el->m_children )
298        {
299                recalculate_absolute( o );
300        }
301}
302
303void nv::gui::environment::set_class( handle e, const string_view& text )
304{
305        element* ep = m_elements.get(e);
306        if ( ep != nullptr )
307        {
308                ep->m_class        = m_strings.insert( text );
309                ep->m_flags[DIRTY] = true;
310                m_renderer->on_style_change( ep );
311        }
312}
313
314void nv::gui::environment::set_text( handle e, const string_twine& text )
315{
316        element* ep = m_elements.get(e);
317        if ( ep != nullptr )
318        {
319                // TODO : implement twine == operator
320                ep->m_text.assign( text );
321                ep->m_flags[DIRTY] = true;
322        }
323}
324
325void nv::gui::environment::remove_child( handle parent, handle child )
326{
327        element* p = m_elements.get( parent );
328        if ( p )
329        {
330                auto it = find( p->m_children.begin(), p->m_children.end(), child );
331                if ( it != p->m_children.end() )
332                {
333                        element* e = m_elements.get( *it );
334                        e->m_parent = handle();
335                        p->m_children.erase( it );
336                }
337        }
338}
339
Note: See TracBrowser for help on using the repository browser.