Some cleanup, resize handles lifted to ui_resizeable_handles
Fixed some bugs with the handles as well. Old cruft for resizing was removed.
This commit is contained in:
parent
a2b6325b5b
commit
1afe74b4b5
@ -340,6 +340,7 @@ tick :: proc( host_delta_time : f64, host_delta_ns : Duration ) -> b32
|
||||
{
|
||||
// profile("Client tick timing processing")
|
||||
config.engine_refresh_hz = uint(monitor_refresh_hz)
|
||||
// config.engine_refresh_hz = 10
|
||||
frametime_target_ms = 1.0 / f64(config.engine_refresh_hz) * S_To_MS
|
||||
sub_ms_granularity_required := frametime_target_ms <= Frametime_High_Perf_Threshold_MS
|
||||
|
||||
|
@ -9,7 +9,7 @@ Color_Red :: rl.RED
|
||||
Color_White :: rl.WHITE
|
||||
|
||||
Color_Transparent :: Color { 0, 0, 0, 0 }
|
||||
Color_BG :: Color { 61, 61, 64, 255 }
|
||||
Color_BG :: Color { 55, 55, 60, 255 }
|
||||
Color_BG_TextBox :: Color { 32, 32, 32, 180 }
|
||||
Color_BG_Panel :: Color { 32, 32, 32, 255 }
|
||||
Color_BG_Panel_Translucent :: Color { 32, 32, 32, 220 }
|
||||
@ -21,7 +21,7 @@ Color_GreyRed :: Color { 220, 100, 100, 50 }
|
||||
Color_White_A125 :: Color { 255, 255, 255, 165 }
|
||||
Color_Black :: Color { 0, 0, 0, 255 }
|
||||
Color_Green :: Color { 0, 180, 0, 255 }
|
||||
Color_ResizeHandle :: Color { 90, 90, 100, 255 }
|
||||
Color_ResizeHandle :: Color { 20, 40, 50, 80 }
|
||||
|
||||
Color_3D_BG :: Color { 188, 182 , 170, 255 }
|
||||
|
||||
|
@ -10,7 +10,6 @@ import rl "vendor:raylib"
|
||||
|
||||
Str_App_State := "App State"
|
||||
|
||||
|
||||
Memory_App : Memory
|
||||
|
||||
Memory_Base_Address_Persistent :: Terabyte * 1
|
||||
|
@ -10,14 +10,14 @@ StackFixed :: struct ( $ Type : typeid, $ Size : u32 ) {
|
||||
items : [ Size ] Type,
|
||||
}
|
||||
|
||||
stack_push :: proc( using stack : ^ StackFixed( $ Type, $ Size ), value : Type ) {
|
||||
stack_push :: #force_inline proc( using stack : ^ StackFixed( $ Type, $ Size ), value : Type ) {
|
||||
verify( idx < len( items ), "Attempted to push on a full stack" )
|
||||
|
||||
items[ idx ] = value
|
||||
idx += 1
|
||||
}
|
||||
|
||||
stack_pop :: proc( using stack : ^StackFixed( $ Type, $ Size ) ) {
|
||||
stack_pop :: #force_inline proc( using stack : ^StackFixed( $ Type, $ Size ) ) {
|
||||
verify( idx > 0, "Attempted to pop an empty stack" )
|
||||
|
||||
idx -= 1
|
||||
@ -26,13 +26,13 @@ stack_pop :: proc( using stack : ^StackFixed( $ Type, $ Size ) ) {
|
||||
}
|
||||
}
|
||||
|
||||
stack_peek_ref :: proc( using stack : ^StackFixed( $ Type, $ Size ) ) -> ( ^Type) {
|
||||
stack_peek_ref :: #force_inline proc "contextless" ( using stack : ^StackFixed( $ Type, $ Size ) ) -> ( ^Type) {
|
||||
last_idx := max( 0, idx - 1 ) if idx > 0 else 0
|
||||
last := & items[last_idx]
|
||||
return last
|
||||
}
|
||||
|
||||
stack_peek :: proc ( using stack : ^StackFixed( $ Type, $ Size ) ) -> Type {
|
||||
stack_peek :: #force_inline proc "contextless" ( using stack : ^StackFixed( $ Type, $ Size ) ) -> Type {
|
||||
last := max( 0, idx - 1 ) if idx > 0 else 0
|
||||
return items[last]
|
||||
}
|
||||
|
@ -19,11 +19,13 @@ import "core:strings"
|
||||
StringKey :: distinct u64
|
||||
RunesCached :: []rune
|
||||
|
||||
// TODO(Ed): Should this just track the key instead? (by default)
|
||||
StrRunesPair :: struct {
|
||||
str : string,
|
||||
runes : []rune,
|
||||
}
|
||||
to_str_runes_pair :: proc ( content : string ) -> StrRunesPair {
|
||||
return { content, to_runes(content) }
|
||||
}
|
||||
|
||||
StringCache :: struct {
|
||||
slab : Slab,
|
||||
@ -65,8 +67,9 @@ str_cache_init :: proc( /*allocator : Allocator*/ ) -> ( cache : StringCache ) {
|
||||
return
|
||||
}
|
||||
|
||||
// str_cache_intern_string :: proc(
|
||||
// cache : ^StringCache,
|
||||
str_intern_key :: #force_inline proc( content : string ) -> StringKey { return cast(StringKey) crc32( transmute([]byte) content ) }
|
||||
str_intern_lookup :: #force_inline proc( key : StringKey ) -> (^StrRunesPair) { return zpl_hmap_get( & get_state().string_cache.table, transmute(u64) key ) }
|
||||
|
||||
str_intern :: proc(
|
||||
content : string
|
||||
) -> StrRunesPair
|
||||
@ -74,8 +77,8 @@ str_intern :: proc(
|
||||
// profile(#procedure)
|
||||
cache := & get_state().string_cache
|
||||
|
||||
key := u64( crc32( transmute([]byte) content ))
|
||||
result := zpl_hmap_get( & cache.table, key )
|
||||
key := str_intern_key(content)
|
||||
result := zpl_hmap_get( & cache.table, transmute(u64) key )
|
||||
if result != nil {
|
||||
return (result ^)
|
||||
}
|
||||
@ -98,7 +101,7 @@ str_intern :: proc(
|
||||
slab_validate_pools( get_state().persistent_slab )
|
||||
|
||||
// result, alloc_error = zpl_hmap_set( & cache.table, key, StrRunesPair { transmute(string) byte_slice(str_mem, length), runes } )
|
||||
result, alloc_error = zpl_hmap_set( & cache.table, key, StrRunesPair { transmute(string) str_mem, runes } )
|
||||
result, alloc_error = zpl_hmap_set( & cache.table, transmute(u64) key, StrRunesPair { transmute(string) str_mem, runes } )
|
||||
verify( alloc_error == .None, "String cache had a backing allocator error" )
|
||||
|
||||
slab_validate_pools( get_state().persistent_slab )
|
||||
|
@ -122,5 +122,6 @@ log :: proc( msg : string, level := LogLevel.Info, loc := #caller_location ) {
|
||||
}
|
||||
|
||||
logf :: proc( fmt : string, args : ..any, level := LogLevel.Info, loc := #caller_location ) {
|
||||
// context.allocator = transient_allocator()
|
||||
core_log.logf( level, fmt, args, location = loc )
|
||||
}
|
||||
|
@ -180,28 +180,6 @@ render_mode_2d_workspace :: proc()
|
||||
}
|
||||
// profile_end()
|
||||
|
||||
if .Mouse_Resizable in current.flags
|
||||
{
|
||||
// profile("Resize Bounds")
|
||||
resize_border_width := cast(f32) get_state().config.ui_resize_border_width
|
||||
resize_percent_width := computed_size * (resize_border_width * 1.0/ 200.0)
|
||||
resize_border_non_range := add(current.computed.bounds, range2(
|
||||
{ resize_percent_width.x, -resize_percent_width.x },
|
||||
{ -resize_percent_width.x, resize_percent_width.x }))
|
||||
|
||||
render_resize := range2(
|
||||
ws_view_to_render_pos(resize_border_non_range.min),
|
||||
ws_view_to_render_pos(resize_border_non_range.max),
|
||||
)
|
||||
rect_resize := rl.Rectangle {
|
||||
render_resize.min.x,
|
||||
render_resize.min.y,
|
||||
render_resize.max.x - render_resize.min.x,
|
||||
render_resize.max.y - render_resize.min.y,
|
||||
}
|
||||
draw_rectangle_lines( rect_padding, style, Color_Red, line_thickness )
|
||||
}
|
||||
|
||||
point_radius := 3 * cam_zoom_ratio
|
||||
|
||||
// profile_begin("circles")
|
||||
@ -216,7 +194,7 @@ render_mode_2d_workspace :: proc()
|
||||
// profile_end()
|
||||
|
||||
if len(current.text.str) > 0 {
|
||||
ws_view_draw_text( current.text, ws_view_to_render_pos(computed.text_pos * {1, -1}), style.font_size, style.text_color )
|
||||
ws_view_draw_text( current.text, ws_view_to_render_pos(computed.text_pos * {1, -1}), style.layout.font_size, style.text_color )
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -290,6 +268,7 @@ render_mode_screenspace :: proc ()
|
||||
|
||||
if debug.mouse_vis {
|
||||
debug_text("Mouse Vertical Wheel: %v", input.mouse.vertical_wheel )
|
||||
debug_text("Mouse Delta : %v", input.mouse.delta )
|
||||
debug_text("Mouse Position (Render) : %v", input.mouse.raw_pos )
|
||||
debug_text("Mouse Position (Surface) : %v", input.mouse.pos )
|
||||
debug_text("Mouse Position (Workspace View): %v", surface_to_ws_view_pos(input.mouse.pos) )
|
||||
@ -299,18 +278,31 @@ render_mode_screenspace :: proc ()
|
||||
|
||||
ui := & project.workspace.ui
|
||||
|
||||
// debug_text("Box Count: %v", ui.built_box_count )
|
||||
debug_text("Box Count: %v", ui.built_box_count )
|
||||
|
||||
hot_box := ui_box_from_key( ui.curr_cache, ui.hot )
|
||||
active_box := ui_box_from_key( ui.curr_cache, ui.active )
|
||||
if hot_box != nil {
|
||||
debug_text("Hot Box : %v", hot_box.label.str )
|
||||
// debug_text("Hot Range2: %v", hot_box.computed.bounds.pts)
|
||||
debug_text("Worksapce Hot Box : %v", hot_box.label.str )
|
||||
debug_text("Workspace Hot Range2: %v", hot_box.computed.bounds.pts)
|
||||
}
|
||||
if active_box != nil{
|
||||
// debug_text("Active Box: %v", active_box.label.str )
|
||||
debug_text("Workspace Active Box: %v", active_box.label.str )
|
||||
}
|
||||
|
||||
ui = & app_ui
|
||||
|
||||
debug_text("Box Count: %v", ui.built_box_count )
|
||||
|
||||
hot_box = ui_box_from_key( ui.curr_cache, ui.hot )
|
||||
active_box = ui_box_from_key( ui.curr_cache, ui.active )
|
||||
if hot_box != nil {
|
||||
debug_text("Hot Box : %v", hot_box.label.str )
|
||||
debug_text("Hot Range2: %v", hot_box.computed.bounds.pts)
|
||||
}
|
||||
if active_box != nil{
|
||||
debug_text("Active Box: %v", active_box.label.str )
|
||||
}
|
||||
// debug_text("Active Resizing: %v", ui.active_start_signal.resizing)
|
||||
|
||||
view := view_get_bounds()
|
||||
// debug_text("View Bounds (World): %v", view.pts )
|
||||
@ -432,7 +424,7 @@ render_app_ui :: proc()
|
||||
// profile_end()
|
||||
|
||||
if len(current.text.str) > 0 {
|
||||
draw_text_screenspace( current.text, surface_to_render_pos(computed.text_pos), style.font_size, style.text_color )
|
||||
draw_text_screenspace( current.text, surface_to_render_pos(computed.text_pos), style.layout.font_size, style.text_color )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,6 @@ frametime_delta32 :: #force_inline proc "contextless" () -> f32 {
|
||||
return cast(f32) get_state().frametime_delta_seconds
|
||||
}
|
||||
|
||||
|
||||
update :: proc( delta_time : f64 ) -> b32
|
||||
{
|
||||
profile(#procedure)
|
||||
@ -210,7 +209,7 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
{
|
||||
fmt :: str_fmt_alloc
|
||||
|
||||
@static bar_pos := Vec2{}
|
||||
@static bar_pos := Vec2{0, 100}
|
||||
bar_size := vec2( 400, 40 )
|
||||
|
||||
menu_bar : UI_Widget
|
||||
@ -218,28 +217,28 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
theme := UI_Style {
|
||||
flags = {
|
||||
},
|
||||
bg_color = { 0, 0, 0, 30 },
|
||||
bg_color = { 0, 0, 0, 30 },
|
||||
border_color = { 0, 0, 0, 200 },
|
||||
|
||||
font = default_font,
|
||||
font_size = 12,
|
||||
text_color = Color_White,
|
||||
|
||||
layout = UI_Layout {
|
||||
anchor = {},
|
||||
border_width = 1.0,
|
||||
font_size = 12,
|
||||
pos = bar_pos,
|
||||
size = range2( bar_size, {}),
|
||||
// padding = { 10, 10, 10, 10 },
|
||||
},
|
||||
}
|
||||
|
||||
ui_theme_via_style(theme)
|
||||
menu_bar = ui_widget("App Menu Bar", UI_BoxFlags {} )
|
||||
menu_bar.text = { fmt("%v", bar_pos), {} }
|
||||
menu_bar.text.runes = to_runes(menu_bar.text.str)
|
||||
menu_bar = ui_widget("App Menu Bar", {} )
|
||||
menu_bar.text = to_str_runes_pair( fmt("%v", bar_pos))
|
||||
|
||||
if (menu_bar.first_frame) {
|
||||
bar_pos = screen_get_corners().top_right - vec2(0, app_window.extent.y * 0.5)
|
||||
// bar_pos = screen_get_corners().top_right - vec2(0, app_window.extent.y * 0.5)
|
||||
}
|
||||
}
|
||||
// Setup Children
|
||||
@ -255,49 +254,43 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
bg_color = Color_Frame_Disabled,
|
||||
|
||||
font = default_font,
|
||||
font_size = 18,
|
||||
text_color = Color_White,
|
||||
|
||||
layout = UI_Layout {
|
||||
anchor = range2( {0, 0}, {0.0, 0} ),
|
||||
alignment = { 0.0, 1.0 },
|
||||
font_size = 18,
|
||||
text_alignment = { 0.5, 0.5 },
|
||||
pos = { 0, 0 },
|
||||
size = range2( {25, bar_size.y}, {0, 0})
|
||||
}
|
||||
}
|
||||
theme := UI_StyleTheme { styles = {
|
||||
style,
|
||||
style,
|
||||
style,
|
||||
style,
|
||||
}}
|
||||
theme := to_ui_styletheme(style)
|
||||
theme.disabled.bg_color = Color_Frame_Disabled
|
||||
theme.hot.bg_color = Color_White
|
||||
theme.hot.bg_color = Color_Red
|
||||
theme.active.bg_color = Color_Frame_Select
|
||||
ui_style_theme(theme)
|
||||
|
||||
move_box : UI_Widget
|
||||
{
|
||||
move_box = ui_button("Move Box")
|
||||
if move_box.dragging {
|
||||
if move_box.active {
|
||||
bar_pos += input.mouse.delta
|
||||
}
|
||||
}
|
||||
// bar_pos = {0, 400}
|
||||
|
||||
move_settings_spacer := ui_widget("Move-Settings Spacer", {})
|
||||
move_settings_spacer.text = str_intern("spacer")
|
||||
move_settings_spacer.style.font_size = 10
|
||||
move_settings_spacer.style.bg_color = Color_Transparent
|
||||
|
||||
// settings_btn : UI_Widget
|
||||
{
|
||||
settings_btn = ui_button("Settings Btn")
|
||||
settings_btn.text = str_intern("Settings")
|
||||
settings_btn.style.flags = {
|
||||
.Scale_Width_By_Height_Ratio,
|
||||
}
|
||||
using move_settings_spacer
|
||||
text = str_intern("spacer")
|
||||
style.bg_color = Color_Transparent
|
||||
style.layout.font_size = 10
|
||||
}
|
||||
|
||||
settings_btn = ui_button("Settings Btn")
|
||||
settings_btn.text = str_intern("Settings")
|
||||
settings_btn.style.flags = {
|
||||
.Scale_Width_By_Height_Ratio,
|
||||
}
|
||||
|
||||
// HBox layout calculation?
|
||||
@ -319,175 +312,80 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@static settings_open := true
|
||||
if settings_btn.left_clicked || settings_open
|
||||
if settings_btn.pressed || settings_open
|
||||
{
|
||||
settings_open = true
|
||||
|
||||
@static pos := Vec2 {0, 0}
|
||||
@static size := Vec2 { 600, 800 }
|
||||
resize_border_width : f32 = 10
|
||||
|
||||
// Prototype for a resize box
|
||||
// Will surround one box with a resize borders
|
||||
// All sides can have their borders toggled
|
||||
resize_box := ui_widget("Settings Menu: Resize Box", {})
|
||||
{
|
||||
using resize_box
|
||||
style.pos = pos
|
||||
style.alignment = { 0.5, 0.5 }
|
||||
style.bg_color = {}
|
||||
style.size = range2( size, {})
|
||||
resize_border_width : f32 = 20
|
||||
@static pos := Vec2 {0, 0}
|
||||
@static size := Vec2 { 200, 200 }
|
||||
if size.x < 200 {
|
||||
size.x = 200
|
||||
}
|
||||
ui_parent(resize_box)
|
||||
|
||||
// Resize handles and corners
|
||||
{
|
||||
flags := UI_BoxFlags { .Mouse_Clickable, .Focusable }
|
||||
|
||||
style_resize_width := UI_Style {
|
||||
flags = { .Fixed_Width },
|
||||
size = range2({resize_border_width, 0}, {}),
|
||||
bg_color = Color_ResizeHandle,
|
||||
alignment = {0, 1},
|
||||
margins = { resize_border_width, resize_border_width, 0, 0 },
|
||||
}
|
||||
style_resize_height := style_resize_width
|
||||
style_resize_height.flags = {.Fixed_Height}
|
||||
style_resize_height.size.min = {0, resize_border_width}
|
||||
style_resize_height.margins = { 0, 0, resize_border_width, resize_border_width }
|
||||
|
||||
ui_theme_via_style(style_resize_width)
|
||||
left := ui_widget("Settings Menu: Resize Left Border", flags )
|
||||
right := ui_widget("Settings Menu: Resize Right Border", flags)
|
||||
right.style.anchor.left = 1
|
||||
right.style.alignment = {1, 1}
|
||||
|
||||
ui_theme_via_style(style_resize_height)
|
||||
top := ui_widget("Settings Menu: Resize Top Border", flags )
|
||||
bottom := ui_widget("Settings Menu: Resize Bottom Border", flags)
|
||||
bottom.style.anchor.top = 1
|
||||
bottom.style.alignment = {0, 0}
|
||||
|
||||
style_corner := UI_Style {
|
||||
flags = { .Fixed_Width, .Fixed_Height },
|
||||
size = range2({resize_border_width, resize_border_width}, {}),
|
||||
bg_color = Color_Blue,
|
||||
alignment = {0, 1}
|
||||
}
|
||||
ui_theme_via_style(style_corner)
|
||||
corner_tl := ui_widget("Settings Menu: Corner TL", flags)
|
||||
corner_tr := ui_widget("Settings Menu: Corner TR", flags)
|
||||
corner_tr.style.anchor = range2({1, 0}, {})
|
||||
corner_tr.style.alignment = {1, 1}
|
||||
|
||||
corner_bl := ui_widget("Settings Menu: Corner BL", flags)
|
||||
corner_bl.style.anchor = range2({}, {0, 1})
|
||||
corner_bl.style.alignment = {}
|
||||
corner_br := ui_widget("Settings Menu: Corner BR", flags)
|
||||
corner_br.style.anchor = range2({1, 0}, {0, 1})
|
||||
corner_br.style.alignment = {1, 0}
|
||||
|
||||
process_handle_drag :: #force_inline proc ( handle : ^UI_Widget,
|
||||
side_scalar : f32,
|
||||
size_axis : ^f32,
|
||||
size_delta_axis : f32,
|
||||
pos_axis : ^f32,
|
||||
alignment_axis : ^f32,
|
||||
alignment_while_dragging : f32 )
|
||||
{
|
||||
if get_state().ui_context.last_pressed_key != handle.key { return }
|
||||
|
||||
@static was_dragging := false
|
||||
@static within_drag := false
|
||||
|
||||
using handle.signal
|
||||
if dragging
|
||||
{
|
||||
if ! was_dragging {
|
||||
was_dragging = true
|
||||
(pos_axis ^) += size_axis^ * 0.5 * side_scalar
|
||||
}
|
||||
(size_axis ^) += size_delta_axis * -side_scalar
|
||||
(alignment_axis ^) = alignment_while_dragging
|
||||
}
|
||||
else if was_dragging && released
|
||||
{
|
||||
(pos_axis ^) += size_axis^ * 0.5 * -side_scalar
|
||||
was_dragging = false
|
||||
}
|
||||
}
|
||||
|
||||
process_handle_drag( & right , -1.0, & size.x, input.mouse.delta.x, & pos.x, & resize_box.style.alignment.x, 0)
|
||||
process_handle_drag( & left, 1.0, & size.x, input.mouse.delta.x, & pos.x, & resize_box.style.alignment.x, 1)
|
||||
process_handle_drag( & top, -1.0, & size.y, input.mouse.delta.y, & pos.y, & resize_box.style.alignment.y, 0)
|
||||
process_handle_drag( & bottom, 1.0, & size.y, input.mouse.delta.y, & pos.y, & resize_box.style.alignment.y, 1)
|
||||
|
||||
// process_corner_drag :: #force_inline proc()
|
||||
{
|
||||
|
||||
}
|
||||
if size.y < 200 {
|
||||
size.y = 200
|
||||
}
|
||||
|
||||
settings_menu := ui_widget("Settings Menu", {})
|
||||
settings_menu := ui_widget("Settings Menu", {.Mouse_Clickable})
|
||||
{
|
||||
using settings_menu
|
||||
style.alignment = { 0.0, 1.0 }
|
||||
style.bg_color = Color_BG_Panel_Translucent
|
||||
// style.border_width = 1.0
|
||||
// style.border_color = Color_Blue
|
||||
style.margins = {
|
||||
resize_border_width,
|
||||
resize_border_width,
|
||||
resize_border_width,
|
||||
resize_border_width, }
|
||||
style.flags = {
|
||||
// .Origin_At_Anchor_Center
|
||||
}
|
||||
style.pos = pos
|
||||
style.alignment = { 1.0, 0.5 }
|
||||
style.bg_color = Color_BG_Panel_Translucent
|
||||
style.size = range2( size, {})
|
||||
}
|
||||
ui_parent(settings_menu)
|
||||
|
||||
ui_parent(settings_menu)
|
||||
ui_theme_via_style({
|
||||
bg_color = Color_Transparent,
|
||||
font = default_font,
|
||||
font_size = 16,
|
||||
bg_color = Color_Transparent,
|
||||
font = default_font,
|
||||
text_color = Color_White,
|
||||
size = range2({0, 40}, {0, 40}) // TODO(Ed): Implment ratio scaling for height
|
||||
size = range2({0, 40}, {0, 40}), // TODO(Ed): Implment ratio scaling for height
|
||||
layout = { font_size = 16 },
|
||||
})
|
||||
ui_style_theme_ref().hot.bg_color = Color_Blue
|
||||
frame_bar := ui_widget("Settings Menu: Frame Bar", { .Mouse_Clickable, .Focusable, .Click_To_Focus })
|
||||
{
|
||||
using frame_bar
|
||||
style.bg_color = Color_BG_Panel
|
||||
style.flags = {}
|
||||
style.bg_color = Color_BG_Panel
|
||||
style.flags = {}
|
||||
style.alignment = { 0, 1 }
|
||||
// style.size = {}
|
||||
style.anchor = range2( {0, 0.95}, {0, 0} )
|
||||
ui_parent(frame_bar)
|
||||
}
|
||||
ui_parent(frame_bar)
|
||||
|
||||
if dragging {
|
||||
pos += input.mouse.delta
|
||||
}
|
||||
if frame_bar.active {
|
||||
pos += input.mouse.delta
|
||||
}
|
||||
|
||||
title := ui_text("Settings Menu: Title", str_intern("Settings Menu"))
|
||||
{
|
||||
using title
|
||||
style.alignment = {0, 1}
|
||||
style.margins = { 0, 0, 15, 0}
|
||||
style.text_alignment = {0.0 , 0.5}
|
||||
}
|
||||
title := ui_text("Settings Menu: Title", str_intern("Settings Menu"), {.Disabled})
|
||||
{
|
||||
using title
|
||||
style.alignment = {0, 1}
|
||||
style.margins = { 0, 0, 15, 0}
|
||||
style.text_alignment = {0 , 0.5}
|
||||
}
|
||||
|
||||
close_btn := ui_button("Settings Menu: Close Btn")
|
||||
{
|
||||
using close_btn
|
||||
text = str_intern("close")
|
||||
style.bg_color = Color_GreyRed
|
||||
style.size.min = {50, 0}
|
||||
style.anchor = range2( {1.0, 0}, {})
|
||||
style.alignment = {1, 1}
|
||||
style.text_alignment = {0.5, 0.5}
|
||||
if close_btn.pressed {
|
||||
settings_open = false
|
||||
}
|
||||
ui_style_theme(ui_style_theme_peek())
|
||||
ui_style_theme_ref().default.bg_color = Color_GreyRed
|
||||
ui_style_theme_ref().hot. bg_color = Color_Red
|
||||
close_btn := ui_button("Settings Menu: Close Btn")
|
||||
{
|
||||
using close_btn
|
||||
text = str_intern("close")
|
||||
// style.bg_color = Color_GreyRed
|
||||
style.size.min = {50, 0}
|
||||
style.anchor = range2( {1.0, 0}, {})
|
||||
style.alignment = {1, 1}
|
||||
style.text_alignment = {0.5, 0.5}
|
||||
if close_btn.pressed {
|
||||
settings_open = false
|
||||
}
|
||||
}
|
||||
|
||||
ui_resizable_handles( & settings_menu, & pos, & size )
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -508,6 +406,7 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
default_layout := UI_Layout {
|
||||
anchor = {},
|
||||
alignment = { 0., 0.0 },
|
||||
font_size = 30,
|
||||
text_alignment = { 0.0, 0.0 },
|
||||
// corner_radii = { 0.2, 0.2, 0.2, 0.2 },
|
||||
pos = { 0, 0 },
|
||||
@ -516,25 +415,18 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
}
|
||||
|
||||
frame_style_default := UI_Style {
|
||||
flags = frame_style_flags,
|
||||
bg_color = Color_BG_TextBox,
|
||||
|
||||
flags = frame_style_flags,
|
||||
bg_color = Color_BG_TextBox,
|
||||
font = default_font,
|
||||
font_size = 30,
|
||||
text_color = Color_White,
|
||||
|
||||
layout = default_layout,
|
||||
}
|
||||
|
||||
frame_theme := UI_StyleTheme { styles = {
|
||||
frame_style_default,
|
||||
frame_style_default,
|
||||
frame_style_default,
|
||||
frame_style_default,
|
||||
}}
|
||||
frame_theme := to_ui_styletheme(frame_style_default)
|
||||
frame_theme.disabled.bg_color = Color_Frame_Disabled
|
||||
frame_theme.hot.bg_color = Color_Frame_Hover
|
||||
frame_theme.active.bg_color = Color_Frame_Select
|
||||
frame_theme.hot. bg_color = Color_Frame_Hover
|
||||
frame_theme.active. bg_color = Color_Frame_Select
|
||||
ui_style_theme( frame_theme )
|
||||
|
||||
config.ui_resize_border_width = 2.5
|
||||
|
28
code/ui.odin
28
code/ui.odin
@ -114,24 +114,6 @@ UI_ScalarConstraint :: struct {
|
||||
|
||||
UI_Scalar2 :: [Axis2.Count]UI_Scalar
|
||||
|
||||
UI_Signal :: struct {
|
||||
cursor_pos : Vec2,
|
||||
drag_delta : Vec2,
|
||||
scroll : Vec2,
|
||||
|
||||
left_clicked : b8,
|
||||
right_clicked : b8,
|
||||
double_clicked : b8,
|
||||
keyboard_clicked : b8,
|
||||
|
||||
pressed : b8,
|
||||
released : b8,
|
||||
dragging : b8,
|
||||
resizing : b8,
|
||||
cursor_over : b8,
|
||||
commit : b8,
|
||||
}
|
||||
|
||||
UI_Box :: struct {
|
||||
// Cache ID
|
||||
key : UI_Key,
|
||||
@ -192,7 +174,6 @@ UI_State :: struct {
|
||||
// flag_stack : Stack( UI_BoxFlags, UI_BoxFlags_Stack_Size ),
|
||||
|
||||
hot : UI_Key,
|
||||
hot_resizable : b32,
|
||||
hot_start_style : UI_Style,
|
||||
|
||||
active_mouse : [MouseBtn.count] UI_Key,
|
||||
@ -330,7 +311,7 @@ ui_cursor_pos :: #force_inline proc "contextless" () -> Vec2 {
|
||||
return surface_to_ws_view_pos( input.mouse.pos )
|
||||
}
|
||||
else {
|
||||
return input.mouse.pos
|
||||
return input.mouse.pos
|
||||
}
|
||||
}
|
||||
|
||||
@ -355,9 +336,6 @@ ui_graph_build_begin :: proc( ui : ^ UI_State, bounds : Vec2 = {} )
|
||||
//ui.hot = UI_Key(0)
|
||||
ui.active_start_signal = {}
|
||||
}
|
||||
if ui.hot == UI_Key(0) {
|
||||
ui.hot_resizable = false
|
||||
}
|
||||
|
||||
ui.built_box_count = 0
|
||||
root = ui_box_make( {}, "root#001" )
|
||||
@ -419,6 +397,4 @@ ui_parent_pop :: proc() {
|
||||
}
|
||||
|
||||
@(deferred_none = ui_parent_pop)
|
||||
ui_parent :: proc( ui : ^UI_Box) {
|
||||
ui_parent_push( ui )
|
||||
}
|
||||
ui_parent :: #force_inline proc( ui : ^UI_Box) { ui_parent_push( ui ) }
|
||||
|
@ -106,11 +106,11 @@ ui_compute_layout :: proc( ui : ^UI_State )
|
||||
}
|
||||
|
||||
text_size : Vec2
|
||||
if style.font_size == computed.text_size.y {
|
||||
if style.layout.font_size == computed.text_size.y {
|
||||
text_size = computed.text_size
|
||||
}
|
||||
else {
|
||||
text_size = cast(Vec2) measure_text_size( current.text.str, style.font, style.font_size, 0 )
|
||||
text_size = cast(Vec2) measure_text_size( current.text.str, style.font, style.layout.font_size, 0 )
|
||||
}
|
||||
|
||||
if size_to_text {
|
||||
@ -154,7 +154,7 @@ ui_compute_layout :: proc( ui : ^UI_State )
|
||||
// Determine Content Bounds
|
||||
content_bounds := range2(
|
||||
bounds.min + { layout.padding.left, layout.padding.bottom } + border_offset,
|
||||
bounds.max - { layout.padding.right, layout.padding.top } - border_offset,
|
||||
bounds.max - { layout.padding.right, layout.padding.top } - border_offset,
|
||||
)
|
||||
|
||||
computed.anchors = anchored_bounds
|
||||
|
@ -1,5 +1,23 @@
|
||||
package sectr
|
||||
|
||||
UI_Signal :: struct {
|
||||
cursor_pos : Vec2,
|
||||
drag_delta : Vec2,
|
||||
scroll : Vec2,
|
||||
|
||||
left_clicked : b8,
|
||||
right_clicked : b8,
|
||||
double_clicked : b8,
|
||||
keyboard_clicked : b8,
|
||||
|
||||
active : b8,
|
||||
was_active : b8,
|
||||
|
||||
pressed : b8,
|
||||
released : b8,
|
||||
cursor_over : b8,
|
||||
commit : b8,
|
||||
}
|
||||
|
||||
ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal
|
||||
{
|
||||
@ -15,18 +33,6 @@ 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 )
|
||||
|
||||
computed_size := box.computed.bounds.p1 - box.computed.bounds.p0
|
||||
|
||||
resize_border_width := cast(f32) get_state().config.ui_resize_border_width
|
||||
resize_percent_width := computed_size * (resize_border_width * 1.0/ 200.0)
|
||||
resize_border_non_range := add(box.computed.bounds, range2(
|
||||
{ resize_percent_width.x, -resize_percent_width.x },
|
||||
{ -resize_percent_width.x, resize_percent_width.x }))
|
||||
|
||||
within_resize_range := cast(b8) ! pos_within_range2( signal.cursor_pos, resize_border_non_range )
|
||||
within_resize_range &= signal.cursor_over
|
||||
within_resize_range &= .Mouse_Resizable in box.flags
|
||||
// profile_end()
|
||||
|
||||
// profile_begin("misc")
|
||||
@ -46,29 +52,17 @@ ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal
|
||||
ui.active = box.key
|
||||
ui.active_mouse[MouseBtn.Left] = box.key
|
||||
|
||||
ui.last_pressed_key = box.key
|
||||
ui.active_start_style = box.style
|
||||
ui.last_pressed_key = box.key
|
||||
ui.active_start_style = box.style
|
||||
|
||||
signal.pressed = true
|
||||
// TODO(Ed) : Support double-click detection
|
||||
}
|
||||
|
||||
if mouse_clickable && signal.cursor_over && left_released
|
||||
{
|
||||
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)
|
||||
|
||||
@ -100,14 +94,14 @@ 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
|
||||
if signal.cursor_over && ! is_disabled
|
||||
{
|
||||
hot_vacant := ui.hot == UI_Key(0)
|
||||
active_vacant := ui.active == UI_Key(0)
|
||||
|
||||
if (hot_vacant || is_hot) &&
|
||||
(active_vacant || is_active)
|
||||
// (active_vacant is_active)
|
||||
if (hot_vacant && signal.cursor_over || is_hot)
|
||||
{
|
||||
// prev_hot := zpl_hmap_get( ui.prev_cache, u64(ui.hot) )
|
||||
// prev_hot_label := prev_hot != nil ? prev_hot.label.str : ""
|
||||
@ -125,10 +119,20 @@ ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal
|
||||
ui.hot = UI_Key(0)
|
||||
}
|
||||
}
|
||||
// profile_end()
|
||||
|
||||
signal.resizing = cast(b8) is_active && (within_resize_range || ui.active_start_signal.resizing)
|
||||
ui.hot_resizable = cast(b32) (is_hot && within_resize_range) || signal.resizing
|
||||
if mouse_clickable && signal.cursor_over && left_released
|
||||
{
|
||||
ui.active = UI_Key(0)
|
||||
ui.active_mouse[MouseBtn.Left] = UI_Key(0)
|
||||
|
||||
signal.released = true
|
||||
|
||||
if was_active {
|
||||
signal.left_clicked = true
|
||||
ui.last_clicked = box.key
|
||||
}
|
||||
}
|
||||
// profile_end()
|
||||
|
||||
// State Deltas update
|
||||
// profile_begin( "state deltas upate")
|
||||
@ -164,7 +168,9 @@ ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal
|
||||
}
|
||||
// profile_end()
|
||||
|
||||
signal.dragging = cast(b8) is_active && ( ! within_resize_range && ! ui.active_start_signal.resizing)
|
||||
signal.active = cast(b8) is_active
|
||||
signal.was_active = cast(b8) was_active
|
||||
// logf("was_active: %v", was_active)
|
||||
|
||||
// Update style if not in default state
|
||||
{
|
||||
@ -210,5 +216,6 @@ ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal
|
||||
if is_active && ! was_active {
|
||||
ui.active_start_signal = signal
|
||||
}
|
||||
|
||||
return signal
|
||||
}
|
||||
|
@ -13,18 +13,18 @@ UI_Layout :: struct {
|
||||
alignment : Vec2,
|
||||
text_alignment : Vec2,
|
||||
|
||||
border_width : UI_Scalar,
|
||||
font_size : f32,
|
||||
|
||||
margins : UI_LayoutSide,
|
||||
padding : UI_LayoutSide,
|
||||
|
||||
// TODO(Ed): We cannot support individual corners unless we add it to raylib (or finally change the rendering backend)
|
||||
corner_radii : [Corner.Count]f32,
|
||||
border_width : UI_Scalar,
|
||||
|
||||
// Position in relative coordinate space.
|
||||
// If the box's flags has Fixed_Position, then this will be its aboslute position in the relative coordinate space
|
||||
pos : Vec2,
|
||||
|
||||
pos : Vec2,
|
||||
size : Range2,
|
||||
|
||||
// TODO(Ed) : Should thsi just always be WS_Pos for workspace UI?
|
||||
@ -33,6 +33,7 @@ UI_Layout :: struct {
|
||||
// tile_pos : WS_Pos,
|
||||
}
|
||||
|
||||
// TODO(Ed): Change this to layout flags? Everything so far is just related to auto-layout
|
||||
UI_StyleFlag :: enum u32 {
|
||||
|
||||
// Will perform scissor pass on children to their parent's bounds
|
||||
@ -65,8 +66,14 @@ UI_StyleFlag :: enum u32 {
|
||||
// By Default, the origin is at the top left of the anchor's bounds
|
||||
Origin_At_Anchor_Center,
|
||||
|
||||
// Will size the box to its text. (Padding & Margins will thicken )
|
||||
// TODO(Ed): Implement this!
|
||||
// For this to work, the children must have a minimum size set & their size overall must be greater than the parent's minimum size
|
||||
Size_To_Content,
|
||||
|
||||
// Will size the box to its text.
|
||||
Size_To_Text,
|
||||
|
||||
// TODO(Ed): Implement this!
|
||||
Text_Wrap,
|
||||
|
||||
Count,
|
||||
@ -92,11 +99,14 @@ UI_Style :: struct {
|
||||
|
||||
font : FontID,
|
||||
// TODO(Ed): Should this get moved to the layout struct? Techncially font-size is mainly
|
||||
font_size : f32,
|
||||
text_color : Color,
|
||||
|
||||
cursor : UI_Cursor,
|
||||
|
||||
// TODO(Ed): Should layout be separate from style?
|
||||
// It technically entirely makes up style flags
|
||||
// and the only thing shared I guess is the font determining the measured text size + transition time
|
||||
// Technically we can provide a separate transition time option just for layout...
|
||||
using layout : UI_Layout,
|
||||
|
||||
// Used with style, prev_style, and style_delta to produce a simple interpolated animation
|
||||
@ -118,43 +128,28 @@ UI_TextAlign :: enum u32 {
|
||||
Count
|
||||
}
|
||||
|
||||
ui_layout_padding :: proc( pixels : f32 ) -> UI_LayoutSide {
|
||||
return { pixels, pixels, pixels, pixels }
|
||||
}
|
||||
to_ui_layoutside :: #force_inline proc( pixels : f32 ) -> UI_LayoutSide { return { pixels, pixels, pixels, pixels } }
|
||||
|
||||
ui_style_peek :: proc( box_state : UI_StylePreset ) -> UI_Style {
|
||||
return stack_peek_ref( & get_state().ui_context.theme_stack ).array[box_state]
|
||||
}
|
||||
to_ui_styletheme :: #force_inline proc( style : UI_Style ) -> UI_StyleTheme { return { styles = {style, style, style, style} } }
|
||||
|
||||
ui_style_ref :: proc( box_state : UI_StylePreset ) -> (^ UI_Style) {
|
||||
return & stack_peek_ref( & get_state().ui_context.theme_stack ).array[box_state]
|
||||
}
|
||||
ui_style_peek :: #force_inline proc( box_state : UI_StylePreset ) -> UI_Style { return stack_peek_ref( & get_state().ui_context.theme_stack ).array[box_state] }
|
||||
ui_style_ref :: #force_inline proc( box_state : UI_StylePreset ) -> (^ UI_Style) { return & stack_peek_ref( & get_state().ui_context.theme_stack ).array[box_state] }
|
||||
|
||||
ui_style_set :: proc ( style : UI_Style, box_state : UI_StylePreset ) {
|
||||
stack_peek_ref( & get_state().ui_context.theme_stack ).array[box_state] = style
|
||||
}
|
||||
ui_style_set :: #force_inline proc ( style : UI_Style, box_state : UI_StylePreset ) { stack_peek_ref( & get_state().ui_context.theme_stack ).array[box_state] = style }
|
||||
|
||||
ui_style_set_layout :: proc ( layout : UI_Layout, preset : UI_StylePreset ) {
|
||||
stack_peek_ref( & get_state().ui_context.theme_stack ).array[preset].layout = layout
|
||||
}
|
||||
ui_style_set_layout :: #force_inline proc ( layout : UI_Layout, preset : UI_StylePreset ) { stack_peek_ref( & get_state().ui_context.theme_stack ).array[preset].layout = layout }
|
||||
|
||||
ui_style_theme_push :: proc( preset : UI_StyleTheme ) {
|
||||
push( & get_state().ui_context.theme_stack, preset )
|
||||
}
|
||||
|
||||
ui_style_theme_pop :: proc() {
|
||||
pop( & get_state().ui_context.theme_stack )
|
||||
}
|
||||
ui_style_theme_push :: #force_inline proc( preset : UI_StyleTheme ) { push( & get_state().ui_context.theme_stack, preset ) }
|
||||
ui_style_theme_pop :: #force_inline proc() { pop( & get_state().ui_context.theme_stack ) }
|
||||
|
||||
@(deferred_none = ui_style_theme_pop)
|
||||
ui_style_theme :: proc( preset : UI_StyleTheme ) {
|
||||
ui_style_theme_push( preset )
|
||||
}
|
||||
ui_style_theme :: #force_inline proc( preset : UI_StyleTheme ) { ui_style_theme_push( preset ) }
|
||||
|
||||
ui_style_theme_peek :: #force_inline proc() -> UI_StyleTheme { return stack_peek( & get_state().ui_context.theme_stack ) }
|
||||
ui_style_theme_ref :: #force_inline proc() -> (^ UI_StyleTheme) { return stack_peek_ref( & get_state().ui_context.theme_stack ) }
|
||||
|
||||
@(deferred_none = ui_style_theme_pop)
|
||||
ui_theme_via_style :: proc ( style : UI_Style ) {
|
||||
ui_style_theme_push( UI_StyleTheme { styles = { style, style, style, style } })
|
||||
}
|
||||
ui_theme_via_style :: #force_inline proc ( style : UI_Style ) { ui_style_theme_push( UI_StyleTheme { styles = { style, style, style, style } }) }
|
||||
|
||||
ui_style_theme_set_layout :: proc ( layout : UI_Layout ) {
|
||||
for & preset in stack_peek_ref( & get_state().ui_context.theme_stack ).array {
|
||||
@ -169,6 +164,4 @@ ui_style_theme_layout_push :: proc ( layout : UI_Layout ) {
|
||||
}
|
||||
|
||||
@(deferred_none = ui_style_theme_pop)
|
||||
ui_style_theme_layout :: proc( layout : UI_Layout ) {
|
||||
ui_style_theme_layout_push(layout)
|
||||
}
|
||||
ui_style_theme_layout :: #force_inline proc( layout : UI_Layout ) { ui_style_theme_layout_push(layout) }
|
||||
|
3
code/ui_style_themes.odin
Normal file
3
code/ui_style_themes.odin
Normal file
@ -0,0 +1,3 @@
|
||||
package sectr
|
||||
|
||||
ui_theme_btn_default : proc( ) -> UI_StyleTheme
|
@ -43,24 +43,11 @@ test_draggable :: proc()
|
||||
}
|
||||
|
||||
// Dragging
|
||||
if draggable.dragging {
|
||||
if draggable.active {
|
||||
debug.draggable_box_pos += mouse_world_delta()
|
||||
}
|
||||
|
||||
// Resize
|
||||
if draggable.resizing
|
||||
{
|
||||
og_layout := ui_context.active_start_style.layout
|
||||
|
||||
center := debug.draggable_box_pos
|
||||
original_distance := linalg.distance(ui.active_start_signal.cursor_pos, center)
|
||||
cursor_distance := linalg.distance(draggable.cursor_pos, center)
|
||||
scale_factor := cursor_distance * (1 / original_distance)
|
||||
|
||||
debug.draggable_box_size = og_layout.size.min * scale_factor
|
||||
}
|
||||
|
||||
if (ui.hot == draggable.key) && (ui.hot_resizable || ui.active_start_signal.resizing) {
|
||||
if (ui.hot == draggable.key) {
|
||||
draggable.style.bg_color = Color_Blue
|
||||
}
|
||||
|
||||
@ -100,21 +87,10 @@ test_parenting :: proc( default_layout : ^UI_Layout, frame_style_default : ^UI_S
|
||||
debug.draggable_box_pos = parent.style.layout.pos
|
||||
debug.draggable_box_size = parent.style.layout.size.min
|
||||
}
|
||||
if parent.dragging {
|
||||
if parent.active {
|
||||
debug.draggable_box_pos += mouse_world_delta()
|
||||
}
|
||||
if parent.resizing
|
||||
{
|
||||
og_layout := ui_context.active_start_style.layout
|
||||
|
||||
center := debug.draggable_box_pos
|
||||
original_distance := linalg.distance(ui.active_start_signal.cursor_pos, center)
|
||||
cursor_distance := linalg.distance(parent.cursor_pos, center)
|
||||
scale_factor := cursor_distance * (1 / original_distance)
|
||||
|
||||
debug.draggable_box_size = og_layout.size.min * scale_factor
|
||||
}
|
||||
if (ui.hot == parent.key) && (ui.hot_resizable || ui.active_start_signal.resizing) {
|
||||
if (ui.hot == parent.key) {
|
||||
parent.style.bg_color = Color_Blue
|
||||
}
|
||||
parent.style.layout.pos = debug.draggable_box_pos
|
||||
@ -150,7 +126,7 @@ test_text_box :: proc()
|
||||
style.text_alignment = { 1.0, 1.0 }
|
||||
// style.flags = { .Size_To_Text }
|
||||
style.padding = { 10, 10, 10, 10 }
|
||||
style.font_size = 32
|
||||
style.layout.font_size = 32
|
||||
ui_style_theme( { styles = { style, style, style, style, }} )
|
||||
|
||||
text := str_intern( "Lorem ipsum dolor sit amet")
|
||||
@ -160,7 +136,7 @@ test_text_box :: proc()
|
||||
pos = text_box.style.layout.pos
|
||||
}
|
||||
|
||||
if text_box.dragging {
|
||||
if text_box.active {
|
||||
pos += mouse_world_delta()
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@ ui_hbox_begin :: proc( label : string, flags : UI_BoxFlags = {}
|
||||
widget.signal = ui_signal_from_box( widget.box )
|
||||
return
|
||||
}
|
||||
|
||||
ui_hbox_end :: proc( hbox : UI_Widget ) -> UI_Widget {
|
||||
hbox_width := hbox.computed.content.max.y - hbox.computed.content.min.y
|
||||
|
||||
@ -73,12 +74,11 @@ ui_hbox_end :: proc( hbox : UI_Widget ) -> UI_Widget {
|
||||
size_req_children += size.min.x
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
availble_flexible_space := hbox_width - size_req_children
|
||||
return hbox
|
||||
}
|
||||
|
||||
ui_hbox_auto_end :: proc( vbox : UI_Widget ) {
|
||||
ui_hbox_end(vbox)
|
||||
ui_parent_pop()
|
||||
@ -90,9 +90,150 @@ ui_hbox :: #force_inline proc( label : string, flags : UI_BoxFlags = {} ) -> (wi
|
||||
ui_parent(widget)
|
||||
return
|
||||
}
|
||||
|
||||
//endregion Horizontal Box
|
||||
|
||||
// Adds resizable handles to a widget
|
||||
ui_resizable_handles :: proc( parent : ^UI_Widget,
|
||||
pos, size : ^Vec2,
|
||||
handle_width : f32 = 15,
|
||||
handle_color_non_default : Color = Color_ResizeHandle,
|
||||
handle_color_default : Color = Color_Transparent,
|
||||
left := true,
|
||||
right := true,
|
||||
top := true,
|
||||
bottom := true,
|
||||
corner_tr := true,
|
||||
corner_tl := true,
|
||||
corner_br := true,
|
||||
corner_bl := true, )
|
||||
{
|
||||
handle_left : UI_Widget
|
||||
handle_right : UI_Widget
|
||||
handle_top : UI_Widget
|
||||
handle_bottom : UI_Widget
|
||||
handle_corner_tr : UI_Widget
|
||||
handle_corner_tl : UI_Widget
|
||||
handle_corner_br : UI_Widget
|
||||
handle_corner_bl : UI_Widget
|
||||
|
||||
ui_parent(parent)
|
||||
flags := UI_BoxFlags { .Mouse_Clickable, .Focusable }
|
||||
|
||||
style_bar := UI_Style {
|
||||
flags = { .Fixed_Width },
|
||||
size = range2({handle_width, 0}, {}),
|
||||
bg_color = Color_ResizeHandle,
|
||||
alignment = {1, 1},
|
||||
margins = { handle_width, handle_width, 0, 0 },
|
||||
corner_radii = { 5, 0, 0, 0 }
|
||||
}
|
||||
theme_bar := to_ui_styletheme(style_bar)
|
||||
theme_bar.default.bg_color = handle_color_default
|
||||
theme_bar.default.corner_radii[0] = 0
|
||||
ui_style_theme(theme_bar)
|
||||
style_resize_height := style_bar
|
||||
style_resize_height.flags = {.Fixed_Height}
|
||||
style_resize_height.size.min = {0, handle_width}
|
||||
style_resize_height.margins = { 0, 0, handle_width, handle_width }
|
||||
style_resize_height.alignment = {0, 0}
|
||||
|
||||
context.user_ptr = & parent.label
|
||||
name :: proc( ) -> StrRunesPair {
|
||||
parent_label := (transmute(^string) context.user_ptr) ^
|
||||
return str_intern(str_fmt_tmp("%v: %v", ))
|
||||
}
|
||||
|
||||
if left do handle_left = ui_widget("Settings Menu: Resize Left Border", flags )
|
||||
if right {
|
||||
handle_right = ui_widget("Settings Menu: Resize Right Border", flags)
|
||||
handle_right.style.anchor.left = 1
|
||||
handle_right.style.alignment = { 0, 1 }
|
||||
}
|
||||
|
||||
ui_theme_via_style(style_resize_height)
|
||||
ui_style_theme_ref().default.bg_color = handle_color_default
|
||||
if top do handle_top = ui_widget("Settings Menu: Resize Top Border", flags )
|
||||
if bottom {
|
||||
handle_bottom = ui_widget("Settings Menu: Resize Bottom Border", flags)
|
||||
handle_bottom.style.anchor.top = 1
|
||||
handle_bottom.style.alignment = { 0, 1 }
|
||||
}
|
||||
|
||||
style_corner := UI_Style {
|
||||
flags = { .Fixed_Width, .Fixed_Height },
|
||||
size = range2({handle_width, handle_width}, {}),
|
||||
bg_color = Color_ResizeHandle,
|
||||
alignment = {1, 0},
|
||||
corner_radii = { 5, 0, 0, 0 },
|
||||
}
|
||||
ui_theme_via_style(style_corner)
|
||||
ui_style_theme_ref().default.bg_color = handle_color_default
|
||||
if corner_tl do handle_corner_tl = ui_widget("Settings Menu: Corner TL", flags)
|
||||
if corner_tr {
|
||||
handle_corner_tr = ui_widget("Settings Menu: Corner TR", flags)
|
||||
handle_corner_tr.style.anchor = range2({1, 0}, {})
|
||||
handle_corner_tr.style.alignment = {0, 0}
|
||||
}
|
||||
|
||||
if corner_bl {
|
||||
handle_corner_bl = ui_widget("Settings Menu: Corner BL", flags)
|
||||
handle_corner_bl.style.anchor = range2({}, {0, 1})
|
||||
handle_corner_bl.style.alignment = { 1, 1 }
|
||||
}
|
||||
if corner_br {
|
||||
handle_corner_br = ui_widget("Settings Menu: Corner BR", flags)
|
||||
handle_corner_br.style.anchor = range2({1, 0}, {0, 1})
|
||||
handle_corner_br.style.alignment = {0, 1}
|
||||
}
|
||||
|
||||
process_handle_drag :: #force_inline proc ( handle : ^UI_Widget,
|
||||
direction : Vec2,
|
||||
size_delta : Vec2,
|
||||
target_alignment : Vec2,
|
||||
pos : ^Vec2,
|
||||
size : ^Vec2,
|
||||
alignment : ^Vec2, )
|
||||
{
|
||||
ui := get_state().ui_context
|
||||
if ui.last_pressed_key != handle.key { return }
|
||||
|
||||
size_delta := size_delta
|
||||
pos_adjust := size^ * (alignment^ - target_alignment)
|
||||
|
||||
@static was_dragging := false
|
||||
|
||||
using handle
|
||||
if active
|
||||
{
|
||||
size^ += size_delta * direction
|
||||
if pressed {
|
||||
pos^ -= pos_adjust
|
||||
}
|
||||
else {
|
||||
alignment^ = target_alignment
|
||||
}
|
||||
was_dragging = true
|
||||
}
|
||||
else if released && was_dragging
|
||||
{
|
||||
pos^ += pos_adjust
|
||||
alignment^ = target_alignment
|
||||
was_dragging = false
|
||||
}
|
||||
}
|
||||
|
||||
delta := get_state().input.mouse.delta
|
||||
alignment := & parent.style.alignment
|
||||
if right do process_handle_drag( & handle_right, { 1, 0 }, delta, {0, 0}, pos, size, alignment )
|
||||
if left do process_handle_drag( & handle_left, { -1, 0 }, delta, {1, 0}, pos, size, alignment )
|
||||
if top do process_handle_drag( & handle_top, { 0, 1 }, delta, {0, 0}, pos, size, alignment )
|
||||
if bottom do process_handle_drag( & handle_bottom, { 0, -1 }, delta, {0, 1}, pos, size, alignment )
|
||||
if corner_tr do process_handle_drag( & handle_corner_tr, { 1, 1 }, delta, {0, 0}, pos, size, alignment )
|
||||
if corner_tl do process_handle_drag( & handle_corner_tl, { -1, 1 }, delta, {1, 0}, pos, size, alignment )
|
||||
if corner_br do process_handle_drag( & handle_corner_br, { 1, -1 }, delta, {0, 1}, pos, size, alignment )
|
||||
if corner_bl do process_handle_drag( & handle_corner_bl, { -1, -1 }, delta, {1, 1}, pos, size, alignment )
|
||||
}
|
||||
|
||||
ui_text :: proc( label : string, content : StrRunesPair, flags : UI_BoxFlags = {} ) -> UI_Widget
|
||||
{
|
||||
// profile(#procedure)
|
||||
@ -135,6 +276,7 @@ ui_text_tabs :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget
|
||||
return { box, signal }
|
||||
}
|
||||
|
||||
//region Vertical Box
|
||||
ui_vbox_begin :: proc( label : string, flags : UI_BoxFlags = {} ) -> (widget : UI_Widget) {
|
||||
// profile(#procedure)
|
||||
|
||||
@ -159,3 +301,4 @@ ui_vbox :: #force_inline proc( label : string, flags : UI_BoxFlags = {} ) -> (wi
|
||||
ui_parent_push(widget)
|
||||
return
|
||||
}
|
||||
//endregion Vertical Box
|
||||
|
Loading…
Reference in New Issue
Block a user