Got centered resize working for the handles

Impl feels jank... but thats what I get for supporting two origins for the auto-layout
This commit is contained in:
Edward R. Gonzalez 2024-05-16 02:14:54 -04:00
parent 85cf9d8db2
commit 7250456db5
6 changed files with 125 additions and 86 deletions

View File

@ -179,7 +179,8 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b
layout.flags = {.Origin_At_Anchor_Center }
layout.pos = {}
}
should_raise |= ui_resizable_handles( & container, & pos, & size)
should_raise |= ui_resizable_handles( & container, & pos, & size/*, compute_layout = true*/)
// ui_box_compute_layout(container)
vbox := ui_vbox_begin( .Top_To_Bottom, "Settings Menu: VBox", {.Mouse_Clickable}, compute_layout = true)
{
@ -198,10 +199,8 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b
ui_style_ref().hot.bg_color = Color_Blue
frame_bar := ui_hbox_begin(.Left_To_Right, "Settings Menu: Frame Bar", { .Mouse_Clickable, .Focusable, .Click_To_Focus })
{
// frame_bar.style.bg_color = Color_BG_Panel
frame_bar.layout.flags = {.Fixed_Height}
frame_bar.layout.size.min.y = 50
// frame_bar.layout.anchor.ratio.y = 0.8
ui_parent(frame_bar)
ui_layout( UI_Layout {
@ -221,8 +220,6 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b
ui_style(ui_style_peek())
style := ui_style_ref()
// style.default.bg_color = Color_Black
// style.hot.bg_color = Color_Frame_Hover
maximize_btn := ui_button("Settings Menu: Maximize Btn")
{
using maximize_btn
@ -237,9 +234,6 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b
if settings_menu.is_maximized do text = str_intern("min")
else do text = str_intern("max")
}
// style.default.bg_color = Color_GreyRed
// style.hot. bg_color = Color_Red
close_btn := ui_button("Settings Menu: Close Btn")
{
using close_btn
@ -274,6 +268,7 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b
// bg_color = Color_GreyRed
})
drop_down_bar := ui_hbox_begin(.Left_To_Right, "settings_menu.vbox: config drop_down_bar", {.Mouse_Clickable})
btn : UI_Widget
{
drop_down_bar.layout.anchor.ratio.y = 0.1
{
@ -289,21 +284,22 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b
}
ui_parent(drop_down_bar)
btn := ui_text("pls", str_intern("Lets figure this out..."))
btn = ui_text("pls", str_intern("Lets figure this out..."))
{
using btn
text = str_intern("Config")
style.font = default_font
style.text_color = Color_White
layout.flags = {.Origin_At_Anchor_Center}
layout.alignment = {0.0, 0.0} // ??? (Wtf is this alignment)
// layout.flags = {.Origin_At_Anchor_Center}
layout.alignment = {0.0, 0.0}
layout.anchor.ratio.x = 1.0
layout.font_size = 12
layout.margins = {0,0, 15, 0}
layout.size.min.y = 35
}
ui_hbox_end(drop_down_bar, compute_layout = false)
ui_box_compute_layout(btn)
um := ui_spacer("um...")
um.layout.anchor.ratio.x = 1.0
ui_hbox_end(drop_down_bar, compute_layout = true)
}
// ui_layout(UI_Layout {
@ -315,15 +311,10 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b
// res_width_hbox := ui_hbox_begin(.Left_To_Right, "settings_menu.vbox: config.resolution_width: hbox", {})
// ui_parent(res_width_hbox)
// ui_layout_ref().default.flags = {.Fixed_Width, .Fixed_Height, .Fixed_Position_Y}
// ui_layout_ref().default.size.min = {50, 50}
spacer := ui_spacer("Settings Menu: Spacer")
spacer.layout.anchor.ratio.y = 1.0
// spacer.layout.flags = {.Origin_At_Anchor_Center}
// spacer.layout.alignment = {0.5, 0.5}
// spacer.style.bg_color = Color_Red
ui_vbox_end(vbox, compute_layout = true )
ui_vbox_end(vbox, compute_layout = false )
}
return
}

View File

@ -1,6 +1,7 @@
package sectr
ui_box_compute_layout :: proc( box : ^UI_Box,
dont_mark_fresh : b32 = false,
ancestors_layout_required : b32 = false,
root_layout_required : b32 = false )
{
@ -43,7 +44,7 @@ ui_box_compute_layout :: proc( box : ^UI_Box,
* Ignore Parent constraints (can only be clipped)
If an axis is auto-sized by a ratio of the other axis
*
* Using the referenced axis, set the size of the ratio'd axis by that ratio.
If auto-sized:
* Enforce parent size constraint of bounds relative to
@ -85,13 +86,6 @@ ui_box_compute_layout :: proc( box : ^UI_Box,
adjusted_size.x = max( adjusted_max_size_x, layout.size.min.x)
adjusted_size.y = max( adjusted_max_size_y, layout.size.min.y)
if .Fixed_Width in layout.flags {
adjusted_size.x = layout.size.min.x
}
if .Fixed_Height in layout.flags {
adjusted_size.y = layout.size.min.y
}
text_size : Vec2
if layout.font_size == computed.text_size.y {
text_size = computed.text_size
@ -104,6 +98,22 @@ ui_box_compute_layout :: proc( box : ^UI_Box,
adjusted_size = text_size
}
if .Size_To_Content in layout.flags {
// Preemtively traverse the children of this parent and have them compute their layout.
// This parent will just set its size to the max bounding area of those children.
// This will recursively occur if child also depends on their content size from their children, etc.
ui_box_compute_layout_children(box)
//ui_compute_children_bounding_area(box)
}
// TODO(Ed): Should this force override all of the previous auto-sizing possible?
if .Fixed_Width in layout.flags {
adjusted_size.x = layout.size.min.x
}
if .Fixed_Height in layout.flags {
adjusted_size.y = layout.size.min.y
}
// 5. Determine relative position
origin_center := margined_bounds_origin
@ -166,18 +176,19 @@ ui_box_compute_layout :: proc( box : ^UI_Box,
content_size := content_bounds.max - content_bounds.min
text_pos : Vec2
text_pos = content_bounds.min + { 0, text_size.y }
text_pos.x += ( content_size.x - text_size.x ) * layout.text_alignment.x
text_pos.y += ( content_size.y - text_size.y ) * layout.text_alignment.y
// text_pos.x += ( content_size.x - text_size.x ) * layout.text_alignment.x
// text_pos.y += ( content_size.y - text_size.y ) * layout.text_alignment.y
text_pos += (content_size - text_size) * layout.text_alignment
computed.text_size = text_size
computed.text_pos = { text_pos.x, text_pos.y }
}
computed.fresh = true
computed.fresh = true && !dont_mark_fresh
}
ui_box_compute_layout_children :: proc( box : ^UI_Box )
{
for current := box.first; current != nil; current = ui_box_tranverse_next( current )
for current := box.first; current != nil && current.prev != box; current = ui_box_tranverse_next( current )
{
if current == box do return
if current.computed.fresh do continue
@ -195,10 +206,10 @@ ui_compute_layout :: proc( ui : ^UI_State )
computed := & root.computed
style := root.style
layout := & root.layout
// if ui == & state.screen_ui {
if ui == & state.screen_ui {
computed.bounds.min = transmute(Vec2) state.app_window.extent * -1
computed.bounds.max = transmute(Vec2) state.app_window.extent
// }
}
computed.content = computed.bounds
}

View File

@ -11,8 +11,8 @@ UI_Signal :: struct {
right_clicked : b8,
double_clicked : b8,
keyboard_clicked : b8,
left_shift : b8,
left_ctrl : b8,
left_shift_held : b8,
left_ctrl_held : b8,
active : b8,
hot : b8,
@ -66,7 +66,7 @@ ui_signal_from_box :: proc ( box : ^ UI_Box, update_style := true, update_deltas
left_pressed := pressed( input.mouse.left )
left_released := released( input.mouse.left )
left_shift := pressed(input.keyboard.left_shift)
signal.left_shift_held = b8(input.keyboard.left_shift.ended_down)
mouse_clickable := UI_BoxFlag.Mouse_Clickable in box.flags
keyboard_clickable := UI_BoxFlag.Keyboard_Clickable in box.flags
@ -74,9 +74,9 @@ ui_signal_from_box :: proc ( box : ^ UI_Box, update_style := true, update_deltas
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 {
// if was_hot {
// runtime.debug_trap()
}
// }
// Check to see if this box is active
if mouse_clickable && signal.cursor_over && left_pressed && was_hot
@ -90,7 +90,6 @@ ui_signal_from_box :: proc ( box : ^ UI_Box, update_style := true, update_deltas
signal.pressed = true
signal.left_clicked = b8(left_pressed)
signal.left_shift = b8(left_shift)
// TODO(Ed) : Support double-click detection
}
@ -102,7 +101,6 @@ ui_signal_from_box :: proc ( box : ^ UI_Box, update_style := true, update_deltas
ui.active_mouse[MouseBtn.Left] = UI_Key(0)
signal.released = true
signal.left_clicked = false
}
if keyboard_clickable

View File

@ -208,7 +208,7 @@ ui_graph_build_begin :: proc( ui : ^ UI_State, bounds : Vec2 = {} )
}
ui.built_box_count = 0
root = ui_box_make( {}, "root#001" )
root = ui_box_make( {}, str_intern(str_fmt_tmp("%s: root#001", ui == & state.screen_ui ? "Screen" : "Workspace" )).str)
if ui == & state.screen_ui {
root.layout.size = range2(Vec2(state.app_window.extent) * 2, {})
}
@ -271,6 +271,10 @@ ui_parent_pop :: proc() {
@(deferred_none = ui_parent_pop)
ui_parent :: #force_inline proc( ui : ^UI_Box) { ui_parent_push( ui ) }
ui_prev_cached_box :: #force_inline proc( box : ^UI_Box ) -> ^UI_Box {
return zpl_hmap_get( ui_context().prev_cache, cast(u64) box.key )
}
// 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

View File

@ -1,5 +1,6 @@
package sectr
import "base:runtime"
import lalg "core:math/linalg"
UI_Widget :: struct {
@ -58,7 +59,7 @@ ui_hbox_begin :: proc( direction : UI_LayoutDirectionX, label : string, flags :
ui_hbox_end :: proc( hbox : UI_HBox, width_ref : ^f32 = nil, compute_layout := true )
{
// profile(#procedure)
if compute_layout do ui_box_compute_layout(hbox.box)
if compute_layout do ui_box_compute_layout(hbox.box, dont_mark_fresh = true)
ui_layout_children_horizontally( hbox.box, hbox.direction, width_ref )
}
@ -148,7 +149,6 @@ ui_resizable_end_auto :: proc() {
}
// Adds resizable handles to a widget
// TODO(Ed): Add centered resize support (use center alignment on shift-click)
ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2,
handle_width : f32 = 15,
theme : ^UI_Theme = nil,
@ -280,12 +280,12 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2,
handle_corner_tr.layout.alignment = {0, -1}
}
if corner_bl {
handle_corner_bl = ui_widget("Settings Menu: Corner BL", flags)
handle_corner_bl = ui_widget("corner_bottom_left", flags)
handle_corner_bl.layout.anchor = range2({}, {0, 1})
handle_corner_bl.layout.alignment = { 1, 0 }
}
if corner_br {
handle_corner_br = ui_widget("Settings Menu: Corner BR", flags)
handle_corner_br = ui_widget("corner_bottom_right", flags)
handle_corner_br.layout.anchor = range2({1, 0}, {0, 1})
handle_corner_br.layout.alignment = {0, 0}
}
@ -293,26 +293,32 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2,
process_handle_drag :: #force_inline proc ( handle : ^UI_Widget,
direction : Vec2,
size_delta : Vec2,
target_alignment : Vec2,
target_center_aligned : Vec2,
pos : ^Vec2,
size : ^Vec2,
alignment : ^Vec2, ) -> b32
{
@static active_context : ^UI_State
@static was_dragging : b32 = false
@static start_size : Vec2
@static active_context : ^UI_State
@static was_dragging : b32 = false
@static start_size : Vec2
@static prev_left_shift_held : b8
@static prev_alignment : Vec2
ui := get_state().ui_context
if ui.last_pressed_key != handle.key do return false
using handle
if ui.last_pressed_key != key || (!active && (!released || !was_dragging)) do return false
direction := direction
target_alignment := target_alignment
align_adjsutment := left_shift_held ? target_center_aligned : target_alignment
size_delta := ui_drag_delta()
pos_adjust := size^ * (alignment^ - target_alignment)
size_delta := ui_drag_delta()
pos_adjust := size^ * (alignment^ - align_adjsutment)
pos_reverse := size^ * (alignment^ - prev_alignment)
shift_changed := (left_shift_held != prev_left_shift_held)
need_to_change_alignment_and_pos := pressed || shift_changed
if active
{
@ -320,16 +326,41 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2,
{
active_context = ui
start_size = size^
if .Origin_At_Anchor_Center in parent.layout.flags {
pos_adjust = size^ * 0.5 * direction
}
prev_left_shift_held = left_shift_held
}
size^ = start_size + size_delta * direction
if pressed {
if (.Origin_At_Anchor_Center in parent.layout.flags) && !left_shift_held {
pos_adjust = size^ * 0.5 * direction
pos_reverse = size^ * 0.5 * direction
}
latest_size := start_size + size_delta * direction
if pressed
{
pos^ -= pos_adjust
}
else {
alignment^ = target_alignment
else if shift_changed
{
if (.Origin_At_Anchor_Center in parent.layout.flags) {
pos^ -= pos_reverse
alignment^ = !left_shift_held ? target_center_aligned : target_alignment
}
else
{
if !left_shift_held {
pos^ -= size^ * direction * 0.5
alignment^ = target_center_aligned
}
else {
pos^ += size^ * direction * 0.5 // Right
alignment^ = target_alignment
}
}
}
else
{
size^ = latest_size
alignment^ = align_adjsutment
}
was_dragging = true
}
@ -338,43 +369,47 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2,
// This needed to be added as for some reason, this was getting called in screen_ui even when we were resizing with a handle in a worksapce
if active_context != ui do return false
if .Origin_At_Anchor_Center in parent.layout.flags {
pos_adjust = size^ * 0.5 * direction
if (.Origin_At_Anchor_Center in parent.layout.flags) && !left_shift_held {
pos_adjust = size^ * 0.5 * direction
pos_reverse = size^ * 0.5 * direction
}
pos^ += pos_adjust
alignment^ = target_alignment
alignment^ = align_adjsutment
was_dragging = false
start_size = 0
active_context = ui
}
// text = active_context.root.label
// style.text_color = Color_White
prev_left_shift_held = handle.left_shift_held
prev_alignment = align_adjsutment
return was_dragging
}
state := get_state()
delta := state.input.mouse.delta //state.ui_context == & state.screen_ui ? state.input.mouse.delta : ui_ws_drag_delta()
state := get_state()
alignment := & parent.layout.alignment
if .Origin_At_Anchor_Center in parent.layout.flags
{
if right do drag_signal |= process_handle_drag( & handle_right, { 1, 0}, delta, { 0.5, 0}, {}, pos, size, alignment )
if left do drag_signal |= process_handle_drag( & handle_left, {-1, 0}, delta, {-0.5, 0}, {}, pos, size, alignment )
if top do drag_signal |= process_handle_drag( & handle_top, { 0, 1}, delta, { 0, 0.5}, {}, pos, size, alignment )
if bottom do drag_signal |= process_handle_drag( & handle_bottom, { 0, -1}, delta, { 0, -0.5}, {}, pos, size, alignment )
if corner_tr do drag_signal |= process_handle_drag( & handle_corner_tr, { 1, 1}, delta, { 0.5, 0.5}, {}, pos, size, alignment )
if corner_tl do drag_signal |= process_handle_drag( & handle_corner_tl, {-1, 1}, delta, {-0.5, 0.5}, {}, pos, size, alignment )
if corner_br do drag_signal |= process_handle_drag( & handle_corner_br, { 1, -1}, delta, { 0.5, -0.5}, {}, pos, size, alignment )
if corner_bl do drag_signal |= process_handle_drag( & handle_corner_bl, {-1, -1}, delta, {-0.5, -0.5}, {}, pos, size, alignment )
if right do drag_signal |= process_handle_drag( & handle_right, { 1, 0}, { 0.5, 0}, {0, 0}, pos, size, alignment )
if left do drag_signal |= process_handle_drag( & handle_left, {-1, 0}, {-0.5, 0}, {0, 0}, pos, size, alignment )
if top do drag_signal |= process_handle_drag( & handle_top, { 0, 1}, { 0, 0.5}, {0, 0}, pos, size, alignment )
if bottom do drag_signal |= process_handle_drag( & handle_bottom, { 0, -1}, { 0, -0.5}, {0, 0}, pos, size, alignment )
if corner_tr do drag_signal |= process_handle_drag( & handle_corner_tr, { 1, 1}, { 0.5, 0.5}, {0, 0}, pos, size, alignment )
if corner_tl do drag_signal |= process_handle_drag( & handle_corner_tl, {-1, 1}, {-0.5, 0.5}, {0, 0}, pos, size, alignment )
if corner_br do drag_signal |= process_handle_drag( & handle_corner_br, { 1, -1}, { 0.5, -0.5}, {0, 0}, pos, size, alignment )
if corner_bl do drag_signal |= process_handle_drag( & handle_corner_bl, {-1, -1}, {-0.5, -0.5}, {0, 0}, pos, size, alignment )
}
else
{
if right do drag_signal |= process_handle_drag( & handle_right, { 1, 0 }, delta, {0, 0}, {}, pos, size, alignment )
if left do drag_signal |= process_handle_drag( & handle_left, { -1, 0 }, delta, {1, 0}, {}, pos, size, alignment )
if top do drag_signal |= process_handle_drag( & handle_top, { 0, 1 }, delta, {0, -1}, {}, pos, size, alignment )
if bottom do drag_signal |= process_handle_drag( & handle_bottom, { 0, -1 }, delta, {0, 0}, {}, pos, size, alignment )
if corner_tr do drag_signal |= process_handle_drag( & handle_corner_tr, { 1, 1 }, delta, {0, -1}, {}, pos, size, alignment )
if corner_tl do drag_signal |= process_handle_drag( & handle_corner_tl, { -1, 1 }, delta, {1, -1}, {}, pos, size, alignment )
if corner_br do drag_signal |= process_handle_drag( & handle_corner_br, { 1, -1 }, delta, {0, 0}, {}, pos, size, alignment )
if corner_bl do drag_signal |= process_handle_drag( & handle_corner_bl, { -1, -1 }, delta, {1, 0}, {}, pos, size, alignment )
if right do drag_signal |= process_handle_drag( & handle_right, { 1, 0 }, {0, 0}, { 0.5, 0}, pos, size, alignment )
if left do drag_signal |= process_handle_drag( & handle_left, { -1, 0 }, {1, 0}, { 0.5, 0}, pos, size, alignment )
if top do drag_signal |= process_handle_drag( & handle_top, { 0, 1 }, {0, -1}, { 0.0, -0.5}, pos, size, alignment )
if bottom do drag_signal |= process_handle_drag( & handle_bottom, { 0, -1 }, {0, 0}, { 0.0, -0.5}, pos, size, alignment )
if corner_tr do drag_signal |= process_handle_drag( & handle_corner_tr, { 1, 1 }, {0, -1}, { 0.5, -0.5}, pos, size, alignment )
if corner_tl do drag_signal |= process_handle_drag( & handle_corner_tl, { -1, 1 }, {1, -1}, { 0.5, -0.5}, pos, size, alignment )
if corner_br do drag_signal |= process_handle_drag( & handle_corner_br, { 1, -1 }, {0, 0}, { 0.5, -0.5}, pos, size, alignment )
if corner_bl do drag_signal |= process_handle_drag( & handle_corner_bl, { -1, -1 }, {1, 0}, { 0.5, -0.5}, pos, size, alignment )
}
if drag_signal && compute_layout do ui_box_compute_layout(parent)
@ -462,14 +497,14 @@ ui_vbox_begin :: proc( direction : UI_LayoutDirectionY, label : string, flags :
vbox.direction = direction
vbox.box = ui_box_make( flags, label )
vbox.signal = ui_signal_from_box( vbox.box )
if compute_layout do ui_box_compute_layout(vbox)
if compute_layout do ui_box_compute_layout(vbox, dont_mark_fresh = true)
return
}
// Auto-layout children
ui_vbox_end :: proc( vbox : UI_VBox, height_ref : ^f32 = nil, compute_layout := true ) {
// profile(#procedure)
if compute_layout do ui_box_compute_layout(vbox)
if compute_layout do ui_box_compute_layout(vbox, dont_mark_fresh = true)
ui_layout_children_vertically( vbox.box, vbox.direction, height_ref )
}

View File

@ -169,8 +169,8 @@ push-location $path_root
# $build_args += $flag_micro_architecture_native
# $build_args += $flag_use_separate_modules
# $build_args += $flag_thread_count + $CoreCount_Physical
# $build_args += $flag_optimize_none
$build_args += $flag_optimize_minimal
$build_args += $flag_optimize_none
# $build_args += $flag_optimize_minimal
# $build_args += $flag_optimize_speed
# $build_args += $falg_optimize_aggressive
$build_args += $flag_debug