From 2973df584978d9aae6f164ce0204179c8a28b3ae Mon Sep 17 00:00:00 2001 From: 2lag <96544487+2lag@users.noreply.github.com> Date: Sat, 8 Aug 2026 17:33:36 +0200 Subject: console, textbox changes, some other shit --- src/gui/contextmenu.cpp | 437 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 437 insertions(+) create mode 100644 src/gui/contextmenu.cpp (limited to 'src/gui/contextmenu.cpp') diff --git a/src/gui/contextmenu.cpp b/src/gui/contextmenu.cpp new file mode 100644 index 0000000..73cbafd --- /dev/null +++ b/src/gui/contextmenu.cpp @@ -0,0 +1,437 @@ +#include "base.h" + +U8 gui_contextmenu_item_enabled( GUI_CONTEXTMENU_ITEM* item ) { + if( !item ) + return 0; + + if( item->enabled_cb ) + return item->enabled_cb( item ); + + return item->enabled; +} + +I32 gui_contextmenu_title_h( GUI_CONTEXTMENU* menu ) { + return ( menu && menu->title[0] ) ? 18 : 0; +} + +I32 gui_contextmenu_row_h() { + return 20; +} + +I32 gui_contextmenu_width( LIST* items, const char* title ) { + I32 width = 0; + 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; +} + +I32 gui_contextmenu_height( I32 rows, const char* title ) { + I32 height = 4 + gui_contextmenu_row_h() * rows; + if( title && title[0] ) + height += 18 + 1; + return max( height, gui_contextmenu_row_h() + 4 ); +} + +static I32 gui_contextmenu_items_y( GUI_CONTEXTMENU* menu ) { + if( !menu ) + return 0; + I32 y = gui_rely( menu ) + 2; + if( menu->title[0] ) + y += gui_contextmenu_title_h( menu ) + 1; + return y; +} + +I32 gui_contextmenu_hit_test( GUI_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 = gui_contextmenu_items_y( menu ); + if( my < items_y ) + return -1; + + I32 row = ( my - items_y ) / gui_contextmenu_row_h(); + if( row < 0 || row >= menu->visible_rows ) + return -1; + + I32 idx = menu->first_visible + row; + if( idx < 0 || idx >= (I32)menu->items->size ) + return -1; + + return idx; +} + +static I32 gui_contextmenu_draw_frame( + GUI_CONTEXTMENU* menu, + I32 x, I32 y, + CLR border +) { + 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 item_y = y + 2; + + if( menu->title[0] ) { + gui_draw_str( + x + 8, item_y + 1, + ALIGN_L, FNT_JPN12, + ui_clr.txt, + "%s", menu->title + ); + item_y += gui_contextmenu_title_h( menu ); + gui_draw_line( + x + 1, item_y, + x + menu->w - 2, item_y, + border + ); + ++item_y; + } + return item_y; +} + +static void gui_contextmenu_draw_rows( + GUI_CONTEXTMENU* menu, + I32 x, I32 y, + I32 hit, + U8 left_down +) { + I32 item_count = (I32)menu->items->size; + I32 first = m_clamp( + menu->first_visible, + 0, item_count + ); + I32 rows = min( + menu->visible_rows, + item_count - first + ); + + CLR hover = CLR::blend( ui_clr.border, ui_clr.bg, 0.7f ); + CLR active = CLR::blend( ui_clr.bg_sec, ui_clr.border, 0.22f ); + + gui_draw_push_clip( + x + 1, y, + max( 0, menu->w - 2 ), + max( 0, rows * gui_contextmenu_row_h() ) + ); + + for( I32 row = 0; row < rows; ++row ) { + I32 idx = first + row; + GUI_CONTEXTMENU_ITEM* item = &( *menu->items )[idx]; + U8 enabled = gui_contextmenu_item_enabled( item ); + U8 pressed = menu->held + && menu->held_idx == idx + && left_down + && enabled; + CLR fill = pressed + ? active + : ( hit == idx || menu->selected_idx == idx ) + ? hover + : ui_clr.bg_sec; + I32 row_y = y + row * gui_contextmenu_row_h(); + + gui_draw_frect( + x + 1, row_y, + max( 1, menu->w - 2 ), + gui_contextmenu_row_h(), + fill + ); + gui_draw_str( + x + 8, row_y + 2, + ALIGN_L, FNT_JPN12, + enabled ? ui_clr.txt : ui_clr.txt_inactive, + "%s", item->text + ); + } + gui_draw_pop_clip(); +} + +void gui_contextmenu_draw_fn( void* ptr ) { + GUI_CONTEXTMENU* menu = (GUI_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; + gui_cursor_pos( &mx, &my ); + + CLR border = gui_is_fg_window( menu ) + ? ui_clr.border + : ui_clr.border_inactive; + + I32 item_y = gui_contextmenu_draw_frame( + menu, + x, y, + border + ); + + gui_contextmenu_draw_rows( + menu, x, item_y, + gui_contextmenu_hit_test( menu, mx, my ), + gui_mbutton_down( GUI_MBTNLEFT ) + ); +} + +void gui_contextmenu_input_fn( void* ptr ) { + GUI_CONTEXTMENU* menu = (GUI_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 = gui_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 ) { + gui_hide_contextmenu( menu ); + return; + } + + if( hit == menu->held_idx ) { + GUI_CONTEXTMENU_ITEM* item = &( *menu->items )[hit]; + if( gui_contextmenu_item_enabled( item ) && item->cb ) { + menu->selected_idx = hit; + + GUI_BASE* parent = menu->parent; + item->cb( item->data ); + + if( parent + && parent->children.idx_of( (GUI_BASE*)menu ) != -1 + ) gui_hide_contextmenu( menu ); + return; + } + } + + menu->held = 0; + menu->held_idx = -1; +} + +void gui_hide_contextmenu( GUI_CONTEXTMENU* menu ) { + if( !menu ) + return; + + if( menu->owner_ref && *menu->owner_ref == menu ) + *menu->owner_ref = 0; + + if( menu->parent ) { + I32 idx = menu->parent->children.idx_of( (GUI_BASE*)menu ); + if( idx != -1 ) + menu->parent->children.erase( idx ); + } + + gui_free( menu ); +} + +U8 gui_contextmenu_open( GUI_CONTEXTMENU *menu ) { + return !menu ? 0 : menu->enabled; +} + +void gui_contextmenu_set_item( + GUI_CONTEXTMENU_ITEM* item, + const char* text, + GUI_CONTEXTMENU_CALLBACK cb, + void* data, + GUI_CONTEXTMENU_ENABLED_CALLBACK enabled_cb +) { + 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; +} + +GUI_CONTEXTMENU_ITEM* gui_contextmenu_selected( GUI_CONTEXTMENU* menu ) { + if( !menu || !menu->items ) + return 0; + + if( menu->selected_idx < 0 || menu->selected_idx >= (I32)menu->items->size ) + return 0; + + return &( *menu->items )[menu->selected_idx]; +} + +static I32 gui_contextmenu_next_enabled( + GUI_CONTEXTMENU* menu, + I32 delta, + U8 wrap +) { + I32 item_count = (I32)menu->items->size; + I32 direction = delta < 0 ? -1 : 1; + I32 candidate = menu->selected_idx; + U8 has_candidate = candidate >= 0 + && candidate < item_count; + for( I32 scanned = 0; scanned < item_count; ++scanned ) { + if( !has_candidate ) { + candidate = direction < 0 + ? item_count - 1 + : 0; + has_candidate = 1; + } + else { + candidate += direction; + + if( candidate < 0 || candidate >= item_count ) { + if( !wrap ) + return -1; + + candidate = direction < 0 + ? item_count - 1 + : 0; + } + } + + if( gui_contextmenu_item_enabled( + &( *menu->items )[candidate] + ) ) return candidate; + } + return -1; +} + +void gui_contextmenu_reveal_selection( + GUI_CONTEXTMENU* menu +) { + if( !menu || !menu->items || menu->visible_rows <= 0 ) + return; + + I32 selected = menu->selected_idx; + + if( selected < 0 || selected >= (I32)menu->items->size ) + return; + + if( selected < menu->first_visible ) + menu->first_visible = selected; + else if( selected >= menu->first_visible + menu->visible_rows ) + menu->first_visible = selected - menu->visible_rows + 1; + + I32 max_first = max( 0, + (I32)menu->items->size - menu->visible_rows + ); + + menu->first_visible = m_clamp( + menu->first_visible, + 0, max_first + ); +} + +void gui_contextmenu_move_selection( + GUI_CONTEXTMENU* menu, + I32 delta, + U8 wrap +) { + if( !menu || !menu->items || !menu->items->size || !delta ) + return; + + I32 selected = gui_contextmenu_next_enabled( + menu, + delta, + wrap + ); + + if( selected < 0 ) + return; + + menu->selected_idx = selected; + gui_contextmenu_reveal_selection( menu ); +} + +GUI_CONTEXTMENU* gui_show_contextmenu( + I32 x, I32 y, + LIST* items, + GUI_BASE* parent, + const char* title, + I32 max_visible_rows, + GUI_CONTEXTMENU** owner_ref +) { + if( !parent || !items || !items->size ) + return 0; + + GUI_WINDOW* owner_window = gui_get_parent_wnd( parent ); + if( !owner_window ) + return 0; + + if( owner_ref && *owner_ref ) + gui_hide_contextmenu( *owner_ref ); + + GUI_CONTEXTMENU* menu = new GUI_CONTEXTMENU; + menu->items = items; + menu->draw_fn = gui_contextmenu_draw_fn; + menu->input_fn = gui_contextmenu_input_fn; + menu->enabled = 1; + menu->initheld = 1; + menu->held = 0; + menu->held_idx = -1; + menu->selected_idx = -1; + menu->parent = owner_window; + menu->owner_ref = owner_ref; + I32 item_count = (I32)items->size; + menu->max_visible_rows = max_visible_rows > 0 + ? min( max_visible_rows, item_count ) + : item_count; + menu->visible_rows = menu->max_visible_rows; + menu->first_visible = max( 0, + item_count - menu->visible_rows + ); + + snprintf( menu->name, sizeof( menu->name ), "GUI_CONTEXTMENU" ); + snprintf( menu->title, sizeof( menu->title ), "%s", title ? title : "" ); + + menu->w = gui_contextmenu_width( items, title ); + menu->h = gui_contextmenu_height( menu->visible_rows, title ); + menu->xbound = menu->w; + menu->ybound = menu->h; + + menu->x = x - gui_relx( owner_window ); + menu->y = y - gui_rely( owner_window ); + owner_window->children.push( menu ); + + if( owner_ref ) + *owner_ref = menu; + + return menu; +} -- cgit v1.2.3 From 02f118d025a75f60b33cfee6bd8cd8d45ece2c07 Mon Sep 17 00:00:00 2001 From: 2lag <96544487+2lag@users.noreply.github.com> Date: Mon, 10 Aug 2026 19:35:23 +0200 Subject: fix the gay --- src/gui/contextmenu.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'src/gui/contextmenu.cpp') diff --git a/src/gui/contextmenu.cpp b/src/gui/contextmenu.cpp index 73cbafd..0775651 100644 --- a/src/gui/contextmenu.cpp +++ b/src/gui/contextmenu.cpp @@ -119,11 +119,11 @@ static void gui_contextmenu_draw_rows( U8 left_down ) { I32 item_count = (I32)menu->items->size; - I32 first = m_clamp( + I32 first = m_clamp( menu->first_visible, 0, item_count ); - I32 rows = min( + I32 rows = min( menu->visible_rows, item_count - first ); @@ -133,8 +133,8 @@ static void gui_contextmenu_draw_rows( gui_draw_push_clip( x + 1, y, - max( 0, menu->w - 2 ), - max( 0, rows * gui_contextmenu_row_h() ) + max( 0, menu->w - 2 ), + max( 0, rows * gui_contextmenu_row_h() ) ); for( I32 row = 0; row < rows; ++row ) { @@ -154,7 +154,7 @@ static void gui_contextmenu_draw_rows( gui_draw_frect( x + 1, row_y, - max( 1, menu->w - 2 ), + max( 1, menu->w - 2 ), gui_contextmenu_row_h(), fill ); @@ -225,7 +225,7 @@ void gui_contextmenu_input_fn( void* ptr ) { return; if( hit == -1 ) { - gui_hide_contextmenu( menu ); + gui_contextmenu_hide( menu ); return; } @@ -239,7 +239,7 @@ void gui_contextmenu_input_fn( void* ptr ) { if( parent && parent->children.idx_of( (GUI_BASE*)menu ) != -1 - ) gui_hide_contextmenu( menu ); + ) gui_contextmenu_hide( menu ); return; } } @@ -248,7 +248,7 @@ void gui_contextmenu_input_fn( void* ptr ) { menu->held_idx = -1; } -void gui_hide_contextmenu( GUI_CONTEXTMENU* menu ) { +void gui_contextmenu_hide( GUI_CONTEXTMENU* menu ) { if( !menu ) return; @@ -349,11 +349,11 @@ void gui_contextmenu_reveal_selection( else if( selected >= menu->first_visible + menu->visible_rows ) menu->first_visible = selected - menu->visible_rows + 1; - I32 max_first = max( 0, + I32 max_first = max( 0, (I32)menu->items->size - menu->visible_rows ); - menu->first_visible = m_clamp( + menu->first_visible = m_clamp( menu->first_visible, 0, max_first ); @@ -396,7 +396,7 @@ GUI_CONTEXTMENU* gui_show_contextmenu( return 0; if( owner_ref && *owner_ref ) - gui_hide_contextmenu( *owner_ref ); + gui_contextmenu_hide( *owner_ref ); GUI_CONTEXTMENU* menu = new GUI_CONTEXTMENU; menu->items = items; @@ -411,10 +411,10 @@ GUI_CONTEXTMENU* gui_show_contextmenu( menu->owner_ref = owner_ref; I32 item_count = (I32)items->size; menu->max_visible_rows = max_visible_rows > 0 - ? min( max_visible_rows, item_count ) + ? min( max_visible_rows, item_count ) : item_count; menu->visible_rows = menu->max_visible_rows; - menu->first_visible = max( 0, + menu->first_visible = max( 0, item_count - menu->visible_rows ); -- cgit v1.2.3