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

Last change on this file since 444 was 444, checked in by epyon, 10 years ago
  • slowly fixing up gui
File size: 7.7 KB
RevLine 
[395]1// Copyright (C) 2012-2015 ChaosForge Ltd
[69]2// http://chaosforge.org/
3//
[395]4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
[69]6
7#include "nv/gui/gui_environment.hh"
8
[126]9#include "nv/gui/gui_renderer.hh"
10
11        /*
12
13        TODO: parse a lua stylesheet as per Trac wiki
14
[392]15        IDEA: Store everything in unordered_maps, with lua_value's?
[126]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
[354]24nv::gui::environment::environment( renderer* r )
25        : m_renderer( r )
[126]26{
[440]27        r->set_environment( this );
[354]28        m_screen   = create_element( handle(), m_renderer->get_area() );
[126]29}
30
[433]31void nv::gui::environment::load_style( const string_view& filename )
[126]32{
33        m_renderer->load_style( filename );
34}
35
[269]36nv::gui::handle nv::gui::environment::create_element( const rectangle& r )
[257]37{
[269]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;
[351]44
[354]45        handle result  = m_elements.create();
46        element* e     = m_elements.get( result );
47        rectangle ar   = r;
48        rectangle full = m_renderer->get_area();
[344]49
[354]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; }
[344]52
[351]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;
[344]58        e->m_absolute = ar;
59        e->m_relative = ar;
[351]60
61        if ( !parent.is_nil() ) // screen creation
62                add_child( parent, result );
[444]63
[257]64        return result;
65}
66
[269]67void nv::gui::environment::destroy_element( handle e )
68{
[271]69        element* dead_element = m_elements.get( e );
[269]70        if ( dead_element == nullptr ) return;
[264]71        destroy_children( e );
[269]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
[271]78        m_elements.destroy( e );
[264]79}
80
[269]81void nv::gui::environment::update( handle e, uint32 elapsed )
[126]82{
[271]83        element* el = m_elements.get( e );
[269]84        if ( !el ) return;
85        //      el->on_update( elapsed );
[351]86        if ( el->m_flags[ENABLED] )
[257]87        {
[351]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;
[356]93                        // gain lose hover event
[444]94                        m_renderer->on_hover_change( el );
[351]95                }
96        }
97
98        if ( el->m_flags[VISIBLE] )
99        {
[269]100                for ( handle i : el->m_children )
[257]101                {
[268]102                        update( i, elapsed );
[257]103                }
104        }
[351]105        if ( el->m_flags[DIRTY] || el->m_render_data == nullptr )
[126]106        {
[269]107                m_renderer->redraw( el, elapsed );
[351]108                el->m_flags[DIRTY] = false;
[126]109        }
110}
111
[269]112void nv::gui::environment::draw( handle e )
[69]113{
[271]114        element* el = m_elements.get( e );
[269]115        if ( !el ) return;
[351]116        if ( el->m_flags[VISIBLE] )
[257]117        {
[269]118//              el->on_draw();
119                m_renderer->draw( el );
120                for ( handle i : el->m_children )
[257]121                {
[268]122                        draw(i);
[257]123                }
124        }
[69]125}
[126]126
[267]127void nv::gui::environment::update()
[126]128{
[257]129        update( m_screen, 0 );
[126]130}
131
[267]132void nv::gui::environment::draw()
[126]133{
[257]134        draw( m_screen );
[126]135        m_renderer->draw();
136}
137
[269]138void nv::gui::environment::add_child( handle child )
[126]139{
[268]140        add_child( m_screen, child );
[126]141}
142
[269]143void nv::gui::environment::add_child( handle parent, handle child )
[268]144{
[271]145        element* e = m_elements.get( child );
146        element* p = m_elements.get( parent );
[269]147        if ( e && p )
[268]148        {
[269]149                remove_child( e->m_parent, child );
150                e->m_parent = parent;
151                p->m_children.push_back( child );
152                p->m_child_count++;
[268]153        }
154}
155
[269]156void nv::gui::environment::destroy_children( handle e )
[264]157{
[271]158        element* parent = m_elements.get(e);
[269]159        if ( parent )
[264]160        {
[269]161                while ( !parent->m_children.empty() )
162                {
[440]163                        destroy_element( parent->m_children.back() );
[269]164                }
[264]165        }
166}
167
168
[267]169nv::gui::environment::~environment()
[126]170{
[269]171        destroy_children( handle() );
[126]172        delete m_renderer;
173}
174
[351]175bool nv::gui::environment::process_io_event( const io_event& ev )
[267]176{
[351]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        }
[267]195        return false;
196}
197
[440]198nv::string_view nv::gui::environment::get_string( shash64 h )
199{
200        return m_strings[h];
201}
202
[351]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;
[444]212                        m_renderer->on_select_change( eold );
[351]213                }
214                if ( el )
215                {
216                        el->m_flags[SELECTED] = true;
[444]217                        m_renderer->on_select_change( el );
[351]218                }
219                m_selected = e;
220                return true;
221        }
222        return false;
223}
224
[269]225bool nv::gui::environment::process_io_event( handle e, const io_event& ev )
[267]226{
[271]227        element* el = m_elements.get( e );
[270]228        return el && el->m_parent.is_valid() ? process_io_event( el->m_parent, ev ) : false;
[267]229}
230
[269]231nv::gui::handle nv::gui::environment::get_element( const position& p )
[267]232{
233        return get_deepest_child( m_screen, p );
234}
235
[269]236nv::gui::handle nv::gui::environment::get_deepest_child( handle e, const position& p )
237{
[271]238        element* el = m_elements.get(e);
[351]239        if ( !el && !el->m_flags[VISIBLE] ) return handle();
[267]240
[269]241        handle result;
[440]242        auto it = el->m_children.rbegin();
[269]243
244        while ( it != el->m_children.rend() )
[267]245        {
[268]246                result = get_deepest_child( *it, p );
[270]247                if ( result.is_valid() ) return result;
[267]248                ++it;
249        }
250
[269]251        if ( el->m_absolute.contains(p) ) return e;
252        return handle();
[267]253}
254
[269]255void nv::gui::environment::move_to_top( handle child )
[267]256{
[271]257        element* e      = m_elements.get( child );
258        element* parent = m_elements.get( e->m_parent );
[269]259        if ( e && parent )
[267]260        {
[440]261                auto it = find( parent->m_children.begin(), parent->m_children.end(), child );
[267]262                if ( it != parent->m_children.end() )
263                {
264                        parent->m_children.erase( it );
265                        parent->m_children.push_back( child );
[351]266                        parent->m_flags[DIRTY] = true;
[267]267                }       
268        }
269}
270
[269]271void nv::gui::environment::set_relative( handle e, const rectangle& r )
[267]272{
[271]273        element* el = m_elements.get(e);
[269]274        if ( el )
275        {
[351]276                el->m_flags[DIRTY] = true;
277                el->m_relative     = r;
[269]278                recalculate_absolute( e );
279        }
[267]280}
281
[269]282void nv::gui::environment::set_relative( handle e, const position& p )
[267]283{
[271]284        element* el = m_elements.get(e);
[269]285        if ( el )
286        {
287                set_relative( e, rectangle( p, p + el->m_relative.get_size() ) );
288        }
[267]289}
290
[269]291void nv::gui::environment::recalculate_absolute( handle e )
[267]292{
[271]293        element* el = m_elements.get(e);
294        rectangle pabsolute = m_elements.get( el->m_parent )->m_absolute;
[269]295        el->m_absolute = el->m_relative + pabsolute.ul;
[267]296
[269]297        for ( handle o : el->m_children )
[267]298        {
[268]299                recalculate_absolute( o );
[267]300        }
301}
302
[440]303void nv::gui::environment::set_class( handle e, const string_view& text )
[268]304{
[271]305        element* ep = m_elements.get(e);
[269]306        if ( ep != nullptr )
307        {
[440]308                ep->m_class        = m_strings.insert( text );
[351]309                ep->m_flags[DIRTY] = true;
[444]310                m_renderer->on_style_change( ep );
[269]311        }
[268]312}
313
[440]314void nv::gui::environment::set_text( handle e, const string_twine& text )
[268]315{
[271]316        element* ep = m_elements.get(e);
[269]317        if ( ep != nullptr )
318        {
[444]319                // TODO : implement twine == operator
[440]320                ep->m_text.assign( text );
[351]321                ep->m_flags[DIRTY] = true;
[269]322        }
[268]323}
324
[269]325void nv::gui::environment::remove_child( handle parent, handle child )
[268]326{
[271]327        element* p = m_elements.get( parent );
[269]328        if ( p )
[268]329        {
[440]330                auto it = find( p->m_children.begin(), p->m_children.end(), child );
[269]331                if ( it != p->m_children.end() )
332                {
[271]333                        element* e = m_elements.get( *it );
[269]334                        e->m_parent = handle();
[440]335                        p->m_children.erase( it );
336                }
[268]337        }
338}
339
Note: See TracBrowser for help on using the repository browser.