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

Last change on this file since 351 was 351, checked in by epyon, 10 years ago
  • gui hover and selected support
  • minor changes
File size: 8.1 KB
Line 
1// Copyright (C) 2012-2014 ChaosForge Ltd
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 )
28        : m_renderer( nullptr ), m_window( w )
29{
30        m_area.dim( dimension( w->get_width(), w->get_height() ) );
31        m_renderer = new renderer( w );
32        m_screen   = create_element( handle(), m_area );
33}
34
35void nv::gui::environment::load_style( const std::string& filename )
36{
37        m_renderer->load_style( filename );
38}
39
40nv::gui::handle nv::gui::environment::create_element( const rectangle& r )
41{
42        return create_element( m_screen, r );
43}
44
45nv::gui::handle nv::gui::environment::create_element( handle parent, const rectangle& r )
46{
47        if ( parent.is_nil() ) parent = m_screen;
48
49        handle result = m_elements.create();
50        element* e    = m_elements.get( result );
51        rectangle ar  = r;
52
53        if ( ar.ul.x < 0 ) { ar.ul.x += m_area.lr.x; ar.lr.x += m_area.lr.x; }
54        if ( ar.ul.y < 0 ) { ar.ul.y += m_area.lr.y; ar.lr.y += m_area.lr.y; }
55
56        e->m_child_count = 0;
57        e->m_flags[ENABLED] = true;
58        e->m_flags[VISIBLE] = true;
59        e->m_flags[DIRTY]   = true;
60        e->m_render_data    = nullptr;
61        e->m_absolute = ar;
62        e->m_relative = ar;
63
64        if ( !parent.is_nil() ) // screen creation
65                add_child( parent, result );
66        return result;
67}
68
69void nv::gui::environment::destroy_element( handle e )
70{
71        element* dead_element = m_elements.get( e );
72        if ( dead_element == nullptr ) return;
73        destroy_children( e );
74        remove_child( dead_element->m_parent, e );
75
76        delete dead_element->m_render_data;
77        dead_element->m_render_data = nullptr;
78        dead_element->m_parent = handle();
79
80        m_elements.destroy( e );
81}
82
83void nv::gui::environment::update( handle e, uint32 elapsed )
84{
85        element* el = m_elements.get( e );
86        if ( !el ) return;
87        //      el->on_update( elapsed );
88        if ( el->m_flags[ENABLED] )
89        {
90                bool hover     = el->m_flags[HOVER];
91                bool new_hover = el->m_absolute.contains( m_mouse_position );
92                if ( hover != new_hover )
93                {
94                        el->m_flags[HOVER] = new_hover;
95                        // gain loose hover event
96                        m_renderer->on_hover_change( el, hover );
97                }
98        }
99
100        if ( el->m_flags[VISIBLE] )
101        {
102                for ( handle i : el->m_children )
103                {
104                        update( i, elapsed );
105                }
106        }
107        if ( el->m_flags[DIRTY] || el->m_render_data == nullptr )
108        {
109                m_renderer->redraw( el, elapsed );
110                el->m_flags[DIRTY] = false;
111        }
112}
113
114void nv::gui::environment::draw( handle e )
115{
116        element* el = m_elements.get( e );
117        if ( !el ) return;
118        if ( el->m_flags[VISIBLE] )
119        {
120//              el->on_draw();
121                m_renderer->draw( el );
122                for ( handle i : el->m_children )
123                {
124                        draw(i);
125                }
126        }
127}
128
129void nv::gui::environment::update()
130{
131        update( m_screen, 0 );
132}
133
134void nv::gui::environment::draw()
135{
136        draw( m_screen );
137        m_renderer->draw();
138}
139
140void nv::gui::environment::add_child( handle child )
141{
142        add_child( m_screen, child );
143}
144
145void nv::gui::environment::add_child( handle parent, handle child )
146{
147        element* e = m_elements.get( child );
148        element* p = m_elements.get( parent );
149        if ( e && p )
150        {
151                remove_child( e->m_parent, child );
152                e->m_parent = parent;
153                p->m_children.push_back( child );
154                p->m_child_count++;
155        }
156}
157
158void nv::gui::environment::destroy_children( handle e )
159{
160        element* parent = m_elements.get(e);
161        if ( parent )
162        {
163                while ( !parent->m_children.empty() )
164                {
165                        destroy_element( parent->m_children.front() );
166                }
167        }
168}
169
170
171nv::gui::environment::~environment()
172{
173        destroy_children( handle() );
174        delete m_renderer;
175}
176
177bool nv::gui::environment::process_io_event( const io_event& ev )
178{
179        switch ( ev.type )
180        {
181//      case EV_KEY          :
182        case EV_MOUSE_BUTTON :
183                if ( ev.mbutton.pressed && ev.mbutton.button == MOUSE_LEFT )
184                {
185                        handle h = get_element( position( ev.mbutton.x, ev.mbutton.y ) );
186                        set_selected( h );
187                        return true;
188                }
189                return false;
190        case EV_MOUSE_MOVE:
191                m_mouse_position = position( ev.mmove.x, ev.mmove.y );
192                return false;
193//      case EV_MOUSE_WHEEL  :
194        default:
195                break;
196        }
197        return false;
198}
199
200bool nv::gui::environment::set_selected( handle e )
201{
202        if ( e != m_selected )
203        {
204                element* eold = m_elements.get( m_selected );
205                element* el   = m_elements.get( e );
206                if ( eold )
207                {
208                        eold->m_flags[SELECTED] = false;
209                        m_renderer->on_select_change( eold, false );
210                }
211                if ( el )
212                {
213                        el->m_flags[SELECTED] = true;
214                        m_renderer->on_select_change( el, true );
215                }
216                m_selected = e;
217                return true;
218        }
219        return false;
220}
221
222bool nv::gui::environment::process_io_event( handle e, const io_event& ev )
223{
224        element* el = m_elements.get( e );
225        return el && el->m_parent.is_valid() ? process_io_event( el->m_parent, ev ) : false;
226}
227
228nv::gui::handle nv::gui::environment::get_element( const position& p )
229{
230        return get_deepest_child( m_screen, p );
231}
232
233nv::gui::handle nv::gui::environment::get_deepest_child( handle e, const position& p )
234{
235        element* el = m_elements.get(e);
236        if ( !el && !el->m_flags[VISIBLE] ) return handle();
237
238        handle result;
239        element::list::reverse_iterator it = el->m_children.rbegin();
240
241        while ( it != el->m_children.rend() )
242        {
243                result = get_deepest_child( *it, p );
244                if ( result.is_valid() ) return result;
245                ++it;
246        }
247
248        if ( el->m_absolute.contains(p) ) return e;
249        return handle();
250}
251
252void nv::gui::environment::move_to_top( handle child )
253{
254        element* e      = m_elements.get( child );
255        element* parent = m_elements.get( e->m_parent );
256        if ( e && parent )
257        {
258                auto it = std::find( parent->m_children.begin(), parent->m_children.end(), child );
259                if ( it != parent->m_children.end() )
260                {
261                        parent->m_children.erase( it );
262                        parent->m_children.push_back( child );
263                        parent->m_flags[DIRTY] = true;
264                }       
265        }
266}
267
268void nv::gui::environment::move_to_bottom( handle child )
269{
270        element* e      = m_elements.get( child );
271        element* parent = m_elements.get( e->m_parent );
272        if ( e && parent )
273        {
274                auto it = std::find( parent->m_children.begin(), parent->m_children.end(), child );
275                if ( it != parent->m_children.end() )
276                {
277                        parent->m_children.erase( it );
278                        parent->m_children.push_front( child );
279                        parent->m_flags[DIRTY] = true;
280                }
281        }
282}
283
284void nv::gui::environment::set_relative( handle e, const rectangle& r )
285{
286        element* el = m_elements.get(e);
287        if ( el )
288        {
289                el->m_flags[DIRTY] = true;
290                el->m_relative     = r;
291                recalculate_absolute( e );
292        }
293}
294
295void nv::gui::environment::set_relative( handle e, const position& p )
296{
297        element* el = m_elements.get(e);
298        if ( el )
299        {
300                set_relative( e, rectangle( p, p + el->m_relative.get_size() ) );
301        }
302}
303
304void nv::gui::environment::recalculate_absolute( handle e )
305{
306        element* el = m_elements.get(e);
307        rectangle pabsolute = m_elements.get( el->m_parent )->m_absolute;
308        el->m_absolute = el->m_relative + pabsolute.ul;
309
310        for ( handle o : el->m_children )
311        {
312                recalculate_absolute( o );
313        }
314}
315
316void nv::gui::environment::set_class( handle e, const string& text )
317{
318        element* ep = m_elements.get(e);
319        if ( ep != nullptr )
320        {
321                ep->m_class        = text;
322                ep->m_flags[DIRTY] = true;
323        }
324}
325
326void nv::gui::environment::set_text( handle e, const string& text )
327{
328        element* ep = m_elements.get(e);
329        if ( ep != nullptr )
330        {
331                ep->m_text         = text;
332                ep->m_flags[DIRTY] = true;
333        }
334}
335
336void nv::gui::environment::remove_child( handle parent, handle child )
337{
338        element* p = m_elements.get( parent );
339        if ( p )
340        {
341                auto it = std::find( p->m_children.begin(), p->m_children.end(), child );
342                if ( it != p->m_children.end() )
343                {
344                        element* e = m_elements.get( *it );
345                        e->m_parent = handle();
346                        p->m_children.erase(it);
347                }       
348        }
349}
350
Note: See TracBrowser for help on using the repository browser.