WIP: Stuff related to working on the settings menu + more

Moved core ui to its own folder.
Worked on theming (proper light and dark theme)
Began to work on the scroll box widget and input box constructions

I added back a script for flattening the codebase: gen_flattened_codebase.ps1
This commit is contained in:
Edward R. Gonzalez 2024-05-19 01:21:51 -04:00
parent ddff1fcae6
commit b137bc542c
30 changed files with 1420 additions and 664 deletions

2
.gitignore vendored
View File

@ -4,4 +4,4 @@ build/**
logs
.ark
logs*.zip
code_compiler_staged
code_flattened

View File

@ -52,12 +52,13 @@ ui_screen_menu_bar :: proc( captures : rawptr = nil ) -> (should_raise : b32 = f
{
@static theme : UI_Theme
@static loaded : b32 = false
if true && ! loaded
if ! loaded
{
app_color := app_color_theme()
layout := UI_Layout {
flags = {},
anchor = range2({},{}),
alignment = {0.5, 0.5},
// alignment = UI_Align_Presets.text_centered,
text_alignment = {0.0, 1.5},
font_size = 12,
margins = {0, 0, 0, 0},
@ -67,34 +68,30 @@ ui_screen_menu_bar :: proc( captures : rawptr = nil ) -> (should_raise : b32 = f
size = range2({},{})
}
style := UI_Style {
bg_color = Color_ThmDark_BG,
border_color = Color_ThmDark_Border_Default,
bg_color = app_color.bg,
border_color = app_color.border_default,
corner_radii = {},
blur_size = 0,
font = get_state().default_font,
text_color = Color_ThmDark_Text_Default,
text_color = app_color.text_default,
cursor = {},
}
// loaded = true
layout_combo := to_ui_layout_combo(layout)
style_combo := to_ui_style_combo(style)
{
Hot: {
using layout_combo.hot
using style_combo.hot
bg_color = Color_ThmDark_Btn_BG_Hot
text_color = Color_ThmDark_Text_Hot
bg_color = app_color.btn_bg_hot
text_color = app_color.text_hot
}
{
Active: {
using layout_combo.active
using style_combo.active
bg_color = Color_ThmDark_Btn_BG_Active
text_color = Color_ThmDark_Text_Active
}
theme = UI_Theme {
layout_combo, style_combo
bg_color = app_color.btn_bg_active
text_color = app_color.text_active
}
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
@ -105,7 +102,8 @@ ui_screen_menu_bar :: proc( captures : rawptr = nil ) -> (should_raise : b32 = f
{
using screen_ui.menu_bar
ui_theme_app_menu_bar_default()
container = ui_hbox( .Left_To_Right, "Menu Bar" )
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}
@ -114,7 +112,7 @@ ui_screen_menu_bar :: proc( captures : rawptr = nil ) -> (should_raise : b32 = f
text = str_intern("menu_bar")
}
ui_theme_btn_default()
ui_theme_btn()
move_box := ui_button("Move Box");
{
using move_box
@ -122,7 +120,7 @@ ui_screen_menu_bar :: proc( captures : rawptr = nil ) -> (should_raise : b32 = f
pos += input.mouse.delta
should_raise = true
}
layout.anchor.ratio.x = 0.4
layout.anchor.ratio.x = 1.0
}
spacer := ui_spacer("Menu Bar: Move Spacer")
@ -135,17 +133,18 @@ ui_screen_menu_bar :: proc( captures : rawptr = nil ) -> (should_raise : b32 = f
using settings_btn
text = str_intern("Settings")
layout.flags = {
// .Scale_Width_By_Height_Ratio,
.Fixed_Width
.Scale_Width_By_Height_Ratio,
// .Fixed_Width
}
layout.size.min.x = 100
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 = 1.0
spacer.layout.anchor.ratio.x = 2.0
ui_hbox_end(container, compute_layout = false)
}
return
}
@ -156,22 +155,18 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b
using state := get_state()
using state.screen_ui
if ! settings_menu.is_open do return
app_color := app_color_theme()
using settings_menu
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_transparent()
container = ui_widget("Settings Menu", {})
{
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 }
style.bg_color = Color_ThmDark_Translucent_Panel
style.border_color = { 0, 0, 0, 200 }
layout.alignment = {0.0, 0.0}
layout.border_width = 1.0
layout.pos = pos
layout.size = range2( size, {})
layout.flags = { .Fixed_Width, .Fixed_Height, .Fixed_Position_X, .Fixed_Position_Y, .Origin_At_Anchor_Center }
layout.pos = pos
layout.size = range2( size, {})
}
ui_parent(container)
if settings_menu.is_maximized {
@ -179,54 +174,27 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b
layout.flags = {.Origin_At_Anchor_Center }
layout.pos = {}
}
should_raise |= ui_resizable_handles( & container, & pos, & size/*, compute_layout = true*/)
// ui_box_compute_layout(container)
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_layout( UI_Layout {
// font_size = 16,
// alignment = {0, 1},
})
ui_style( UI_Style {
// bg_color = Color_Transparent,
font = default_font,
text_color = Color_White,
})
ui_style_ref().hot.bg_color = Color_Blue
frame_bar := ui_hbox_begin(.Left_To_Right, "Settings Menu: Frame Bar", { .Mouse_Clickable, .Focusable, .Click_To_Focus })
ui_theme_window_bar()
frame_bar := ui_hbox_begin(.Left_To_Right, "Settings Menu: Frame Bar", { .Mouse_Clickable })
{
frame_bar.layout.flags = {.Fixed_Height}
frame_bar.layout.size.min.y = 50
ui_parent(frame_bar)
ui_layout( UI_Layout {
font_size = 18,
})
title := ui_text("Settings Menu: Title", str_intern("Settings Menu"), {.Disabled})
{
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.text_alignment = {0 , 0.5}
layout.anchor.ratio.x = 1.0
layout.font_size = 16
}
ui_layout( UI_Layout {
font_size = 16,
})
ui_style(ui_style_peek())
style := ui_style_ref()
maximize_btn := ui_button("Settings Menu: Maximize Btn")
{
ui_theme_window_bar_btn()
maximize_btn := ui_button("Settings Menu: Maximize Btn"); {
using maximize_btn
layout.flags = {.Fixed_Width}
layout.size.min = {50, 50}
layout.text_alignment = {0.5, 0.5}
layout.anchor.ratio.x = 1.0
if maximize_btn.pressed {
settings_menu.is_maximized = ~settings_menu.is_maximized
should_raise = true
@ -234,19 +202,12 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b
if settings_menu.is_maximized do text = str_intern("min")
else do text = str_intern("max")
}
close_btn := ui_button("Settings Menu: Close Btn")
{
close_btn := ui_button("Settings Menu: Close Btn"); {
using close_btn
text = str_intern("close")
layout.flags = {.Fixed_Width}
layout.size.min = {50, 0}
layout.text_alignment = {0.5, 0.5}
layout.anchor.ratio.x = 1.0
if close_btn.pressed {
settings_menu.is_open = false
}
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
}
ui_hbox_end(frame_bar, compute_layout = true)
}
if frame_bar.active {
@ -254,66 +215,109 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b
should_raise = true
}
// Populate settings with values from config (hardcoded for now)
ui_layout(UI_Layout {
flags = {
// .Origin_At_Anchor_Center,
// .Fixed_Height,
},
// pos = {0, 50},
// size = range2({100, 100},{}),
// alignment = {0,0},
})
ui_style( UI_Style {
// bg_color = Color_GreyRed
})
drop_down_bar := ui_hbox_begin(.Left_To_Right, "settings_menu.vbox: config drop_down_bar", {.Mouse_Clickable})
btn : UI_Widget
@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 })
{
drop_down_bar.layout.anchor.ratio.y = 0.1
ui_parent_push(drop_down_bar)
{
using drop_down_bar
text = str_intern("drop_down_bar")
// style.bg_color = { 55, 55, 55, 100 }
style.font = default_font
style.text_color = Color_White
layout.flags = {.Fixed_Height}
layout.font_size = 12
layout.text_alignment = {1, 0}
layout.size.min.y = 35
layout.anchor.ratio.y = 1.0
}
ui_parent(drop_down_bar)
btn = ui_text("pls", str_intern("Lets figure this out..."))
{
using btn
text = str_intern("Config")
style.font = default_font
style.text_color = Color_White
// layout.flags = {.Origin_At_Anchor_Center}
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
layout.font_size = 12
layout.margins = {0,0, 15, 0}
layout.size.min.y = 35
}
um := ui_spacer("um...")
um.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
}
// ui_layout(UI_Layout {
if config_drop_down_open
{
{
ui_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)
}
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}
// })
// ui_style( UI_Style {
}
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
style.corner_radii[0] = 0.35
}
@static value_str : Array(rune)
if value_str.data == 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")
array_append( & value_str, rune('_'))
}
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 {
// })
// res_width_hbox := ui_hbox_begin(.Left_To_Right, "settings_menu.vbox: config.resolution_width: hbox", {})
// ui_parent(res_width_hbox)
spacer := ui_spacer("Settings Menu: Spacer")
spacer.layout.anchor.ratio.y = 1.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(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))
}
{
ui_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}
}
ui_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
}
}
{
ui_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}
}
ui_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 )
}
return

View File

