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)
This commit is contained in:
Edward R. Gonzalez 2024-05-10 04:16:04 -04:00
parent 1afe74b4b5
commit 5b24e591eb
6 changed files with 74 additions and 21 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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
}

View File

@ -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

View File

@ -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

@ -1 +1 @@
Subproject commit 373733fb2b410cd51b4d674b09f5ed9e38677c99
Subproject commit e1b5ccf2dc07b6218c8d7c2ec3184594d085af89