summaryrefslogtreecommitdiff
path: root/src/editor/editor_infobox.cpp
diff options
context:
space:
mode:
authorkasull <qsullian@gmail.com>2026-03-05 11:38:03 -0500
committerkasull <qsullian@gmail.com>2026-03-05 11:38:03 -0500
commit7c8b5072d8441aa6a7da9bd7560c47ba8c41270b (patch)
tree7f3a076dd4c651047dfcea82dbf05aa90ea83ed0 /src/editor/editor_infobox.cpp
parent54bcabc374b438ee288964d6f6314f5da2121a0e (diff)
split UI components and make menubar data-driven
replace monolithic gui.cpp with focused editor UI component files shared editor_gui_internal.h for layout constants and cross-component helpers modular menubar rendering/input
Diffstat (limited to 'src/editor/editor_infobox.cpp')
-rw-r--r--src/editor/editor_infobox.cpp238
1 files changed, 238 insertions, 0 deletions
diff --git a/src/editor/editor_infobox.cpp b/src/editor/editor_infobox.cpp
new file mode 100644
index 0000000..8e455d9
--- /dev/null
+++ b/src/editor/editor_infobox.cpp
@@ -0,0 +1,238 @@
+#include "editor_gui_internal.h"
+
+#include "../game.h"
+#include "../render/gl_2d.h"
+
+constexpr I32 EDITOR_ASSETS_ROW_H = 28;
+constexpr I32 EDITOR_ASSETS_THUMB = 20;
+constexpr I32 EDITOR_ASSETS_INNER_PAD_X = 8;
+constexpr I32 EDITOR_ASSETS_INNER_PAD_Y = 6;
+constexpr I32 EDITOR_ASSETS_SCROLLBAR_W = 7;
+constexpr I32 EDITOR_ASSETS_SCROLLBAR_GAP = 4;
+constexpr I32 EDITOR_ASSETS_SCROLL_STEP = 20;
+
+struct EDITOR_ASSETS_LAYOUT {
+ I32 inner_x{};
+ I32 inner_y{};
+ I32 inner_w{};
+ I32 list_h{};
+ I32 row_x{};
+ I32 row_w{};
+ I32 count{};
+ I32 content_h{};
+ I32 max_scroll{};
+ U8 show_scroll{};
+ I32 track_x{};
+ I32 track_y{};
+ I32 track_h{};
+};
+
+static EDITOR_ASSETS_LAYOUT editor_assets_layout( GUI_EDITOR_INFOBOX* box, I32 panel_x, I32 panel_y, I32 prop_count ) {
+ EDITOR_ASSETS_LAYOUT l{};
+ l.inner_x = panel_x + EDITOR_ASSETS_INNER_PAD_X;
+ l.inner_y = panel_y + EDITOR_ASSETS_INNER_PAD_Y;
+ l.inner_w = max( 1, box->w - ( EDITOR_ASSETS_INNER_PAD_X * 2 ) );
+ l.list_h = max( 1, box->h - ( EDITOR_ASSETS_INNER_PAD_Y * 2 ) );
+ l.count = prop_count + 1;
+ l.content_h = l.count * EDITOR_ASSETS_ROW_H;
+ l.max_scroll = max( 0, l.content_h - l.list_h );
+ l.show_scroll = l.content_h > l.list_h;
+ l.row_x = l.inner_x + 1;
+ l.row_w = l.inner_w - 2;
+ if( l.show_scroll )
+ l.row_w -= EDITOR_ASSETS_SCROLLBAR_W + EDITOR_ASSETS_SCROLLBAR_GAP;
+ l.row_w = max( 1, l.row_w );
+ l.track_x = l.inner_x + l.inner_w - EDITOR_ASSETS_SCROLLBAR_W - 1 - ( EDITOR_ASSETS_SCROLLBAR_GAP / 2 );
+ l.track_y = l.inner_y;
+ l.track_h = l.list_h - 2;
+ return l;
+}
+
+static void editor_assets_clamp_scroll( const EDITOR_ASSETS_LAYOUT& l ) {
+ editor->gui.assets_scroll = min( max( 0, editor->gui.assets_scroll ), l.max_scroll );
+}
+
+static void gui_editor_infobox_draw_assets( GUI_EDITOR_INFOBOX* box, I32 panel_x, I32 panel_y ) {
+ if( !editor->map )
+ return;
+
+ WORLD_MAP* map = editor->map;
+ EDITOR_ASSETS_LAYOUT l = editor_assets_layout( box, panel_x, panel_y, (I32)map->props.size );
+ editor_assets_clamp_scroll( l );
+ I32 yoff = -editor->gui.assets_scroll;
+
+ for( I32 idx = 0; idx < l.count; ++idx ) {
+ I32 row_y = l.inner_y + idx * EDITOR_ASSETS_ROW_H + yoff;
+ if( row_y + EDITOR_ASSETS_ROW_H - 2 <= l.inner_y || row_y >= l.inner_y + l.list_h )
+ continue;
+
+ U8 map_entry = idx == 0;
+ SURF_PROPS* p = map_entry ? 0 : &map->props[idx - 1];
+ U8 selected = 0;
+ if( editor->gui.props ) {
+ if( map_entry ) {
+ selected = editor->gui.props->seltype == EDITOR_SELECT_ORIGIN
+ && editor->gui.props->curselect == editor->map;
+ } else {
+ selected = editor->gui.props->seltype == EDITOR_SELECT_SURFPROPS
+ && editor->gui.props->curselect == p;
+ }
+ }
+
+ CLR rowbg = idx % 2 ? ui_clr.bg : ui_clr.bg_alt;
+ if( selected )
+ rowbg = CLR::blend( ui_clr.border, ui_clr.bg, 0.70f );
+
+ gui_draw_frect( l.row_x, row_y, l.row_w, EDITOR_ASSETS_ROW_H - 2, rowbg );
+
+ I32 tx = l.row_x + 3;
+ I32 ty = row_y + 3;
+ gui_draw_frect( tx, ty, EDITOR_ASSETS_THUMB, EDITOR_ASSETS_THUMB, ui_clr.border );
+ if( map_entry ) {
+ gui_draw_frect( tx + 1, ty + 1, EDITOR_ASSETS_THUMB - 2, EDITOR_ASSETS_THUMB - 2, ui_clr.bg_alt );
+ gui_draw_str( tx + EDITOR_ASSETS_THUMB / 2, ty + 4, ALIGN_C, FNT_JPN12, ui_clr.txt, "m" );
+ } else if( p->tex ) {
+ gl_2d_textured_frect( _gui.gl2d_font, { (F32)(tx + 1), (F32)(ty + 1) }, { (F32)(EDITOR_ASSETS_THUMB - 2), (F32)(EDITOR_ASSETS_THUMB - 2) }, p->tex );
+ } else {
+ gui_draw_frect( tx + 1, ty + 1, EDITOR_ASSETS_THUMB - 2, EDITOR_ASSETS_THUMB - 2, p->clr );
+ }
+
+ I32 text_x = tx + EDITOR_ASSETS_THUMB + 8;
+ CLR txt = ui_clr.txt;
+ if( map_entry ) {
+ gui_draw_str( text_x, row_y + 7, ALIGN_L, FNT_JPN12, txt, "[map] -> %s", map->name );
+ } else if( p->tex ) {
+ gui_draw_str( text_x, row_y + 7, ALIGN_L, FNT_JPN12, txt, "[%d] -> %s", idx - 1, p->tex->name );
+ } else {
+ gui_draw_str( text_x, row_y + 7, ALIGN_L, FNT_JPN12, txt, "[%d] -> %.2f, %.2f, %.2f", idx - 1, p->clr.r, p->clr.g, p->clr.b );
+ }
+ }
+
+ if( !l.show_scroll )
+ return;
+
+ gui_draw_frect( l.track_x, l.track_y, EDITOR_ASSETS_SCROLLBAR_W, l.track_h, ui_clr.bg_alt );
+ gui_draw_rect( l.track_x, l.track_y, EDITOR_ASSETS_SCROLLBAR_W, l.track_h, ui_clr.border );
+
+ I32 thumb_h = max( 18, ( l.track_h * l.list_h ) / max( 1, l.content_h ) );
+ thumb_h = min( thumb_h, l.track_h );
+ I32 travel = max( 1, l.track_h - thumb_h );
+ I32 thumb_y = l.track_y + ( travel * editor->gui.assets_scroll ) / max( 1, l.max_scroll );
+ gui_draw_frect( l.track_x, thumb_y + 1, EDITOR_ASSETS_SCROLLBAR_W, max( 1, thumb_h - 1 ), ui_clr.txt );
+}
+
+static void gui_editor_infobox_draw_fn( void* ptr ) {
+ GUI_EDITOR_INFOBOX* box = (GUI_EDITOR_INFOBOX*)ptr;
+ I32 x = gui_relx( box );
+ I32 y = gui_rely( box );
+ I32 w = box->w;
+ I32 h = box->h;
+
+ if( box->type == EDITOR_INFOBOX_STATUS ) {
+ CLR col = gui_is_fg_window( box ) ? ui_clr.border : ui_clr.border_inactive;
+ gui_draw_frect( x, y, w, h, col );
+ gui_draw_frect( x + 1, y + 1, w - 2, h - 2, ui_clr.bg_sec );
+ gui_draw_str(
+ x + 6,
+ y + 4,
+ ALIGN_L,
+ FNT_JPN12,
+ ui_clr.txt,
+ "selected tool: %s. click in viewport to create/edit.",
+ editor_tool_name()
+ );
+
+ if( editor->game && editor->game->gl ) {
+ GL_DATA* gl = editor->game->gl;
+ gui_draw_str(
+ x + w - 6,
+ y + 4,
+ ALIGN_R,
+ FNT_JPN12,
+ ui_clr.txt,
+ "fps: %.3f (%.5f ms) %dx%d",
+ gl->fps,
+ gl->frametime,
+ gl->canvas_size[0],
+ gl->canvas_size[1]
+ );
+ }
+ return;
+ }
+
+ gui_draw_str( x, y, ALIGN_L, FNT_JPN12, ui_clr.txt, "assets" );
+ y += EDITOR_LAYOUT_TITLE_OFFSET;
+
+ CLR col = gui_is_fg_window( box ) ? ui_clr.border : ui_clr.border_inactive;
+ gui_draw_frect( x, y, w, h, col );
+ gui_draw_frect( x + 1, y + 1, w - 2, h - 2, ui_clr.bg_sec );
+
+ gui_draw_push_clip( x + 2, y + 2, w - 4, h - 4 );
+ gui_editor_infobox_draw_assets( box, x, y );
+ gui_draw_pop_clip();
+}
+
+static void gui_editor_infobox_input_fn( void* ptr ) {
+ GUI_EDITOR_INFOBOX* box = (GUI_EDITOR_INFOBOX*)ptr;
+ static U8 assets_click_held = 0;
+ if( box->type == EDITOR_INFOBOX_ASSETS ) {
+ I32 x = gui_relx( box );
+ I32 y = gui_rely( box ) + EDITOR_LAYOUT_TITLE_OFFSET;
+ I32 w = box->w;
+ I32 h = box->h;
+ I32 prop_count = editor->map ? (I32)editor->map->props.size : 0;
+ EDITOR_ASSETS_LAYOUT l = editor_assets_layout( box, x, y, prop_count );
+ editor_assets_clamp_scroll( l );
+ I32 mx, my;
+ gui_cursor_pos( &mx, &my );
+ U8 inbounds = mx >= x && mx <= x + w && my >= y && my <= y + h;
+ if( inbounds ) {
+ U8 scroll = gui_mbutton_down( GUI_MBTNSCROLL );
+ if( scroll ) {
+ gui_capture_scroll();
+ if( scroll == 1 ) editor->gui.assets_scroll -= EDITOR_ASSETS_SCROLL_STEP;
+ else if( scroll == (U8)-1 ) editor->gui.assets_scroll += EDITOR_ASSETS_SCROLL_STEP;
+ editor_assets_clamp_scroll( l );
+ }
+
+ U8 m1 = gui_mbutton_down( GUI_MBTNLEFT );
+ if( m1 && !assets_click_held && editor->map ) {
+ if( mx >= l.row_x && mx < l.row_x + l.row_w ) {
+ I32 idx = ( my - l.inner_y + editor->gui.assets_scroll ) / EDITOR_ASSETS_ROW_H;
+ if( idx >= 0 && idx < l.count && editor->gui.props ) {
+ if( idx == 0 ) gui_editor_propview_select( editor->gui.props, editor->map, EDITOR_SELECT_ORIGIN );
+ else gui_editor_propview_select( editor->gui.props, &editor->map->props[idx - 1], EDITOR_SELECT_SURFPROPS );
+ }
+ }
+ }
+ assets_click_held = m1;
+ }
+
+ if( !gui_mbutton_down( GUI_MBTNLEFT ) )
+ assets_click_held = 0;
+ }
+
+ gui_base_input_fn( box );
+}
+
+GUI_EDITOR_INFOBOX* gui_editor_infobox( I32 x, I32 y, I32 w, I32 h, U8 type, const char* name ) {
+ if( !gui_check_target() )
+ return 0;
+
+ GUI_EDITOR_INFOBOX* box = new GUI_EDITOR_INFOBOX;
+ box->x = x;
+ box->y = y;
+ box->w = w;
+ box->h = h;
+ box->xbound = w;
+ box->ybound = h + ( type == EDITOR_INFOBOX_STATUS ? 0 : EDITOR_LAYOUT_TITLE_OFFSET );
+ box->draw_fn = gui_editor_infobox_draw_fn;
+ box->input_fn = gui_editor_infobox_input_fn;
+ box->type = type;
+ strcpy( box->name, name );
+
+ GUI_VIEW* parent = gui_get_view();
+ box->parent = parent;
+ parent->children.push( box );
+ return box;
+}