Improvements to UI signal
This commit is contained in:
parent
4b026c379a
commit
cb58f4faef
@ -252,9 +252,14 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
}
|
||||
}
|
||||
|
||||
config.ui_resize_border_width = 50
|
||||
config.ui_resize_border_width = 10
|
||||
when Test_Draggable
|
||||
{
|
||||
// draggable_box_layout := default_layout
|
||||
// draggable_box_layout.pos = debug.draggable_box_pos
|
||||
// draggable_box_layout.size = debug.draggable_box_size
|
||||
// ui_set_layout(draggable_box_layout)
|
||||
|
||||
draggable_flags := UI_BoxFlags { .Mouse_Clickable, .Focusable, .Click_To_Focus }
|
||||
draggable_box := ui_box_make( draggable_flags, "Draggable Box!" )
|
||||
signal := ui_signal_from_box( draggable_box )
|
||||
@ -272,25 +277,22 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
// Resize
|
||||
if signal.resizing
|
||||
{
|
||||
if ! debug.box_resize_started {
|
||||
if signal.pressed {
|
||||
debug.box_original_size = debug.draggable_box_size
|
||||
}
|
||||
center := debug.draggable_box_pos
|
||||
original_distance := linalg.distance(ui_context.cursor_active_start, center)
|
||||
cursor_distance := linalg.distance(signal.cursor_pos, center)
|
||||
|
||||
scale_factor := cursor_distance * (1 / original_distance)
|
||||
scale_factor := cursor_distance * (1 / original_distance)
|
||||
|
||||
debug.draggable_box_size = debug.box_original_size * scale_factor
|
||||
}
|
||||
debug.box_resize_started = cast(b32) signal.resizing
|
||||
|
||||
if workspace.ui.hot_resizable || workspace.ui.active_resizing {
|
||||
draggable_box.style.bg_color = Color_Blue
|
||||
}
|
||||
|
||||
// Note(Ed): Don't necessarily need a layout if its simple...
|
||||
draggable_box.style.pos = debug.draggable_box_pos
|
||||
draggable_box.style.layout.pos = debug.draggable_box_pos
|
||||
draggable_box.style.layout.size = debug.draggable_box_size
|
||||
}
|
||||
}
|
||||
|
165
code/ui.odin
165
code/ui.odin
@ -232,17 +232,18 @@ UI_Box :: struct {
|
||||
parent : ^UI_Box,
|
||||
num_children : i32,
|
||||
|
||||
flags : UI_BoxFlags,
|
||||
computed : UI_Computed,
|
||||
theme : UI_StyleTheme,
|
||||
|
||||
style : ^UI_Style,
|
||||
flags : UI_BoxFlags,
|
||||
computed : UI_Computed,
|
||||
prev_style : UI_Style,
|
||||
style : UI_Style,
|
||||
|
||||
// Persistent Data
|
||||
first_frame : b8,
|
||||
hot_delta : f32,
|
||||
active_delta : f32,
|
||||
style_delta : f32,
|
||||
first_frame : b8,
|
||||
hot_delta : f32,
|
||||
active_delta : f32,
|
||||
disabled_delta : f32,
|
||||
style_delta : f32,
|
||||
|
||||
// prev_computed : UI_Computed,
|
||||
// prev_style : UI_Style,v
|
||||
mouse : UI_InteractState,
|
||||
@ -286,10 +287,10 @@ UI_State :: struct {
|
||||
clipboard_copy : UI_Key,
|
||||
last_clicked : UI_Key,
|
||||
|
||||
cursor_active_start : Vec2,
|
||||
// cursor_resize_start : Vec2,
|
||||
// drag_state_arena : ^ Arena,
|
||||
// drag_state data : string,
|
||||
cursor_active_start : Vec2,
|
||||
|
||||
hot_start_style : UI_Style,
|
||||
active_start_style : UI_Style,
|
||||
|
||||
last_pressed_key : [MouseBtn.count] UI_Key,
|
||||
last_pressed_key_us : [MouseBtn.count] f32,
|
||||
@ -360,16 +361,7 @@ ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box)
|
||||
curr_box.first_frame = prev_box == nil
|
||||
}
|
||||
|
||||
// TODO(Ed) : Review this when we learn layouts more...
|
||||
if prev_box != nil {
|
||||
layout_dirty &= ! ui_box_equal( curr_box, prev_box )
|
||||
}
|
||||
else {
|
||||
layout_dirty = true
|
||||
}
|
||||
|
||||
curr_box.flags = flags
|
||||
curr_box.theme = stack_peek( & theme_stack )
|
||||
curr_box.parent = stack_peek( & parent_stack )
|
||||
|
||||
// Clear old links
|
||||
@ -434,7 +426,6 @@ ui_graph_build_begin :: proc( ui : ^ UI_State, bounds : Vec2 = {} )
|
||||
}
|
||||
|
||||
root = ui_box_make( {}, "root#001" )
|
||||
root.style = & root.theme.default
|
||||
ui_parent_push(root)
|
||||
}
|
||||
|
||||
@ -478,134 +469,6 @@ ui_parent :: proc( ui : ^ UI_Box) {
|
||||
ui_parent_push( ui )
|
||||
}
|
||||
|
||||
ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal
|
||||
{
|
||||
ui := get_state().ui_context
|
||||
input := get_state().input
|
||||
|
||||
frame_delta := frametime_delta32()
|
||||
|
||||
signal := UI_Signal { box = box }
|
||||
|
||||
// Cursor Collision
|
||||
signal.cursor_pos = ui_cursor_pos()
|
||||
signal.cursor_over = cast(b8) pos_within_range2( signal.cursor_pos, box.computed.bounds )
|
||||
|
||||
resize_border_width := cast(f32) get_state().config.ui_resize_border_width
|
||||
resize_border_non_range := add(box.computed.bounds, range2(
|
||||
{ resize_border_width, -resize_border_width },
|
||||
{ -resize_border_width, resize_border_width }))
|
||||
|
||||
within_resize_range := cast(b8) ! pos_within_range2( signal.cursor_pos, resize_border_non_range )
|
||||
within_resize_range &= signal.cursor_over
|
||||
|
||||
left_pressed := pressed( input.mouse.left )
|
||||
left_released := released( input.mouse.left )
|
||||
|
||||
mouse_clickable := UI_BoxFlag.Mouse_Clickable in box.flags
|
||||
keyboard_clickable := UI_BoxFlag.Keyboard_Clickable in box.flags
|
||||
|
||||
if mouse_clickable && signal.cursor_over && left_pressed
|
||||
{
|
||||
ui.hot = box.key
|
||||
ui.active = box.key
|
||||
ui.active_mouse[MouseBtn.Left] = box.key
|
||||
ui.cursor_active_start = signal.cursor_pos
|
||||
ui.last_pressed_key = box.key
|
||||
|
||||
signal.pressed = true
|
||||
// TODO(Ed) : Support double-click detection
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
signal.released = true
|
||||
signal.left_clicked = true
|
||||
|
||||
ui.last_clicked = box.key
|
||||
}
|
||||
|
||||
if mouse_clickable && ! signal.cursor_over && left_released
|
||||
{
|
||||
box.hot_delta = 0
|
||||
|
||||
ui.hot = UI_Key(0)
|
||||
ui.active = UI_Key(0)
|
||||
ui.active_mouse[MouseBtn.Left] = UI_Key(0)
|
||||
|
||||
signal.released = true
|
||||
signal.left_clicked = false
|
||||
}
|
||||
|
||||
if keyboard_clickable
|
||||
{
|
||||
// TODO(Ed) : Add keyboard interaction support
|
||||
}
|
||||
|
||||
// TODO(Ed) : Add scrolling support
|
||||
if UI_BoxFlag.Scroll_X in box.flags {
|
||||
|
||||
}
|
||||
if UI_BoxFlag.Scroll_Y in box.flags {
|
||||
|
||||
}
|
||||
// TODO(Ed) : Add panning support
|
||||
if UI_BoxFlag.Pan_X in box.flags {
|
||||
|
||||
}
|
||||
if UI_BoxFlag.Pan_Y in box.flags {
|
||||
|
||||
}
|
||||
|
||||
is_hot := ui.hot == box.key
|
||||
is_active := ui.active == box.key
|
||||
|
||||
if signal.cursor_over &&
|
||||
ui.hot == UI_Key(0) || is_hot &&
|
||||
ui.active == UI_Key(0) || is_active
|
||||
{
|
||||
ui.hot = box.key
|
||||
is_hot = true
|
||||
}
|
||||
|
||||
if ! is_active {
|
||||
ui.hot_resizable = cast(b32) within_resize_range
|
||||
}
|
||||
signal.resizing = cast(b8) is_active && (within_resize_range || ui.active_resizing)
|
||||
|
||||
if is_hot {
|
||||
box.hot_delta += frame_delta
|
||||
}
|
||||
if is_active {
|
||||
box.active_delta += frame_delta
|
||||
}
|
||||
ui.active_resizing = cast(b32) is_active && signal.resizing
|
||||
|
||||
signal.dragging = cast(b8) is_active && ( ! within_resize_range && ! ui.active_resizing)
|
||||
|
||||
style_preset := UI_StylePreset.Default
|
||||
// box.style = stack_peek( & ui.them_stack ).default
|
||||
if box.key == ui.hot {
|
||||
style_preset = UI_StylePreset.Hovered
|
||||
// box.stye = stack_peek( & ui.theme_stack ).hovered
|
||||
}
|
||||
if box.key == ui.active {
|
||||
style_preset = UI_StylePreset.Focused
|
||||
// box.stye = stack_peek( & ui.theme_stack ).focused
|
||||
}
|
||||
if UI_BoxFlag.Disabled in box.flags {
|
||||
style_preset = UI_StylePreset.Disabled
|
||||
// box.style = stack_peek( & ui.theme.stack ).disabled
|
||||
}
|
||||
box.style = & box.theme.array[style_preset]
|
||||
|
||||
return signal
|
||||
}
|
||||
|
||||
ui_style_ref :: proc( box_state : UI_StylePreset ) -> (^ UI_Style) {
|
||||
return & stack_peek_ref( & get_state().ui_context.theme_stack ).array[box_state]
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
package sectr
|
||||
|
||||
when false {
|
||||
ui_box_cache_insert :: proc( using cache : HMap_RJF( ^ UI_Box ), key : u64, value : ^ UI_Box ) -> ^ UI_Box {
|
||||
slot := rjf_hmap_get_slot( cache, key )
|
||||
|
||||
// dll_insert_raw( nil, slot.first, slot.last, slot.last, value )
|
||||
{
|
||||
new_links := & new.hash_links
|
||||
|
||||
// Empty Case
|
||||
if first == null {
|
||||
first = new
|
||||
last = new
|
||||
new_links.next = null
|
||||
new_links.prev = null
|
||||
}
|
||||
else if position == null {
|
||||
// Position is not set, insert at beginning
|
||||
new_links.next = first
|
||||
first.first = new
|
||||
first = new
|
||||
new_links.prev = null
|
||||
}
|
||||
else if position == last {
|
||||
// Positin is set to last, insert at end
|
||||
last.last = new
|
||||
new_links.prev = last
|
||||
last = new
|
||||
new_links.next = null
|
||||
}
|
||||
else {
|
||||
// Insert around position
|
||||
if position.next != null {
|
||||
position.next.prev = new
|
||||
}
|
||||
new.next = position.next
|
||||
position.next = new
|
||||
new.prev = position
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
184
code/ui_signal.odin
Normal file
184
code/ui_signal.odin
Normal file
@ -0,0 +1,184 @@
|
||||
package sectr
|
||||
|
||||
ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal
|
||||
{
|
||||
ui := get_state().ui_context
|
||||
input := get_state().input
|
||||
|
||||
frame_delta := frametime_delta32()
|
||||
|
||||
signal := UI_Signal { box = box }
|
||||
|
||||
// Cursor Collision
|
||||
signal.cursor_pos = ui_cursor_pos()
|
||||
signal.cursor_over = cast(b8) pos_within_range2( signal.cursor_pos, box.computed.bounds )
|
||||
|
||||
resize_border_width := cast(f32) get_state().config.ui_resize_border_width
|
||||
resize_border_non_range := add(box.computed.bounds, range2(
|
||||
{ resize_border_width, -resize_border_width },
|
||||
{ -resize_border_width, resize_border_width }))
|
||||
|
||||
within_resize_range := cast(b8) ! pos_within_range2( signal.cursor_pos, resize_border_non_range )
|
||||
within_resize_range &= signal.cursor_over
|
||||
|
||||
left_pressed := pressed( input.mouse.left )
|
||||
left_released := released( input.mouse.left )
|
||||
|
||||
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_disabled := box.disabled_delta > 0
|
||||
|
||||
if mouse_clickable && signal.cursor_over && left_pressed
|
||||
{
|
||||
ui.hot = box.key
|
||||
ui.active = box.key
|
||||
ui.active_mouse[MouseBtn.Left] = box.key
|
||||
ui.last_pressed_key = box.key
|
||||
|
||||
ui.cursor_active_start = signal.cursor_pos
|
||||
|
||||
signal.pressed = true
|
||||
// TODO(Ed) : Support double-click detection
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
signal.released = true
|
||||
signal.left_clicked = true
|
||||
|
||||
ui.last_clicked = box.key
|
||||
}
|
||||
|
||||
if mouse_clickable && ! signal.cursor_over && left_released
|
||||
{
|
||||
box.hot_delta = 0
|
||||
|
||||
ui.hot = UI_Key(0)
|
||||
ui.active = UI_Key(0)
|
||||
ui.active_mouse[MouseBtn.Left] = UI_Key(0)
|
||||
|
||||
signal.released = true
|
||||
signal.left_clicked = false
|
||||
}
|
||||
|
||||
if keyboard_clickable
|
||||
{
|
||||
// TODO(Ed) : Add keyboard interaction support
|
||||
}
|
||||
|
||||
// TODO(Ed) : Add scrolling support
|
||||
if UI_BoxFlag.Scroll_X in box.flags {
|
||||
|
||||
}
|
||||
if UI_BoxFlag.Scroll_Y in box.flags {
|
||||
|
||||
}
|
||||
|
||||
// TODO(Ed) : Add panning support
|
||||
if UI_BoxFlag.Pan_X in box.flags {
|
||||
|
||||
}
|
||||
if UI_BoxFlag.Pan_Y in box.flags {
|
||||
|
||||
}
|
||||
|
||||
is_disabled := UI_BoxFlag.Disabled in box.flags
|
||||
is_hot := ui.hot == box.key
|
||||
is_active := ui.active == box.key
|
||||
|
||||
if signal.cursor_over &&
|
||||
ui.hot == UI_Key(0) || is_hot &&
|
||||
ui.active == UI_Key(0) || is_active
|
||||
{
|
||||
ui.hot = box.key
|
||||
is_hot = true
|
||||
}
|
||||
|
||||
if ! is_active {
|
||||
ui.hot_resizable = cast(b32) within_resize_range
|
||||
}
|
||||
signal.resizing = cast(b8) is_active && (within_resize_range || ui.active_resizing)
|
||||
|
||||
// State Deltas update
|
||||
if is_hot
|
||||
{
|
||||
box.hot_delta += frame_delta
|
||||
if was_hot {
|
||||
box.style_delta += frame_delta
|
||||
}
|
||||
}
|
||||
else {
|
||||
box.hot_delta = 0
|
||||
}
|
||||
if is_active
|
||||
{
|
||||
box.active_delta += frame_delta
|
||||
if was_active {
|
||||
box.style_delta += frame_delta
|
||||
}
|
||||
}
|
||||
else {
|
||||
box.active_delta = 0
|
||||
}
|
||||
if is_disabled
|
||||
{
|
||||
box.disabled_delta += frame_delta
|
||||
if was_hot {
|
||||
box.style_delta += frame_delta
|
||||
}
|
||||
}
|
||||
else {
|
||||
box.disabled_delta = 0
|
||||
}
|
||||
|
||||
ui.active_resizing = cast(b32) is_active && signal.resizing
|
||||
signal.dragging = cast(b8) is_active && ( ! within_resize_range && ! ui.active_resizing)
|
||||
|
||||
// Update style if not in default state
|
||||
{
|
||||
if is_hot
|
||||
{
|
||||
if ! was_hot {
|
||||
box.prev_style = box.style
|
||||
box.style_delta = 0
|
||||
}
|
||||
box.style = stack_peek( & ui.theme_stack ).hovered
|
||||
}
|
||||
if is_active
|
||||
{
|
||||
if ! was_active {
|
||||
box.prev_style = box.style
|
||||
box.style_delta = 0
|
||||
}
|
||||
box.style = stack_peek( & ui.theme_stack ).focused
|
||||
}
|
||||
if is_disabled
|
||||
{
|
||||
if ! was_disabled {
|
||||
box.prev_style = box.style
|
||||
box.style_delta = 0
|
||||
}
|
||||
box.style = stack_peek( & ui.theme_stack ).disabled
|
||||
}
|
||||
|
||||
if ! is_disabled && ! is_active && ! is_hot {
|
||||
if was_disabled || was_active || was_hot {
|
||||
box.prev_style = box.style
|
||||
box.style_delta = 0
|
||||
}
|
||||
else {
|
||||
box.style_delta += frame_delta
|
||||
}
|
||||
box.style = stack_peek( & ui.theme_stack ).default
|
||||
}
|
||||
}
|
||||
|
||||
return signal
|
||||
}
|
4
code/ui_widgets.odin
Normal file
4
code/ui_widgets.odin
Normal file
@ -0,0 +1,4 @@
|
||||
package sectr
|
||||
|
||||
|
||||
ui_button :: proc( )
|
2
thirdparty/Odin
vendored
2
thirdparty/Odin
vendored
@ -1 +1 @@
|
||||
Subproject commit 242d5b8c5c92cab6c76757af2a4acc763fed41e3
|
||||
Subproject commit c448b34143971698fa0d2a69b91dd274d21ca328
|
Loading…
Reference in New Issue
Block a user