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

Last change on this file since 492 was 492, checked in by epyon, 9 years ago
File size: 7.9 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 ) );
[492]184                        element* e = m_elements.get( h );
185                        if ( e->m_on_click ) e->m_on_click();
186
[351]187                        set_selected( h );
188                        return true;
189                }
190                return false;
191        case EV_MOUSE_MOVE:
192                m_mouse_position = position( ev.mmove.x, ev.mmove.y );
193                return false;
194//      case EV_MOUSE_WHEEL  :
195        default:
196                break;
197        }
[267]198        return false;
199}
200
[440]201nv::string_view nv::gui::environment::get_string( shash64 h )
202{
203        return m_strings[h];
204}
205
[351]206bool nv::gui::environment::set_selected( handle e )
207{
208        if ( e != m_selected )
209        {
210                element* eold = m_elements.get( m_selected );
211                element* el   = m_elements.get( e );
212                if ( eold )
213                {
214                        eold->m_flags[SELECTED] = false;
[444]215                        m_renderer->on_select_change( eold );
[351]216                }
217                if ( el )
218                {
219                        el->m_flags[SELECTED] = true;
[444]220                        m_renderer->on_select_change( el );
[351]221                }
222                m_selected = e;
223                return true;
224        }
225        return false;
226}
227
[269]228bool nv::gui::environment::process_io_event( handle e, const io_event& ev )
[267]229{
[271]230        element* el = m_elements.get( e );
[270]231        return el && el->m_parent.is_valid() ? process_io_event( el->m_parent, ev ) : false;
[267]232}
233
[269]234nv::gui::handle nv::gui::environment::get_element( const position& p )
[267]235{
236        return get_deepest_child( m_screen, p );
237}
238
[269]239nv::gui::handle nv::gui::environment::get_deepest_child( handle e, const position& p )
240{
[271]241        element* el = m_elements.get(e);
[351]242        if ( !el && !el->m_flags[VISIBLE] ) return handle();
[267]243
[269]244        handle result;
[440]245        auto it = el->m_children.rbegin();
[269]246
247        while ( it != el->m_children.rend() )
[267]248        {
[268]249                result = get_deepest_child( *it, p );
[270]250                if ( result.is_valid() ) return result;
[267]251                ++it;
252        }
253
[269]254        if ( el->m_absolute.contains(p) ) return e;
255        return handle();
[267]256}
257
[269]258void nv::gui::environment::move_to_top( handle child )
[267]259{
[271]260        element* e      = m_elements.get( child );
261        element* parent = m_elements.get( e->m_parent );
[269]262        if ( e && parent )
[267]263        {
[440]264                auto it = find( parent->m_children.begin(), parent->m_children.end(), child );
[267]265                if ( it != parent->m_children.end() )
266                {
267                        parent->m_children.erase( it );
268                        parent->m_children.push_back( child );
[351]269                        parent->m_flags[DIRTY] = true;
[267]270                }       
271        }
272}
273
[269]274void nv::gui::environment::set_relative( handle e, const rectangle& r )
[267]275{
[271]276        element* el = m_elements.get(e);
[269]277        if ( el )
278        {
[351]279                el->m_flags[DIRTY] = true;
280                el->m_relative     = r;
[269]281                recalculate_absolute( e );
282        }
[267]283}
284
[269]285void nv::gui::environment::set_relative( handle e, const position& p )
[267]286{
[271]287        element* el = m_elements.get(e);
[269]288        if ( el )
289        {
290                set_relative( e, rectangle( p, p + el->m_relative.get_size() ) );
291        }
[267]292}
293
[269]294void nv::gui::environment::recalculate_absolute( handle e )
[267]295{
[271]296        element* el = m_elements.get(e);
297        rectangle pabsolute = m_elements.get( el->m_parent )->m_absolute;
[269]298        el->m_absolute = el->m_relative + pabsolute.ul;
[267]299
[269]300        for ( handle o : el->m_children )
[267]301        {
[268]302                recalculate_absolute( o );
[267]303        }
304}
305
[440]306void nv::gui::environment::set_class( handle e, const string_view& text )
[268]307{
[271]308        element* ep = m_elements.get(e);
[269]309        if ( ep != nullptr )
310        {
[440]311                ep->m_class        = m_strings.insert( text );
[351]312                ep->m_flags[DIRTY] = true;
[444]313                m_renderer->on_style_change( ep );
[269]314        }
[268]315}
316
[492]317void nv::gui::environment::set_on_click( handle e, const function< void() >& on_click )
318{
319        element* ep = m_elements.get( e );
320        if ( ep != nullptr )
321        {
322                ep->m_on_click = on_click;
323        }
324}
325
[440]326void nv::gui::environment::set_text( handle e, const string_twine& text )
[268]327{
[271]328        element* ep = m_elements.get(e);
[269]329        if ( ep != nullptr )
330        {
[444]331                // TODO : implement twine == operator
[440]332                ep->m_text.assign( text );
[351]333                ep->m_flags[DIRTY] = true;
[269]334        }
[268]335}
336
[269]337void nv::gui::environment::remove_child( handle parent, handle child )
[268]338{
[271]339        element* p = m_elements.get( parent );
[269]340        if ( p )
[268]341        {
[440]342                auto it = find( p->m_children.begin(), p->m_children.end(), child );
[269]343                if ( it != p->m_children.end() )
344                {
[271]345                        element* e = m_elements.get( *it );
[269]346                        e->m_parent = handle();
[440]347                        p->m_children.erase( it );
348                }
[268]349        }
350}
351
Note: See TracBrowser for help on using the repository browser.