AppUI lifted to its own file, Got horizontal and vertical boxes working
This commit is contained in:
parent
5b24e591eb
commit
2b1565e35b
@ -191,7 +191,15 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
|
||||
}
|
||||
|
||||
// Setup the app ui state
|
||||
ui_startup( & app_ui, cache_allocator = persistent_slab_allocator() )
|
||||
{
|
||||
ui_startup( & app_ui.base, cache_allocator = persistent_slab_allocator() )
|
||||
|
||||
using app_ui
|
||||
menu_bar.pos = Vec2(app_window.extent) * { -1, 1 }
|
||||
menu_bar.size = {200, 40}
|
||||
|
||||
settings_menu.min_size = {200, 200}
|
||||
}
|
||||
|
||||
// Demo project setup
|
||||
{
|
||||
@ -340,7 +348,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
|
||||
// config.engine_refresh_hz = 30
|
||||
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
|
||||
|
||||
|
185
code/app_ui.odin
Normal file
185
code/app_ui.odin
Normal file
@ -0,0 +1,185 @@
|
||||
package sectr
|
||||
|
||||
App_UI_State :: struct
|
||||
{
|
||||
using base : UI_State,
|
||||
menu_bar : struct
|
||||
{
|
||||
pos, size : Vec2,
|
||||
container : UI_HBox,
|
||||
settings_btn : struct
|
||||
{
|
||||
using widget : UI_Widget,
|
||||
is_open : b32,
|
||||
}
|
||||
},
|
||||
settings_menu : struct
|
||||
{
|
||||
pos, size, min_size : Vec2,
|
||||
container : UI_VBox,
|
||||
},
|
||||
}
|
||||
|
||||
ui_app_menu_bar :: proc()
|
||||
{
|
||||
profile("App Menu Bar")
|
||||
fmt :: str_fmt_alloc
|
||||
|
||||
using state := get_state()
|
||||
using app_ui
|
||||
{
|
||||
using menu_bar
|
||||
ui_theme_via_style({
|
||||
flags = {},
|
||||
bg_color = { 0, 0, 0, 30 },
|
||||
border_color = { 0, 0, 0, 200 },
|
||||
font = default_font,
|
||||
text_color = Color_White,
|
||||
layout = {
|
||||
anchor = {},
|
||||
alignment = { 0, 1 },
|
||||
border_width = 1.0,
|
||||
font_size = 12,
|
||||
pos = menu_bar.pos,
|
||||
size = range2( menu_bar.size, {}),
|
||||
},
|
||||
})
|
||||
container = ui_hbox( .Left_To_Right, "App Menu Bar", { .Mouse_Clickable} )
|
||||
|
||||
theme := to_ui_styletheme({
|
||||
bg_color = Color_Frame_Disabled,
|
||||
font = default_font,
|
||||
text_color = Color_White,
|
||||
layout = {
|
||||
anchor = range2( {0, 0}, {0, 0} ),
|
||||
alignment = { 0.0, 0.0 },
|
||||
font_size = 18,
|
||||
text_alignment = { 0.5, 0.5 },
|
||||
size = range2({25, 0}, {0, 0})
|
||||
}
|
||||
})
|
||||
theme.hot.bg_color = Color_Blue
|
||||
theme.active.bg_color = Color_Frame_Select
|
||||
ui_style_theme(theme)
|
||||
|
||||
move_box := ui_button("Move Box");
|
||||
{
|
||||
using move_box
|
||||
if active {
|
||||
menu_bar.pos += input.mouse.delta
|
||||
}
|
||||
style.anchor.ratio.x = 0.2
|
||||
}
|
||||
|
||||
spacer := ui_spacer("Menu Bar: Move Spacer")
|
||||
spacer.style.flags |= {.Fixed_Width}
|
||||
spacer.style.size.min.x = 50
|
||||
// spacer.style.bg_color = Color_Red
|
||||
|
||||
settings_btn.widget = ui_button("Settings Btn")
|
||||
settings_btn.text = str_intern("Settings")
|
||||
settings_btn.style.flags = {
|
||||
// .Scale_Width_By_Height_Ratio,
|
||||
.Fixed_Width
|
||||
}
|
||||
settings_btn.style.size.min.x = 100
|
||||
if settings_btn.pressed {
|
||||
settings_btn.is_open = true
|
||||
}
|
||||
|
||||
spacer = ui_spacer("Menu Bar: End Spacer")
|
||||
spacer.style.anchor.ratio.x = 1.0
|
||||
// spacer.style.bg_color = Color_Red
|
||||
}
|
||||
|
||||
ui_app_settings_menu()
|
||||
}
|
||||
|
||||
ui_app_settings_menu :: proc()
|
||||
{
|
||||
profile("Settings Menu")
|
||||
using state := get_state()
|
||||
using state.app_ui
|
||||
if menu_bar.settings_btn.pressed || ! menu_bar.settings_btn.is_open {
|
||||
return
|
||||
}
|
||||
|
||||
using settings_menu
|
||||
if size.x < min_size.x {
|
||||
size.x = min_size.x
|
||||
}
|
||||
if size.y < min_size.y {
|
||||
size.y = min_size.y
|
||||
}
|
||||
container = ui_vbox_begin( .Top_To_Bottom, "Settings Menu", {.Mouse_Clickable})
|
||||
{
|
||||
using container
|
||||
style.flags = {
|
||||
// .Origin_At_Anchor_Center
|
||||
}
|
||||
style.pos = pos
|
||||
style.alignment = { 0.5, 0.5 }
|
||||
style.bg_color = Color_BG_Panel_Translucent
|
||||
style.size = range2( size, {})
|
||||
}
|
||||
ui_parent(container)
|
||||
{
|
||||
ui_theme_via_style({
|
||||
bg_color = Color_Transparent,
|
||||
font = default_font,
|
||||
text_color = Color_White,
|
||||
layout = { font_size = 16 },
|
||||
})
|
||||
ui_style_theme_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.style.flags = {.Fixed_Height}
|
||||
frame_bar.style.alignment = { 0, 0 }
|
||||
// frame_bar.style.anchor.ratio.y = 0.25
|
||||
frame_bar.style.size.min.y = 50
|
||||
if frame_bar.active {
|
||||
pos += input.mouse.delta
|
||||
}
|
||||
ui_parent(frame_bar)
|
||||
|
||||
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}
|
||||
style.anchor.ratio.x = 1.0
|
||||
}
|
||||
|
||||
ui_style_theme(ui_style_theme_peek())
|
||||
theme := ui_style_theme_ref()
|
||||
theme.default.bg_color = Color_GreyRed
|
||||
theme.hot. bg_color = Color_Red
|
||||
close_btn := ui_button("Settings Menu: Close Btn")
|
||||
{
|
||||
using close_btn
|
||||
text = str_intern("close")
|
||||
style.flags = {.Fixed_Width}
|
||||
// style.bg_color = Color_GreyRed
|
||||
style.size.min = {50, 0}
|
||||
// style.anchor = range2( {1.0, 0}, {})
|
||||
// style.alignment = {0, 0}
|
||||
style.text_alignment = {0.5, 0.5}
|
||||
style.anchor.ratio.x = 1.0
|
||||
if close_btn.pressed {
|
||||
menu_bar.settings_btn.is_open = false
|
||||
}
|
||||
}
|
||||
|
||||
ui_hbox_end(frame_bar, & size.x)
|
||||
}
|
||||
|
||||
spacer := ui_spacer("Settings Menu: Spacer")
|
||||
spacer.style.anchor.ratio.y = 1.0
|
||||
|
||||
ui_vbox_end(container, & size.y)
|
||||
}
|
||||
|
||||
ui_resizable_handles( & container, & pos, & size )
|
||||
}
|
@ -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 { 20, 40, 50, 80 }
|
||||
Color_ResizeHandle :: Color { 80, 80, 90, 180 }
|
||||
|
||||
Color_3D_BG :: Color { 188, 182 , 170, 255 }
|
||||
|
||||
|
@ -177,7 +177,7 @@ State :: struct {
|
||||
|
||||
config : AppConfig,
|
||||
app_window : AppWindow,
|
||||
app_ui : UI_State,
|
||||
app_ui : App_UI_State,
|
||||
|
||||
monitor_id : i32,
|
||||
monitor_refresh_hz : i32,
|
||||
|
@ -26,12 +26,14 @@ debug_draw_text :: proc( content : string, pos : Vec2, size : f32, color : rl.Co
|
||||
px_size := size
|
||||
|
||||
rl_font := to_rl_Font(font, px_size )
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.POINT)
|
||||
rl.DrawTextCodepoints( rl_font,
|
||||
raw_data(runes), cast(i32) len(runes),
|
||||
position = transmute(rl.Vector2) pos,
|
||||
fontSize = px_size,
|
||||
spacing = 0.0,
|
||||
tint = color );
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.POINT)
|
||||
}
|
||||
|
||||
draw_text_screenspace :: proc( content : StrRunesPair, pos : Vec2, size : f32, color : rl.Color = rl.WHITE, font : FontID = Font_Default )
|
||||
@ -51,7 +53,7 @@ draw_text_screenspace :: proc( content : StrRunesPair, pos : Vec2, size : f32, c
|
||||
rl_font := to_rl_Font(font, size )
|
||||
runes := content.runes
|
||||
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.TRILINEAR)
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.POINT)
|
||||
rl.DrawTextCodepoints( rl_font,
|
||||
raw_data(runes), cast(i32) len(runes),
|
||||
position = transmute(rl.Vector2) pos,
|
||||
@ -83,14 +85,14 @@ ws_view_draw_text_string :: proc( content : string, pos : Vec2, size : f32, colo
|
||||
zoom_adjust := px_size * project.workspace.cam.zoom
|
||||
|
||||
rl_font := to_rl_Font(font, zoom_adjust )
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.TRILINEAR)
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.BILINEAR)
|
||||
rl.DrawTextCodepoints( rl_font,
|
||||
raw_data(runes), cast(i32) len(runes),
|
||||
position = transmute(rl.Vector2) pos,
|
||||
fontSize = px_size,
|
||||
spacing = 0.0,
|
||||
tint = color );
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.POINT)
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.ANISOTROPIC_16X)
|
||||
}
|
||||
|
||||
ws_view_draw_text_StrRunesPair :: proc( content : StrRunesPair, pos : Vec2, size : f32, color : rl.Color = rl.WHITE, font : FontID = Font_Default )
|
||||
@ -112,14 +114,14 @@ ws_view_draw_text_StrRunesPair :: proc( content : StrRunesPair, pos : Vec2, size
|
||||
rl_font := to_rl_Font(font, zoom_adjust )
|
||||
runes := content.runes
|
||||
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.TRILINEAR)
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.BILINEAR)
|
||||
rl.DrawTextCodepoints( rl_font,
|
||||
raw_data(runes), cast(i32) len(runes),
|
||||
position = transmute(rl.Vector2) pos,
|
||||
fontSize = px_size,
|
||||
spacing = 0.0,
|
||||
tint = color );
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.POINT)
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.ANISOTROPIC_16X)
|
||||
}
|
||||
|
||||
// Raylib's equivalent doesn't take a length for the string (making it a pain in the ass)
|
||||
|
@ -111,6 +111,7 @@ render_mode_2d_workspace :: proc()
|
||||
if root.num_children == 0 {
|
||||
break ImguiRender
|
||||
}
|
||||
state.ui_context = ui
|
||||
|
||||
current := root.first
|
||||
for ; current != nil; current = ui_box_tranverse_next( current )
|
||||
@ -173,10 +174,10 @@ render_mode_2d_workspace :: proc()
|
||||
|
||||
// profile_begin("rl.DrawRectangleRoundedLines: padding & content")
|
||||
if equal_range2(computed.content, computed.padding) {
|
||||
// draw_rectangle_lines( rect_padding, style, Color_Debug_UI_Padding_Bounds, line_thickness )
|
||||
draw_rectangle_lines( rect_padding, style, Color_Debug_UI_Padding_Bounds, line_thickness )
|
||||
}
|
||||
else {
|
||||
// draw_rectangle_lines( rect_content, style, Color_Debug_UI_Content_Bounds, line_thickness )
|
||||
draw_rectangle_lines( rect_content, style, Color_Debug_UI_Content_Bounds, line_thickness )
|
||||
}
|
||||
// profile_end()
|
||||
|
||||
@ -278,7 +279,7 @@ render_mode_screenspace :: proc ()
|
||||
|
||||
ui := & project.workspace.ui
|
||||
|
||||
debug_text("Box Count: %v", ui.built_box_count )
|
||||
debug_text("Box Count (Workspace): %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 )
|
||||
@ -324,6 +325,7 @@ render_app_ui :: proc()
|
||||
{
|
||||
profile("App UI")
|
||||
ui := & state.app_ui
|
||||
state.ui_context = ui
|
||||
root := ui.root
|
||||
if root.num_children == 0 {
|
||||
break Render_App_UI
|
||||
@ -423,7 +425,7 @@ render_app_ui :: proc()
|
||||
// rl.DrawCircleV( render_bounds.p1, point_radius, Color_Blue )
|
||||
// profile_end()
|
||||
|
||||
if len(current.text.str) > 0 {
|
||||
if len(current.text.str) > 0 && style.font.key != 0 {
|
||||
draw_text_screenspace( current.text, surface_to_render_pos(computed.text_pos), style.layout.font_size, style.text_color )
|
||||
}
|
||||
}
|
||||
|
@ -200,209 +200,7 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
ui_graph_build( & state.app_ui )
|
||||
ui := ui_context
|
||||
|
||||
/*
|
||||
Prototype app menu
|
||||
This is a menu bar for the app for now inside the same ui as the workspace's UI state
|
||||
Eventually this will get moved out to its own UI state for the app itself.
|
||||
*/
|
||||
if true
|
||||
{
|
||||
profile("App Menu Bar")
|
||||
fmt :: str_fmt_alloc
|
||||
|
||||
@static bar_pos := Vec2{0, 100}
|
||||
bar_size := vec2( 400, 40 )
|
||||
|
||||
menu_bar : UI_Widget
|
||||
{
|
||||
theme := UI_Style {
|
||||
flags = {
|
||||
},
|
||||
bg_color = { 0, 0, 0, 30 },
|
||||
border_color = { 0, 0, 0, 200 },
|
||||
|
||||
font = default_font,
|
||||
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", { .Mouse_Clickable} )
|
||||
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)
|
||||
}
|
||||
}
|
||||
// Setup Children
|
||||
settings_btn : UI_Widget
|
||||
{
|
||||
ui_parent(menu_bar)
|
||||
|
||||
style := UI_Style {
|
||||
flags = {
|
||||
// .Origin_At_Anchor_Center
|
||||
.Fixed_Height
|
||||
},
|
||||
bg_color = Color_Frame_Disabled,
|
||||
|
||||
font = default_font,
|
||||
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 := to_ui_styletheme(style)
|
||||
theme.disabled.bg_color = Color_Frame_Disabled
|
||||
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.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", {})
|
||||
{
|
||||
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?
|
||||
{
|
||||
hb_space_ratio_move_box := 0.1
|
||||
hb_space_ratio_move_settings_spacer := 0.05
|
||||
hb_space_ratio_settings_btn := 1.0
|
||||
|
||||
style := & move_box.box.style
|
||||
style.anchor.max.x = 0.9
|
||||
|
||||
style = & move_settings_spacer.box.style
|
||||
style.anchor.min.x = 0.1
|
||||
style.anchor.max.x = 0.8
|
||||
|
||||
style = & settings_btn.box.style
|
||||
style.anchor.min.x = 0.2
|
||||
style.anchor.max.x = 0.55
|
||||
}
|
||||
}
|
||||
|
||||
@static settings_open := true
|
||||
if settings_btn.pressed || settings_open
|
||||
{
|
||||
profile("Settings Menu")
|
||||
settings_open = true
|
||||
|
||||
resize_border_width : f32 = 20
|
||||
@static pos := Vec2 {0, 0}
|
||||
@static size := Vec2 { 200, 200 }
|
||||
if size.x < 200 {
|
||||
size.x = 200
|
||||
}
|
||||
if size.y < 200 {
|
||||
size.y = 200
|
||||
}
|
||||
settings_menu := ui_widget("Settings Menu", {.Mouse_Clickable})
|
||||
{
|
||||
using settings_menu
|
||||
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, {})
|
||||
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)
|
||||
ui_theme_via_style({
|
||||
bg_color = Color_Transparent,
|
||||
font = default_font,
|
||||
text_color = Color_White,
|
||||
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.alignment = { 0, 1 }
|
||||
}
|
||||
ui_parent(frame_bar)
|
||||
|
||||
if frame_bar.active {
|
||||
pos += input.mouse.delta
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
||||
|
||||
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 )
|
||||
}
|
||||
}
|
||||
ui_app_menu_bar()
|
||||
}
|
||||
//endregion App UI Tick
|
||||
|
||||
|
@ -291,9 +291,14 @@ ui_box_tranverse_next :: proc "contextless" ( box : ^ UI_Box ) -> (^ UI_Box)
|
||||
{
|
||||
// Check to make sure parent is present on the screen, if its not don't bother.
|
||||
// If current has children, do them first
|
||||
if intersects_range2( view_get_bounds(), box.computed.bounds) && box.first != nil
|
||||
using state := get_state()
|
||||
if box.first != nil
|
||||
{
|
||||
return box.first
|
||||
is_app_ui := ui_context == & app_ui
|
||||
if is_app_ui || intersects_range2( view_get_bounds(), box.computed.bounds)
|
||||
{
|
||||
return box.first
|
||||
}
|
||||
}
|
||||
|
||||
if box.next == nil
|
||||
|
@ -21,7 +21,7 @@ UI_Signal :: struct {
|
||||
commit : b8,
|
||||
}
|
||||
|
||||
ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal
|
||||
ui_signal_from_box :: proc ( box : ^ UI_Box, update_style := true, update_deltas := true ) -> UI_Signal
|
||||
{
|
||||
// profile(#procedure)
|
||||
ui := get_state().ui_context
|
||||
@ -199,6 +199,7 @@ ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal
|
||||
// logf("was_active: %v", was_active)
|
||||
|
||||
// Update style if not in default state
|
||||
if update_style
|
||||
{
|
||||
// profile("Update style")
|
||||
|
||||
|
@ -1,5 +1,15 @@
|
||||
package sectr
|
||||
|
||||
UI_LayoutDirectionX :: enum(i32) {
|
||||
Left_To_Right,
|
||||
Right_To_Left,
|
||||
}
|
||||
|
||||
UI_LayoutDirectionY :: enum(i32) {
|
||||
Top_To_Bottom,
|
||||
Bottom_To_Top,
|
||||
}
|
||||
|
||||
UI_LayoutSide :: struct {
|
||||
// using _ : struct {
|
||||
top, bottom : UI_Scalar,
|
||||
|
@ -202,7 +202,7 @@ test_whitespace_ast :: proc( default_layout : ^UI_Layout, frame_style_default :
|
||||
}
|
||||
|
||||
ui_style_theme_set_layout( layout_text )
|
||||
line_hbox := ui_widget(str_fmt_alloc( "line %v", line_id ), {})
|
||||
line_hbox := ui_widget(str_fmt_alloc( "line %v", line_id ), {.Mouse_Clickable})
|
||||
|
||||
if line_hbox.key == ui.hot
|
||||
{
|
||||
|
@ -7,8 +7,6 @@ UI_Widget :: struct {
|
||||
|
||||
ui_widget :: proc( label : string, flags : UI_BoxFlags ) -> (widget : UI_Widget)
|
||||
{
|
||||
// profile(#procedure)
|
||||
|
||||
widget.box = ui_box_make( flags, label )
|
||||
widget.signal = ui_signal_from_box( widget.box )
|
||||
return
|
||||
@ -16,8 +14,6 @@ ui_widget :: proc( label : string, flags : UI_BoxFlags ) -> (widget : UI_Widget)
|
||||
|
||||
ui_button :: proc( label : string, flags : UI_BoxFlags = {} ) -> (btn : UI_Widget)
|
||||
{
|
||||
// profile(#procedure)
|
||||
|
||||
btn_flags := UI_BoxFlags { .Mouse_Clickable, .Focusable, .Click_To_Focus }
|
||||
btn.box = ui_box_make( btn_flags | flags, label )
|
||||
btn.signal = ui_signal_from_box( btn.box )
|
||||
@ -32,7 +28,7 @@ attempt to slot them adjacent to each other along the x-axis.
|
||||
The user must provide the direction that the hbox will append entries.
|
||||
How the widgets will be scaled will be based on the individual entires style flags.
|
||||
|
||||
All the usual behaviors that the style and box flags do apply when manage by the box widget.
|
||||
All the usual behaviors that the style and box flags do apply when managed by the box widget.
|
||||
Whether or not the horizontal box will scale the widget's width is if:
|
||||
fixed size or "scale by ratio" flags are not used for the width.
|
||||
The hbox will use the anchor's (range2) ratio.x value to determine the "stretch ratio".
|
||||
@ -40,18 +36,31 @@ The hbox will use the anchor's (range2) ratio.x value to determine the "stretch
|
||||
Keep in mind the stretch ratio is only respected if no size.min.x value is violated for each of the widgets.
|
||||
*/
|
||||
|
||||
ui_hbox_begin :: proc( label : string, flags : UI_BoxFlags = {}
|
||||
//, direction
|
||||
) -> (widget : UI_Widget) {
|
||||
// profile(#procedure)
|
||||
// Horizontal Widget
|
||||
UI_HBox :: struct {
|
||||
using widget : UI_Widget,
|
||||
direction : UI_LayoutDirectionX,
|
||||
}
|
||||
|
||||
widget.box = ui_box_make( flags, label )
|
||||
widget.signal = ui_signal_from_box( widget.box )
|
||||
// Boilerplate creation
|
||||
ui_hbox_begin :: proc( direction : UI_LayoutDirectionX, label : string, flags : UI_BoxFlags = {} ) -> (hbox : UI_HBox) {
|
||||
// profile(#procedure)
|
||||
hbox.direction = direction
|
||||
hbox.box = ui_box_make( flags, label )
|
||||
hbox.signal = ui_signal_from_box( hbox.box )
|
||||
return
|
||||
}
|
||||
|
||||
ui_hbox_end :: proc( hbox : UI_Widget ) -> UI_Widget {
|
||||
hbox_width := hbox.computed.content.max.y - hbox.computed.content.min.y
|
||||
// Auto-layout children
|
||||
ui_hbox_end :: proc( hbox : UI_HBox, width_ref : ^f32 = nil ) {
|
||||
// profile(#procedure)
|
||||
hbox_width : f32
|
||||
if width_ref != nil {
|
||||
hbox_width = width_ref ^
|
||||
}
|
||||
else {
|
||||
hbox_width = hbox.computed.content.max.x - hbox.computed.content.min.x
|
||||
}
|
||||
|
||||
// do layout calculations for the children
|
||||
total_stretch_ratio : f32 = 0.0
|
||||
@ -74,20 +83,53 @@ ui_hbox_end :: proc( hbox : UI_Widget ) -> UI_Widget {
|
||||
size_req_children += size.min.x
|
||||
continue
|
||||
}
|
||||
|
||||
total_stretch_ratio += anchor.ratio.x
|
||||
}
|
||||
|
||||
avail_flex_space := hbox_width - size_req_children
|
||||
|
||||
allocate_space :: proc( child : ^UI_Box, total_stretch_ratio, avail_flex_space : f32 )
|
||||
{
|
||||
using child.style
|
||||
if ! (.Fixed_Width in child.style.flags) {
|
||||
size.min.x = anchor.ratio.x * (1 / total_stretch_ratio) * avail_flex_space
|
||||
}
|
||||
flags |= {.Fixed_Width}
|
||||
alignment = {0, 1}
|
||||
}
|
||||
|
||||
space_used : f32 = 0.0
|
||||
switch hbox.direction{
|
||||
case .Right_To_Left:
|
||||
for child := hbox.last; child != nil; child = child.prev {
|
||||
allocate_space(child, total_stretch_ratio, avail_flex_space)
|
||||
using child.style
|
||||
anchor = range2({0, 0}, {0, 0})
|
||||
pos.x = space_used
|
||||
space_used += size.min.x
|
||||
}
|
||||
case .Left_To_Right:
|
||||
for child := hbox.first; child != nil; child = child.next {
|
||||
allocate_space(child, total_stretch_ratio, avail_flex_space)
|
||||
using child.style
|
||||
anchor = range2({0, 0}, {0, 0})
|
||||
pos.x = space_used
|
||||
space_used += size.min.x
|
||||
}
|
||||
}
|
||||
availble_flexible_space := hbox_width - size_req_children
|
||||
return hbox
|
||||
}
|
||||
|
||||
ui_hbox_auto_end :: proc( vbox : UI_Widget ) {
|
||||
ui_hbox_end(vbox)
|
||||
// Auto-layout children and pop parent from parent stack
|
||||
ui_hbox_end_pop_parent :: proc( hbox : UI_HBox ) {
|
||||
ui_hbox_end(hbox)
|
||||
ui_parent_pop()
|
||||
}
|
||||
|
||||
@(deferred_out = ui_hbox_end)
|
||||
ui_hbox :: #force_inline proc( label : string, flags : UI_BoxFlags = {} ) -> (widget : UI_Widget) {
|
||||
widget = ui_hbox_begin(label, flags)
|
||||
ui_parent(widget)
|
||||
@(deferred_out = ui_hbox_end_pop_parent)
|
||||
ui_hbox :: #force_inline proc( direction : UI_LayoutDirectionX, label : string, flags : UI_BoxFlags = {} ) -> (hbox : UI_HBox) {
|
||||
hbox = ui_hbox_begin(direction, label, flags)
|
||||
ui_parent_push(hbox.widget)
|
||||
return
|
||||
}
|
||||
//endregion Horizontal Box
|
||||
@ -235,6 +277,14 @@ ui_resizable_handles :: proc( parent : ^UI_Widget,
|
||||
if corner_bl do process_handle_drag( & handle_corner_bl, { -1, -1 }, delta, {1, 1}, pos, size, alignment )
|
||||
}
|
||||
|
||||
ui_spacer :: proc( label : string ) -> (widget : UI_Widget) {
|
||||
widget.box = ui_box_make( {.Mouse_Clickable}, label )
|
||||
widget.signal = ui_signal_from_box( widget.box )
|
||||
|
||||
widget.style.bg_color = Color_Transparent
|
||||
return
|
||||
}
|
||||
|
||||
ui_text :: proc( label : string, content : StrRunesPair, flags : UI_BoxFlags = {} ) -> UI_Widget
|
||||
{
|
||||
// profile(#procedure)
|
||||
@ -278,28 +328,115 @@ ui_text_tabs :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget
|
||||
}
|
||||
|
||||
//region Vertical Box
|
||||
ui_vbox_begin :: proc( label : string, flags : UI_BoxFlags = {} ) -> (widget : UI_Widget) {
|
||||
// profile(#procedure)
|
||||
/*
|
||||
Vertical Boxes automatically manage a collection of widgets and
|
||||
attempt to slot them adjacent to each other along the y-axis.
|
||||
|
||||
widget.box = ui_box_make( flags, label )
|
||||
// widget.signal = ui_signal_from_box( widget.box )
|
||||
The user must provide the direction that the vbox will append entries.
|
||||
How the widgets will be scaled will be based on the individual entires style flags.
|
||||
|
||||
All the usual behaviors that the style and box flags do apply when managed by the box widget.
|
||||
Whether or not the horizontal box will scale the widget's width is if:
|
||||
fixed size or "scale by ratio" flags are not used for the width.
|
||||
The hbox will use the anchor's (range2) ratio.y value to determine the "stretch ratio".
|
||||
|
||||
Keep in mind the stretch ratio is only respected if no size.min.y value is violated for each of the widgets.
|
||||
*/
|
||||
|
||||
UI_VBox :: struct {
|
||||
using widget : UI_Widget,
|
||||
direction : UI_LayoutDirectionY,
|
||||
}
|
||||
|
||||
// Boilerplate creation
|
||||
ui_vbox_begin :: proc( direction : UI_LayoutDirectionY, label : string, flags : UI_BoxFlags = {} ) -> (vbox : UI_VBox) {
|
||||
// profile(#procedure)
|
||||
vbox.direction = direction
|
||||
vbox.box = ui_box_make( flags, label )
|
||||
vbox.signal = ui_signal_from_box( vbox.box )
|
||||
return
|
||||
}
|
||||
ui_vbox_end :: proc( hbox : UI_Widget ) -> UI_Widget {
|
||||
|
||||
// Auto-layout children
|
||||
ui_vbox_end :: proc( vbox : UI_VBox, height_ref : ^f32 = nil ) {
|
||||
// profile(#procedure)
|
||||
|
||||
vbox_height : f32
|
||||
if height_ref != nil {
|
||||
vbox_height = height_ref ^
|
||||
}
|
||||
else {
|
||||
vbox_height = vbox.computed.bounds.max.y - vbox.computed.bounds.min.y
|
||||
}
|
||||
|
||||
// do layout calculations for the children
|
||||
return hbox
|
||||
total_stretch_ratio : f32 = 0.0
|
||||
size_req_children : f32 = 0
|
||||
for child := vbox.first; child != nil; child = child.next
|
||||
{
|
||||
using child
|
||||
using style.layout
|
||||
scaled_width_by_height : b32 = b32(.Scale_Width_By_Height_Ratio in style.flags)
|
||||
if .Fixed_Height in style.flags
|
||||
{
|
||||
if scaled_width_by_height {
|
||||
width := size.max.x != 0 ? size.max.x : vbox_height
|
||||
height := width * size.min.y
|
||||
|
||||
size_req_children += height
|
||||
continue
|
||||
}
|
||||
|
||||
size_req_children += size.min.y
|
||||
continue
|
||||
}
|
||||
|
||||
total_stretch_ratio += anchor.ratio.y
|
||||
}
|
||||
|
||||
avail_flex_space := vbox_height - size_req_children
|
||||
|
||||
allocate_space :: proc( child : ^UI_Box, total_stretch_ratio, avail_flex_space : f32 )
|
||||
{
|
||||
using child.style
|
||||
if ! (.Fixed_Height in child.style.flags) {
|
||||
size.min.y = anchor.ratio.y * (1 / total_stretch_ratio) * avail_flex_space
|
||||
}
|
||||
flags |= {.Fixed_Height}
|
||||
alignment = {0, 0}
|
||||
}
|
||||
|
||||
space_used : f32 = 0.0
|
||||
switch vbox.direction {
|
||||
case .Top_To_Bottom:
|
||||
for child := vbox.last; child != nil; child = child.prev {
|
||||
allocate_space(child, total_stretch_ratio, avail_flex_space)
|
||||
using child.style
|
||||
anchor = range2({0, 0}, {0, 1})
|
||||
pos.y = space_used
|
||||
space_used += size.min.y
|
||||
}
|
||||
case .Bottom_To_Top:
|
||||
for child := vbox.first; child != nil; child = child.next {
|
||||
allocate_space(child, total_stretch_ratio, avail_flex_space)
|
||||
using child.style
|
||||
anchor = range2({0, 0}, {0, 1})
|
||||
pos.y = space_used
|
||||
space_used += size.min.y
|
||||
}
|
||||
}
|
||||
}
|
||||
ui_vbox_auto_end :: proc( hbox : UI_Widget ) {
|
||||
ui_vbox_end(hbox)
|
||||
|
||||
// Auto-layout children and pop parent from parent stack
|
||||
ui_vbox_end_pop_parent :: proc( vbox : UI_VBox ) {
|
||||
ui_vbox_end(vbox)
|
||||
ui_parent_pop()
|
||||
}
|
||||
|
||||
// ui_vbox_append( widget : UI_Widget )
|
||||
|
||||
@(deferred_out = ui_vbox_auto_end)
|
||||
ui_vbox :: #force_inline proc( label : string, flags : UI_BoxFlags = {} ) -> (widget : UI_Widget) {
|
||||
widget = ui_vbox_begin(label, flags)
|
||||
ui_parent_push(widget)
|
||||
@(deferred_out = ui_vbox_end_pop_parent)
|
||||
ui_vbox :: #force_inline proc( direction : UI_LayoutDirectionY, label : string, flags : UI_BoxFlags = {} ) -> (vbox : UI_VBox) {
|
||||
vbox = ui_vbox_begin(direction, label, flags)
|
||||
ui_parent_push(vbox.widget)
|
||||
return
|
||||
}
|
||||
//endregion Vertical Box
|
||||
|
0
docs/Persistent
Normal file
0
docs/Persistent
Normal 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
|
||||
@ -251,8 +251,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
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit e1b5ccf2dc07b6218c8d7c2ec3184594d085af89
|
||||
Subproject commit e462116f9428c3a871663eae4363c8d7da35497e
|
Loading…
Reference in New Issue
Block a user