diff options
Diffstat (limited to 'src/editor/editor_menubar.cpp')
| -rw-r--r-- | src/editor/editor_menubar.cpp | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/src/editor/editor_menubar.cpp b/src/editor/editor_menubar.cpp new file mode 100644 index 0000000..5491c05 --- /dev/null +++ b/src/editor/editor_menubar.cpp @@ -0,0 +1,430 @@ +#include "editor_gui_internal.h" + +U8 editor_menu_hover_mask_active = 0; +I32 editor_menu_hover_real_x = 0; +I32 editor_menu_hover_real_y = 0; + +static void editor_header_back_cb( void* ) { + editor_toolbar_close_menu(); + editor_close( editor ); +} + +static void editor_header_mode_2d_cb( void* ) { + editor_set_view_mode( EDITOR_VIEWMODE_2D ); +} + +static void editor_header_mode_3d_cb( void* ) { + editor_set_view_mode( EDITOR_VIEWMODE_3D ); +} + +static void editor_header_mode_sim_cb( void* ) { + editor_set_view_mode( EDITOR_VIEWMODE_SIM ); +} + +void editor_apply_view_mode( GAME_EDITOR* e ) { + if( !e || !e->gui.v2d || !e->gui.v3d ) + return; + + if( e->gui.view_mode == EDITOR_VIEWMODE_2D ) { + e->gui.v2d->enabled = 1; + e->gui.v3d->enabled = 0; + return; + } + + e->gui.v2d->enabled = 0; + 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 ); +} + +void editor_set_view_mode( I32 mode ) { + if( !editor ) + return; + + editor_toolbar_close_menu(); + editor->gui.view_mode = mode; + editor_apply_view_mode( editor ); + editor_layout_map_view( editor ); +} + +void editor_raise_header_toolbar( GAME_EDITOR* e ) { + if( !e || !e->map || !e->wnd || !e->gui.header_toolbar ) + return; + + GUI_BASE* bar = e->gui.header_toolbar; + GUI_BASE* parent = bar->parent; + if( !parent ) + return; + + I32 idx = parent->children.idx_of( bar ); + if( idx == -1 || idx == (I32)parent->children.size - 1 ) + return; + + parent->children.erase( idx ); + parent->children.push( bar ); +} + +static void editor_menubar_set_entry( EDITOR_MENUBAR_ENTRY* entry, const char* text, U8 type ) { + if( !entry ) + return; + + entry->entries.clear(); + snprintf( entry->text, sizeof( entry->text ), "%s", text ); + entry->type = type; +} + +static void editor_toolbar_init_entries( GUI_EDITOR_TOOLBAR* bar ) { + if( !bar ) + return; + + 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 ); +} + +static I32 editor_toolbar_root_width( EDITOR_MENUBAR_ENTRY* entry ) { + if( !entry ) + return 44; + + I32 text_w = 0; + gui_draw_get_str_bounds( &text_w, 0, FNT_JPN12, "%s", entry->text ); + 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 ); + I32 cx = x + 8; + 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 ); +} + +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; +} + +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{}; + 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 ); + if( editor_toolbar_pt_in_rect( mx, my, x, y, w, h ) ) { + hit.root = i; + return hit; + } + } + + 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" ) ) settool( EDITOR_TOOL_NONE ); + else if( !strcmp( entry->text, "select" ) ) settool( EDITOR_TOOL_SELECT ); + else if( !strcmp( entry->text, "wall" ) ) settool( EDITOR_TOOL_WALL ); + else if( !strcmp( entry->text, "poly" ) ) settool( EDITOR_TOOL_POLY ); + else if( !strcmp( entry->text, "sprite" ) ) settool( EDITOR_TOOL_SPRITE ); + else if( !strcmp( entry->text, "ent" ) ) 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 ); + I32 y = gui_rely( bar ); + I32 mx = 0, my = 0; + if( editor_menu_hover_mask_active ) { + mx = editor_menu_hover_real_x; + my = editor_menu_hover_real_y; + } else { + gui_cursor_pos( &mx, &my ); + } + + U8 m1 = gui_mbutton_down( GUI_MBTNLEFT ); + EDITOR_MENUBAR_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; + + CLR fill = ui_clr.bg_sec; + if( enabled && is_active ) + fill = active_fill; + else if( is_hover ) + 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 ); + } +} + +static void gui_editor_toolbar_input_fn( void* ptr ) { + GUI_EDITOR_TOOLBAR* bar = (GUI_EDITOR_TOOLBAR*)ptr; + I32 mx, my; + gui_cursor_pos( &mx, &my ); + U8 m1 = gui_mbutton_down( GUI_MBTNLEFT ); + EDITOR_MENUBAR_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; + } + } + } + + 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 ) { + if( !gui_check_target() ) + return 0; + + GUI_EDITOR_TOOLBAR* bar = new GUI_EDITOR_TOOLBAR; + bar->x = x; + bar->y = y; + bar->w = w; + bar->h = h; + bar->xbound = w; + bar->ybound = h + 120; + 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 ); + editor_toolbar_init_entries( bar ); + + GUI_VIEW* parent = gui_get_view(); + bar->parent = parent; + parent->children.push( bar ); + return bar; +} + +void editor_create_header_controls( GAME_EDITOR* e ) { + GAME_EDITOR::EDITOR_GUI* egui = &e->gui; + egui->header_toolbar = gui_editor_toolbar( 1, EDITOR_LAYOUT_MENU_Y, e->wnd->w - 3, EDITOR_LAYOUT_MENU_H, "editor toolbar" ); + egui->header_back = gui_button( 10, EDITOR_LAYOUT_NAV_Y, 92, 20, "[ back ]", editor_header_back_cb ); + egui->header_viewtype_label = gui_label( 250, EDITOR_LAYOUT_NAV_Y + 4, "view type:" ); + egui->header_viewtype = gui_editor_viewtype_segment( 320, EDITOR_LAYOUT_NAV_Y, 186, 20, "viewtype segment" ); + egui->header_mode_2d = gui_button( 500, EDITOR_LAYOUT_NAV_Y, 92, 20, "[ 2d view ]", editor_header_mode_2d_cb ); + egui->header_mode_3d = gui_button( 600, EDITOR_LAYOUT_NAV_Y, 92, 20, "[ 3d view ]", editor_header_mode_3d_cb ); + egui->header_mode_sim = gui_button( 700, EDITOR_LAYOUT_NAV_Y, 92, 20, "[ simulation ]", editor_header_mode_sim_cb ); +} |
