summaryrefslogtreecommitdiff
path: root/src/editor/editor_menubar.cpp
diff options
context:
space:
mode:
authorkasull <qsullian@gmail.com>2026-03-11 00:24:47 -0400
committerkasull <qsullian@gmail.com>2026-03-11 00:24:47 -0400
commitae6718ec0fb21077b767e189aca26b0fed488775 (patch)
treea4216103d8a9a77edbc470dc4ab094e77ac30261 /src/editor/editor_menubar.cpp
parentbc1ea16c5be92e3bc810b0a30e01fbc9a7f191a9 (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.cpp337
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();