@ -159,6 +159,8 @@ AppConfig :: struct {
timing_fps_moving_avg_alpha : f32,
ui_resize_border_width : f32,
color_theme : AppColorTheme,
}
AppWindow :: struct {
@ -257,4 +259,7 @@ get_state :: #force_inline proc "contextless" () -> ^ State {
// return get_state().frametime
// }
app_config :: #force_inline proc "contextless" () -> AppConfig { return get_state().config }
app_color_theme :: #force_inline proc "contextless" () -> AppColorTheme { return get_state().config.color_theme }
#endregion("State")

View File

@ -0,0 +1,473 @@
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
*/
// TODO(Ed): Eventually this will have a configuration wizard, and we'll save the presets
@(deferred_none = ui_theme_pop)
ui_theme_btn :: proc()
{
@static theme : UI_Theme
@static loaded : b32 = false
if ! loaded
{
app_color := app_color_theme()
layout := UI_Layout {
flags = {},
anchor = range2_zero,
alignment = {0, 0},
text_alignment = {0.5, 0.5},
font_size = 16,
margins = {0, 0, 0, 0},
padding = {0, 0, 0, 0},
border_width = 1,
pos = {0, 0},
size = range2_zero,
}
style := UI_Style {
bg_color = app_color.btn_bg_default,
border_color = app_color.border_default,
corner_radii = {},
blur_size = 0,
font = get_state().default_font,
text_color = app_color.text_default,
cursor = {},
}
layout_combo := to_ui_layout_combo(layout)
style_combo := to_ui_style_combo(style)
Hot: {
using layout_combo.hot
using style_combo.hot
bg_color = app_color.btn_bg_hot
text_color = app_color.text_hot
}
Active: {
using layout_combo.active
using style_combo.active
bg_color = app_color.btn_bg_active
text_color = app_color.text_active
margins = {2, 2, 2, 2}
}
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
}
@(deferred_none = ui_theme_pop)
ui_theme_drop_down :: proc()
{
@static theme : UI_Theme
@static loaded : b32 = false
if ! loaded
{
app_color := app_color_theme()
layout := UI_Layout {
flags = {.Fixed_Height},
anchor = range2({0, 0},{}),
alignment = {0, 0},
text_alignment = {0.5, 0.5},
font_size = 14,
margins = {0, 0, 0, 0},
padding = {0, 0, 0, 0},
border_width = 1,
pos = {0, 0},
size = range2({0,20},{})
}
style := UI_Style {
bg_color = app_color.btn_bg_default,
border_color = app_color.border_default,
corner_radii = {},
blur_size = 0,
font = get_state().default_font,
text_color = app_color.text_default,
cursor = {},
}
layout_combo := to_ui_layout_combo(layout)
style_combo := to_ui_style_combo(style)
Hot: {
using layout_combo.hot
using style_combo.hot
bg_color = app_color.btn_bg_hot
text_color = app_color.text_hot
margins = {2, 2, 2, 2}
}
Active: {
using layout_combo.active
using style_combo.active
bg_color = app_color.btn_bg_active
text_color = app_color.text_active
margins = {2, 2, 2, 2}
}
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
}
@(deferred_none = ui_theme_pop)
ui_theme_table_row :: proc(is_even : bool)
{
@static theme : UI_Theme
@static loaded : b32 = false
// if ! loaded
{
app_color := app_color_theme()
table_bg : Color
if is_even {
table_bg = app_color.table_even_bg_color
}
else {
table_bg = app_color.table_odd_bg_color
}
layout := UI_Layout {
flags = {},
anchor = range2({},{}),
alignment = {0, 0},
text_alignment = {0.0, 0.0},
font_size = 16,
margins = {0, 0, 0, 0},
padding = {0, 0, 0, 0},
border_width = 0,
pos = {0, 0},
size = range2({},{})
}
style := UI_Style {
bg_color = table_bg,
border_color = Color_Transparent,
corner_radii = {},
blur_size = 0,
font = get_state().default_font,
text_color = app_color_theme().text_default,
cursor = {},
}
layout_combo := to_ui_layout_combo(layout)
style_combo := to_ui_style_combo(style)
Hot: {
using layout_combo.disabled
using style_combo.disabled
}
Active: {
using layout_combo.hot
using style_combo.hot
}
{
using layout_combo.active
using style_combo.active
}
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
}
@(deferred_none = ui_theme_pop)
ui_theme_window_bar :: proc()
{
@static theme : UI_Theme
@static loaded : b32 = false
if ! loaded || true
{
app_color := app_color_theme()
layout := UI_Layout {
flags = {.Fixed_Height},
anchor = range2({},{}),
alignment = {0, 0},
text_alignment = {0.0, 0.0},
font_size = 16,
margins = {0, 0, 0, 0},
padding = {0, 0, 0, 0},
border_width = 0.0,
pos = {0, 0},
size = range2({0, 35},{})
}
style := UI_Style {
bg_color = app_color.window_bar_bg,
border_color = Color_Transparent,
corner_radii = {},
blur_size = 0,
font = get_state().default_font,
text_color = app_color.text_default,
cursor = {},
}
layout_combo := to_ui_layout_combo(layout)
style_combo := to_ui_style_combo(style)
Disabled : {
using layout_combo.disabled
using style_combo.disabled
}
Hot: {
using layout_combo.hot
using style_combo.hot
border_color = app_color.window_bar_border
border_width = 1.0
}
Active: {
using layout_combo.active
using style_combo.active
border_color = app_color.window_bar_border
border_width = 2.0
}
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
}
@(deferred_none = ui_theme_pop)
ui_theme_window_bar_title :: proc()
{
@static theme : UI_Theme
@static loaded : b32 = false
if ! loaded
{
app_color := app_color_theme()
layout := UI_Layout {
flags = {},
anchor = range2({},{}),
alignment = {0, 0},
text_alignment = {0.0, 0.0},
font_size = 16,
margins = {0, 0, 0, 0},
padding = {0, 0, 0, 0},
border_width = 0,
pos = {0, 0},
size = range2({},{})
}
style := UI_Style {
bg_color = Color_Transparent,
border_color = Color_Transparent,
corner_radii = {},
blur_size = 0,
font = get_state().default_font,
text_color = app_color.text_default,
cursor = {},
}
layout_combo := to_ui_layout_combo(layout)
style_combo := to_ui_style_combo(style)
Disabed: {
using layout_combo.disabled
using style_combo.disabled
}
Hot: {
using layout_combo.hot
using style_combo.hot
}
Active: {
using layout_combo.active
using style_combo.active
}
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
}
@(deferred_none = ui_theme_pop)
ui_theme_window_bar_btn :: proc()
{
@static theme : UI_Theme
@static loaded : b32 = false
if ! loaded
{
app_color := app_color_theme()
layout := UI_Layout {
flags = {.Fixed_Width},
anchor = range2({1, 0},{}),
alignment = {0, 0},
text_alignment = {0.5, 0.5},
font_size = 16,
margins = {0, 0, 0, 0},
padding = {0, 0, 0, 0},
border_width = 1,
pos = {0, 0},
size = range2({50,0},{})
}
style := UI_Style {
bg_color = app_color.btn_bg_default,
border_color = app_color.border_default,
corner_radii = {},
blur_size = 0,
font = get_state().default_font,
text_color = app_color.text_default,
cursor = {},
}
layout_combo := to_ui_layout_combo(layout)
style_combo := to_ui_style_combo(style)
Hot: {
using layout_combo.hot
using style_combo.hot
bg_color = app_color.btn_bg_hot
text_color = app_color.text_hot
}
Active: {
using layout_combo.active
using style_combo.active
bg_color = app_color.btn_bg_active
text_color = app_color.text_active
margins = {2, 2, 2, 2}
}
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
}
@(deferred_none = ui_theme_pop)
ui_theme_window_panel :: proc()
{
@static theme : UI_Theme
@static loaded : b32 = false
if ! loaded
{
app_color := app_color_theme()
layout := UI_Layout {
flags = {},
anchor = range2({},{}),
alignment = {0, 0},
text_alignment = {0.0, 0.0},
font_size = 16,
margins = {0, 0, 0, 0},
padding = {0, 0, 0, 0},
border_width = 1,
pos = {0, 0},
size = range2({},{})
}
style := UI_Style {
bg_color = app_color.window_panel_bg,
border_color = app_color.window_panel_border,
corner_radii = {},
blur_size = 0,
font = get_state().default_font,
text_color = app_color.text_default,
cursor = {},
}
layout_combo := to_ui_layout_combo(layout)
style_combo := to_ui_style_combo(style)
Disabled: {
using layout_combo.disabled
using style_combo.disabled
}
Hot: {
using layout_combo.hot
using style_combo.hot
}
Active: {
using layout_combo.active
using style_combo.active
}
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
}
@(deferred_none = ui_theme_pop)
ui_theme_transparent :: proc()
{
@static theme : UI_Theme
@static loaded : b32 = false
if ! loaded
{
app_color := app_color_theme()
layout := UI_Layout {
flags = {},
anchor = range2({},{}),
alignment = {0, 0},
text_alignment = {0.0, 0.0},
font_size = 16,
margins = {0, 0, 0, 0},
padding = {0, 0, 0, 0},
border_width = 0,
pos = {0, 0},
size = range2({},{})
}
style := UI_Style {
bg_color = Color_Transparent,
border_color = Color_Transparent,
corner_radii = {},
blur_size = 0,
font = get_state().default_font,
text_color = app_color.text_default,
cursor = {},
}
layout_combo := to_ui_layout_combo(layout)
style_combo := to_ui_style_combo(style)
{
using layout_combo.disabled
using style_combo.disabled
}
{
using layout_combo.hot
using style_combo.hot
}
{
using layout_combo.active
using style_combo.active
}
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
}
@(deferred_none = ui_theme_pop)
ui_theme_text :: proc()
{
@static theme : UI_Theme
@static loaded : b32 = false
if ! loaded
{
app_color := app_color_theme()
layout := UI_Layout {
flags = {},
anchor = range2({},{}),
alignment = {0, 0},
text_alignment = {0.0, 0.5},
font_size = 14,
margins = {0, 0, 0, 0},
padding = {0, 0, 0, 0},
border_width = 0,
pos = {0, 0},
size = range2({},{})
}
style := UI_Style {
bg_color = Color_Transparent,
border_color = Color_Transparent,
corner_radii = {},
blur_size = 0,
font = get_state().default_font,
text_color = app_color.text_default,
cursor = {},
}
layout_combo := to_ui_layout_combo(layout)
style_combo := to_ui_style_combo(style)
{
using layout_combo.disabled
using style_combo.disabled
}
{
using layout_combo.hot
using style_combo.hot
}
{
using layout_combo.active
using style_combo.active
}
theme = UI_Theme { layout_combo, style_combo }
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
}

View File

@ -1,114 +0,0 @@
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
*/
// TODO(Ed): Eventually this will have a configuration wizard, and we'll save the presets
@(deferred_none = ui_theme_pop)
ui_theme_btn_default :: proc()
{
@static theme : UI_Theme
@static loaded : b32 = false
if ! loaded
{
layout := UI_Layout {
flags = {},
anchor = range2({},{}),
alignment = {0, 0},
text_alignment = {0.5, 0.5},
font_size = 16,
margins = {0, 0, 0, 0},
padding = {0, 0, 0, 0},
border_width = 1,
pos = {0, 0},
size = range2({},{})
}
style := UI_Style {
bg_color = Color_ThmDark_Btn_BG_Default,
border_color = Color_ThmDark_Border_Default,
corner_radii = {},
blur_size = 0,
font = get_state().default_font,
text_color = Color_ThmDark_Text_Default,
cursor = {},
}
layout_combo := to_ui_layout_combo(layout)
style_combo := to_ui_style_combo(style)
{
using layout_combo.hot
using style_combo.hot
bg_color = Color_ThmDark_Btn_BG_Hot
text_color = Color_ThmDark_Text_Hot
margins = {2, 2, 2, 2}
}
{
using layout_combo.active
using style_combo.active
bg_color = Color_ThmDark_Btn_BG_Active
text_color = Color_ThmDark_Text_Active
margins = {2, 2, 2, 2}
}
theme = UI_Theme {
layout_combo, style_combo
}
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
}
@(deferred_none = ui_theme_pop)
ui_theme_transparent :: proc()
{
@static theme : UI_Theme
@static loaded : b32 = false
if ! loaded || true
{
layout := UI_Layout {
flags = {},
anchor = range2({},{}),
alignment = {0, 0},
text_alignment = {0.0, 0.0},
font_size = 16,
margins = {0, 0, 0, 0},
padding = {0, 0, 0, 0},
border_width = 0,
pos = {0, 0},
size = range2({},{})
}
style := UI_Style {
bg_color = Color_Transparent,
border_color = Color_Transparent,
corner_radii = {},
blur_size = 0,
font = get_state().default_font,
text_color = Color_ThmDark_Text_Default,
cursor = {},
}
layout_combo := to_ui_layout_combo(layout)
style_combo := to_ui_style_combo(style)
{
using layout_combo.disabled
using style_combo.disabled
}
{
using layout_combo.hot
using style_combo.hot
}
{
using layout_combo.active
using style_combo.active
}
theme = UI_Theme {
layout_combo, style_combo
}
loaded = true
}
ui_layout_push(theme.layout)
ui_style_push(theme.style)
}

View File

@ -31,32 +31,114 @@ Color_Debug_UI_Content_Bounds :: Color { 170, 120, 240, 160 }
// TODO(Ed): The entire rendering pass should be post-processed by a tone curve configurable for the user
// This is how you properly support any tonality of light or dark themes and not have it be base don the monitors raw output.
// Dark Theme
AppColorTheme :: struct {
light_limit,
dark_limit,
// Brightest value limited to (text is the only exception):
Color_ThmDark_BrightLimit :: Color {230, 230, 230, 255}
// Darkness value limited to (text is the only exception):
Color_ThmDark_DarkLimit :: Color {10, 10, 10, 255}
bg,
border_default,
Color_ThmDark_BG :: Color {33, 33, 33, 255}
btn_bg_default,
btn_bg_hot,
btn_bg_active,
Color_ThmDark_Translucent_Panel :: Color { 0, 0, 0, 60}
input_box_bg,
input_box_bg_hot,
input_box_bg_active,
Color_ThmDark_ResizeHandle_Default :: Color_Transparent
Color_ThmDark_ResizeHandle_Hot :: Color { 72, 72, 72, 90}
Color_ThmDark_ResizeHandle_Active :: Color { 88, 88, 88, 90}
resize_hndl_default,
resize_hndl_hot,
resize_hndl_active,
Color_ThmDark_Border_Default :: Color { 64, 64, 64, 255}
table_even_bg_color,
table_odd_bg_color,
Color_ThmDark_Btn_BG_Default :: Color { 40, 40, 40, 255}
Color_ThmDark_Btn_BG_Hot :: Color { 60, 60, 70, 255}
Color_ThmDark_Btn_BG_Active :: Color { 90, 100, 130, 255}
text_default,
text_hot,
text_active,
Color_ThmDark_Text_Default :: Color {120, 117, 115, 255}
Color_ThmDark_Text_Hot :: Color {180, 180, 180, 255}
Color_ThmDark_Text_Active :: Color {240, 240, 240, 255}
translucent_panel,
// Light Theme
window_bar_border,
window_bar_bg,
window_btn_close_bg_hot,
// LightTheme_BG :: Color { 120, 120, 120, 255 }
window_panel_bg,
window_panel_border \
: Color
}
App_Thm_Dusk :: AppColorTheme {
light_limit = Color {125, 125, 125, 255},
dark_limit = Color { 10, 10, 10, 255},
bg = Color {33, 33, 33, 255},
border_default = Color { 64, 64, 64, 255},
btn_bg_default = Color { 40, 40, 40, 255},
btn_bg_hot = Color { 60, 60, 70, 255},
btn_bg_active = Color { 90, 100, 130, 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 {120, 117, 115, 255},
text_hot = Color {180, 180, 180, 255},
text_active = Color {240, 240, 240, 255},
translucent_panel = Color { 10, 10, 10, 50},
window_bar_border = Color { 64, 64, 64, 255}, // border_default
window_bar_bg = Color{35, 35, 35, 255},
window_btn_close_bg_hot = Color{45, 35, 35, 255},
window_panel_bg = Color { 10, 10, 10, 50}, // translucent_panel
window_panel_border = Color{24, 24, 24, 255},
}
App_Thm_Light :: AppColorTheme {
light_limit = Color {195, 195, 195, 255},
dark_limit = Color { 60, 60, 60, 255},
bg = Color {135, 135, 135, 255},
border_default = Color { 174, 174, 174, 255},
btn_bg_default = Color { 160, 160, 160, 255},
btn_bg_hot = Color { 145, 145, 155, 255},
btn_bg_active = Color { 124, 124, 136, 255},
input_box_bg = Color {115, 115, 115, 255},
input_box_bg_hot = Color {125, 125, 125, 255},
input_box_bg_active = Color {105, 105, 105, 255},
resize_hndl_default = Color_Transparent,
resize_hndl_hot = Color { 95, 95, 95, 90},
resize_hndl_active = Color { 80, 80, 80, 90},
table_even_bg_color = Color {150, 150, 150, 255},
table_odd_bg_color = Color {160, 160, 160, 255},
text_default = Color { 55, 55, 55, 255},
text_hot = Color { 85, 85, 85, 255},
text_active = Color { 45, 45, 49, 255},
translucent_panel = Color { 110, 110, 110, 50},
window_bar_border = Color{ 174, 174, 174, 255}, // border_default
window_bar_bg = Color{ 155, 155, 155, 255},
window_btn_close_bg_hot = Color{ 145, 135, 135, 255},
window_panel_bg = Color {135, 135, 135, 50}, // translucent_panel
window_panel_border = Color{184, 184, 184, 255},
}

View File

@ -60,7 +60,7 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
Memory_App.state = state
using state
// Setup Persistent Slab
// Setup Persistent Slabs & String Cache
{
alignment := uint(mem.DEFAULT_ALIGNMENT)
@ -93,14 +93,24 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
verify( alloc_error == .None, "Failed to allocate transient slab" )
transient_clear_time = 120 // Seconds, 2 Minutes
string_cache = str_cache_init()
}
string_cache = str_cache_init()
// Setup input frame poll references
input = & input_data[1]
input_prev = & input_data[0]
for & input in input_data {
using input
error : AllocatorError
keyboard_events.keys_pressed, error = array_init_reserve(KeyboardKey, persistent_slab_allocator(), Kilo)
ensure(error == AllocatorError.None, "Failed to allocate input.keyboard_events.keys_pressed array")
keyboard_events.chars_pressed, error = array_init_reserve(rune, persistent_slab_allocator(), Kilo)
ensure(error == AllocatorError.None, "Failed to allocate input.keyboard_events.chars_pressed array")
}
// Configuration Load
// TODO(Ed): Make this actually load from an ini
{
using config
resolution_width = 1000
@ -119,6 +129,8 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
timing_fps_moving_avg_alpha = 0.9
ui_resize_border_width = 5
color_theme = App_Thm_Dusk
}
Desired_OS_Scheduler_MS :: 1
@ -182,6 +194,7 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
}
// Demo project setup
// TODO(Ed): This will eventually have to occur when the user either creates or loads a workspace. I don't know
{
using project
path = str_intern("./")
@ -318,10 +331,12 @@ tick :: proc( host_delta_time : f64, host_delta_ns : Duration ) -> b32
rl.PollInputEvents()
debug.draw_ui_box_bounds_points = true
debug.draw_ui_box_bounds_points = false
debug.draw_UI_padding_bounds = false
debug.draw_ui_content_bounds = true
debug.draw_ui_content_bounds = false
config.color_theme = App_Thm_Light
// config.color_theme = App_Thm_Dusk
should_close = update( host_delta_time )
render()

View File

@ -43,7 +43,7 @@ render :: proc()
render_mode_3d()
rl.BeginDrawing()
rl.ClearBackground( Color_ThmDark_BG )
rl.ClearBackground( app_color_theme().bg )
render_mode_2d_workspace()
render_mode_screenspace()
@ -252,7 +252,7 @@ render_mode_screenspace :: proc ()
{
// debug_text( "Screen Width : %v", rl.GetScreenWidth () )
// debug_text( "Screen Height: %v", rl.GetScreenHeight() )
debug_text( "frametime_target_ms : %f ms", frametime_target_ms )
// debug_text( "frametime_target_ms : %f ms", frametime_target_ms )
debug_text( "frametime : %f ms", frametime_delta_ms )
// debug_text( "frametime_last_elapsed_ms : %f ms", frametime_elapsed_ms )
if replay.mode == ReplayMode.Record {
@ -261,10 +261,9 @@ render_mode_screenspace :: proc ()
if replay.mode == ReplayMode.Playback {
debug_text( "Replaying Input")
}
// debug_text("Zoom Target: %v", project.workspace.zoom_target)
}
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 )
@ -277,34 +276,39 @@ render_mode_screenspace :: proc ()
ui := & project.workspace.ui
debug_text("Box Count (Workspace): %v", ui.built_box_count )
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 active_box != nil{
debug_text("Workspace Active Box: %v", active_box.label.str )
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
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)
}
if active_box != nil{
debug_text("Active Box: %v", active_box.label.str )
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 )
}
}
view := view_get_bounds()
debug.draw_debug_text_y = 14
// Define the triangle vertices and colors

View File

@ -239,7 +239,7 @@ update :: proc( delta_time : f64 ) -> b32
// test_hover_n_click()
// test_draggable()
// test_text_box()
test_parenting( & default_layout, & frame_style_default )
// test_parenting( & default_layout, & frame_style_default )
// test_whitespace_ast( & default_layout, & frame_style_default )
}
//endregion Workspace Imgui Tick

View File

@ -75,7 +75,7 @@ array_init_reserve :: proc
return
}
array_append :: proc( self : ^Array( $ Type), value : Type ) -> AllocatorError
array_append_value :: proc( self : ^Array( $ Type), value : Type ) -> AllocatorError
{
// profile(#procedure)
if self.header.num == self.header.capacity
@ -91,11 +91,11 @@ array_append :: proc( self : ^Array( $ Type), value : Type ) -> AllocatorError
return AllocatorError.None
}
array_append_slice :: proc( using self : ^Array( $ Type ), items : []Type ) -> AllocatorError
array_append_array :: proc( using self: ^Array( $ Type), other : Array(Type)) -> AllocatorError
{
if num + len(items) > capacity
if num + other.num > capacity
{
grow_result := array_grow( self, capacity )
grow_result := array_grow( self, num + other.num )
if grow_result != AllocatorError.None {
return grow_result
}
@ -106,9 +106,31 @@ array_append_slice :: proc( using self : ^Array( $ Type ), items : []Type ) -> A
// TODO(Ed) : VERIFY VIA DEBUG THIS COPY IS FINE.
target := ptr_offset( data, num )
copy( slice_ptr(target, capacity - num), items )
copy( slice_ptr(target, int(capacity - num)), array_to_slice(other) )
num += len(items)
num += other.num
return AllocatorError.None
}
array_append_slice :: proc( using self : ^Array( $ Type ), items : []Type ) -> AllocatorError
{
items_num :=u64(len(items))
if num + items_num > capacity
{
grow_result := array_grow( self, num + items_num )
if grow_result != AllocatorError.None {
return grow_result
}
}
// 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 )
num += items_num
return AllocatorError.None
}

View File

@ -107,6 +107,12 @@ add :: proc {
add_range2,
}
array_append :: proc {
array_append_value,
array_append_array,
array_append_slice,
}
bivec3 :: proc {
bivec3_via_f32s,
vec3_to_bivec3,

View File

@ -1 +1 @@
package sectr
package sectr

View File

@ -281,221 +281,13 @@ mouse_world_delta :: #force_inline proc "contextless" () -> Vec2 {
InputState :: struct {
keyboard : KeyboardState,
mouse : MouseState
mouse : MouseState,
keyboard_events : KeyboardEvents,
}
import "core:os"
import c "core:c/libc"
import rl "vendor:raylib"
poll_input :: proc( old, new : ^ InputState )
{
profile(#procedure)
input_process_digital_btn :: proc( old_state, new_state : ^ DigitalBtn, is_down : b32 )
{
new_state.ended_down = is_down
had_transition := old_state.ended_down != new_state.ended_down
if had_transition {
new_state.half_transitions += 1
}
else {
new_state.half_transitions = 0
}
}
// Keyboard
{
// profile("Keyboard")
check_range :: proc( old, new : ^ InputState, start, end : i32 )
{
for id := start; id < end; id += 1
{
// TODO(Ed) : LOOK OVER THIS...
entry_old := & old.keyboard.keys[id - 1]
entry_new := & new.keyboard.keys[id - 1]
key_id := cast(KeyboardKey) id
is_down := cast(b32) rl.IsKeyDown( to_raylib_key(id) )
input_process_digital_btn( entry_old, entry_new, is_down )
}
}
DeadBound_1 :: 0x0A
DeadBound_2 :: 0x2E
DeadBound_3 :: 0x19
DeadBound_4 :: 0x3F
check_range( old, new, cast(i32) KeyboardKey.enter, DeadBound_1 )
check_range( old, new, cast(i32) KeyboardKey.caps_lock, DeadBound_2 )
check_range( old, new, cast(i32) KeyboardKey.escape, DeadBound_3 )
check_range( old, new, cast(i32) KeyboardKey.backtick, DeadBound_4 )
check_range( old, new, cast(i32) KeyboardKey.A, cast(i32) KeyboardKey.count )
}
// Mouse
{
// profile("Mouse")
// Process Buttons
for id : i32 = 0; id < i32(MouseBtn.count); id += 1
{
old_btn := & old.mouse.btns[id]
new_btn := & new.mouse.btns[id]
mouse_id := cast(MouseBtn) id
is_down := cast(b32) rl.IsMouseButtonDown( to_raylib_mouse_btn(id) )
input_process_digital_btn( old_btn, new_btn, is_down )
}
new.mouse.raw_pos = rl.GetMousePosition()
new.mouse.pos = render_to_screen_pos(new.mouse.raw_pos)
new.mouse.delta = rl.GetMouseDelta() * {1, -1}
new.mouse.vertical_wheel = rl.GetMouseWheelMove()
}
}
record_input :: proc( replay_file : os.Handle, input : ^ InputState ) {
raw_data := slice_ptr( transmute(^ byte) input, size_of(InputState) )
file_write( replay_file, raw_data )
}
play_input :: proc( replay_file : os.Handle, input : ^ InputState ) {
raw_data := slice_ptr( transmute(^ byte) input, size_of(InputState) )
total_read, result_code := file_read( replay_file, raw_data )
if result_code == os.ERROR_HANDLE_EOF {
file_rewind( replay_file )
load_snapshot( & Memory_App.snapshot )
}
}
to_raylib_key :: proc( key : i32 ) -> rl.KeyboardKey {
@static raylib_key_lookup_table := [?] rl.KeyboardKey {
rl.KeyboardKey.KEY_NULL,
rl.KeyboardKey.ENTER,
rl.KeyboardKey.TAB,
rl.KeyboardKey.SPACE,
rl.KeyboardKey.LEFT_BRACKET,
rl.KeyboardKey.RIGHT_BRACKET,
rl.KeyboardKey.SEMICOLON,
rl.KeyboardKey.APOSTROPHE,
rl.KeyboardKey.COMMA,
rl.KeyboardKey.PERIOD,
cast(rl.KeyboardKey) 0, // 0x0A
cast(rl.KeyboardKey) 0, // 0x0B
cast(rl.KeyboardKey) 0, // 0x0C
cast(rl.KeyboardKey) 0, // 0x0D
cast(rl.KeyboardKey) 0, // 0x0E
cast(rl.KeyboardKey) 0, // 0x0F
rl.KeyboardKey.CAPS_LOCK,
rl.KeyboardKey.SCROLL_LOCK,
rl.KeyboardKey.NUM_LOCK,
rl.KeyboardKey.LEFT_ALT,
rl.KeyboardKey.LEFT_SHIFT,
rl.KeyboardKey.LEFT_CONTROL,
rl.KeyboardKey.RIGHT_ALT,
rl.KeyboardKey.RIGHT_SHIFT,
rl.KeyboardKey.RIGHT_CONTROL,
cast(rl.KeyboardKey) 0, // 0x0F
cast(rl.KeyboardKey) 0, // 0x0F
cast(rl.KeyboardKey) 0, // 0x0F
cast(rl.KeyboardKey) 0, // 0x0F
cast(rl.KeyboardKey) 0, // 0x0F
cast(rl.KeyboardKey) 0, // 0x0F
cast(rl.KeyboardKey) 0, // 0x0F
rl.KeyboardKey.ESCAPE,
rl.KeyboardKey.F1,
rl.KeyboardKey.F2,
rl.KeyboardKey.F3,
rl.KeyboardKey.F4,
rl.KeyboardKey.F5,
rl.KeyboardKey.F7,
rl.KeyboardKey.F8,
rl.KeyboardKey.F9,
rl.KeyboardKey.F10,
rl.KeyboardKey.F11,
rl.KeyboardKey.F12,
rl.KeyboardKey.PRINT_SCREEN,
rl.KeyboardKey.PAUSE,
cast(rl.KeyboardKey) 0, // 0x2E
rl.KeyboardKey.GRAVE,
cast(rl.KeyboardKey) '0',
cast(rl.KeyboardKey) '1',
cast(rl.KeyboardKey) '2',
cast(rl.KeyboardKey) '3',
cast(rl.KeyboardKey) '4',
cast(rl.KeyboardKey) '5',
cast(rl.KeyboardKey) '6',
cast(rl.KeyboardKey) '7',
cast(rl.KeyboardKey) '8',
cast(rl.KeyboardKey) '9',
rl.KeyboardKey.MINUS,
rl.KeyboardKey.EQUAL,
rl.KeyboardKey.BACKSPACE,
rl.KeyboardKey.BACKSLASH,
rl.KeyboardKey.SLASH,
cast(rl.KeyboardKey) 0, // 0x3F
cast(rl.KeyboardKey) 0, // 0x40
rl.KeyboardKey.A,
rl.KeyboardKey.B,
rl.KeyboardKey.C,
rl.KeyboardKey.D,
rl.KeyboardKey.E,
rl.KeyboardKey.F,
rl.KeyboardKey.G,
rl.KeyboardKey.H,
rl.KeyboardKey.I,
rl.KeyboardKey.J,
rl.KeyboardKey.K,
rl.KeyboardKey.L,
rl.KeyboardKey.M,
rl.KeyboardKey.N,
rl.KeyboardKey.O,
rl.KeyboardKey.P,
rl.KeyboardKey.Q,
rl.KeyboardKey.R,
rl.KeyboardKey.S,
rl.KeyboardKey.T,
rl.KeyboardKey.U,
rl.KeyboardKey.V,
rl.KeyboardKey.W,
rl.KeyboardKey.X,
rl.KeyboardKey.Y,
rl.KeyboardKey.Z,
rl.KeyboardKey.INSERT,
rl.KeyboardKey.DELETE,
rl.KeyboardKey.HOME,
rl.KeyboardKey.END,
rl.KeyboardKey.PAGE_UP,
rl.KeyboardKey.PAGE_DOWN,
rl.KeyboardKey.KP_0,
rl.KeyboardKey.KP_1,
rl.KeyboardKey.KP_2,
rl.KeyboardKey.KP_3,
rl.KeyboardKey.KP_4,
rl.KeyboardKey.KP_5,
rl.KeyboardKey.KP_6,
rl.KeyboardKey.KP_7,
rl.KeyboardKey.KP_8,
rl.KeyboardKey.KP_9,
rl.KeyboardKey.KP_DECIMAL,
rl.KeyboardKey.KP_EQUAL,
rl.KeyboardKey.KP_ADD,
rl.KeyboardKey.KP_SUBTRACT,
rl.KeyboardKey.KP_MULTIPLY,
rl.KeyboardKey.KP_DIVIDE,
rl.KeyboardKey.KP_ENTER }
return raylib_key_lookup_table[ key ]
}
to_raylib_mouse_btn :: proc( btn : i32 ) -> rl.MouseButton {
@static raylib_mouse_btn_lookup_table := [?] rl.MouseButton {
rl.MouseButton.LEFT,
rl.MouseButton.MIDDLE,
rl.MouseButton.RIGHT,
rl.MouseButton.SIDE,
rl.MouseButton.FORWARD,
rl.MouseButton.BACK,
rl.MouseButton.EXTRA,
}
return raylib_mouse_btn_lookup_table[ btn ]
// TODO(Ed): Whats the lifetime of these events? (So far we're picking per full-frame)
KeyboardEvents :: struct {
keys_pressed : Array(KeyboardKey),
chars_pressed : Array(rune),
}

View File

@ -0,0 +1,350 @@
package sectr
import "base:runtime"
import "core:os"
import c "core:c/libc"
import rl "vendor:raylib"
poll_input :: proc( old, new : ^ InputState )
{
profile(#procedure)
input_process_digital_btn :: proc( old_state, new_state : ^ DigitalBtn, is_down : b32 )
{
new_state.ended_down = is_down
had_transition := old_state.ended_down != new_state.ended_down
if had_transition {
new_state.half_transitions += 1
}
else {
new_state.half_transitions = 0
}
}
// Keyboard
{
// profile("Keyboard")
check_range :: proc( old, new : ^ InputState, start, end : i32 )
{
for id := start; id < end; id += 1
{
// TODO(Ed) : LOOK OVER THIS...
entry_old := & old.keyboard.keys[id - 1]
entry_new := & new.keyboard.keys[id - 1]
key_id := cast(KeyboardKey) id
is_down := cast(b32) rl.IsKeyDown( to_raylib_key(id) )
input_process_digital_btn( entry_old, entry_new, is_down )
}
}
DeadBound_1 :: 0x0A
DeadBound_2 :: 0x2E
DeadBound_3 :: 0x19
DeadBound_4 :: 0x3F
check_range( old, new, cast(i32) KeyboardKey.enter, DeadBound_1 )
check_range( old, new, cast(i32) KeyboardKey.caps_lock, DeadBound_2 )
check_range( old, new, cast(i32) KeyboardKey.escape, DeadBound_3 )
check_range( old, new, cast(i32) KeyboardKey.backtick, DeadBound_4 )
check_range( old, new, cast(i32) KeyboardKey.A, cast(i32) KeyboardKey.count )
swap( & old.keyboard_events.keys_pressed, & new.keyboard_events.keys_pressed )
swap( & old.keyboard_events.chars_pressed, & new.keyboard_events.chars_pressed )
array_clear( new.keyboard_events.keys_pressed )
array_clear( new.keyboard_events.chars_pressed )
for key_pressed := rl.GetKeyPressed(); key_pressed != rl.KeyboardKey.KEY_NULL; key_pressed = rl.GetKeyPressed() {
array_append( & new.keyboard_events.keys_pressed, to_key_from_raylib(key_pressed))
}
for char_pressed := rl.GetCharPressed(); char_pressed != cast(rune)0; char_pressed = rl.GetCharPressed() {
array_append( & new.keyboard_events.chars_pressed, char_pressed)
}
}
// Mouse
{
// profile("Mouse")
// Process Buttons
for id : i32 = 0; id < i32(MouseBtn.count); id += 1
{
old_btn := & old.mouse.btns[id]
new_btn := & new.mouse.btns[id]
mouse_id := cast(MouseBtn) id
is_down := cast(b32) rl.IsMouseButtonDown( to_raylib_mouse_btn(id) )
input_process_digital_btn( old_btn, new_btn, is_down )
}
new.mouse.raw_pos = rl.GetMousePosition()
new.mouse.pos = render_to_screen_pos(new.mouse.raw_pos)
new.mouse.delta = rl.GetMouseDelta() * {1, -1}
new.mouse.vertical_wheel = rl.GetMouseWheelMove()
}
}
record_input :: proc( replay_file : os.Handle, input : ^ InputState ) {
raw_data := slice_ptr( transmute(^ byte) input, size_of(InputState) )
file_write( replay_file, raw_data )
}
play_input :: proc( replay_file : os.Handle, input : ^ InputState ) {
raw_data := slice_ptr( transmute(^ byte) input, size_of(InputState) )
total_read, result_code := file_read( replay_file, raw_data )
if result_code == os.ERROR_HANDLE_EOF {
file_rewind( replay_file )
load_snapshot( & Memory_App.snapshot )
}
}
to_key_from_raylib :: proc( key : rl.KeyboardKey ) -> KeyboardKey {
@static lookup_table := [?] KeyboardKey {
KeyboardKey.null,
KeyboardKey.enter,
KeyboardKey.tab,
KeyboardKey.space,
KeyboardKey.bracket_open,
KeyboardKey.bracket_close,
KeyboardKey.semicolon,
KeyboardKey.apostrophe,
KeyboardKey.comma,
KeyboardKey.period,
cast(KeyboardKey) 0, // 0x0A
cast(KeyboardKey) 0, // 0x0B
cast(KeyboardKey) 0, // 0x0C
cast(KeyboardKey) 0, // 0x0D
cast(KeyboardKey) 0, // 0x0E
cast(KeyboardKey) 0, // 0x0F
KeyboardKey.caps_lock,
KeyboardKey.scroll_lock,
KeyboardKey.num_lock,
KeyboardKey.left_alt,
KeyboardKey.left_shit,
KeyboardKey.left_control,
KeyboardKey.right_alt,
KeyboardKey.right_shift,
KeyboardKey.right_control,
cast(KeyboardKey) 0, // 0x0F
cast(KeyboardKey) 0, // 0x0F
cast(KeyboardKey) 0, // 0x0F
cast(KeyboardKey) 0, // 0x0F
cast(KeyboardKey) 0, // 0x0F
cast(KeyboardKey) 0, // 0x0F
cast(KeyboardKey) 0, // 0x0F
KeyboardKey.escape,
KeyboardKey.F1,
KeyboardKey.F2,
KeyboardKey.F3,
KeyboardKey.F4,
KeyboardKey.F5,
KeyboardKey.F7,
KeyboardKey.F8,
KeyboardKey.F9,
KeyboardKey.F10,
KeyboardKey.F11,
KeyboardKey.F12,
KeyboardKey.print_screen,
KeyboardKey.pause,
cast(KeyboardKey) 0, // 0x2E
KeyboardKey.backtick,
KeyboardKey.nrow_0,
KeyboardKey.nrow_1,
KeyboardKey.nrow_2,
KeyboardKey.nrow_3,
KeyboardKey.nrow_4,
KeyboardKey.nrow_5,
KeyboardKey.nrow_6,
KeyboardKey.nrow_7,
KeyboardKey.nrow_8,
KeyboardKey.nrow_9,
KeyboardKey.hyphen,
KeyboardKey.equals,
KeyboardKey.backspace,
KeyboardKey.backslash,
KeyboardKey.slash,
cast(KeyboardKey) 0, // 0x3F
cast(KeyboardKey) 0, // 0x40
KeyboardKey.A,
KeyboardKey.B,
KeyboardKey.C,
KeyboardKey.D,
KeyboardKey.E,
KeyboardKey.F,
KeyboardKey.G,
KeyboardKey.H,
KeyboardKey.I,
KeyboardKey.J,
KeyboardKey.K,
KeyboardKey.L,
KeyboardKey.M,
KeyboardKey.N,
KeyboardKey.O,
KeyboardKey.P,
KeyboardKey.Q,
KeyboardKey.R,
KeyboardKey.S,
KeyboardKey.T,
KeyboardKey.U,
KeyboardKey.V,
KeyboardKey.W,
KeyboardKey.X,
KeyboardKey.Y,
KeyboardKey.Z,
KeyboardKey.insert,
KeyboardKey.delete,
KeyboardKey.home,
KeyboardKey.end,
KeyboardKey.page_up,
KeyboardKey.page_down,
KeyboardKey.npad_0,
KeyboardKey.npad_1,
KeyboardKey.npad_2,
KeyboardKey.npad_3,
KeyboardKey.npad_4,
KeyboardKey.npad_5,
KeyboardKey.npad_6,
KeyboardKey.npad_7,
KeyboardKey.npad_8,
KeyboardKey.npad_9,
KeyboardKey.npad_decimal,
KeyboardKey.npad_equals,
KeyboardKey.npad_plus,
KeyboardKey.npad_minus,
KeyboardKey.npad_multiply,
KeyboardKey.npad_divide,
KeyboardKey.npad_enter, }
return lookup_table[key]
}
to_raylib_key :: proc( key : i32 ) -> rl.KeyboardKey
{
@static raylib_key_lookup_table := [?] rl.KeyboardKey {
rl.KeyboardKey.KEY_NULL,
rl.KeyboardKey.ENTER,
rl.KeyboardKey.TAB,
rl.KeyboardKey.SPACE,
rl.KeyboardKey.LEFT_BRACKET,
rl.KeyboardKey.RIGHT_BRACKET,
rl.KeyboardKey.SEMICOLON,
rl.KeyboardKey.APOSTROPHE,
rl.KeyboardKey.COMMA,
rl.KeyboardKey.PERIOD,
cast(rl.KeyboardKey) 0, // 0x0A
cast(rl.KeyboardKey) 0, // 0x0B
cast(rl.KeyboardKey) 0, // 0x0C
cast(rl.KeyboardKey) 0, // 0x0D
cast(rl.KeyboardKey) 0, // 0x0E
cast(rl.KeyboardKey) 0, // 0x0F
rl.KeyboardKey.CAPS_LOCK,
rl.KeyboardKey.SCROLL_LOCK,
rl.KeyboardKey.NUM_LOCK,
rl.KeyboardKey.LEFT_ALT,
rl.KeyboardKey.LEFT_SHIFT,
rl.KeyboardKey.LEFT_CONTROL,
rl.KeyboardKey.RIGHT_ALT,
rl.KeyboardKey.RIGHT_SHIFT,
rl.KeyboardKey.RIGHT_CONTROL,
cast(rl.KeyboardKey) 0, // 0x0F
cast(rl.KeyboardKey) 0, // 0x0F
cast(rl.KeyboardKey) 0, // 0x0F
cast(rl.KeyboardKey) 0, // 0x0F
cast(rl.KeyboardKey) 0, // 0x0F
cast(rl.KeyboardKey) 0, // 0x0F
cast(rl.KeyboardKey) 0, // 0x0F
rl.KeyboardKey.ESCAPE,
rl.KeyboardKey.F1,
rl.KeyboardKey.F2,
rl.KeyboardKey.F3,
rl.KeyboardKey.F4,
rl.KeyboardKey.F5,
rl.KeyboardKey.F7,
rl.KeyboardKey.F8,
rl.KeyboardKey.F9,
rl.KeyboardKey.F10,
rl.KeyboardKey.F11,
rl.KeyboardKey.F12,
rl.KeyboardKey.PRINT_SCREEN,
rl.KeyboardKey.PAUSE,
cast(rl.KeyboardKey) 0, // 0x2E
rl.KeyboardKey.GRAVE,
cast(rl.KeyboardKey) '0',
cast(rl.KeyboardKey) '1',
cast(rl.KeyboardKey) '2',
cast(rl.KeyboardKey) '3',
cast(rl.KeyboardKey) '4',
cast(rl.KeyboardKey) '5',
cast(rl.KeyboardKey) '6',
cast(rl.KeyboardKey) '7',
cast(rl.KeyboardKey) '8',
cast(rl.KeyboardKey) '9',
rl.KeyboardKey.MINUS,
rl.KeyboardKey.EQUAL,
rl.KeyboardKey.BACKSPACE,
rl.KeyboardKey.BACKSLASH,
rl.KeyboardKey.SLASH,
cast(rl.KeyboardKey) 0, // 0x3F
cast(rl.KeyboardKey) 0, // 0x40
rl.KeyboardKey.A,
rl.KeyboardKey.B,
rl.KeyboardKey.C,
rl.KeyboardKey.D,
rl.KeyboardKey.E,
rl.KeyboardKey.F,
rl.KeyboardKey.G,
rl.KeyboardKey.H,
rl.KeyboardKey.I,
rl.KeyboardKey.J,
rl.KeyboardKey.K,
rl.KeyboardKey.L,
rl.KeyboardKey.M,
rl.KeyboardKey.N,
rl.KeyboardKey.O,
rl.KeyboardKey.P,
rl.KeyboardKey.Q,
rl.KeyboardKey.R,
rl.KeyboardKey.S,
rl.KeyboardKey.T,
rl.KeyboardKey.U,
rl.KeyboardKey.V,
rl.KeyboardKey.W,
rl.KeyboardKey.X,
rl.KeyboardKey.Y,
rl.KeyboardKey.Z,
rl.KeyboardKey.INSERT,
rl.KeyboardKey.DELETE,
rl.KeyboardKey.HOME,
rl.KeyboardKey.END,
rl.KeyboardKey.PAGE_UP,
rl.KeyboardKey.PAGE_DOWN,
rl.KeyboardKey.KP_0,
rl.KeyboardKey.KP_1,
rl.KeyboardKey.KP_2,
rl.KeyboardKey.KP_3,
rl.KeyboardKey.KP_4,
rl.KeyboardKey.KP_5,
rl.KeyboardKey.KP_6,
rl.KeyboardKey.KP_7,
rl.KeyboardKey.KP_8,
rl.KeyboardKey.KP_9,
rl.KeyboardKey.KP_DECIMAL,
rl.KeyboardKey.KP_EQUAL,
rl.KeyboardKey.KP_ADD,
rl.KeyboardKey.KP_SUBTRACT,
rl.KeyboardKey.KP_MULTIPLY,
rl.KeyboardKey.KP_DIVIDE,
rl.KeyboardKey.KP_ENTER, }
return raylib_key_lookup_table[ key ]
}
to_raylib_mouse_btn :: proc( btn : i32 ) -> rl.MouseButton {
@static raylib_mouse_btn_lookup_table := [?] rl.MouseButton {
rl.MouseButton.LEFT,
rl.MouseButton.MIDDLE,
rl.MouseButton.RIGHT,
rl.MouseButton.SIDE,
rl.MouseButton.FORWARD,
rl.MouseButton.BACK,
rl.MouseButton.EXTRA, }
return raylib_mouse_btn_lookup_table[ btn ]
}

View File

@ -101,6 +101,8 @@ Range2 :: struct #raw_union {
UnitRange2 :: distinct Range2
range2_zero :: Range2 {}
range2 :: #force_inline proc "contextless" ( a, b : Vec2 ) -> Range2 {
result := Range2 { pts = { a, b } }
return result

View File

@ -0,0 +1,7 @@
# Plans
Eventually want to generalize this core UI as its own library.
This will keep track of here whats needed for it to work wihtout the rest of this codebase.
* Provide UI input state in its own data stucture at the beginning of `ui_build_graph`:
*

View File

@ -15,6 +15,10 @@ UI_BoxFlag :: enum u64
UI_BoxFlags :: bit_set[UI_BoxFlag; u64]
// UI_BoxFlag_Scroll :: UI_BoxFlags { .Scroll_X, .Scroll_Y }
UI_NavLinks :: struct {
left, right, up, down : ^UI_Box,
}
UI_RenderBoxInfo :: struct {
using computed : UI_Computed,
using style : UI_Style,
@ -26,12 +30,15 @@ UI_RenderBoxInfo :: struct {
UI_Box :: struct {
// Cache ID
key : UI_Key,
// label : string,
label : StrRunesPair,
text : StrRunesPair,
// Regenerated per frame.
nav : UI_NavLinks,
// signal_callback : #type proc(),
// first, last : The first and last child of this box
// prev, next : The adjacent neighboring boxes who are children of to the same parent
using links : DLL_NodeFull( UI_Box ),
@ -129,7 +136,7 @@ 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.
is_app_ui := ui_context == & screen_ui
if intersects_range2( view_get_bounds(), box.computed.bounds)
if intersects_range2( ui_view_bounds(), box.computed.bounds)
{
return box.first
}

View File

@ -16,13 +16,17 @@ LayoutAlign_OriginTL_Bottom :: Vec2{0.5, 1}
LayoutAlign_OriginTL_BottomLeft :: Vec2{ 0, 1}
LayoutAlign_OriginTL_BottomRight :: Vec2{ 1, 1}
// LayoutAlign_OriginTL_
Layout_OriginCenter_Centered :: Vec2{0.5, 0.5}
UI_Align_Presets_Struct :: struct {
origin_tl_centered : Vec2,
text_centered : Vec2,
}
UI_Align_Presets :: UI_Align_Presets_Struct {
origin_tl_centered = {0.5, 0.5},
text_centered = {0.5, 0.5},
}
// The UI_Box's actual positioning and sizing

View File

@ -85,9 +85,16 @@ ui_box_compute_layout :: proc( box : ^UI_Box,
if .Scale_Width_By_Height_Ratio in layout.flags {
adjusted_size.x = adjusted_size.y * layout.size.min.x
}
else if .Fixed_Width in layout.flags {
adjusted_size.x = layout.size.min.x
}
if .Scale_Height_By_Width_Ratio in layout.flags {
adjusted_size.y = adjusted_size.x * layout.size.min.y
}
else if .Fixed_Height in layout.flags {
adjusted_size.y = layout.size.min.y
}
if .Size_To_Content in layout.flags {
// Preemtively traverse the children of this parent and have them compute their layout.
@ -97,14 +104,6 @@ ui_box_compute_layout :: proc( box : ^UI_Box,
//ui_compute_children_bounding_area(box)
}
// TODO(Ed): Should this force override all of the previous auto-sizing possible?
if .Fixed_Width in layout.flags {
adjusted_size.x = layout.size.min.x
}
if .Fixed_Height in layout.flags {
adjusted_size.y = layout.size.min.y
}
// 5. Determine relative position
origin_center := margined_bounds_origin
@ -186,34 +185,3 @@ ui_box_compute_layout_children :: proc( box : ^UI_Box )
}
}
ui_core_compute_layout :: proc( ui : ^UI_State )
{
profile(#procedure)
state := get_state()
root := ui.root
{
computed := & root.computed
style := root.style
layout := & root.layout
if ui == & state.screen_ui {
computed.bounds.min = transmute(Vec2) state.app_window.extent * -1
computed.bounds.max = transmute(Vec2) state.app_window.extent
}
computed.content = computed.bounds
}
for current := root.first; current != nil; current = ui_box_tranverse_next( current )
{
if ! current.computed.fresh {
ui_box_compute_layout( current )
}
array_append( & ui.render_queue, UI_RenderBoxInfo {
current.computed,
current.style,
current.text,
current.layout.font_size,
current.layout.border_width,
})
}
}

View File

@ -70,13 +70,13 @@ ui_signal_from_box :: proc ( box : ^ UI_Box, update_style := true, update_deltas
mouse_clickable := UI_BoxFlag.Mouse_Clickable in box.flags
keyboard_clickable := UI_BoxFlag.Keyboard_Clickable in box.flags
is_focusable := .Focusable in box.flags
was_hot := (box.hot_delta > 0)
was_active := (ui.active == box.key) && (box.active_delta > 0)
was_hot := (box.hot_delta > 0)
was_disabled := box.disabled_delta > 0
// if was_hot {
// runtime.debug_trap()
// }
is_focused_locked := is_focusable ? was_active : false
// Check to see if this box is active
if mouse_clickable && signal.cursor_over && left_pressed && was_hot
@ -93,14 +93,14 @@ ui_signal_from_box :: proc ( box : ^ UI_Box, update_style := true, update_deltas
// TODO(Ed) : Support double-click detection
}
if mouse_clickable && ! signal.cursor_over && left_released
if ! is_focused_locked && was_active && mouse_clickable && ! signal.cursor_over && left_released
{
box.active_delta = 0
ui.active = UI_Key(0)
ui.active_mouse[MouseBtn.Left] = UI_Key(0)
signal.released = true
signal.released = true
}
if keyboard_clickable
@ -109,6 +109,7 @@ ui_signal_from_box :: proc ( box : ^ UI_Box, update_style := true, update_deltas
}
// TODO(Ed): Should panning and scrolling get supported here? (problably not...)
// We can just report the scroll amount in the signal and have the scrollbox widget handle it
// TODO(Ed) : Add scrolling support
// if UI_BoxFlag.Scroll_X in box.flags {
@ -123,39 +124,7 @@ ui_signal_from_box :: proc ( box : ^ UI_Box, update_style := true, update_deltas
// if UI_BoxFlag.Pan_Y in box.flags {
// }
is_disabled := UI_BoxFlag.Disabled in box.flags
is_hot := ui.hot == box.key
is_active := ui.active == box.key
// TODO(Ed): It should be able to enter hot without mouse_clickable
if mouse_clickable && signal.cursor_over && ! is_disabled
{
hot_vacant := ui.hot == UI_Key(0)
active_vacant := ui.active == UI_Key(0)
// (active_vacant is_active)
if signal.cursor_over && active_vacant
{
if ! hot_vacant {
prev := ui_box_from_key( ui.curr_cache, ui.hot )
prev.hot_delta = 0
}
// prev_hot := zpl_hmap_get( ui.prev_cache, u64(ui.hot) )
// prev_hot_label := prev_hot != nil ? prev_hot.label.str : ""
// log( str_fmt_tmp("Detected HOT via CURSOR OVER: %v is_hot: %v is_active: %v prev_hot: %v", box.label.str, is_hot, is_active, prev_hot_label ))
ui.hot = box.key
is_hot = true
ui.hot_start_style = box.style
}
}
else if ! signal.cursor_over && was_hot
{
ui.hot = UI_Key(0)
is_hot = false
box.hot_delta = 0
}
if mouse_clickable && signal.cursor_over && left_released
if ! is_focused_locked && was_active && mouse_clickable && signal.cursor_over && left_released
{
box.active_delta = 0
@ -169,6 +138,39 @@ ui_signal_from_box :: proc ( box : ^ UI_Box, update_style := true, update_deltas
ui.last_clicked = box.key
}
}
is_disabled := UI_BoxFlag.Disabled in box.flags
is_hot := ui.hot == box.key
is_active := ui.active == box.key
// TODO(Ed): It should be able to enter hot without mouse_clickable
if mouse_clickable && signal.cursor_over && ! is_disabled
{
hot_vacant := ui.hot == UI_Key(0)
// active_vacant := ui.active == UI_Key(0)
if signal.cursor_over //&& active_vacant
{
if ! hot_vacant {
prev := ui_box_from_key( ui.curr_cache, ui.hot )
prev.hot_delta = 0
}
// prev_hot := zpl_hmap_get( ui.prev_cache, u64(ui.hot) )
// prev_hot_label := prev_hot != nil ? prev_hot.label.str : ""
// log( str_fmt_tmp("Detected HOT via CURSOR OVER: %v is_hot: %v is_active: %v prev_hot: %v", box.label.str, is_hot, is_active, prev_hot_label ))
ui.hot = box.key
is_hot = true
ui.hot_start_style = box.style
signal.hot = true
}
}
else if ! signal.cursor_over && was_hot
{
ui.hot = UI_Key(0)
is_hot = false
box.hot_delta = 0
}
// profile_end()
// State Deltas update

View File

@ -206,14 +206,55 @@ ui_graph_build_begin :: proc( ui : ^ UI_State, bounds : Vec2 = {} )
ui_parent_push(root)
}
ui_core_compute_layout :: proc( ui : ^UI_State )
{
profile(#procedure)
state := get_state()
}
ui_graph_build_end :: proc( ui : ^UI_State )
{
profile(#procedure)
state := get_state()
ui_parent_pop() // Should be ui_context.root
// Regenerate the computed layout if dirty
ui_compute_layout( ui )
Post_Build_Graph_Traversal:
{
root := ui.root
{
computed := & root.computed
style := root.style
layout := & root.layout
if ui == & state.screen_ui {
computed.bounds.min = transmute(Vec2) state.app_window.extent * -1
computed.bounds.max = transmute(Vec2) state.app_window.extent
}
computed.content = computed.bounds
}
for current := root.first; current != nil; current = ui_box_tranverse_next( current )
{
if ! current.computed.fresh {
ui_box_compute_layout( current )
}
// Enqueue for rendering
array_append( & ui.render_queue, UI_RenderBoxInfo {
current.computed,
current.style,
current.text,
current.layout.font_size,
current.layout.border_width,
})
}
}
get_state().ui_context = nil
}
@ -259,4 +300,14 @@ ui_top_ancestor :: #force_inline proc "contextless" ( box : ^UI_Box ) -> (^UI_Bo
return ancestor
}
ui_view_bounds :: #force_inline proc "contextless" () -> (range : Range2) {
using state := get_state();
if ui_context == & screen_ui {
return screen_get_bounds()
}
else {
return view_get_bounds()
}
}
ui_context :: #force_inline proc() -> ^UI_State { return get_state().ui_context }

View File

@ -117,20 +117,6 @@ ui_floating_build :: proc()
}
lookup.queued = true
dll_full_push_back(floating, lookup, nil )
// if first == nil {
// first = lookup
// last = lookup
// continue
// }
// if first == last {
// last = lookup
// last.prev = first
// first.next = last
// continue
// }
// last.next = lookup
// lookup.prev = last
// last = lookup
}
array_clear(build_queue)
@ -140,28 +126,7 @@ ui_floating_build :: proc()
if ! entry.queued
{
ensure(false, "There should be no queue failures yet")
if entry == first
{
first = entry.next
entry.next = nil
continue
}
if entry == last
{
last = last.prev
last.prev = nil
entry.prev = nil
continue
}
left := entry.prev
right := entry.next
left.next = right
right.prev = left
entry.prev = nil
entry.next = nil
dll_full_pop(to_raise, floating)
}
if entry.builder( entry.captures ) && entry != last && to_raise == nil

View File

@ -1,5 +1,7 @@
package sectr
import "base:runtime"
/*
Widget Layout Ops
*/
@ -13,6 +15,7 @@ ui_layout_children_horizontally :: proc( container : ^UI_Box, direction : UI_Lay
else {
container_width = container.computed.content.max.x - container.computed.content.min.x
}
container_height := container.computed.content.max.y - container.computed.content.min.y
// do layout calculations for the children
total_stretch_ratio : f32 = 0.0
@ -21,16 +24,13 @@ ui_layout_children_horizontally :: proc( container : ^UI_Box, direction : UI_Lay
{
using child.layout
scaled_width_by_height : b32 = b32(.Scale_Width_By_Height_Ratio in flags)
if .Scale_Width_By_Height_Ratio in flags
{
size_req_children += size.min.x * container_height
continue
}
if .Fixed_Width in flags
{
if scaled_width_by_height {
height := size.max.y != 0 ? size.max.y : container_width
width := height * size.min.x
size_req_children += width
continue
}
size_req_children += size.min.x
continue
}
@ -40,32 +40,45 @@ ui_layout_children_horizontally :: proc( container : ^UI_Box, direction : UI_Lay
avail_flex_space := container_width - 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_height : f32 ) -> (space_allocated : f32)
{
using child.layout
if ! (.Fixed_Width in flags) {
size.min.x = anchor.ratio.x * (1 / total_stretch_ratio) * avail_flex_space - child.layout.margins.left - child.layout.margins.right
if .Scale_Width_By_Height_Ratio in flags {
size.min.y = container_height
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
}
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
flags |= {.Fixed_Width}
return
}
space_used : f32 = 0.0
switch direction{
case .Right_To_Left:
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.x = space_used
space_used += size.min.x + child.layout.margins.left + child.layout.margins.right
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
}
case .Left_To_Right:
for child := container.first; child != nil; child = child.next {
allocate_space(child, total_stretch_ratio, avail_flex_space)
using child.layout
anchor = range2({0, 0}, {0, 0})
pos.x = space_used
space_used += size.min.x + child.layout.margins.left + child.layout.margins.right
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
}
}
}
@ -123,9 +136,8 @@ ui_layout_children_vertically :: proc( container : ^UI_Box, direction : UI_Layou
allocate_space(child, total_stretch_ratio, avail_flex_space)
using child.layout
anchor = range2({0,0}, {0, 0})
// alignment = {0, 0}
pos.y = -space_used
space_used += size.min.y
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
}
case .Top_To_Bottom:
@ -133,9 +145,8 @@ ui_layout_children_vertically :: proc( container : ^UI_Box, direction : UI_Layou
allocate_space(child, total_stretch_ratio, avail_flex_space)
using child.layout
anchor = range2({0, 0}, {0, 0})
// alignment = {0, 0}
pos.y = -space_used
space_used += size.min.y
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
}
}

View File

@ -17,7 +17,7 @@ ui_widget :: proc( label : string, flags : UI_BoxFlags ) -> (widget : UI_Widget)
ui_button :: proc( label : string, flags : UI_BoxFlags = {} ) -> (btn : UI_Widget)
{
btn_flags := UI_BoxFlags { .Mouse_Clickable, .Focusable, .Click_To_Focus }
btn_flags := UI_BoxFlags { .Mouse_Clickable }
btn.box = ui_box_make( btn_flags | flags, label )
btn.signal = ui_signal_from_box( btn.box )
return
@ -197,6 +197,7 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2,
}
else
{
app_color := app_color_theme()
layout := UI_Layout {
flags = flags,
anchor = range2({},{}),
@ -215,7 +216,7 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2,
corner_radii = {5, 0, 0, 0},
blur_size = 0,
font = get_state().default_font,
text_color = Color_ThmDark_Text_Default,
text_color = app_color.text_default,
cursor = {},
}
layout_combo = to_ui_layout_combo(layout)
@ -223,12 +224,12 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2,
{
using layout_combo.hot
using style_combo.hot
bg_color = Color_ThmDark_ResizeHandle_Hot
bg_color = app_color.resize_hndl_hot
}
{
using layout_combo.active
using style_combo.active
bg_color = Color_ThmDark_ResizeHandle_Active
bg_color = app_color.resize_hndl_active
}
}
theme := UI_Theme {
@ -364,7 +365,7 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2,
}
was_dragging = true
}
else if released && was_dragging
else if released// && was_dragging
{
// This needed to be added as for some reason, this was getting called in screen_ui even when we were resizing with a handle in a worksapce
if active_context != ui do return false

View File

@ -1,13 +1,21 @@
{
"$schema": "https://raw.githubusercontent.com/DanielGavin/ols/master/misc/ols.schema.json",
"odin_command": "C:/projects/SectrPrototype/toolchain/Odin/odin.exe",
"collections": [
{
"name": "sectr_host",
"path": "C:/projects/SectrPrototype/code/host"
},
{
"name": "sectr",
"path": "C:/projects/SectrPrototype/code/sectr"
},
{
"name": "thirdparty",
"path": "C:/projects/SectrPrototype/thirdparty"
}
],
"odin_command": "C:/projects/SectrPrototype/toolchain/Odin/odin.exe",
"enable_document_symbols": true,
"enable_document_symbols": false,
"enable_fake_methods": true,
"enable_format": false,
"enable_hover": true,
@ -18,5 +26,6 @@
"enable_inlay_hints": true,
"enable_procedure_context": true,
"enable_procedure_snippet": false,
"verbose": true,
"disable_parser_errors": false
}

View File

@ -0,0 +1,84 @@
cls
Write-Host "Reverse Build.ps1"
$ps_misc = join-path $PSScriptRoot 'helpers/misc.ps1'
. $ps_misc
$path_root = git rev-parse --show-toplevel
$path_code = Join-Path $path_root 'code'
$path_code_flattened = Join-Path $path_root 'code_flattened'
if (Test-Path $path_code_flattened) {
Remove-Item -Path $path_code_flattened -Recurse -Force -ErrorAction Ignore
}
New-Item -ItemType Directory -Path $path_code_flattened
# $whitelist_package = 'sectr'
function get-flattened-package
{
param(
[string]$pkg_name,
[string]$path_pkg_dir,
[string]$path_flattend_dir
)
$files = Get-ChildItem -Path $path_pkg_dir -File -Recurse
foreach ($file in $files)
{
if ($file.Name -eq '.ODIN_MONOLITHIC_PACKAGE') {
continue
}
# Read the file line by line to determine the package name, ignoring comments
$package_name = $null
Get-Content -Path $file.FullName | ForEach-Object {
if ($_ -notmatch '^\s*//')
{
if ($_ -match '^package\s+(\w+)$') {
$package_name = $Matches[1]
return $false
}
}
}
if ($pacakge_name -ne $pkg_name) {
Write-Host "Warning: The file $($file.FullName) does not contain a valid package declaration."
}
# Calculate relative path and prepend directory names to the file name
$relative_path = $file.FullName.Substring($path_pkg_dir.Length + 1)
$relative_dir = Split-Path $relative_path -Parent
$relative_dir = $relative_dir.Replace('\', '_').Replace('/', '_')
if ($relative_dir -ne '') {
$target_file_name = "$relative_dir" + "_" + $file.Name
} else {
$target_file_name = $file.Name
}
$target_file_path = Join-Path $path_flattend_dir $target_file_name
if (-not (Test-Path $target_file_path))
{ New-Item -ItemType SymbolicLink -Path $target_file_path -Value $file.FullName }
else
{ Write-Host "Warning: The link for $($file.FullName) already exists at $target_file_path. Skipping..." }
}
}
$path_pkg_gen = join-path $path_code 'gen'
$path_pkg_host = join-path $path_code 'host'
$path_pkg_sectr = join-path $path_code 'sectr'
$path_flattend_gen = join-path $path_code_flattened 'gen'
$path_flattend_host = join-path $path_code_flattened ' host'
$path_flattend_sectr = join-path $path_code_flattened ' sectr'
verify-path $path_flattend_gen
verify-path $path_flattend_host
verify-path $path_flattend_sectr
get-flattened-package 'gen' $path_pkg_gen $path_flattend_gen
get-flattened-package 'host' $path_pkg_host $path_flattend_host
get-flattened-package 'sectr' $path_pkg_sectr $path_flattend_sectr
Write-Host "Flattened directory structure for packages created successfully."

6
scripts/helpers/misc.ps1 Normal file
View File

@ -0,0 +1,6 @@
function verify-path { param( $path )
if (test-path $path) {return $true}
new-item -ItemType Directory -Path $path
return $false
}

@ -1 +1 @@
Subproject commit 67ae530d22c116f86d476743b5dfc978255391d4
Subproject commit 389e12a78580362cae32d522ac021d74187d02b5