From 7c8b5072d8441aa6a7da9bd7560c47ba8c41270b Mon Sep 17 00:00:00 2001 From: kasull Date: Thu, 5 Mar 2026 11:38:03 -0500 Subject: 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 --- src/editor/editor_infobox.cpp | 238 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 src/editor/editor_infobox.cpp (limited to 'src/editor/editor_infobox.cpp') 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; +} -- cgit v1.2.3