diff options
| author | navewindre <boneyaard@gmail.com> | 2025-09-03 20:10:09 +0200 |
|---|---|---|
| committer | navewindre <boneyaard@gmail.com> | 2025-09-03 20:10:09 +0200 |
| commit | f8b92ce3aa08b1445c9f956d8166830946562d12 (patch) | |
| tree | 94e63a5aec9f8f52b577f56799e0c9201fd976a5 /src/gui/base.cpp | |
a
Diffstat (limited to 'src/gui/base.cpp')
| -rw-r--r-- | src/gui/base.cpp | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/src/gui/base.cpp b/src/gui/base.cpp new file mode 100644 index 0000000..5d345d8 --- /dev/null +++ b/src/gui/base.cpp @@ -0,0 +1,405 @@ +#include <string.h> + +#include "base.h" +#include "../game.h" + +// =========== [ impl ] =========== +#include "../util/input.h" +#include "../render/gl_2d.h" +#include "../render/gl_2d_font.h" +// ================================ + +__gui_internal _gui; + +void gui_load_font( GL_DATA* gl, __gui_internal::__font* fnt, const char* name ) { + // todo: this probably crashes when fonts r re-created + GL_FONT** fptr = gl->fonts.where( fn( GL_FONT** ptr ) { + GL_FONT* f = *ptr; + return strstr( f->name, name ) != 0; + } ); + + if( !fptr ) { + dlog( "gui_load_font() : error loading font %s\n", name ); + return; + } + + fnt->glfnt = *fptr; +} + +void gui_init( GAME_DATA* game ) { + GL_DATA* gl = game->gl; + gui_load_font( gl, &_gui.fonts.jpn12, "jpn12" ); + gui_load_font( gl, &_gui.fonts.jpn16, "jpn16" ); +} + +void gui_end() { + _gui.cur_window = 0; +} + +void gui_draw( GAME_DATA* game ) { + _gui.gl2d = game->shaders.gl2d; + _gui.gl2d_font = game->shaders.gl2d_texcoord; + + _gui.windows.each( fn( GUI_WINDOW** w ) { + GUI_WINDOW* wnd = *w; + if( !wnd->enabled ) return; + + wnd->draw_fn( wnd ); + } ); +} + +void gui_input( GAME_DATA* game ) { + for( I32 i = (I32)_gui.windows.size - 1; i >= 0; --i ) { + GUI_WINDOW* wnd = _gui.windows[i]; + if( !wnd->enabled ) continue; + + wnd->input_fn( wnd ); + break; + } +} + +void gui_onframe( GAME_DATA* game ) { + gui_run_callbacks(); + + gui_input( game ); + gui_draw( game ); +} + +void gui_free( GUI_BASE* node ) { + node->children.each( fn( GUI_BASE** ptr ) { + GUI_BASE* child = *ptr; + gui_free( child ); + } ); + + node->children.clear(); + + if( !node->parent ) { + I32 idx = _gui.windows.idx_of( (GUI_WINDOW*)node ); + if( idx != -1 ) + _gui.windows.erase( idx ); + + if( _gui.cur_window == node ) { + if( _gui.windows.size > 0 ) { + idx = idx > _gui.windows.size - 1 ? _gui.windows.size - 1 : 0; + _gui.cur_window = _gui.windows[idx]; + } + } + } + else if( _gui.cur_view == node ) { + _gui.cur_view = 0; + for( U32 i = 0; i < node->parent->children.size; ++i ) { + GUI_BASE* n = node->parent->children.data[i]; + if( n == node ) + continue; + + if( !strcmp( n->name, "BASE_VIEW" ) ) { + _gui.cur_view = (GUI_VIEW*)n; + break; + } + + n = gui_find_node( n, "BASE_VIEW" ); + if( n != node ) { + _gui.cur_view = (GUI_VIEW*)n; + break; + } + } + } + + delete node; +} + +I32 gui_relx( GUI_BASE* node ) { + I32 x = node->x; + for( GUI_BASE* p = node->parent; !!p; p = p->parent ) { + x += p->x; + } + return x; +} + +I32 gui_rely( GUI_BASE* node ) { + I32 y = node->y; + for( GUI_BASE* p = node->parent; !!p; p = p->parent ) { + y += p->y; + } + return y; +} + +GUI_BASE* gui_find_node( GUI_BASE* root, const char* name ) { + if( !root ) + return 0; + + if( !strcmp( root->name, name ) ) + return root; + + for( U32 i = 0; i < root->children.size; ++i ) { + GUI_BASE* child = root->children.data[i]; + GUI_BASE* node = gui_find_node( child, name ); + if( node ) + return node; + } + + return 0; +} + +GUI_WINDOW* gui_get_parent_wnd( GUI_BASE* node ) { + if( !node->parent ) + return (GUI_WINDOW*)node; + + for( GUI_BASE* b = node; !!b; b = b->parent ) { + if( !b->parent ) + return (GUI_WINDOW*)b; + } + + return (GUI_WINDOW*)node; +} + +void gui_empty_children( GUI_BASE* node ) { + node->children.each( fn( GUI_BASE** ptr ) { + gui_free( *ptr ); + } ); + + node->children.clear(); +} + +GUI_VIEW* gui_get_view() { + return _gui.cur_view; +} + +void gui_set_view( struct GUI_VIEW* view ) { + _gui.cur_view = view; +} + +GUI_WINDOW* gui_get_window() { + return _gui.cur_window; +} + +void gui_set_window( GUI_WINDOW* window ) { + _gui.cur_window = window; +} + +void gui_bring_to_top( GUI_WINDOW* window ) { + for( U32 i = 0; i < _gui.windows.size; ++i ) { + if( _gui.windows[i] == window ) { + _gui.windows.erase( i ); + break; + } + } + + _gui.windows.push( window ); +} + +U8 gui_is_fg_window( GUI_BASE* node ) { + GUI_WINDOW* top_wnd; + for( I32 i = _gui.windows.size - 1; i >= 0; --i ) { + GUI_WINDOW* wnd = _gui.windows[i]; + if( !wnd->enabled ) + continue; + + top_wnd = wnd; + break; + } + + if( !node->parent ) { + return top_wnd == node; + } + + return gui_get_parent_wnd( node ) == top_wnd; +} + +U8 gui_check_target() { + if( !_gui.cur_view ) { + dlog( "gui_check_target() : no view" ); + return 0; + } + + return 1; +} + +void gui_run_callbacks() { + LIST<__gui_internal::callback_entry> cb_copy = _gui.callbacks; + _gui.callbacks.clear(); + + for( I32 i = cb_copy.size - 1; i >= 0; --i ) { + __gui_internal::callback_entry* e = &cb_copy[i]; + if( e->callback ) + e->callback( e->data ); + } +} + +void gui_push_callback( GUI_CALLBACK cb ) { + __gui_internal::callback_entry e; + e.data = 0; + e.callback = cb; + + _gui.callbacks.push( e ); +} + +void gui_push_callback( void* data, GUI_CALLBACK cb ) { + __gui_internal::callback_entry e; + e.data = data; + e.callback = cb; + + _gui.callbacks.push( e ); +} + +void gui_base_input_fn( void* ptr ) { + GUI_BASE* e = (GUI_BASE*)ptr; + if( !e ) return; + + e->children.each( fn( GUI_BASE** ptr ) { + GUI_BASE* child = *ptr; + if( child->enabled && child->input_fn ) + child->input_fn( child ); + } ); +} + +void gui_draw_frect( I32 x, I32 y, I32 w, I32 h, CLR col ) { + gl_2d_frect( _gui.gl2d, { (F32)x, (F32)y }, { (F32)w, (F32)h }, col ); +} + +void gui_draw_rect( I32 x, I32 y, I32 w, I32 h, CLR col ) { + gl_2d_rect( _gui.gl2d, { (F32)x, (F32)y }, { (F32)w, (F32)h }, col ); +} + +void gui_draw_line( I32 x0, I32 y0, I32 x1, I32 y1, CLR col ) { + gl_2d_line( _gui.gl2d, { (F32)x0, (F32)y0 }, { (F32)x1, (F32)y1 }, col ); +} + +GL_FONT* gui_font_from_idx( U32 fnt ) { + if( fnt > FNT_LAST ) { + dlog( "gui_font_from_idx() : invalid font index %d", fnt ); + return 0; + } + + __gui_internal::__font* pfnt; + switch( fnt ) { + case FNT_JPN12: pfnt = &_gui.fonts.jpn12; break; + case FNT_JPN16: pfnt = &_gui.fonts.jpn16; break; + default: return 0; + }; + + return pfnt->glfnt; +} + +void gui_draw_str_internal( I32 x, I32 y, U8 align, U32 fnt, CLR col, const char* str ) { + GL_FONT* pfnt = gui_font_from_idx( fnt ); + if( !pfnt ) return; + + I32 w; + gui_draw_get_str_bounds( &w, 0, fnt, str ); + switch( align ) { + case ALIGN_R: x -= w; break; + case ALIGN_C: x -= (I32)( w * 0.5f ); break; + } + + gl_font_draw( pfnt, _gui.gl2d_font, { (F32)x, (F32)y }, str, col ); +} + +void gui_draw_str( I32 x, I32 y, U8 align, U32 fnt, CLR col, const char* fmt, ... ) { + va_list args; + va_start( args, fmt ); + char buf[GUI_STR_BUF_MAX]; + vsprintf( buf, fmt, args ); + va_end( args ); + + gui_draw_str_internal( x, y, align, fnt, col, buf ); +} + +void gui_draw_get_str_bounds_internal( I32* w, I32* h, U32 fnt, const char* buf ) { + GL_FONT* pfnt = gui_font_from_idx( fnt ); + if( !pfnt ) return; + + VEC2 dim = gl_font_dim( pfnt, buf ); + if( w ) *w = dim.x; + if( h ) *h = dim.y; +} + +void gui_draw_get_str_bounds( I32* w, I32* h, U32 fnt, const char *fmt, ... ) { + va_list args; + va_start( args, fmt ); + char buf[GUI_STR_BUF_MAX]; + vsprintf( buf, fmt, args ); + va_end( args ); + + gui_draw_get_str_bounds_internal( w, h, fnt, buf ); +} + +void gui_draw_get_clip( I32 *x, I32 *y, I32 *w, I32 *h ) { + VEC2 start, dim; + gl_get_clip( _gui.gl2d->gl, &start, &dim ); + + if( x ) *x = (I32)start.x; + if( y ) *y = (I32)start.y; + if( w ) *w = (I32)dim.x; + if( h ) *h = (I32)dim.y; +} + +void gui_draw_set_clip( I32 x, I32 y, I32 w, I32 h ) { + VEC2 start, dim; + start.x = (F32)x; + start.y = (F32)y; + dim.x = (F32)w; + dim.y = (F32)h; + + gl_set_clip( _gui.gl2d->gl, start, dim ); +} + +void gui_draw_reset_clip() { + gl_reset_clip( _gui.gl2d->gl ); +} + +void gui_draw_push_clip( I32 x, I32 y, I32 w, I32 h ) { + I32 cx,cy,cw,ch; + gui_draw_get_clip( &cx, &cy, &cw, &ch ); + + __gui_internal::clip_rect rect{ cx, cy, cw, ch }; + _gui.clip_rects.push( rect ); + + gui_draw_set_clip( x, y, w, h ); +} + +void gui_draw_pop_clip() { + if( !_gui.clip_rects.size ) { + dlog( "gui_draw_pop_clip() : clip stack empty\n" ); + return gui_draw_reset_clip(); + } + + __gui_internal::clip_rect rect = _gui.clip_rects.pop(); + gui_draw_set_clip( rect.x, rect.y, rect.w, rect.h ); +} + +void gui_cursor_pos( I32 *x, I32 *y ) { + if( x ) *x = input.mouse.pos.x; + if( y ) *y = input.mouse.pos.y; +} + +U8 gui_mbutton_down( U8 button ) { + switch( button ) { + case GUI_MBTNLEFT: + return input.mouse.left; + case GUI_MBTNRIGHT: + return input.mouse.right; + case GUI_MBTNMIDDLE: + return input.mouse.middle; + case GUI_MBTNSCROLL: + return input.mouse.wheel; + }; + + return 0; +} + +void gui_capture_scroll() { + input.mouse.wheel = 0; +} + +U8 gui_key_down( U8 key ) { + return input.keys[key]; +} + +F32 gui_frametime() { + return _gui.gl2d->gl->frametime; +} + +F32 gui_time() { + return u_time(); +} |
