#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; } void editor_toolbar_close_menu() { editor_hide_contextmenu(); } 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_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; 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 ) { if( !bar ) return; bar->entries.clear(); bar->entries.resize( 4 ); 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( const EDITOR_CONTEXTMENU_ITEM* 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 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; 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 ); } 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; } 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 ); if( editor_toolbar_pt_in_rect( mx, my, x, y, w, h ) ) { hit.root = i; return hit; } } return hit; } 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_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 ); 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 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( active ) fill = active_fill; else if( open || hovered ) fill = hover_fill; 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 = 0, my = 0; gui_cursor_pos( &mx, &my ); U8 m1 = gui_mbutton_down( GUI_MBTNLEFT ); EDITOR_TOOLBAR_HIT hit = editor_toolbar_hit_test( bar, mx, my ); if( m1 ) { if( !bar->held ) { bar->held = 1; bar->held_root = hit.root; } return; } 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; } 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; bar->draw_fn = gui_editor_toolbar_draw_fn; bar->input_fn = gui_editor_toolbar_input_fn; bar->held = 0; bar->held_root = -1; bar->active_root = -1; snprintf( bar->name, sizeof( bar->name ), "%s", 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 ); }