summaryrefslogtreecommitdiff
path: root/src/gui/base.cpp
diff options
context:
space:
mode:
authornavewindre <boneyaard@gmail.com>2025-09-03 20:10:09 +0200
committernavewindre <boneyaard@gmail.com>2025-09-03 20:10:09 +0200
commitf8b92ce3aa08b1445c9f956d8166830946562d12 (patch)
tree94e63a5aec9f8f52b577f56799e0c9201fd976a5 /src/gui/base.cpp
a
Diffstat (limited to 'src/gui/base.cpp')
-rw-r--r--src/gui/base.cpp405
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();
+}