#include "editor_gui_internal.h" static U8 editor_contextmenu_item_enabled( const EDITOR_CONTEXTMENU_ITEM* item ) { if( !item ) return 0; if( item->enabled_cb ) return item->enabled_cb( item ); return item->enabled; } static I32 editor_contextmenu_title_h( const GUI_EDITOR_CONTEXTMENU* menu ) { return ( menu && menu->title[0] ) ? 18 : 0; } static I32 editor_contextmenu_row_h() { return 20; } static I32 editor_contextmenu_width( LIST* items, const char* title ) { I32 width = EDITOR_TOOLBAR_DROPDOWN_W; if( title && title[0] ) { I32 text_w = 0; gui_draw_get_str_bounds( &text_w, 0, FNT_JPN12, "%s", title ); width = max( width, text_w + 18 ); } if( !items ) return width; for( I32 i = 0; i < (I32)items->size; ++i ) { I32 text_w = 0; gui_draw_get_str_bounds( &text_w, 0, FNT_JPN12, "%s", ( *items )[i].text ); width = max( width, text_w + 20 ); } return width; } static I32 editor_contextmenu_height( LIST* items, const char* title ) { I32 height = 4 + editor_contextmenu_row_h() * ( items ? (I32)items->size : 0 ); if( title && title[0] ) height += 18 + 1; return max( height, editor_contextmenu_row_h() + 4 ); } static I32 editor_contextmenu_items_y( GUI_EDITOR_CONTEXTMENU* menu ) { I32 y = gui_rely( menu ) + 2; if( menu->title[0] ) y += editor_contextmenu_title_h( menu ) + 1; return y; } static I32 editor_contextmenu_hit_test( GUI_EDITOR_CONTEXTMENU* menu, I32 mx, I32 my ) { if( !menu || !menu->items ) return -1; I32 x = gui_relx( menu ); I32 y = gui_rely( menu ); if( mx < x || mx >= x + menu->w || my < y || my >= y + menu->h ) return -1; I32 items_y = editor_contextmenu_items_y( menu ); if( my < items_y ) return -1; I32 idx = ( my - items_y ) / editor_contextmenu_row_h(); if( idx < 0 || idx >= (I32)menu->items->size ) return -1; return idx; } static void gui_editor_contextmenu_draw_fn( void* ptr ) { GUI_EDITOR_CONTEXTMENU* menu = (GUI_EDITOR_CONTEXTMENU*)ptr; if( !menu || !menu->items || !menu->items->size ) return; I32 x = gui_relx( menu ); I32 y = gui_rely( menu ); 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 ); } I32 hit = editor_contextmenu_hit_test( menu, mx, my ); U8 m1 = gui_mbutton_down( GUI_MBTNLEFT ); 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( menu ) ? ui_clr.border : ui_clr.border_inactive; gui_draw_frect( x, y, menu->w, menu->h, border ); gui_draw_frect( x + 1, y + 1, max( 1, menu->w - 2 ), max( 1, menu->h - 2 ), ui_clr.bg_sec ); I32 cy = y + 2; if( menu->title[0] ) { gui_draw_str( x + 8, cy + 1, ALIGN_L, FNT_JPN12, ui_clr.txt, "%s", menu->title ); cy += editor_contextmenu_title_h( menu ); gui_draw_line( x + 1, cy, x + menu->w - 2, cy, border ); cy += 1; } for( I32 i = 0; i < (I32)menu->items->size; ++i ) { EDITOR_CONTEXTMENU_ITEM* item = &( *menu->items )[i]; U8 enabled = editor_contextmenu_item_enabled( item ); U8 hovered = hit == i; U8 active = menu->held && menu->held_idx == i && m1 && enabled; CLR fill = ui_clr.bg_sec; if( active ) fill = active_fill; else if( hovered ) fill = hover_fill; gui_draw_frect( x + 1, cy + i * editor_contextmenu_row_h(), max( 1, menu->w - 2 ), editor_contextmenu_row_h(), fill ); gui_draw_str( x + 8, cy + i * editor_contextmenu_row_h() + 2, ALIGN_L, FNT_JPN12, enabled ? ui_clr.txt : ui_clr.txt_inactive, "%s", item->text ); } } static void gui_editor_contextmenu_input_fn( void* ptr ) { GUI_EDITOR_CONTEXTMENU* menu = (GUI_EDITOR_CONTEXTMENU*)ptr; if( !menu || !menu->items || !menu->items->size ) return; U8 m1 = gui_mbutton_down( GUI_MBTNLEFT ); U8 m2 = gui_mbutton_down( GUI_MBTNRIGHT ); if( menu->initheld ) { if( m1 || m2 ) return; menu->initheld = 0; return; } I32 mx = 0, my = 0; gui_cursor_pos( &mx, &my ); I32 hit = editor_contextmenu_hit_test( menu, mx, my ); if( m1 || m2 ) { if( !menu->held ) { menu->held = 1; menu->held_idx = hit; } return; } if( !menu->held ) return; if( hit == -1 ) { editor_hide_contextmenu(); return; } if( hit == menu->held_idx ) { EDITOR_CONTEXTMENU_ITEM* item = &( *menu->items )[hit]; if( editor_contextmenu_item_enabled( item ) && item->cb ) { item->cb( item->data ); editor_hide_contextmenu(); return; } } menu->held = 0; menu->held_idx = -1; } void editor_hide_contextmenu() { if( !editor || !editor->gui.contextmenu ) return; GUI_EDITOR_CONTEXTMENU* menu = editor->gui.contextmenu; editor->gui.contextmenu = 0; if( menu->parent ) { I32 idx = menu->parent->children.idx_of( (GUI_BASE*)menu ); if( idx != -1 ) menu->parent->children.erase( idx ); } GUI_EDITOR_TOOLBAR* bar = (GUI_EDITOR_TOOLBAR*)editor->gui.header_toolbar; if( bar ) bar->active_root = -1; gui_free( menu ); } U8 editor_contextmenu_open() { return editor && editor->gui.contextmenu && editor->gui.contextmenu->enabled; } void editor_show_contextmenu( I32 x, I32 y, LIST* items, const char* title ) { editor_hide_contextmenu(); if( !editor || !editor->wnd || !items || !items->size ) return; GUI_EDITOR_CONTEXTMENU* menu = new GUI_EDITOR_CONTEXTMENU; menu->items = items; menu->draw_fn = gui_editor_contextmenu_draw_fn; menu->input_fn = gui_editor_contextmenu_input_fn; menu->enabled = 1; menu->initheld = 1; menu->held = 0; menu->held_idx = -1; menu->parent = editor->wnd; snprintf( menu->name, sizeof( menu->name ), "EDITOR_CONTEXTMENU" ); snprintf( menu->title, sizeof( menu->title ), "%s", title ? title : "" ); menu->w = editor_contextmenu_width( items, title ); menu->h = editor_contextmenu_height( items, title ); menu->xbound = menu->w; menu->ybound = menu->h; if( x + menu->w > editor->wnd->w - 2 ) x = max( 1, editor->wnd->w - menu->w - 2 ); if( y + menu->h > editor->wnd->h - 2 ) y = max( 1, editor->wnd->h - menu->h - 2 ); if( x < 1 ) x = 1; if( y < 1 ) y = 1; menu->x = x; menu->y = y; editor->wnd->children.push( menu ); editor->gui.contextmenu = menu; }