Cleanup and setup of drop down widget

Got an initial variant of the drop down widget, not completely set on it..
I put some more time to figuring out how I'm going to be ideomatically constructing the widgets. screen.odin I think its getting pretty close to what it will be like.
I'm ready to start lifting the input box. I'll be adding the constraints when I lift it.

Added the option to toggle the debug text in screenspace
Added the fixes from the ui_layout_children_horizontally for margins to ui_layout_children_vertically

Known issue:
There is a bug with test_whitespace that forced me todo a null check on a box. Not sure why.
It needs to be redone anyway.. (compose it with the h/vboxes instead)

There is some sublime files added in, started to use it.
This commit is contained in:
Edward R. Gonzalez 2024-05-20 22:05:52 -04:00
parent cdfc3d65bb
commit e5be246d30
23 changed files with 23871 additions and 411 deletions

22
Sectr.sublime-project Normal file
View File

@ -0,0 +1,22 @@
{
"folders":
[
{
"path": ".",
}
],
"settings":
{
"LSP":
{
"ols":
{
"enabled": true,
},
"odin":
{
"enabled": true
},
},
},
}

23292
Sectr.sublime-workspace Normal file

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@ DebugData :: struct {
square_size : i32,
square_pos : rl.Vector2,
debug_text_vis : b32,
draw_debug_text_y : f32,
cursor_locked : b32,

View File

@ -20,8 +20,9 @@ UI_ScreenState :: struct
},
settings_menu : struct
{
pos, size, min_size : Vec2,
container : UI_Widget,
cfg_drop_down : UI_DropDown,
pos, size, min_size : Vec2,
is_open : b32,
is_maximized : b32,
},
@ -34,21 +35,16 @@ ui_screen_tick :: proc() {
ui_graph_build( & screen_ui )
ui := ui_context
ui_floating_manager_begin( & screen_ui.floating )
{
ui_floating("Menu Bar", ui_screen_menu_bar)
ui_floating("Settings Menu", ui_screen_settings_menu)
}
ui_floating_manager_end()
ui_floating_manager( & screen_ui.floating )
ui_floating("Menu Bar", ui_screen_menu_bar)
ui_floating("Settings Menu", ui_screen_settings_menu)
}
ui_screen_menu_bar :: proc( captures : rawptr = nil ) -> (should_raise : b32 = false )
{
profile("App Menu Bar")
fmt :: str_fmt_alloc
@(deferred_none = ui_theme_pop)
ui_theme_app_menu_bar_default :: proc()
theme_app_menu_bar :: proc() -> UI_Theme
{
@static theme : UI_Theme
@static loaded : b32 = false
@ -63,7 +59,7 @@ ui_screen_menu_bar :: proc( captures : rawptr = nil ) -> (should_raise : b32 = f
font_size = 12,
margins = {0, 0, 0, 0},
padding = {0, 0, 0, 0},
border_width = 0.6,
border_width = 1.0,
pos = {0, 0},
size = range2({},{})
}
@ -93,58 +89,46 @@ ui_screen_menu_bar :: proc( captures : rawptr = nil ) -> (should_raise : b32 = f
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
return theme
}
using state := get_state()
using screen_ui
{
using screen_ui.menu_bar
ui_theme_app_menu_bar_default()
container = ui_hbox_begin( .Left_To_Right, "Menu Bar" )
ui_parent(container)
{
using container
layout.flags = {.Fixed_Position_X, .Fixed_Position_Y, .Fixed_Width, .Fixed_Height, .Origin_At_Anchor_Center}
layout.pos = pos
layout.size = range2( size, {})
text = str_intern("menu_bar")
using screen_ui.menu_bar
scope(theme_app_menu_bar)
container = ui_hbox( .Left_To_Right, "Menu Bar" ); {
using container
layout.flags = {.Fixed_Position_X, .Fixed_Position_Y, .Fixed_Width, .Fixed_Height, .Origin_At_Anchor_Center}
layout.pos = pos
layout.size = range2( size, {})
text = str_intern("menu_bar")
}
scope(theme_transparent)
move_box : UI_Widget; {
scope(theme_button)
move_box = ui_button("Move Box")
using move_box
layout.size.min.x = 20
if active {
pos += input.mouse.delta
should_raise = true
}
}
ui_theme_btn()
move_box := ui_button("Move Box");
{
using move_box
if active {
pos += input.mouse.delta
should_raise = true
}
layout.anchor.ratio.x = 1.0
}
spacer := ui_spacer("Menu Bar: Move Spacer")
spacer.layout.flags |= {.Fixed_Width}
spacer.layout.size.min.x = 30
spacer := ui_spacer("Menu Bar: Move Spacer")
spacer.layout.flags |= {.Fixed_Width}
spacer.layout.size.min.x = 30
// TODO(Ed): Implement an external composition for theme interpolation using the settings btn
settings_btn.widget = ui_button("Menu Bar: Settings Btn")
{
using settings_btn
text = str_intern("Settings")
layout.flags = {
.Scale_Width_By_Height_Ratio,
// .Fixed_Width
}
layout.size.ratio.x = 2.0
if pressed {
screen_ui.settings_menu.is_open = true
}
}
spacer = ui_spacer("Menu Bar: End Spacer")
spacer.layout.anchor.ratio.x = 2.0
ui_hbox_end(container, compute_layout = false)
Build_Settings_Btn: {
scope(theme_button)
using settings_btn
widget = ui_button("Menu Bar: Settings Btn")
text = str_intern("Settings")
layout.flags = { .Scale_Width_By_Height_Ratio }
layout.size.ratio.x = 2.0
if pressed do screen_ui.settings_menu.is_open = true
}
return
}
@ -154,6 +138,7 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b
profile("Settings Menu")
using state := get_state()
using state.screen_ui
if ! settings_menu.is_open do return
app_color := app_color_theme()
@ -161,169 +146,182 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b
if size.x < min_size.x do size.x = min_size.x
if size.y < min_size.y do size.y = min_size.y
ui_theme_window_panel()
container = ui_widget("Settings Menu", {}); {
using container
layout.flags = { .Fixed_Width, .Fixed_Height, .Fixed_Position_X, .Fixed_Position_Y, .Origin_At_Anchor_Center }
layout.pos = pos
layout.size = range2( size, {})
Construct_Container:
{
scope(theme_window_panel)
container = ui_widget("Settings Menu", {}); {
using container
layout.flags = { .Fixed_Width, .Fixed_Height, .Fixed_Position_X, .Fixed_Position_Y, .Origin_At_Anchor_Center }
layout.pos = pos
layout.size = range2( size, {})
}
if settings_menu.is_maximized {
using container
layout.flags = {.Origin_At_Anchor_Center }
layout.pos = {}
}
should_raise |= ui_resizable_handles( & container, & pos, & size)
}
ui_parent(container)
if settings_menu.is_maximized {
using container
layout.flags = {.Origin_At_Anchor_Center }
layout.pos = {}
}
should_raise |= ui_resizable_handles( & container, & pos, & size)
vbox := ui_vbox_begin( .Top_To_Bottom, "Settings Menu: VBox", {.Mouse_Clickable}, compute_layout = true)
{
should_raise |= b32(vbox.active)
ui_parent(vbox)
ui_theme_window_bar()
frame_bar := ui_hbox_begin(.Left_To_Right, "Settings Menu: Frame Bar", { .Mouse_Clickable })
Frame_Bar:
{
ui_parent(frame_bar)
ui_theme_text()
title := ui_text("Settings Menu: Title", str_intern("Settings Menu"), {.Disabled}); {
using title
layout.anchor.ratio.x = 1.0
layout.margins = { 0, 0, 15, 0}
layout.font_size = 16
}
ui_theme_window_bar_btn()
maximize_btn := ui_button("Settings Menu: Maximize Btn"); {
using maximize_btn
if maximize_btn.pressed {
settings_menu.is_maximized = ~settings_menu.is_maximized
should_raise = true
scope(theme_window_bar)
frame_bar := ui_hbox(.Left_To_Right, "Settings Menu: Frame Bar", { .Mouse_Clickable })
{
ui_parent(frame_bar)
scope(theme_text)
title := ui_text("Settings Menu: Title", str_intern("Settings Menu"), {.Disabled}); {
using title
layout.anchor.ratio.x = 1.0
layout.margins = { 0, 0, 15, 0}
layout.font_size = 16
}
scope(theme_window_bar_btn)
maximize_btn := ui_button("Settings Menu: Maximize Btn"); {
using maximize_btn
if maximize_btn.pressed {
settings_menu.is_maximized = ~settings_menu.is_maximized
should_raise = true
}
if settings_menu.is_maximized do text = str_intern("min")
else do text = str_intern("max")
}
close_btn := ui_button("Settings Menu: Close Btn"); {
using close_btn
text = str_intern("close")
if close_btn.hot do style.bg_color = app_color.window_btn_close_bg_hot
if close_btn.pressed do settings_menu.is_open = false
}
if settings_menu.is_maximized do text = str_intern("min")
else do text = str_intern("max")
}
close_btn := ui_button("Settings Menu: Close Btn"); {
using close_btn
text = str_intern("close")
if close_btn.hot do style.bg_color = app_color.window_btn_close_bg_hot
if close_btn.pressed do settings_menu.is_open = false
if frame_bar.active {
pos += input.mouse.delta
should_raise = true
}
ui_hbox_end(frame_bar, compute_layout = true)
}
if frame_bar.active {
pos += input.mouse.delta
should_raise = true
}
@static config_drop_down_open := false
ui_theme_drop_down()
drop_down_bar := ui_hbox_begin(.Left_To_Right, "settings_menu.vbox: config drop_down_bar", {.Mouse_Clickable })
if ui_drop_down( & cfg_drop_down, "settings_menu.config", str_intern("App Config"), vb_compute_layout = true).is_open
{
ui_parent_push(drop_down_bar)
Engien_Refresh_Hz:
{
using drop_down_bar
text = str_intern("drop_down_bar")
layout.text_alignment = {1, 0}
layout.anchor.ratio.y = 1.0
}
ui_theme_text()
title := ui_text("drop_down_bar.btn", str_intern("drop_down_bar.btn")); {
using title
text = str_intern("App Config")
style.text_color = drop_down_bar.style.text_color
layout.alignment = {0.0, 0.0}
layout.text_alignment = {0.0, 0.5}
layout.anchor.ratio.x = 1.0
}
ui_parent_pop()
ui_hbox_end(drop_down_bar, compute_layout = true)
if drop_down_bar.pressed do config_drop_down_open = !config_drop_down_open
}
if config_drop_down_open
{
{
ui_theme_table_row(is_even = false)
scope(theme_table_row(is_even = false))
hb := ui_hbox(.Left_To_Right, "settings_menu.engine_refresh_hz.hb"); { using hb
layout.size.min = {0, 30}
layout.flags = {.Fixed_Height}
layout.padding = to_ui_layout_side(4)
layout.flags = {.Fixed_Height}
layout.padding = to_ui_layout_side(4)
}
ui_theme_text(); title := ui_text("settings_menu.engine_refresh_hz.title", str_intern("Engine Refresh Hz")); { using title
layout.anchor.ratio.x = 1.0
layout.margins.left = 10
layout.text_alignment = {0, 0.5}
title : UI_Widget; {
scope(theme_text)
title = ui_text("settings_menu.engine_refresh_hz.title", str_intern("Engine Refresh Hz"))
using title
layout.anchor.ratio.x = 1.0
layout.margins.left = 10
layout.text_alignment = {0, 0.5}
}
input_box := ui_widget("settings_menu.engine_refresh.input_box", {.Mouse_Clickable, .Focusable, .Click_To_Focus}); { using input_box
layout.flags = {.Fixed_Width}
layout.margins.left = 5
layout.padding.right = 10
layout.size.min.x = 80
if input_box.active do style.bg_color = app_color.input_box_bg_active
else if input_box.hot do style.bg_color = app_color.input_box_bg_hot
else do style.bg_color = app_color.input_box_bg
input_box := ui_widget("settings_menu.engine_refresh.input_box", {.Mouse_Clickable, .Focusable, .Click_To_Focus}); {
using input_box
layout.flags = {.Fixed_Width}
layout.margins.left = 5
layout.padding.right = 10
layout.size.min.x = 80
style.corner_radii[0] = 0.35
}
@static value_str : Array(rune)
if value_str.header == nil {
error : AllocatorError
value_str, error = array_init_reserve(rune, persistent_slab_allocator(), Kilo)
ensure(error == AllocatorError.None, "Failed to allocate array for value_str of input_box")
}
if input_box.pressed {
array_clear( value_str )
}
if input_box.active {
array_append( & value_str, input.keyboard_events.chars_pressed )
array_clear( input.keyboard_events.chars_pressed )
}
else if input_box.was_active {
value, success := parse_uint(to_string(array_to_slice(value_str)))
if success {
config.engine_refresh_hz = value
if input_box.active do style.bg_color = app_color.input_box_bg_active
else if input_box.hot do style.bg_color = app_color.input_box_bg_hot
else do style.bg_color = app_color.input_box_bg
@static value_str : Array(rune)
if value_str.header == nil {
error : AllocatorError
value_str, error = array_init_reserve(rune, persistent_slab_allocator(), Kilo)
ensure(error == AllocatorError.None, "Failed to allocate array for value_str of input_box")
}
if input_box.pressed {
array_clear( value_str )
}
if input_box.active {
array_append( & value_str, input.keyboard_events.chars_pressed )
array_clear( input.keyboard_events.chars_pressed )
}
else if input_box.was_active
{
value, success := parse_uint(to_string(array_to_slice(value_str)))
if success {
config.engine_refresh_hz = value
}
}
else
{
array_clear( value_str)
array_append( & value_str, to_runes(str_fmt_alloc("%v", config.engine_refresh_hz)))
}
ui_parent(input_box)
value_txt : UI_Widget; {
scope(theme_text)
value_txt = ui_text("settings_menu.engine_refresh.input_box.value", to_str_runes_pair(array_to_slice(value_str)))
using value_txt
layout.alignment = {1, 0.0}
layout.text_alignment = {0, 0.5}
layout.anchor.left = 1.0
layout.flags = {.Fixed_Width}
layout.size.min = cast(Vec2) measure_text_size( value_txt.text.str, value_txt.style.font, value_txt.layout.font_size, 0 )
}
}
else {
array_clear( value_str)
array_append( & value_str, to_runes(str_fmt_alloc("%v", config.engine_refresh_hz)))
}
// input_box
{
ui_parent(input_box)
value_txt := ui_text("settings_menu.engine_refresh.refresh_value", to_str_runes_pair(array_to_slice(value_str)))
value_txt.layout.text_alignment = vec2(1, 0.5)
}
spacer := ui_spacer("settings_menu.engine_refresh.end_spacer")
spacer.layout.flags = {.Fixed_Width}
spacer.layout.size.min.x = 10
// input_text := ui_text("settings_menu.engine_refresh", str_fmt_alloc(value_str))
}
// scope(theme_transparent)
// spacer := ui_spacer("settings_menu.engine_refresh.end_spacer")
// spacer.layout.flags = {.Fixed_Height}
// spacer.layout.size.min.y = 10
Min_Zoom:
{
ui_theme_table_row(is_even = true)
hb := ui_hbox(.Left_To_Right, "settings_menu.cam_min_zoom.hb"); { using hb
scope( theme_table_row(is_even = true))
hb := ui_hbox(.Left_To_Right, "settings_menu.cam_min_zoom.hb"); {
using hb
layout.size.min = {0, 30}
layout.flags = {.Fixed_Height}
layout.flags = {.Fixed_Height}
layout.padding = to_ui_layout_side(4)
}
ui_theme_text(); title := ui_text("settings_menu.cam_min_zoom.title", str_intern("Camera: Min Zoom")); { using title
scope(theme_text)
title := ui_text("settings_menu.cam_min_zoom.title", str_intern("Camera: Min Zoom")); {
using title
layout.anchor.ratio.x = 1.0
layout.margins.left = 10
}
}
Max_Zoom:
{
ui_theme_table_row(is_even = false)
hb := ui_hbox(.Left_To_Right, "settings_menu.cam_max_zoom.hb"); { using hb
scope( theme_table_row(is_even = false))
hb := ui_hbox(.Left_To_Right, "settings_menu.cam_max_zoom.hb"); {
using hb
layout.size.min = {0, 30}
layout.flags = {.Fixed_Height}
layout.flags = {.Fixed_Height}
layout.padding = to_ui_layout_side(4)
}
ui_theme_text(); title := ui_text("settings_menu.cam_max_zoom.title", str_intern("Camera: Max Zoom")); { using title
scope(theme_text)
title := ui_text("settings_menu.cam_max_zoom.title", str_intern("Camera: Max Zoom")); {
using title
layout.anchor.ratio.x = 1.0
layout.margins.left = 10
}
}
}
ui_vbox_end(vbox, compute_layout = false )
}
ui_vbox_end(vbox, compute_layout = false )
return
}

View File

@ -4,11 +4,13 @@ package sectr
UI Themes: Comprise of UI_Box's layout & style
Provides presets for themes and their interface for manipulating the combo stacks in UI_State in pairs
The preset UI_Theme structs are populated using theme_<name> procedures.
There are boilerplate procedures that do ui_theme( theme_<name>()) for the user as ui_theme_<name>().
*/
// TODO(Ed): Eventually this will have a configuration wizard, and we'll save the presets
@(deferred_none = ui_theme_pop)
ui_theme_btn :: proc()
theme_button :: proc() -> UI_Theme
{
@static theme : UI_Theme
@static loaded : b32 = false
@ -54,12 +56,10 @@ ui_theme_btn :: proc()
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
return theme
}
@(deferred_none = ui_theme_pop)
ui_theme_drop_down :: proc()
theme_drop_down_btn :: proc() -> UI_Theme
{
@static theme : UI_Theme
@static loaded : b32 = false
@ -106,16 +106,14 @@ ui_theme_drop_down :: proc()
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
return theme
}
@(deferred_none = ui_theme_pop)
ui_theme_table_row :: proc(is_even : bool)
theme_table_row :: proc( is_even : bool ) -> UI_Theme
{
@static theme : UI_Theme
@static loaded : b32 = false
// if ! loaded
if ! loaded
{
app_color := app_color_theme()
table_bg : Color
@ -163,16 +161,14 @@ ui_theme_table_row :: proc(is_even : bool)
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
return theme
}
@(deferred_none = ui_theme_pop)
ui_theme_window_bar :: proc()
theme_window_bar :: proc() -> UI_Theme
{
@static theme : UI_Theme
@static loaded : b32 = false
if ! loaded || true
if ! loaded
{
app_color := app_color_theme()
layout := UI_Layout {
@ -217,12 +213,10 @@ ui_theme_window_bar :: proc()
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
return theme
}
@(deferred_none = ui_theme_pop)
ui_theme_window_bar_title :: proc()
theme_window_bar_title :: proc() -> UI_Theme
{
@static theme : UI_Theme
@static loaded : b32 = false
@ -267,12 +261,10 @@ ui_theme_window_bar_title :: proc()
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
return theme
}
@(deferred_none = ui_theme_pop)
ui_theme_window_bar_btn :: proc()
theme_window_bar_btn :: proc() -> UI_Theme
{
@static theme : UI_Theme
@static loaded : b32 = false
@ -318,12 +310,10 @@ ui_theme_window_bar_btn :: proc()
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
return theme
}
@(deferred_none = ui_theme_pop)
ui_theme_window_panel :: proc()
theme_window_panel :: proc() -> UI_Theme
{
@static theme : UI_Theme
@static loaded : b32 = false
@ -368,12 +358,10 @@ ui_theme_window_panel :: proc()
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
return theme
}
@(deferred_none = ui_theme_pop)
ui_theme_transparent :: proc()
theme_transparent :: proc() -> UI_Theme
{
@static theme : UI_Theme
@static loaded : b32 = false
@ -418,12 +406,10 @@ ui_theme_transparent :: proc()
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
return theme
}
@(deferred_none = ui_theme_pop)
ui_theme_text :: proc()
theme_text :: proc() -> UI_Theme
{
@static theme : UI_Theme
@static loaded : b32 = false
@ -468,6 +454,5 @@ ui_theme_text :: proc()
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
return theme
}

View File

@ -69,6 +69,43 @@ AppColorTheme :: struct {
: Color
}
App_Thm_Dark :: AppColorTheme {
light_limit = Color {185, 185, 185, 255},
dark_limit = Color { 6, 6, 6, 255},
bg = Color {16, 16, 16, 255},
border_default = Color { 54, 54, 54, 255},
btn_bg_default = Color { 32, 32, 32, 255},
btn_bg_hot = Color { 80, 80, 100, 255},
btn_bg_active = Color { 100, 130, 180, 255},
input_box_bg = Color { 20, 20, 20, 255},
input_box_bg_hot = Color { 25, 25, 25, 255},
input_box_bg_active = Color { 15, 15, 15, 255},
resize_hndl_default = Color_Transparent,
resize_hndl_hot = Color { 72, 72, 72, 90},
resize_hndl_active = Color { 88, 88, 88, 90},
table_even_bg_color = Color { 35, 35, 35, 255},
table_odd_bg_color = Color { 30, 30, 30, 255},
text_default = Color {140, 137, 135, 255},
text_hot = Color {210, 210, 210, 255},
text_active = Color {255, 255, 255, 255},
translucent_panel = Color { 30, 30, 30, 50},
window_bar_border = Color{74, 74, 74, 255}, // border_default
window_bar_bg = Color{32, 32, 32, 255},
window_btn_close_bg_hot = Color{65, 45, 45, 255},
window_panel_bg = Color{ 20, 20, 20, 50}, // translucent_panel
window_panel_border = Color{ 84, 84, 84, 255},
}
App_Thm_Dusk :: AppColorTheme {
light_limit = Color {125, 125, 125, 255},
dark_limit = Color { 10, 10, 10, 255},

View File

@ -124,7 +124,7 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
cam_zoom_sensitivity_digital = 0.2
cam_zoom_sensitivity_smooth = 4.0
engine_refresh_hz = 30
engine_refresh_hz = 0
timing_fps_moving_avg_alpha = 0.9
@ -162,7 +162,10 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
// Determining current monitor and setting the target frametime based on it..
monitor_id = rl.GetCurrentMonitor()
monitor_refresh_hz = rl.GetMonitorRefreshRate( monitor_id )
log( str_fmt_tmp( "Set target FPS to: %v", monitor_refresh_hz ) )
if config.engine_refresh_hz == 0 {
config.engine_refresh_hz = uint(monitor_refresh_hz)
}
}
// Basic Font Setup
@ -188,7 +191,7 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
using screen_ui
menu_bar.pos = { -60, 0 }
// menu_bar.pos = Vec2(app_window.extent) * { -1, 1 }
menu_bar.size = {200, 40}
menu_bar.size = {140, 40}
settings_menu.min_size = {250, 200}
}
@ -335,8 +338,9 @@ tick :: proc( host_delta_time : f64, host_delta_ns : Duration ) -> b32
debug.draw_UI_padding_bounds = false
debug.draw_ui_content_bounds = false
config.color_theme = App_Thm_Light
// config.color_theme = App_Thm_Light
// config.color_theme = App_Thm_Dusk
config.color_theme = App_Thm_Dark
should_close = update( host_delta_time )
render()

View File

@ -117,6 +117,10 @@ logger_interface :: proc(
str_to_file_ln( logger.file, to_string(builder) )
}
// TODO(Ed): Use a fixed size block allocation for message formatting used by core_log
// This will prevent stack overflows with the virtual arena debug logs at worst case and not need to do
// some inline arena allocation on-site such as with the memory tracker
log :: proc( msg : string, level := LogLevel.Info, loc := #caller_location ) {
core_log.log( level, msg, location = loc )
}

View File

@ -221,11 +221,6 @@ render_mode_screenspace :: proc ()
render_screen_ui()
fps_msg := str_fmt_tmp( "FPS: %f", fps_avg)
fps_msg_width := measure_text_size( fps_msg, default_font, 12.0, 0.0 ).x
fps_msg_pos := screen_get_corners().top_right - { fps_msg_width, 0 } - { 5, 5 }
debug_draw_text( fps_msg, fps_msg_pos, 12.0, color = rl.GREEN )
debug_text :: proc( format : string, args : ..any )
{
@static draw_text_scratch : [Kilobyte * 64]u8
@ -248,8 +243,13 @@ render_mode_screenspace :: proc ()
debug.draw_debug_text_y += 14
}
// Debug Text
if debug.debug_text_vis
{
fps_msg := str_fmt_tmp( "FPS: %f", fps_avg)
fps_msg_width := measure_text_size( fps_msg, default_font, 12.0, 0.0 ).x
fps_msg_pos := screen_get_corners().top_right - { fps_msg_width, 0 } - { 5, 5 }
debug_draw_text( fps_msg, fps_msg_pos, 12.0, color = rl.GREEN )
// debug_text( "Screen Width : %v", rl.GetScreenWidth () )
// debug_text( "Screen Height: %v", rl.GetScreenHeight() )
// debug_text( "frametime_target_ms : %f ms", frametime_target_ms )
@ -262,61 +262,52 @@ render_mode_screenspace :: proc ()
debug_text( "Replaying Input")
}
// debug_text("Zoom Target: %v", project.workspace.zoom_target)
}
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 (Screen) : %v", input.mouse.pos )
debug_text("Mouse Position (Workspace View): %v", screen_to_ws_view_pos(input.mouse.pos) )
rl.DrawCircleV( input.mouse.raw_pos, 10, Color_White_A125 )
rl.DrawCircleV( screen_to_render_pos(input.mouse.pos), 2, Color_BG )
}
ui := & project.workspace.ui
if false
{
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 )
if hot_box != nil {
debug_text("Worksapce Hot Box : %v", hot_box.label.str )
debug_text("Workspace Hot Range2: %v", hot_box.computed.bounds.pts)
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 (Screen) : %v", input.mouse.pos )
debug_text("Mouse Position (Workspace View): %v", screen_to_ws_view_pos(input.mouse.pos) )
rl.DrawCircleV( input.mouse.raw_pos, 10, Color_White_A125 )
rl.DrawCircleV( screen_to_render_pos(input.mouse.pos), 2, Color_BG )
}
if active_box != nil{
debug_text("Workspace Active Box: %v", active_box.label.str )
ui := & project.workspace.ui
if true
{
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 )
if hot_box != nil {
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("Workspace Active Box: %v", active_box.label.str )
}
}
}
ui = & screen_ui
ui = & screen_ui
if true
{
debug_text("Box Count: %v", ui.built_box_count )
if true
{
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)
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 )
}
}
if active_box != nil{
debug_text("Active Box: %v", active_box.label.str )
}
}
view := view_get_bounds()
debug.draw_debug_text_y = 14
// Define the triangle vertices and colors
vertices := []f32{
// Positions // Colors (RGBA)
-0.5, -0.5, 0.0, 1.0, 0.0, 0.0, 1.0, // Vertex 1: Red
0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 1.0, // Vertex 2: Green
0.0, 0.5, 0.0, 0.0, 0.0, 1.0, 1.0 // Vertex 3: Blue
debug.draw_debug_text_y = 14
}
}

View File

@ -17,7 +17,8 @@ DebugActions :: struct {
record_replay : b32,
play_replay : b32,
show_mouse_pos : b32,
show_debug_text : b32,
show_mouse_pos : b32,
mouse_select : b32,
@ -48,7 +49,8 @@ poll_debug_actions :: proc( actions : ^ DebugActions, input : ^ InputState )
record_replay = base_replay_bind && keyboard.right_shift.ended_down
play_replay = base_replay_bind && ! keyboard.right_shift.ended_down
show_mouse_pos = keyboard.right_alt.ended_down && pressed(keyboard.M)
show_debug_text = keyboard.right_alt.ended_down && pressed(keyboard.T)
show_mouse_pos = keyboard.right_alt.ended_down && pressed(keyboard.M)
mouse_select = pressed(mouse.left)
@ -146,6 +148,9 @@ update :: proc( delta_time : f64 ) -> b32
if debug_actions.show_mouse_pos {
debug.mouse_vis = !debug.mouse_vis
}
if debug_actions.show_debug_text {
debug.debug_text_vis = !debug.debug_text_vis
}
//region 2D Camera Manual Nav
// TODO(Ed): This should be per workspace view
@ -223,17 +228,17 @@ update :: proc( delta_time : f64 ) -> b32
// size = range2( { 1000, 1000 }, {}),
// padding = { 20, 20, 20, 20 }
}
ui_layout( default_layout )
scope( default_layout )
frame_style_default := UI_Style {
bg_color = Color_BG_TextBox,
font = default_font,
text_color = Color_White,
}
frame_theme := to_ui_style_combo(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
ui_style( frame_theme )
frame_style := to_ui_style_combo(frame_style_default)
frame_style.disabled.bg_color = Color_Frame_Disabled
frame_style.hot. bg_color = Color_Frame_Hover
frame_style.active. bg_color = Color_Frame_Select
scope( frame_style )
config.ui_resize_border_width = 2.5
// test_hover_n_click()

View File

@ -68,7 +68,7 @@ array_init_reserve :: proc
result.header = cast( ^ArrayHeader(Type)) raw_mem
result.backing = allocator
// result.dbg_name = dbg_name
result.dbg_name = dbg_name
result.fixed_cap = fixed_cap
result.capacity = capacity
result.data = cast( [^]Type ) (cast( [^]ArrayHeader(Type)) result.header)[ 1:]
@ -123,10 +123,6 @@ array_append_slice :: proc( using self : ^Array( $ Type ), items : []Type ) -> A
}
}
// Note(Ed) : Original code from gencpp
// libc.memcpy( ptr_offset(data, num), raw_data(items), len(items) * size_of(Type) )
// TODO(Ed) : VERIFY VIA DEBUG THIS COPY IS FINE.
target := ptr_offset( data, num )
copy( slice_ptr(target, int(capacity - num)), items )

View File

@ -214,6 +214,15 @@ pressed :: proc {
push :: proc {
stack_push,
stack_allocator_push,
ui_layout_push_layout,
ui_layout_push_combo,
ui_style_push_style,
ui_style_push_combo,
ui_theme_push_via_proc,
ui_theme_push_via_theme,
}
rotor3 :: proc {
@ -242,6 +251,19 @@ inverse_sqrt :: proc {
inverse_sqrt_f32,
}
scope :: proc {
ui_layout_scope_via_layout,
ui_layout_scope_via_combo,
ui_style_scope_via_style,
ui_style_scope_via_combo,
ui_theme_scope_via_layout_style,
ui_theme_scope_via_combos,
ui_theme_scope_via_proc,
ui_theme_scope_via_theme,
}
sub :: proc {
sub_point3,
sub_range2,
@ -302,12 +324,12 @@ ui_floating :: proc {
ui_layout_push :: proc {
ui_layout_push_layout,
ui_layout_push_theme,
ui_layout_push_combo,
}
ui_layout :: proc {
ui_layout_via_layout,
ui_layout_via_combo,
ui_layout_scope_via_layout,
ui_layout_scope_via_combo,
}
ui_style_push :: proc {
@ -315,15 +337,20 @@ ui_style_push :: proc {
ui_style_push_combo,
}
ui_style :: proc {
ui_style_via_style,
ui_style_via_combo,
ui_style_scope :: proc {
ui_style_scope_via_style,
ui_style_scope_via_combo,
}
ui_theme :: proc {
ui_theme_via_layout_style,
ui_theme_via_combos,
ui_theme_via_theme,
ui_theme_push :: proc {
ui_theme_push_via_proc,
ui_theme_push_via_theme,
}
ui_theme_scope :: proc {
ui_theme_scope_via_layout_style,
ui_theme_scope_via_combos,
ui_theme_scope_via_theme,
}
wedge :: proc {

View File

@ -1,13 +1,12 @@
/*
This is a quick and dirty string table.
IT uses the HMapZPL for the hashtable of strings, and the string's content is stored in a dedicated slab.
Future Plans (IF needed for performance):
The goal is to eventually swap out the slab with possilby a dedicated growing vmem arena for the strings.
The table would be swapped with a table stored in the general slab and uses either linear probing or open addressing
String Intering Table using its own dedicated slab & chained hashtable
If linear probing, the hash node list per table bucket is store with the strigns in the same arena.
If open addressing, we just keep the open addressed array of node slots in the general slab (but hopefully better perf)
TODO(Ed): Move the string cache to its own virtual arena?
Its going to be used heavily and we can better utilize memory that way.
The arena can deal with alignment just fine or we can pad in a min amount per string.
*/
package sectr
@ -19,6 +18,10 @@ import "core:strings"
StringKey :: distinct u64
RunesCached :: []rune
// TODO(Ed): There doesn't seem to be a need for caching the runes.
// It seems like no one has had a bottleneck just iterating through the code points on demand when needed.
// So we should problably scrap storing them that way.
StrRunesPair :: struct {
str : string,
runes : []rune,
@ -36,9 +39,10 @@ str_cache_init :: proc( /*allocator : Allocator*/ ) -> ( cache : StringCache ) {
policy : SlabPolicy
policy_ptr := & policy
push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 16, alignment })
push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 32, alignment })
push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 64, alignment })
// push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 8, alignment })
// push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 16, alignment })
push( policy_ptr, SlabSizeClass { 128 * Kilobyte, 32, alignment })
push( policy_ptr, SlabSizeClass { 128 * Kilobyte, 64, alignment })
push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 128, alignment })
push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 256, alignment })
push( policy_ptr, SlabSizeClass { 64 * Kilobyte, 512, alignment })
@ -69,9 +73,7 @@ str_cache_init :: proc( /*allocator : Allocator*/ ) -> ( 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
str_intern :: proc( content : string ) -> StrRunesPair
{
// profile(#procedure)
cache := & get_state().string_cache
@ -110,6 +112,10 @@ str_intern :: proc(
return (result ^)
}
str_intern_fmt :: #force_inline proc( format : string, args : ..any, allocator := context.allocator ) -> StrRunesPair {
return str_intern(str_fmt_alloc(format, args, allocator = allocator))
}
// runes_intern :: proc( content : []rune ) -> StrRunesPair
// {
// cache := get_state().string_cache

View File

@ -91,7 +91,7 @@ PWS_ParseError :: struct {
PWS_ParseError_Max :: 32
PWS_TokenArray_ReserveSize :: 128
PWS_NodeArray_ReserveSize :: 32 * Kilobyte
PWS_LineArray_ReserveSize :: 32
PWS_LineArray_ReserveSize :: 32 * Kilobyte
// TODO(Ed) : The ast arrays should be handled by a slab allocator dedicated to PWS_ASTs
// This can grow in undeterministic ways, persistent will get very polluted otherwise.

View File

@ -113,8 +113,7 @@ ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box)
curr_box.links = {}
curr_box.num_children = 0
// If there is a parent, setup the relevant references
parent := stack_peek( & parent_stack )
parent := ui_parent_peek()
if parent != nil
{
dll_full_push_back( parent, curr_box, nil )

View File

@ -160,10 +160,10 @@ ui_layout_peek :: #force_inline proc() -> UI_LayoutCombo { return stack_peek( &
ui_layout_ref :: #force_inline proc() -> ^UI_LayoutCombo { return stack_peek_ref( & get_state().ui_context.layout_combo_stack) }
ui_layout_push_layout :: #force_inline proc( layout : UI_Layout ) { push( & get_state().ui_context.layout_combo_stack, to_ui_layout_combo(layout)) }
ui_layout_push_theme :: #force_inline proc( combo : UI_LayoutCombo ) { push( & get_state().ui_context.layout_combo_stack, combo ) }
ui_layout_push_combo :: #force_inline proc( combo : UI_LayoutCombo ) { push( & get_state().ui_context.layout_combo_stack, combo ) }
ui_layout_pop :: #force_inline proc() { pop( & get_state().ui_context.layout_combo_stack ) }
@(deferred_none = ui_layout_pop) ui_layout_via_layout :: #force_inline proc( layout : UI_Layout ) { ui_layout_push( layout) }
@(deferred_none = ui_layout_pop) ui_layout_via_combo :: #force_inline proc( combo : UI_LayoutCombo ) { ui_layout_push( combo) }
@(deferred_none = ui_layout_pop) ui_layout_scope_via_layout :: #force_inline proc( layout : UI_Layout ) { ui_layout_push( layout) }
@(deferred_none = ui_layout_pop) ui_layout_scope_via_combo :: #force_inline proc( combo : UI_LayoutCombo ) { ui_layout_push( combo) }
ui_set_layout :: #force_inline proc( layout : UI_Layout, preset : UI_StylePreset ) { stack_peek_ref( & get_state().ui_context.layout_combo_stack).array[preset] = layout }

View File

@ -274,6 +274,8 @@ ui_key_from_string :: #force_inline proc "contextless" ( value : string ) -> UI_
ui_parent_push :: #force_inline proc( ui : ^ UI_Box ) { stack_push( & ui_context().parent_stack, ui ) }
ui_parent_pop :: #force_inline proc() { stack_pop( & get_state().ui_context.parent_stack ) }
ui_parent_peek :: #force_inline proc() -> ^UI_Box { return stack_peek( & ui_context().parent_stack )}
@(deferred_none = ui_parent_pop)
ui_parent :: #force_inline proc( ui : ^UI_Box) { ui_parent_push( ui ) }

View File

@ -66,7 +66,7 @@ ui_style_push_style :: #force_inline proc( style : UI_Style ) { push( & get
ui_style_push_combo :: #force_inline proc( combo : UI_StyleCombo ) { push( & get_state().ui_context.style_combo_stack, combo ) }
ui_style_pop :: #force_inline proc() { pop( & get_state().ui_context.style_combo_stack ) }
@(deferred_none = ui_style_pop) ui_style_via_style :: #force_inline proc( style : UI_Style ) { ui_style_push( style) }
@(deferred_none = ui_style_pop) ui_style_via_combo :: #force_inline proc( combo : UI_StyleCombo ) { ui_style_push( combo) }
@(deferred_none = ui_style_pop) ui_style_scope_via_style :: #force_inline proc( style : UI_Style ) { ui_style_push( style) }
@(deferred_none = ui_style_pop) ui_style_scope_via_combo :: #force_inline proc( combo : UI_StyleCombo ) { ui_style_push( combo) }
ui_style_set :: #force_inline proc ( style : UI_Style, preset : UI_StylePreset ) { stack_peek_ref( & get_state().ui_context.style_combo_stack ).array[preset] = style }

View File

@ -10,28 +10,36 @@ UI_Theme :: struct {
style : UI_StyleCombo,
}
ui_theme_push_via_proc :: #force_inline proc( procedure : #type proc() -> UI_Theme ) { ui_theme_push(procedure()) }
ui_theme_push_via_theme ::#force_inline proc( theme : UI_Theme ) {
ui_layout_push( theme.layout )
ui_style_push( theme.style )
}
ui_theme_pop :: #force_inline proc() {
ui_layout_pop()
ui_style_pop()
}
@(deferred_none = ui_theme_pop)
ui_theme_via_layout_style :: #force_inline proc( layout : UI_Layout, style : UI_Style ) {
ui_theme_scope_via_layout_style :: #force_inline proc( layout : UI_Layout, style : UI_Style ) {
using ui := get_state().ui_context
ui_layout_push( layout )
ui_style_push( style )
}
@(deferred_none = ui_theme_pop)
ui_theme_via_combos :: #force_inline proc( layout : UI_LayoutCombo, style : UI_StyleCombo ) {
ui_theme_scope_via_combos :: #force_inline proc( layout : UI_LayoutCombo, style : UI_StyleCombo ) {
using ui := get_state().ui_context
ui_layout_push( layout )
ui_style_push( style )
}
@(deferred_none = ui_theme_pop)
ui_theme_via_theme :: #force_inline proc( theme : UI_Theme ) {
ui_theme_scope_via_proc :: #force_inline proc( procedure : #type proc() -> UI_Theme ) { ui_theme_push(procedure()) }
@(deferred_none = ui_theme_pop)
ui_theme_scope_via_theme :: #force_inline proc( theme : UI_Theme ) {
using ui := get_state().ui_context
ui_layout_push( theme.layout )
ui_style_push( theme.style )
ui_theme_push(theme)
}

View File

@ -1,6 +1,7 @@
package sectr
import "base:runtime"
import lalg "core:math/linalg"
/*
Widget Layout Ops
@ -35,6 +36,7 @@ ui_layout_children_horizontally :: proc( container : ^UI_Box, direction : UI_Lay
continue
}
size_req_children += size.min.x
total_stretch_ratio += anchor.ratio.x
}
@ -48,14 +50,15 @@ ui_layout_children_horizontally :: proc( container : ^UI_Box, direction : UI_Lay
space_allocated = size.min.x * container_height
}
else if ! (.Fixed_Width in flags) {
size.min.x = anchor.ratio.x * (1 / total_stretch_ratio) * avail_flex_space
space_allocated = size.min.x
potential_size := anchor.ratio.x * (1 / total_stretch_ratio) * avail_flex_space
space_allocated = lalg.max(potential_size, size.min.x)
size.min.x = space_allocated
}
else {
space_allocated = size.min.x
}
space_allocated -= child.layout.margins.left - child.layout.margins.right
size.min.x -= child.layout.margins.left - child.layout.margins.right
space_allocated -= margins.left - margins.right
size.min.x -= margins.left - margins.right
flags |= {.Fixed_Width}
return
}
@ -67,7 +70,6 @@ ui_layout_children_horizontally :: proc( container : ^UI_Box, direction : UI_Lay
using child.layout
child_width := allocate_space(child, total_stretch_ratio, avail_flex_space, container_height)
anchor = range2({0, 0}, {0, 0})
width : f32
pos.x = space_used
space_used += child_width + child.layout.margins.left + child.layout.margins.right
}
@ -76,7 +78,6 @@ ui_layout_children_horizontally :: proc( container : ^UI_Box, direction : UI_Lay
using child.layout
child_width := allocate_space(child, total_stretch_ratio, avail_flex_space, container_height)
anchor = range2({0, 0}, {0, 0})
width : f32
pos.x = space_used
space_used += child_width + child.layout.margins.left + child.layout.margins.right
}
@ -92,6 +93,7 @@ ui_layout_children_vertically :: proc( container : ^UI_Box, direction : UI_Layou
else {
container_height = container.computed.content.max.y - container.computed.content.min.y
}
container_width := container.computed.content.max.x - container.computed.content.min.x
// do layout calculations for the children
total_stretch_ratio : f32 = 0.0
@ -99,33 +101,42 @@ ui_layout_children_vertically :: proc( container : ^UI_Box, direction : UI_Layou
for child := container.first; child != nil; child = child.next
{
using child.layout
scaled_width_by_height : b32 = b32(.Scale_Width_By_Height_Ratio in flags)
scaled_height_by_width : b32 = b32(.Scale_Height_By_Width_Ratio in flags)
if scaled_height_by_width {
size_req_children += size.min.y * container_width
continue
}
if .Fixed_Height in flags
{
if scaled_width_by_height {
width := size.max.x != 0 ? size.max.x : container_height
height := width * size.min.y
size_req_children += height
continue
}
size_req_children += size.min.y
continue
}
size_req_children += size.min.y
total_stretch_ratio += anchor.ratio.y
}
avail_flex_space := container_height - size_req_children
allocate_space :: proc( child : ^UI_Box, total_stretch_ratio, avail_flex_space : f32 )
allocate_space :: proc( child : ^UI_Box, total_stretch_ratio, avail_flex_space, container_width : f32 ) -> (space_allocated : f32)
{
using child.layout
if ! (.Fixed_Height in flags) {
size.min.y = (anchor.ratio.y * (1 / total_stretch_ratio) * avail_flex_space)
if .Scale_Height_By_Width_Ratio in flags {
size.min.x = container_width
space_allocated = size.min.y * container_width
}
if ! (.Fixed_Height in flags) {
potential_size := (anchor.ratio.y * (1 / total_stretch_ratio) * avail_flex_space)
space_allocated = lalg.max(potential_size, size.min.y)
size.min.y = space_allocated
}
else {
space_allocated = size.min.y
}
space_allocated -= margins.top - margins.bottom
size.min.y -= margins.top - margins.bottom
flags |= {.Fixed_Height}
return
}
space_used : f32 = 0.0
@ -133,21 +144,19 @@ ui_layout_children_vertically :: proc( container : ^UI_Box, direction : UI_Layou
{
case .Bottom_To_Top:
for child := container.last; child != nil; child = child.prev {
allocate_space(child, total_stretch_ratio, avail_flex_space)
using child.layout
anchor = range2({0,0}, {0, 0})
pos.y = -space_used
space_used += size.min.y + child.layout.margins.top + child.layout.margins.bottom
size.min.x = container.computed.content.max.x + container.computed.content.min.x
child_height := allocate_space(child, total_stretch_ratio, avail_flex_space, container_width)
anchor = range2({0,0}, {0, 0})
pos.y = -space_used
space_used += child_height + child.layout.margins.top + child.layout.margins.bottom
}
case .Top_To_Bottom:
for child := container.first; child != nil; child = child.next {
allocate_space(child, total_stretch_ratio, avail_flex_space)
using child.layout
child_height := allocate_space(child, total_stretch_ratio, avail_flex_space, container_width)
anchor = range2({0, 0}, {0, 0})
pos.y = -space_used
space_used += size.min.y + child.layout.margins.top + child.layout.margins.bottom
size.min.x = container.computed.content.max.x - container.computed.content.min.x
space_used += child_height + child.layout.margins.top + child.layout.margins.bottom
}
}
}

View File

@ -8,6 +8,7 @@ test_hover_n_click :: proc()
state := get_state(); using state
first_btn := ui_button( "FIRST BOX!" )
first_btn.layout.size.min = {1000, 1000}
if first_btn.left_clicked || debug.frame_2_created {
debug.frame_2_created = true
@ -37,8 +38,8 @@ test_draggable :: proc()
pos = { 0, 0 },
size = range2({ 200, 200 }, {}),
}
ui_layout( draggable_layout )
ui_style( UI_Style {
scope( draggable_layout )
scope( UI_Style {
corner_radii = { 0.3, 0.3, 0.3, 0.3 },
})
@ -82,10 +83,10 @@ test_parenting :: proc( default_layout : ^UI_Layout, frame_style_default : ^UI_S
.Fixed_Width, .Fixed_Height,
.Origin_At_Anchor_Center
}
ui_layout(parent_layout)
scope(parent_layout)
parent_style := frame_style_default ^
ui_style(parent_style)
scope(parent_style)
parent := ui_widget( "Parent", { .Mouse_Clickable })
ui_parent_push(parent)
@ -107,7 +108,7 @@ test_parenting :: proc( default_layout : ^UI_Layout, frame_style_default : ^UI_S
child_layout := default_layout ^
child_layout.size = range2({ 100, 100 }, { 0, 0 })
child_layout.alignment = { 0.0, 0.0 }
child_layout.alignment = { 1.0, 0.0 }
// child_layout.margins = { 20, 20, 20, 20 }
child_layout.padding = { 5, 5, 5, 5 }
// child_layout.anchor = range2({ 0.2, 0.1 }, { 0.1, 0.15 })
@ -119,7 +120,7 @@ test_parenting :: proc( default_layout : ^UI_Layout, frame_style_default : ^UI_S
child_style := frame_style_default ^
child_style.bg_color = Color_GreyRed
ui_theme(child_layout, child_style)
scope(child_layout, child_style)
child := ui_widget( "Child", { .Mouse_Clickable })
ui_parent_pop()
}
@ -174,7 +175,7 @@ test_whitespace_ast :: proc( default_layout : ^UI_Layout, frame_style_default :
text_style_combo.disabled.bg_color = Color_Frame_Disabled
text_style_combo.hot.bg_color = Color_Frame_Hover
text_style_combo.active.bg_color = Color_Frame_Select
ui_theme( text_layout, text_style )
scope( text_layout, text_style )
alloc_error : AllocatorError; success : bool
// debug.lorem_content, success = os.read_entire_file( debug.path_lorem, frame_allocator() )
@ -216,7 +217,7 @@ test_whitespace_ast :: proc( default_layout : ^UI_Layout, frame_style_default :
chunk_layout.flags = { .Fixed_Position_X, .Size_To_Text }
chunk_style := text_style
ui_theme( to_ui_layout_combo(chunk_layout), to_ui_style_combo(chunk_style) )
scope( chunk_layout, chunk_style )
head := line.first
for ; head != nil;
@ -289,7 +290,10 @@ test_whitespace_ast :: proc( default_layout : ^UI_Layout, frame_style_default :
text_layout.pos.y += size_range2(line_hbox.computed.bounds).y
}
else {
text_layout.pos.y += size_range2( (& widgets.data[ widgets.num - 1 ]).computed.bounds ).y
widget := & widgets.data[ widgets.num - 1 ]
if widget.box != nil {
text_layout.pos.y += size_range2( widget.computed.bounds ).y
}
}
line_id += 1

View File

@ -3,6 +3,9 @@ package sectr
import "base:runtime"
import lalg "core:math/linalg"
// Problably cursed way to setup a 'scope' for a widget
ui_build :: #force_inline proc( captures : $Type, $maker : #type proc(captures : Type) -> $ReturnType ) -> ReturnType { return maker(captures) }
UI_Widget :: struct {
using box : ^UI_Box,
using signal : UI_Signal,
@ -23,6 +26,80 @@ ui_button :: proc( label : string, flags : UI_BoxFlags = {} ) -> (btn : UI_Widge
return
}
#region("Drop Down")
/* TODO(Ed): Don't feel very good about the abstraction...
*/
UI_DropDown :: struct {
btn : UI_Widget,
title : UI_Widget,
vbox : UI_VBox,
is_open : bool,
}
@(deferred_out = ui_drop_down_end_auto)
ui_drop_down :: proc( drop_down : ^UI_DropDown, label : string, title_text : StrRunesPair,
direction := UI_LayoutDirectionY.Top_To_Bottom,
btn_flags := UI_BoxFlags{},
vb_flags := UI_BoxFlags{},
vb_compute_layout := true,
btn_theme : ^UI_Theme = nil,
title_theme : ^UI_Theme = nil
) -> (deferred : ^UI_DropDown)
{
deferred = drop_down
ui_drop_down_begin(drop_down, label, title_text, direction, btn_flags, vb_flags, btn_theme, title_theme)
if ! drop_down.is_open do return
ui_parent_push(drop_down.vbox)
return
}
// Its assumed that the drop down has a vertical box parent already pushed
ui_drop_down_begin :: proc( drop_down : ^UI_DropDown, label : string, title_text : StrRunesPair,
direction := UI_LayoutDirectionY.Top_To_Bottom,
btn_flags := UI_BoxFlags{},
vb_flags := UI_BoxFlags{},
btn_theme : ^UI_Theme = nil,
title_theme : ^UI_Theme = nil,
vb_compute_layout := true )
{
using drop_down
if btn_theme == nil do push(theme_drop_down_btn)
else do push(btn_theme ^)
defer ui_theme_pop()
btn = ui_button( str_intern_fmt("%s.btn", label).str );
{
btn.layout.padding.left = 4
ui_parent(btn)
if title_theme == nil do push(theme_text)
else do push(title_theme ^)
defer ui_theme_pop()
title = ui_text( str_intern_fmt("%s.btn.title", label).str, title_text)
}
if btn.pressed {
is_open = !is_open
}
if is_open == false do return
scope(theme_transparent)
vbox = ui_vbox_begin( direction, str_intern_fmt("%v : vbox", label).str, compute_layout = vb_compute_layout )
vbox.layout.anchor.ratio.y = 1.0
}
ui_drop_down_end :: proc( drop_down : ^UI_DropDown ) {
if ! drop_down.is_open do return
ui_vbox_end(drop_down.vbox)
}
ui_drop_down_end_auto :: proc( drop_down : ^UI_DropDown) {
if ! drop_down.is_open do return
ui_vbox_end(drop_down.vbox, compute_layout = true)
ui_parent_pop()
}
#endregion("Drop Down")
#region("Horizontal Box")
/*
Horizontal Boxes automatically manage a collection of widgets and
@ -39,13 +116,11 @@ 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.
*/
// Horizontal Widget
UI_HBox :: struct {
using widget : UI_Widget,
direction : UI_LayoutDirectionX,
}
// Boilerplate creation
ui_hbox_begin :: proc( direction : UI_LayoutDirectionX, label : string, flags : UI_BoxFlags = {} ) -> (hbox : UI_HBox) {
// profile(#procedure)
hbox.direction = direction
@ -171,7 +246,6 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2,
handle_corner_tl : UI_Widget
handle_corner_br : UI_Widget
handle_corner_bl : UI_Widget
ui_parent(parent)
@(deferred_none = ui_theme_pop)
theme_handle :: proc( base : ^UI_Theme, margins, size : Vec2, flags : UI_LayoutFlags = {})
@ -247,50 +321,52 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2,
}
context.user_ptr = & parent.label
#region("Handle & Corner construction")
theme_handle( theme, {handle_width, 0}, {handle_width,0})
if left {
handle_left = ui_widget(name("resize_handle_left"), flags )
handle_left.layout.anchor.left = 0
handle_left.layout.anchor.right = 1
handle_left.layout.alignment = {1, 0}
Handle_Construction:
{
ui_parent(parent)
theme_handle( theme, {handle_width, 0}, {handle_width,0})
if left {
handle_left = ui_widget(name("resize_handle_left"), flags )
handle_left.layout.anchor.left = 0
handle_left.layout.anchor.right = 1
handle_left.layout.alignment = {1, 0}
}
if right {
handle_right = ui_widget(name("resize_handle_right"), flags )
handle_right.layout.anchor.left = 1
}
theme_handle( theme, {0, handle_width}, {0, handle_width})
if top {
handle_top = ui_widget(name("resize_handle_top"), flags )
handle_top.layout.anchor.bottom = 1
handle_top.layout.alignment = {0, -1}
}
if bottom {
handle_bottom = ui_widget("resize_handle_bottom", flags)
handle_bottom.layout.anchor.top = 1
handle_bottom.layout.alignment = { 0, 0 }
}
theme_handle( theme, {0,0}, {handle_width, handle_width}, {.Fixed_Width, .Fixed_Height} )
if corner_tl {
handle_corner_tl = ui_widget(name("corner_top_left"), flags)
handle_corner_tl.layout.alignment = {1, -1}
}
if corner_tr {
handle_corner_tr = ui_widget(name("corner_top_right"), flags)
handle_corner_tr.layout.anchor = range2({1, 0}, {})
handle_corner_tr.layout.alignment = {0, -1}
}
if corner_bl {
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("corner_bottom_right", flags)
handle_corner_br.layout.anchor = range2({1, 0}, {0, 1})
handle_corner_br.layout.alignment = {0, 0}
}
}
if right {
handle_right = ui_widget(name("resize_handle_right"), flags )
handle_right.layout.anchor.left = 1
}
theme_handle( theme, {0, handle_width}, {0, handle_width})
if top {
handle_top = ui_widget(name("resize_handle_top"), flags )
handle_top.layout.anchor.bottom = 1
handle_top.layout.alignment = {0, -1}
}
if bottom {
handle_bottom = ui_widget("resize_handle_bottom", flags)
handle_bottom.layout.anchor.top = 1
handle_bottom.layout.alignment = { 0, 0 }
}
theme_handle( theme, {0,0}, {handle_width, handle_width}, {.Fixed_Width, .Fixed_Height} )
if corner_tl {
handle_corner_tl = ui_widget(name("corner_top_left"), flags)
handle_corner_tl.layout.alignment = {1, -1}
}
if corner_tr {
handle_corner_tr = ui_widget(name("corner_top_right"), flags)
handle_corner_tr.layout.anchor = range2({1, 0}, {})
handle_corner_tr.layout.alignment = {0, -1}
}
if corner_bl {
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("corner_bottom_right", flags)
handle_corner_br.layout.anchor = range2({1, 0}, {0, 1})
handle_corner_br.layout.alignment = {0, 0}
}
#endregion("Handle & Corner construction")
process_handle_drag :: #force_inline proc ( handle : ^UI_Widget,
direction : Vec2,
@ -319,8 +395,6 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2,
shift_changed := (left_shift_held != prev_left_shift_held)
need_to_change_alignment_and_pos := pressed || shift_changed
if active
{
if pressed
@ -379,8 +453,6 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2,
was_dragging = false
start_size = 0
}
// text = active_context.root.label
// style.text_color = Color_White
prev_left_shift_held = handle.left_shift_held
prev_alignment = align_adjsutment
@ -433,14 +505,13 @@ UI_ScrollBox :: struct {
}
ui_scroll_box :: proc( label : string, flags : UI_BoxFlags ) -> (scroll_box : UI_ScrollBox) {
fatal("NOT IMPLEMENTED")
return
}
// ui_scrollable_view( )
#region("Text")
ui_text :: proc( label : string, content : StrRunesPair, flags : UI_BoxFlags = {} ) -> UI_Widget
{
// profile(#procedure)
@ -510,7 +581,6 @@ UI_VBox :: struct {
direction : UI_LayoutDirectionY,
}
// Boilerplate creation
ui_vbox_begin :: proc( direction : UI_LayoutDirectionY, label : string, flags : UI_BoxFlags = {}, compute_layout := false ) -> (vbox : UI_VBox) {
// profile(#procedure)
vbox.direction = direction

View File

@ -19,7 +19,7 @@
"enable_fake_methods": true,
"enable_format": false,
"enable_hover": true,
"enable_semantic_tokens": true,
"enable_semantic_tokens": false,
"enable_snippets": false,
"enable_references": true,
"thread_pool_count": 10,