diff options
| author | kasull <qsullian@gmail.com> | 2026-03-11 00:24:47 -0400 |
|---|---|---|
| committer | kasull <qsullian@gmail.com> | 2026-03-11 00:24:47 -0400 |
| commit | ae6718ec0fb21077b767e189aca26b0fed488775 (patch) | |
| tree | a4216103d8a9a77edbc470dc4ab094e77ac30261 /src/editor/editor_menubar.cpp | |
| parent | bc1ea16c5be92e3bc810b0a30e01fbc9a7f191a9 (diff) | |
editor object placement and context menus
replace the editor menubar dropdown flow with a reusable context menu
component
merge sprite/entity placement into a single object tool
persist entities, and add undo
support for created sprites and entities
Diffstat (limited to 'src/editor/editor_menubar.cpp')
| -rw-r--r-- | src/editor/editor_menubar.cpp | 337 |
1 files changed, 102 insertions, 235 deletions
diff --git a/src/editor/editor_menubar.cpp b/src/editor/editor_menubar.cpp index c15053f..b89d1c6 100644 --- a/src/editor/editor_menubar.cpp +++ b/src/editor/editor_menubar.cpp @@ -35,39 +35,8 @@ void editor_apply_view_mode( GAME_EDITOR* e ) { e->gui.v3d->enabled = 1; } -U8 editor_toolbar_menu_open( const GUI_EDITOR_TOOLBAR* bar ) { - return bar && bar->open_root >= 0; -} - -static I32 editor_toolbar_find_root( GUI_EDITOR_TOOLBAR* bar, const char* text ) { - if( !bar || !text ) - return -1; - - for( I32 i = 0; i < (I32)bar->entries.size; ++i ) { - if( !strcmp( bar->entries[i].text, text ) ) - return i; - } - - return -1; -} - -void editor_toolbar_set_open( GUI_EDITOR_TOOLBAR* bar, U8 file_open, U8 edit_open ) { - if( !bar ) - return; - - bar->open_root = -1; - if( file_open ) - bar->open_root = editor_toolbar_find_root( bar, "file" ); - else if( edit_open ) - bar->open_root = editor_toolbar_find_root( bar, "edit" ); -} - void editor_toolbar_close_menu() { - if( !editor ) - return; - - GUI_EDITOR_TOOLBAR* bar = (GUI_EDITOR_TOOLBAR*)editor->gui.header_toolbar; - editor_toolbar_set_open( bar, 0, 0 ); + editor_hide_contextmenu(); } void editor_set_view_mode( I32 mode ) { @@ -97,13 +66,53 @@ void editor_raise_header_toolbar( GAME_EDITOR* e ) { parent->children.push( bar ); } -static void editor_menubar_set_entry( EDITOR_MENUBAR_ENTRY* entry, const char* text, U8 type ) { - if( !entry ) +static void editor_contextmenu_set_item( + EDITOR_CONTEXTMENU_ITEM* item, + const char* text, + EDITOR_CONTEXTMENU_CALLBACK cb = 0, + void* data = 0, + EDITOR_CONTEXTMENU_ENABLED_CALLBACK enabled_cb = 0 +) { + if( !item ) return; - entry->entries.clear(); - snprintf( entry->text, sizeof( entry->text ), "%s", text ); - entry->type = type; + item->items.clear(); + snprintf( item->text, sizeof( item->text ), "%s", text ? text : "" ); + item->cb = cb; + item->data = data; + item->enabled = 1; + item->enabled_cb = enabled_cb; +} + +static void editor_contextmenu_save_cb( void* ) { + if( editor ) + editor_save_map( editor ); +} + +static void editor_contextmenu_undo_cb( void* ) { + if( editor ) + editor_undo( editor ); +} + +static void editor_contextmenu_redo_cb( void* ) { + if( editor ) + editor_redo( editor ); +} + +static void editor_contextmenu_set_view_mode_cb( void* data ) { + editor_set_view_mode( (I32)(I64)data ); +} + +static void editor_contextmenu_set_tool_cb( void* data ) { + editor_settool( (U8)(I64)data ); +} + +static U8 editor_contextmenu_undo_enabled( const EDITOR_CONTEXTMENU_ITEM* ) { + return editor && editor->undo_actions.size > 0; +} + +static U8 editor_contextmenu_redo_enabled( const EDITOR_CONTEXTMENU_ITEM* ) { + return editor && editor->redo_actions.size > 0; } static void editor_toolbar_init_entries( GUI_EDITOR_TOOLBAR* bar ) { @@ -113,32 +122,31 @@ static void editor_toolbar_init_entries( GUI_EDITOR_TOOLBAR* bar ) { bar->entries.clear(); bar->entries.resize( 4 ); - editor_menubar_set_entry( &bar->entries[0], "file", EDITOR_MENUBAR_ENTRY_SUBMENU ); - bar->entries[0].entries.resize( 1 ); - editor_menubar_set_entry( &bar->entries[0].entries[0], "save", EDITOR_MENUBAR_ENTRY_FUNCTION ); - - editor_menubar_set_entry( &bar->entries[1], "edit", EDITOR_MENUBAR_ENTRY_SUBMENU ); - bar->entries[1].entries.resize( 2 ); - editor_menubar_set_entry( &bar->entries[1].entries[0], "undo", EDITOR_MENUBAR_ENTRY_FUNCTION ); - editor_menubar_set_entry( &bar->entries[1].entries[1], "redo", EDITOR_MENUBAR_ENTRY_FUNCTION ); - - editor_menubar_set_entry( &bar->entries[2], "view", EDITOR_MENUBAR_ENTRY_SUBMENU ); - bar->entries[2].entries.resize( 3 ); - editor_menubar_set_entry( &bar->entries[2].entries[0], "2d view", EDITOR_MENUBAR_ENTRY_FUNCTION ); - editor_menubar_set_entry( &bar->entries[2].entries[1], "3d view", EDITOR_MENUBAR_ENTRY_FUNCTION ); - editor_menubar_set_entry( &bar->entries[2].entries[2], "simulation", EDITOR_MENUBAR_ENTRY_FUNCTION ); - - editor_menubar_set_entry( &bar->entries[3], "tools", EDITOR_MENUBAR_ENTRY_SUBMENU ); - bar->entries[3].entries.resize( 6 ); - editor_menubar_set_entry( &bar->entries[3].entries[0], "none", EDITOR_MENUBAR_ENTRY_FUNCTION ); - editor_menubar_set_entry( &bar->entries[3].entries[1], "select", EDITOR_MENUBAR_ENTRY_FUNCTION ); - editor_menubar_set_entry( &bar->entries[3].entries[2], "wall", EDITOR_MENUBAR_ENTRY_FUNCTION ); - editor_menubar_set_entry( &bar->entries[3].entries[3], "poly", EDITOR_MENUBAR_ENTRY_FUNCTION ); - editor_menubar_set_entry( &bar->entries[3].entries[4], "sprite", EDITOR_MENUBAR_ENTRY_FUNCTION ); - editor_menubar_set_entry( &bar->entries[3].entries[5], "ent", EDITOR_MENUBAR_ENTRY_FUNCTION ); + editor_contextmenu_set_item( &bar->entries[0], "file" ); + bar->entries[0].items.resize( 1 ); + editor_contextmenu_set_item( &bar->entries[0].items[0], "save", editor_contextmenu_save_cb ); + + editor_contextmenu_set_item( &bar->entries[1], "edit" ); + bar->entries[1].items.resize( 2 ); + editor_contextmenu_set_item( &bar->entries[1].items[0], "undo", editor_contextmenu_undo_cb, 0, editor_contextmenu_undo_enabled ); + editor_contextmenu_set_item( &bar->entries[1].items[1], "redo", editor_contextmenu_redo_cb, 0, editor_contextmenu_redo_enabled ); + + editor_contextmenu_set_item( &bar->entries[2], "view" ); + bar->entries[2].items.resize( 3 ); + editor_contextmenu_set_item( &bar->entries[2].items[0], "2d view", editor_contextmenu_set_view_mode_cb, (void*)(I64)EDITOR_VIEWMODE_2D ); + editor_contextmenu_set_item( &bar->entries[2].items[1], "3d view", editor_contextmenu_set_view_mode_cb, (void*)(I64)EDITOR_VIEWMODE_3D ); + editor_contextmenu_set_item( &bar->entries[2].items[2], "simulation", editor_contextmenu_set_view_mode_cb, (void*)(I64)EDITOR_VIEWMODE_SIM ); + + editor_contextmenu_set_item( &bar->entries[3], "tools" ); + bar->entries[3].items.resize( 5 ); + editor_contextmenu_set_item( &bar->entries[3].items[0], "none", editor_contextmenu_set_tool_cb, (void*)(I64)EDITOR_TOOL_NONE ); + editor_contextmenu_set_item( &bar->entries[3].items[1], "select", editor_contextmenu_set_tool_cb, (void*)(I64)EDITOR_TOOL_SELECT ); + editor_contextmenu_set_item( &bar->entries[3].items[2], "wall", editor_contextmenu_set_tool_cb, (void*)(I64)EDITOR_TOOL_WALL ); + editor_contextmenu_set_item( &bar->entries[3].items[3], "poly", editor_contextmenu_set_tool_cb, (void*)(I64)EDITOR_TOOL_POLY ); + editor_contextmenu_set_item( &bar->entries[3].items[4], "object", editor_contextmenu_set_tool_cb, (void*)(I64)EDITOR_TOOL_OBJECT ); } -static I32 editor_toolbar_root_width( EDITOR_MENUBAR_ENTRY* entry ) { +static I32 editor_toolbar_root_width( const EDITOR_CONTEXTMENU_ITEM* entry ) { if( !entry ) return 44; @@ -147,20 +155,6 @@ static I32 editor_toolbar_root_width( EDITOR_MENUBAR_ENTRY* entry ) { return max( 44, text_w + 16 ); } -static I32 editor_toolbar_dropdown_width( EDITOR_MENUBAR_ENTRY* entry ) { - if( !entry || entry->type != EDITOR_MENUBAR_ENTRY_SUBMENU ) - return EDITOR_TOOLBAR_DROPDOWN_W; - - I32 width = EDITOR_TOOLBAR_DROPDOWN_W; - for( I32 i = 0; i < (I32)entry->entries.size; ++i ) { - I32 text_w = 0; - gui_draw_get_str_bounds( &text_w, 0, FNT_JPN12, "%s", entry->entries[i].text ); - width = max( width, text_w + 20 ); - } - - return width; -} - static void editor_toolbar_root_rect( GUI_EDITOR_TOOLBAR* bar, I32 idx, I32* rx, I32* ry, I32* rw, I32* rh ) { I32 x = gui_relx( bar ); I32 y = gui_rely( bar ); @@ -168,35 +162,22 @@ static void editor_toolbar_root_rect( GUI_EDITOR_TOOLBAR* bar, I32 idx, I32* rx, for( I32 i = 0; i < idx; ++i ) cx += editor_toolbar_root_width( &bar->entries[i] ) + 4; - I32 w = editor_toolbar_root_width( &bar->entries[idx] ); - *rx = cx; - *ry = y + 2; - *rw = w; - *rh = max( 1, bar->h - 4 ); + if( rx ) *rx = cx; + if( ry ) *ry = y + 2; + if( rw ) *rw = editor_toolbar_root_width( &bar->entries[idx] ); + if( rh ) *rh = max( 1, bar->h - 4 ); } -static void editor_toolbar_sub_rect( GUI_EDITOR_TOOLBAR* bar, I32 root_idx, I32 row, I32* rx, I32* ry, I32* rw, I32* rh ) { - I32 root_x = 0, root_y = 0, root_w = 0, root_h = 0; - editor_toolbar_root_rect( bar, root_idx, &root_x, &root_y, &root_w, &root_h ); - I32 row_h = max( 18, root_h ); - - *rx = root_x; - *ry = gui_rely( bar ) + bar->h + row * row_h; - *rw = editor_toolbar_dropdown_width( &bar->entries[root_idx] ); - *rh = row_h; -} +struct EDITOR_TOOLBAR_HIT { + I32 root{-1}; +}; static U8 editor_toolbar_pt_in_rect( I32 mx, I32 my, I32 x, I32 y, I32 w, I32 h ) { return mx >= x && mx < x + w && my >= y && my < y + h; } -struct EDITOR_MENUBAR_HIT { - I32 root{-1}; - I32 sub{-1}; -}; - -static EDITOR_MENUBAR_HIT editor_toolbar_hit_test( GUI_EDITOR_TOOLBAR* bar, I32 mx, I32 my ) { - EDITOR_MENUBAR_HIT hit{}; +static EDITOR_TOOLBAR_HIT editor_toolbar_hit_test( GUI_EDITOR_TOOLBAR* bar, I32 mx, I32 my ) { + EDITOR_TOOLBAR_HIT hit{}; for( I32 i = 0; i < (I32)bar->entries.size; ++i ) { I32 x = 0, y = 0, w = 0, h = 0; editor_toolbar_root_rect( bar, i, &x, &y, &w, &h ); @@ -206,76 +187,9 @@ static EDITOR_MENUBAR_HIT editor_toolbar_hit_test( GUI_EDITOR_TOOLBAR* bar, I32 } } - if( bar->open_root >= 0 && bar->open_root < (I32)bar->entries.size ) { - EDITOR_MENUBAR_ENTRY* root = &bar->entries[bar->open_root]; - if( root->type == EDITOR_MENUBAR_ENTRY_SUBMENU ) { - for( I32 i = 0; i < (I32)root->entries.size; ++i ) { - I32 x = 0, y = 0, w = 0, h = 0; - editor_toolbar_sub_rect( bar, bar->open_root, i, &x, &y, &w, &h ); - if( editor_toolbar_pt_in_rect( mx, my, x, y, w, h ) ) { - hit.root = bar->open_root; - hit.sub = i; - return hit; - } - } - } - } - return hit; } -static U8 editor_toolbar_entry_enabled( const EDITOR_MENUBAR_ENTRY* root, const EDITOR_MENUBAR_ENTRY* entry ) { - if( !root || !entry ) - return 0; - - if( !strcmp( root->text, "edit" ) && !strcmp( entry->text, "undo" ) ) - return editor && editor->undo_actions.size > 0; - if( !strcmp( root->text, "edit" ) && !strcmp( entry->text, "redo" ) ) - return editor && editor->redo_actions.size > 0; - - return 1; -} - -static void editor_toolbar_invoke( const EDITOR_MENUBAR_ENTRY* root, const EDITOR_MENUBAR_ENTRY* entry ) { - if( !root || !entry || !editor ) - return; - if( !editor_toolbar_entry_enabled( root, entry ) ) - return; - - if( !strcmp( root->text, "file" ) && !strcmp( entry->text, "save" ) ) { - editor_save_map( editor ); - return; - } - if( !strcmp( root->text, "edit" ) && !strcmp( entry->text, "undo" ) ) { - editor_undo( editor ); - return; - } - if( !strcmp( root->text, "edit" ) && !strcmp( entry->text, "redo" ) ) { - editor_redo( editor ); - return; - } - if( !strcmp( root->text, "view" ) && !strcmp( entry->text, "2d view" ) ) { - editor_set_view_mode( EDITOR_VIEWMODE_2D ); - return; - } - if( !strcmp( root->text, "view" ) && !strcmp( entry->text, "3d view" ) ) { - editor_set_view_mode( EDITOR_VIEWMODE_3D ); - return; - } - if( !strcmp( root->text, "view" ) && !strcmp( entry->text, "simulation" ) ) { - editor_set_view_mode( EDITOR_VIEWMODE_SIM ); - return; - } - if( !strcmp( root->text, "tools" ) ) { - if( !strcmp( entry->text, "none" ) ) editor_settool( EDITOR_TOOL_NONE ); - else if( !strcmp( entry->text, "select" ) ) editor_settool( EDITOR_TOOL_SELECT ); - else if( !strcmp( entry->text, "wall" ) ) editor_settool( EDITOR_TOOL_WALL ); - else if( !strcmp( entry->text, "poly" ) ) editor_settool( EDITOR_TOOL_POLY ); - else if( !strcmp( entry->text, "sprite" ) ) editor_settool( EDITOR_TOOL_SPRITE ); - else if( !strcmp( entry->text, "ent" ) ) editor_settool( EDITOR_TOOL_ENT ); - } -} - static void gui_editor_toolbar_draw_fn( void* ptr ) { GUI_EDITOR_TOOLBAR* bar = (GUI_EDITOR_TOOLBAR*)ptr; I32 x = gui_relx( bar ); @@ -289,107 +203,61 @@ static void gui_editor_toolbar_draw_fn( void* ptr ) { } U8 m1 = gui_mbutton_down( GUI_MBTNLEFT ); - EDITOR_MENUBAR_HIT hit = editor_toolbar_hit_test( bar, mx, my ); + EDITOR_TOOLBAR_HIT hit = editor_toolbar_hit_test( bar, mx, my ); CLR hover_fill = CLR::blend( ui_clr.border, ui_clr.bg, 0.70f ); CLR active_fill = CLR::blend( ui_clr.bg_sec, ui_clr.border, 0.22f ); - CLR border = gui_is_fg_window( bar ) ? ui_clr.border : ui_clr.border_inactive; gui_draw_frect( x, y, bar->w, bar->h, ui_clr.bg_sec ); - for( I32 i = 0; i < (I32)bar->entries.size; ++i ) { I32 rx = 0, ry = 0, rw = 0, rh = 0; editor_toolbar_root_rect( bar, i, &rx, &ry, &rw, &rh ); - U8 is_hover = hit.root == i && hit.sub == -1; - U8 is_active = bar->held && bar->held_root == i && bar->held_sub == -1 && m1; - U8 is_open = bar->open_root == i; - - CLR fill = ui_clr.bg_sec; - if( is_open || is_hover ) - fill = hover_fill; - if( is_active ) - fill = active_fill; - - if( is_open || is_active || is_hover ) - gui_draw_frect( rx, ry, rw, rh, fill ); - gui_draw_str( rx + 6, y + bar->h / 2 - 8, ALIGN_L, FNT_JPN12, ui_clr.txt, "%s", bar->entries[i].text ); - } - - if( bar->open_root < 0 || bar->open_root >= (I32)bar->entries.size ) - return; - EDITOR_MENUBAR_ENTRY* root = &bar->entries[bar->open_root]; - if( root->type != EDITOR_MENUBAR_ENTRY_SUBMENU ) - return; - - if( !root->entries.size ) - return; - - I32 panel_x = 0, panel_y = 0, panel_w = 0, panel_h = 0; - editor_toolbar_sub_rect( bar, bar->open_root, 0, &panel_x, &panel_y, &panel_w, &panel_h ); - I32 row_h = panel_h; - gui_draw_frect( panel_x, panel_y, panel_w, row_h * root->entries.size, border ); - gui_draw_frect( panel_x + 1, panel_y + 1, max( 1, panel_w - 2 ), max( 1, row_h * (I32)root->entries.size - 2 ), ui_clr.bg_sec ); - - for( I32 i = 0; i < (I32)root->entries.size; ++i ) { - EDITOR_MENUBAR_ENTRY* entry = &root->entries[i]; - I32 rx = 0, ry = 0, rw = 0, rh = 0; - editor_toolbar_sub_rect( bar, bar->open_root, i, &rx, &ry, &rw, &rh ); - - U8 enabled = editor_toolbar_entry_enabled( root, entry ); - U8 is_hover = hit.root == bar->open_root && hit.sub == i; - U8 is_active = bar->held && bar->held_root == bar->open_root && bar->held_sub == i && m1; + U8 hovered = hit.root == i; + U8 active = bar->held && bar->held_root == i && m1; + U8 open = editor_contextmenu_open() && bar->active_root == i; CLR fill = ui_clr.bg_sec; - if( enabled && is_active ) + if( active ) fill = active_fill; - else if( is_hover ) + else if( open || hovered ) fill = hover_fill; - gui_draw_frect( rx + 1, ry + 1, max( 1, rw - 2 ), max( 1, rh - 2 ), fill ); - CLR txt_clr = enabled ? ui_clr.txt : ui_clr.txt_inactive; - gui_draw_str( rx + 8, ry + rh / 2 - 8, ALIGN_L, FNT_JPN12, txt_clr, "%s", entry->text ); + if( open || hovered || active ) + gui_draw_frect( rx, ry, rw, rh, fill ); + + gui_draw_str( rx + 6, y + bar->h / 2 - 8, ALIGN_L, FNT_JPN12, ui_clr.txt, "%s", bar->entries[i].text ); } } static void gui_editor_toolbar_input_fn( void* ptr ) { GUI_EDITOR_TOOLBAR* bar = (GUI_EDITOR_TOOLBAR*)ptr; - I32 mx, my; + I32 mx = 0, my = 0; gui_cursor_pos( &mx, &my ); + U8 m1 = gui_mbutton_down( GUI_MBTNLEFT ); - EDITOR_MENUBAR_HIT hit = editor_toolbar_hit_test( bar, mx, my ); + EDITOR_TOOLBAR_HIT hit = editor_toolbar_hit_test( bar, mx, my ); if( m1 ) { if( !bar->held ) { bar->held = 1; bar->held_root = hit.root; - bar->held_sub = hit.sub; - if( hit.root == -1 && editor_toolbar_menu_open( bar ) ) - bar->open_root = -1; } return; } - if( bar->held && bar->held_root == hit.root && bar->held_sub == hit.sub ) { - if( hit.sub >= 0 ) { - EDITOR_MENUBAR_ENTRY* root = &bar->entries[hit.root]; - EDITOR_MENUBAR_ENTRY* sub = &root->entries[hit.sub]; - editor_toolbar_invoke( root, sub ); - bar->open_root = -1; - } else if( hit.root >= 0 ) { - EDITOR_MENUBAR_ENTRY* root = &bar->entries[hit.root]; - if( root->type == EDITOR_MENUBAR_ENTRY_SUBMENU ) { - if( bar->open_root == hit.root ) bar->open_root = -1; - else bar->open_root = hit.root; - } else { - editor_toolbar_invoke( root, root ); - bar->open_root = -1; - } + if( bar->held && bar->held_root == hit.root && hit.root >= 0 ) { + if( editor_contextmenu_open() && bar->active_root == hit.root ) { + editor_hide_contextmenu(); + } else { + I32 rx = 0; + editor_toolbar_root_rect( bar, hit.root, &rx, 0, 0, 0 ); + editor_show_contextmenu( rx, gui_rely( bar ) + bar->h, &bar->entries[hit.root].items ); + bar->active_root = hit.root; } } bar->held = 0; bar->held_root = -1; - bar->held_sub = -1; } GUI_EDITOR_TOOLBAR* gui_editor_toolbar( I32 x, I32 y, I32 w, I32 h, const char* name ) { @@ -402,14 +270,13 @@ GUI_EDITOR_TOOLBAR* gui_editor_toolbar( I32 x, I32 y, I32 w, I32 h, const char* bar->w = w; bar->h = h; bar->xbound = w; - bar->ybound = h + 120; + bar->ybound = h; bar->draw_fn = gui_editor_toolbar_draw_fn; bar->input_fn = gui_editor_toolbar_input_fn; bar->held = 0; bar->held_root = -1; - bar->held_sub = -1; - bar->open_root = -1; - strcpy( bar->name, name ); + bar->active_root = -1; + snprintf( bar->name, sizeof( bar->name ), "%s", name ); editor_toolbar_init_entries( bar ); GUI_VIEW* parent = gui_get_view(); |
