From 5b24e591eb2f0fff691e26d90cc715ee0ad2f6e2 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Fri, 10 May 2024 04:16:04 -0400 Subject: [PATCH] Fixed issue with ui_signal_from_box Biggest win was getting the intial fixes for overlapping boxes. Eventually I'll need to add support for sorting actives of top-most ancestors (pretty much just remove from linked list and add to last position (adjust indices of adjacent and new top most, etc) --- Readme.md | 6 ++--- code/tick_update.odin | 17 ++++++++++++- code/ui.odin | 11 ++++++++ code/ui_signal.odin | 58 +++++++++++++++++++++++++++++++------------ code/ui_widgets.odin | 1 + toolchain/Odin | 2 +- 6 files changed, 74 insertions(+), 21 deletions(-) diff --git a/Readme.md b/Readme.md index 24f7d18..5eaf510 100644 --- a/Readme.md +++ b/Readme.md @@ -21,8 +21,8 @@ The dependencies are: * Odin repo's base, core, and vendor(raylib) libaries * An ini parser -The client(sectr) module's organization is relatively flat due to the nature of odin's package management not allowing for cyclic dependencies across modules, and modules can only be in one directory. -This makes it difficult to unflatten as the depedency chain must clear with no inter-module collisions, not something organic todo in a prototype... +The client(sectr) module's organization is relatively flat due to the nature of odin's module suste, not allowing for cyclic dependencies across modules, and modules can only be in one directory. +This makes it difficult to unflatten, not something organic todo in a prototype... Even so the notatble groups are: @@ -37,7 +37,7 @@ Even so the notatble groups are: * Parser : AST generation, editing, and serialization. A 1/3 of this prototype will most likely be this alone. * UI : AST visualzation & editing, backend visualization, project organizationa via workspaces (2d cavnases) * Will most likely be the bulk of this prototype. - * PIMGUI (Persistent Immediate Mode User Interface); + * PIMGUI (Persistent Immediate Mode User Interface) * Auto-layout with heavy procedural generation of box widgets There is some unused code in `code/__imgui_raddbg`. Its a partial translation of some data structures from raddbg's ui. diff --git a/code/tick_update.odin b/code/tick_update.odin index 29d8529..5ed5b79 100644 --- a/code/tick_update.odin +++ b/code/tick_update.odin @@ -207,6 +207,7 @@ update :: proc( delta_time : f64 ) -> b32 */ if true { + profile("App Menu Bar") fmt :: str_fmt_alloc @static bar_pos := Vec2{0, 100} @@ -234,7 +235,7 @@ update :: proc( delta_time : f64 ) -> b32 } ui_theme_via_style(theme) - menu_bar = ui_widget("App Menu Bar", {} ) + menu_bar = ui_widget("App Menu Bar", { .Mouse_Clickable} ) menu_bar.text = to_str_runes_pair( fmt("%v", bar_pos)) if (menu_bar.first_frame) { @@ -277,6 +278,15 @@ update :: proc( delta_time : f64 ) -> b32 if move_box.active { bar_pos += input.mouse.delta } + using move_box + hot := ui_box_from_key(ui.curr_cache, ui.hot) + if hot != nil { + text = to_str_runes_pair(str_fmt_tmp("Hot box: %v %v", hot.label.str, hot.hot_delta)) + style.font = default_font + style.font_size = 12 + style.text_color = Color_White + style.text_alignment = {0, 1} + } } move_settings_spacer := ui_widget("Move-Settings Spacer", {}) @@ -315,6 +325,7 @@ update :: proc( delta_time : f64 ) -> b32 @static settings_open := true if settings_btn.pressed || settings_open { + profile("Settings Menu") settings_open = true resize_border_width : f32 = 20 @@ -336,6 +347,10 @@ update :: proc( delta_time : f64 ) -> b32 style.alignment = { 1.0, 0.5 } style.bg_color = Color_BG_Panel_Translucent style.size = range2( size, {}) + text = to_str_runes_pair(str_fmt_tmp("Hot Delta: %v", hot_delta)) + style.font = default_font + style.font_size = 12 + style.text_color = Color_White } ui_parent(settings_menu) diff --git a/code/ui.odin b/code/ui.odin index 52ebab4..f9d9a19 100644 --- a/code/ui.odin +++ b/code/ui.odin @@ -138,6 +138,8 @@ UI_Box :: struct { disabled_delta : f32, style_delta : f32, + parent_index : i32, + // prev_computed : UI_Computed, // prev_style : UI_Style,v // mouse : UI_InteractState, @@ -276,6 +278,7 @@ ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box) if parent != nil { dll_full_push_back( null_box, parent, curr_box ) + curr_box.parent_index = parent.num_children parent.num_children += 1 curr_box.parent = parent } @@ -398,3 +401,11 @@ ui_parent_pop :: proc() { @(deferred_none = ui_parent_pop) ui_parent :: #force_inline proc( ui : ^UI_Box) { ui_parent_push( ui ) } + +// Topmost ancestor that is not the root +ui_top_ancestor :: #force_inline proc "contextless" ( box : ^UI_Box ) -> (^UI_Box) { + using ui := get_state().ui_context + ancestor := box + for ; ancestor.parent != root; ancestor = ancestor.parent {} + return ancestor +} diff --git a/code/ui_signal.odin b/code/ui_signal.odin index 862095a..6587109 100644 --- a/code/ui_signal.odin +++ b/code/ui_signal.odin @@ -1,5 +1,7 @@ package sectr +import "base:runtime" + UI_Signal :: struct { cursor_pos : Vec2, drag_delta : Vec2, @@ -33,6 +35,25 @@ ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal // profile_begin( "Cursor collision") signal.cursor_pos = ui_cursor_pos() signal.cursor_over = cast(b8) pos_within_range2( signal.cursor_pos, box.computed.bounds ) + + // TODO(Ed): We eventually need to setup a sorted root based on last active history + UnderCheck: + { + if ! signal.cursor_over do break UnderCheck + + last_root := ui_box_from_key( ui.prev_cache, ui.root.key ) + if last_root == nil do break UnderCheck + + top_ancestor := ui_top_ancestor(box) + if top_ancestor.parent_index != last_root.num_children - 1 + { + for curr := last_root.last; curr != nil && curr.key != box.key; curr = curr.prev { + if pos_within_range2( signal.cursor_pos, curr.computed.bounds ) && curr.parent_index > top_ancestor.parent_index { + signal.cursor_over = false + } + } + } + } // profile_end() // profile_begin("misc") @@ -42,13 +63,17 @@ ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal mouse_clickable := UI_BoxFlag.Mouse_Clickable in box.flags keyboard_clickable := UI_BoxFlag.Keyboard_Clickable in box.flags - was_hot := ui.hot == box.key && box.hot_delta > 0 - was_active := ui.active == box.key && box.active_delta > 0 + was_hot := (box.hot_delta > 0) + was_active := (ui.active == box.key) && (box.active_delta > 0) was_disabled := box.disabled_delta > 0 + if was_hot { + // runtime.debug_trap() + } - if mouse_clickable && signal.cursor_over && left_pressed + if mouse_clickable && signal.cursor_over && left_pressed && was_hot { - ui.hot = box.key + // runtime.debug_trap() + // ui.hot = box.key ui.active = box.key ui.active_mouse[MouseBtn.Left] = box.key @@ -61,7 +86,7 @@ ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal if mouse_clickable && ! signal.cursor_over && left_released { - box.hot_delta = 0 + box.active_delta = 0 ui.active = UI_Key(0) ui.active_mouse[MouseBtn.Left] = UI_Key(0) @@ -94,15 +119,18 @@ ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal is_disabled := UI_BoxFlag.Disabled in box.flags is_hot := ui.hot == box.key is_active := ui.active == box.key - is_rooted := ui.root == box.parent - if signal.cursor_over && ! is_disabled + if mouse_clickable && signal.cursor_over && ! is_disabled { hot_vacant := ui.hot == UI_Key(0) active_vacant := ui.active == UI_Key(0) // (active_vacant is_active) - if (hot_vacant && signal.cursor_over || is_hot) + if signal.cursor_over { + if ! hot_vacant { + prev := ui_box_from_key( ui.curr_cache, ui.hot ) + prev.hot_delta = 0 + } // prev_hot := zpl_hmap_get( ui.prev_cache, u64(ui.hot) ) // prev_hot_label := prev_hot != nil ? prev_hot.label.str : "" // log( str_fmt_tmp("Detected HOT via CURSOR OVER: %v is_hot: %v is_active: %v prev_hot: %v", box.label.str, is_hot, is_active, prev_hot_label )) @@ -112,16 +140,17 @@ ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal ui.hot_start_style = box.style } } - else + else if ! signal.cursor_over && was_hot { - is_hot = false - if ui.hot == box.key { - ui.hot = UI_Key(0) - } + ui.hot = UI_Key(0) + is_hot = false + box.hot_delta = 0 } if mouse_clickable && signal.cursor_over && left_released { + box.active_delta = 0 + ui.active = UI_Key(0) ui.active_mouse[MouseBtn.Left] = UI_Key(0) @@ -143,9 +172,6 @@ ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal box.style_delta += frame_delta } } - else { - box.hot_delta = 0 - } if is_active { box.active_delta += frame_delta diff --git a/code/ui_widgets.odin b/code/ui_widgets.odin index 4d8cd70..958c0c2 100644 --- a/code/ui_widgets.odin +++ b/code/ui_widgets.odin @@ -107,6 +107,7 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, corner_br := true, corner_bl := true, ) { + profile(#procedure) handle_left : UI_Widget handle_right : UI_Widget handle_top : UI_Widget diff --git a/toolchain/Odin b/toolchain/Odin index 373733f..e1b5ccf 160000 --- a/toolchain/Odin +++ b/toolchain/Odin @@ -1 +1 @@ -Subproject commit 373733fb2b410cd51b4d674b09f5ed9e38677c99 +Subproject commit e1b5ccf2dc07b6218c8d7c2ec3184594d085af89