diff --git a/code/sectr/app/screen.odin b/code/sectr/app/screen.odin index 1ae9c13..3d9d84c 100644 --- a/code/sectr/app/screen.odin +++ b/code/sectr/app/screen.odin @@ -19,24 +19,7 @@ UI_ScreenState :: struct } }, - settings_menu : struct - { - container : UI_Widget, - engine_refresh_inputbox : UI_TextInputBox, - min_zoom_inputbox : UI_TextInputBox, - max_zoom_inputbox : UI_TextInputBox, - zoom_smooth_snappiness_input : UI_TextInputBox, - zoom_smooth_sensitivity_input : UI_TextInputBox, - zoom_digital_sensitivity_input : UI_TextInputBox, - zoom_scroll_delta_scale_input : UI_TextInputBox, - font_size_canvas_scalar_input : UI_TextInputBox, - font_size_screen_scalar_input : UI_TextInputBox, - cfg_drop_down : UI_DropDown, - zoom_mode_drop_down : UI_DropDown, - pos, size, min_size : Vec2, - is_open : b32, - is_maximized : b32, - }, + settings_menu : UI_SettingsMenu } ui_screen_reload :: proc() { @@ -151,519 +134,3 @@ ui_screen_menu_bar :: proc( captures : rawptr = nil ) -> (should_raise : b32 = f } return } - -ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b32 = false) -{ - profile("Settings Menu") - 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 - - Construct_Container: - { - scope(theme_window_panel) - container = ui_widget("Settings Menu", {}); - if ! settings_menu.is_maximized { - using container - layout.flags = { - // .Size_To_Content, - .Fixed_Width, .Fixed_Height, - .Fixed_Position_X, .Fixed_Position_Y, - .Origin_At_Anchor_Center - } - layout.pos = pos - layout.size = range2( size, {}) - } - else { - using container - layout.flags = {.Origin_At_Anchor_Center } - layout.pos = {} - } - - old_vbox := ui_box_from_key(prev_cache, ui_key_from_string("Settings Menu: VBox")) - if old_vbox != nil { - vbox_size := size_range2(old_vbox.computed.bounds) - larger_than_size := vbox_size.x > size.x || vbox_size.y > size.y - if ! settings_menu.is_maximized && larger_than_size - { - size = vbox_size - container.layout.size = range2(size, {}) - } - } - should_raise |= ui_resizable_handles( & container, & pos, & size) - } - ui_parent_push(container) - - vbox := ui_vbox_begin( .Top_To_Bottom, "Settings Menu: VBox", {.Mouse_Clickable}, compute_layout = true ) - { - should_raise |= b32(vbox.active) - ui_parent(vbox) - - Frame_Bar: - { - 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 = 14 - } - - 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 - style.corner_radii = { 0, 0, 0, 0 } - } - } - if frame_bar.active { - pos += input.mouse.delta - should_raise = true - } - } - - // TODO(Ed): This will eventually be most likely generalized/compressed. For now its the main scope for implementing new widgets. - app_config := ui_drop_down( & cfg_drop_down, "settings_menu.config", str_intern("App Config"), vb_compute_layout = true) - app_config.title.layout.font_size = 12 - if app_config.is_open - { - ui_settings_entry_inputbox :: proc( input_box : ^UI_TextInputBox, is_even : bool, label : string, setting_title : StrRunesPair, input_policy : UI_TextInput_Policy ) - { - scope( theme_table_row(is_even)) - hb := ui_hbox(.Left_To_Right, str_intern_fmt("%v.hb", label).str); { - using hb - - layout.size.min = {0, 25} - layout.flags = {.Fixed_Height} - layout.padding = to_ui_layout_side(4) - } - - scope(theme_text) - title := ui_text(str_intern_fmt("%v.title", label).str, setting_title); { - using title - layout.anchor.ratio.x = 1.0 - layout.margins.left = 10 - layout.font_size = 12 - } - - ui_text_input_box( input_box, str_intern_fmt("%v.input_box", label).str, allocator = persistent_slab_allocator(), policy = input_policy ) - { - using input_box - layout.flags = {.Fixed_Width} - layout.margins.left = 5 - layout.padding.right = 5 - layout.size.min.x = 80 - style.corner_radii = { 3, 3, 3, 3 } - } - } - - Engine_Refresh_Hz: - { - 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, 25} - layout.flags = {.Fixed_Height} - layout.padding = to_ui_layout_side(4) - } - - 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 - title.layout.font_size = 12 - } - - engine_refresh_config: { - using min_zoom_inputbox - digits_only = true - disallow_leading_zeros = true - disallow_decimal = true - digit_min = 1 - digit_max = 9999 - max_length = 4 - } - ui_text_input_box( & engine_refresh_inputbox, "settings_menu.engine_refresh_hz.inputbox", allocator = persistent_slab_allocator() ) - { - using engine_refresh_inputbox - layout.flags = {.Fixed_Width} - layout.margins.left = 5 - layout.padding.right = 5 - layout.size.min.x = 80 - style.corner_radii = { 3, 3, 3, 3 } - - if was_active - { - value, success := parse_uint(to_string(array_to_slice(input_str))) - if success { - value = clamp(value, 1, 9999) - config.engine_refresh_hz = value - } - } - else - { - clear( input_str ) - append( & input_str, to_runes(str_fmt("%v", config.engine_refresh_hz))) - } - } - } - - Min_Zoom: - { - 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, 25} - layout.flags = {.Fixed_Height} - layout.padding = to_ui_layout_side(4) - } - 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 - layout.font_size = 12 - } - - min_zoom_config: { - using min_zoom_inputbox - digits_only = true - disallow_leading_zeros = false - disallow_decimal = false - digit_min = 0.01 - digit_max = 9999 - max_length = 5 - } - ui_text_input_box( & min_zoom_inputbox, "settings_menu.cam_min_zoom.input_box", allocator = persistent_slab_allocator() ) - { - using min_zoom_inputbox - layout.flags = {.Fixed_Width} - layout.margins.left = 5 - layout.padding.right = 5 - layout.size.min.x = 80 - style.corner_radii = { 3, 3, 3, 3 } - - if was_active - { - value, success := parse_f32(to_string(array_to_slice(input_str))) - if success { - value = clamp(value, 0.001, 9999.0) - config.cam_min_zoom = value - } - } - else - { - clear( input_str ) - append( & input_str, to_runes(str_fmt("%v", config.cam_min_zoom))) - } - } - } - - Max_Zoom: - { - 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, 25} - layout.flags = {.Fixed_Height} - layout.padding = to_ui_layout_side(4) - } - 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 - layout.font_size = 12 - } - - max_zoom_config: { - using max_zoom_inputbox - digits_only = true - disallow_leading_zeros = false - disallow_decimal = false - digit_min = 0.01 - digit_max = 9999 - max_length = 5 - ui_text_input_box( & max_zoom_inputbox, "settings_menu.cam_max_zoom.input_box", allocator = persistent_slab_allocator() ) - { - using max_zoom_inputbox - layout.flags = {.Fixed_Width} - layout.margins.left = 5 - layout.padding.right = 5 - layout.size.min.x = 80 - style.corner_radii = { 3, 3, 3, 3 } - - if was_active - { - value, success := parse_f32(to_string(array_to_slice(input_str))) - if success { - value = clamp(value, 0.001, 9999.0) - config.cam_max_zoom = value - } - } - else - { - clear( input_str ) - append( & input_str, to_runes(str_fmt("%v", config.cam_max_zoom))) - } - } - } - } - - Zoom_Mode: - { - scope( theme_table_row(is_even = true)) - hb := ui_hbox(.Left_To_Right, "settings_menu.cam_zoom_mode.hb"); { - using hb - - layout.size.min = {0, 35} - layout.flags = {.Fixed_Height} - layout.padding = to_ui_layout_side(4) - } - - scope(theme_text) - title := ui_text("settings_menu.cam_zoom_mode.title", str_intern("Camera: Zoom Mode")); { - using title - layout.anchor.ratio.x = 1.0 - layout.margins.left = 10 - layout.font_size = 12 - } - - // TODO(Ed): This is technically a manual drop-down as the vbox within ui_dropdown is unusuable for attaching the buttons - // This can be alleviated if we add an option for the drop-down to support a floating vbox (fixed position computed, following drop_down btn) - // For now its buttons are attached to app_config vbox - mode_selector := ui_drop_down( & zoom_mode_drop_down, "settings_menu.cam_zoom_mode.drop_down", str_intern_fmt("%s", config.cam_zoom_mode), vb_compute_layout = true ) - mode_selector.btn.layout.size.min = { 80, mode_selector.btn.layout.size.min.y } - if mode_selector.is_open - { - idx := 1 - for entry in CameraZoomMode - { - ui_parent(app_config.vbox) - scope(theme_button) - btn := ui_button(str_intern_fmt("settings_menu.cam_zoom_mode.%s.btn", entry).str) - { - using btn - layout.size.min = {100, 25} - layout.alignment = {1.0, 0} - layout.anchor.left = 1.0 - layout.flags = {.Fixed_Height} - layout.padding = to_ui_layout_side(4) - - ui_parent(btn) - scope(theme_text) - text_widget := ui_text(str_intern_fmt("settings_menu.cam_zoom_mode.%s.text", entry).str, str_intern_fmt("%s", entry)) - } - - if btn.pressed { - mode_selector.should_close = true - config.cam_zoom_mode = entry - screen_ui.active = 0 - } - } - } - } - - Cam_Zoom_Smooth_Snappiness: - { - ui_settings_entry_inputbox( & zoom_smooth_snappiness_input, false, "settings_menu.cam_zoom_smooth_snappiness", str_intern("Camera: Zoom Smooth Snappiness"), - UI_TextInput_Policy { - digits_only = true, - disallow_leading_zeros = false, - disallow_decimal = false, - digit_min = 0.01, - digit_max = 9999, - max_length = 5, - } - ) - using zoom_smooth_snappiness_input - - if was_active - { - value, success := parse_f32(to_string(array_to_slice(input_str))) - if success { - value = clamp(value, 0.001, 9999.0) - config.cam_zoom_smooth_snappiness = value - } - } - else - { - clear( input_str ) - append( & input_str, to_runes(str_fmt("%v", config.cam_zoom_smooth_snappiness))) - } - } - - Cam_Zoom_Sensitivity_Smooth: - { - ui_settings_entry_inputbox( & zoom_smooth_sensitivity_input, true, "settings_menu.cam_zoom_sensitivity_smooth", str_intern("Camera: Zoom Smooth Sensitivity"), - UI_TextInput_Policy { - digits_only = true, - disallow_leading_zeros = false, - disallow_decimal = false, - digit_min = 0.01, - digit_max = 9999, - max_length = 5, - } - ) - using zoom_smooth_sensitivity_input - - if was_active - { - value, success := parse_f32(to_string(array_to_slice(input_str))) - if success { - value = clamp(value, 0.001, 9999.0) - config.cam_zoom_sensitivity_smooth = value - } - } - else - { - clear( input_str ) - append( & input_str, to_runes(str_fmt("%v", config.cam_zoom_sensitivity_smooth))) - } - } - - Cam_Zoom_Sensitivity_Digital: - { - ui_settings_entry_inputbox( & zoom_digital_sensitivity_input, false, "settings_menu.cam_zoom_sensitivity_digital", str_intern("Camera: Zoom Digital Sensitivity"), - UI_TextInput_Policy { - digits_only = true, - disallow_leading_zeros = false, - disallow_decimal = false, - digit_min = 0.01, - digit_max = 9999, - max_length = 5, - } - ) - using zoom_digital_sensitivity_input - - if was_active - { - value, success := parse_f32(to_string(array_to_slice(input_str))) - if success { - value = clamp(value, 0.001, 9999.0) - config.cam_zoom_sensitivity_digital = value - } - } - else - { - clear( input_str ) - append( & input_str, to_runes(str_fmt("%v", config.cam_zoom_sensitivity_digital))) - } - } - - Cam_Zoom_Scroll_Delta_Scale: - { - ui_settings_entry_inputbox( & zoom_scroll_delta_scale_input, true, "settings_menu.cam_zoom_scroll_delta_scale", str_intern("Camera: Zoom Scroll Delta Scale"), - UI_TextInput_Policy { - digits_only = true, - disallow_leading_zeros = false, - disallow_decimal = false, - digit_min = 0.01, - digit_max = 9999, - max_length = 5, - } - ) - using zoom_scroll_delta_scale_input - - if was_active - { - value, success := parse_f32(to_string(array_to_slice(input_str))) - if success { - value = clamp(value, 0.001, 9999.0) - config.cam_zoom_scroll_delta_scale = value - } - } - else - { - clear( input_str ) - append( & input_str, to_runes(str_fmt("%v", config.cam_zoom_scroll_delta_scale))) - } - } - - Font_Size_Screen_Scalar: - { - ui_settings_entry_inputbox( & font_size_screen_scalar_input, false, "settings_menu.font_size_screen_scalar", str_intern("Font: Size Screen Scalar"), - UI_TextInput_Policy { - digits_only = true, - disallow_leading_zeros = false, - disallow_decimal = false, - digit_min = 0.01, - digit_max = 9999, - max_length = 5, - } - ) - using font_size_screen_scalar_input - - if was_active - { - value, success := parse_f32(to_string(array_to_slice(input_str))) - if success { - value = clamp(value, 0.001, 9999.0) - config.font_size_screen_scalar = value - } - } - else - { - clear( input_str ) - append( & input_str, to_runes(str_fmt("%v", config.font_size_screen_scalar))) - } - } - - Font_Size_Canvas_Scalar: - { - ui_settings_entry_inputbox( & font_size_canvas_scalar_input, false, "settings_menu.font_size_canvas_scalar", str_intern("Font: Size Canvas Scalar"), - UI_TextInput_Policy { - digits_only = true, - disallow_leading_zeros = false, - disallow_decimal = false, - digit_min = 0.01, - digit_max = 9999, - max_length = 5, - } - ) - using font_size_canvas_scalar_input - - if was_active - { - value, success := parse_f32(to_string(array_to_slice(input_str))) - if success { - value = clamp(value, 0.001, 9999.0) - config.font_size_canvas_scalar = value - } - } - else - { - clear( input_str ) - append( & input_str, to_runes(str_fmt("%v", config.font_size_canvas_scalar))) - } - } - } - } - ui_vbox_end(vbox, compute_layout = false ) - - ui_parent_pop() // container - return -} diff --git a/code/sectr/app/settings_menu.odin b/code/sectr/app/settings_menu.odin new file mode 100644 index 0000000..2caf8a9 --- /dev/null +++ b/code/sectr/app/settings_menu.odin @@ -0,0 +1,551 @@ +package sectr + +UI_SettingsMenu :: struct +{ + container : UI_Widget, + engine_refresh_inputbox : UI_TextInputBox, + min_zoom_inputbox : UI_TextInputBox, + max_zoom_inputbox : UI_TextInputBox, + zoom_smooth_snappiness_input : UI_TextInputBox, + zoom_smooth_sensitivity_input : UI_TextInputBox, + zoom_digital_sensitivity_input : UI_TextInputBox, + zoom_scroll_delta_scale_input : UI_TextInputBox, + font_size_canvas_scalar_input : UI_TextInputBox, + font_size_screen_scalar_input : UI_TextInputBox, + cfg_drop_down : UI_DropDown, + zoom_mode_drop_down : UI_DropDown, + pos, size, min_size : Vec2, + is_open : b32, + is_maximized : b32, +} + +ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b32 = false) +{ + profile("Settings Menu") + state := get_state() + using state + using 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 + + scope(theme_window_panel) + container = ui_widget("Settings Menu", {}); + setup_container: + { + using container + if ! is_maximized + { + layout.flags = { + // .Size_To_Content, + .Fixed_Width, .Fixed_Height, + // .Min_Size_To_Content_Y, + .Fixed_Position_X, .Fixed_Position_Y, + .Origin_At_Anchor_Center + } + layout.pos = pos + layout.size = range2( size, {}) + } + else + { + layout.flags = {.Origin_At_Anchor_Center } + layout.pos = {} + } + + dragged := ui_resizable_handles( & container, & pos, & size) + should_raise |= dragged + + old_vbox := ui_box_from_key(prev_cache, ui_key_from_string("Settings Menu: VBox")) + if old_vbox != nil + { + vbox_children_bounds := ui_compute_children_overall_bounds(old_vbox) + joined_size := size_range2( vbox_children_bounds ) + if ! dragged + { + min_size.y = joined_size.y + if min_size.y > size.y { + pos.y += (layout.size.min.y - min_size.y) * 0.5 + layout.pos = pos + layout.size.min.y = min_size.y + } + } + } + } + ui_parent_push(container) + + vbox := ui_vbox_begin( .Top_To_Bottom, "Settings Menu: VBox", {.Mouse_Clickable}, compute_layout = true ) + { + // should_raise |= b32(vbox.active) + ui_parent(vbox) + + Frame_Bar: + { + 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 = 14 + } + + 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 + style.corner_radii = { 0, 0, 0, 0 } + } + } + if frame_bar.active { + pos += input.mouse.delta + should_raise = true + } + } + + // TODO(Ed): This will eventually be most likely generalized/compressed. For now its the main scope for implementing new widgets. + app_config := ui_drop_down( & cfg_drop_down, "settings_menu.config", str_intern("App Config"), vb_compute_layout = true); + app_config_closed: + { + app_config.title.layout.font_size = 12 + if ! app_config.is_open do break app_config_closed + + ui_settings_entry_inputbox :: proc( input_box : ^UI_TextInputBox, is_even : bool, label : string, setting_title : StrRunesPair, input_policy : UI_TextInput_Policy ) + { + scope( theme_table_row(is_even)) + hb := ui_hbox(.Left_To_Right, str_intern_fmt("%v.hb", label).str); { + using hb + + layout.size.min = {0, 25} + layout.flags = {.Fixed_Height} + layout.padding = to_ui_layout_side(4) + } + + scope(theme_text) + title := ui_text(str_intern_fmt("%v.title", label).str, setting_title); { + using title + layout.anchor.ratio.x = 1.0 + layout.margins.left = 10 + layout.font_size = 12 + } + + ui_text_input_box( input_box, str_intern_fmt("%v.input_box", label).str, allocator = persistent_slab_allocator(), policy = input_policy ) + { + using input_box + layout.flags = {.Fixed_Width} + layout.margins.left = 5 + layout.padding.right = 5 + layout.size.min.x = 80 + style.corner_radii = { 3, 3, 3, 3 } + } + } + + Engine_Refresh_Hz: + { + 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, 25} + layout.flags = {.Fixed_Height} + layout.padding = to_ui_layout_side(4) + } + + 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 + title.layout.font_size = 12 + } + + engine_refresh_config: { + using min_zoom_inputbox + digits_only = true + disallow_leading_zeros = true + disallow_decimal = true + digit_min = 1 + digit_max = 9999 + max_length = 4 + } + ui_text_input_box( & engine_refresh_inputbox, "settings_menu.engine_refresh_hz.inputbox", allocator = persistent_slab_allocator() ) + { + using engine_refresh_inputbox + layout.flags = {.Fixed_Width} + layout.margins.left = 5 + layout.padding.right = 5 + layout.size.min.x = 80 + style.corner_radii = { 3, 3, 3, 3 } + + if was_active + { + value, success := parse_uint(to_string(array_to_slice(input_str))) + if success { + value = clamp(value, 1, 9999) + config.engine_refresh_hz = value + } + } + else + { + clear( input_str ) + append( & input_str, to_runes(str_fmt("%v", config.engine_refresh_hz))) + } + } + } + + Min_Zoom: + { + 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, 25} + layout.flags = {.Fixed_Height} + layout.padding = to_ui_layout_side(4) + } + 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 + layout.font_size = 12 + } + + min_zoom_config: { + using min_zoom_inputbox + digits_only = true + disallow_leading_zeros = false + disallow_decimal = false + digit_min = 0.01 + digit_max = 9999 + max_length = 5 + } + ui_text_input_box( & min_zoom_inputbox, "settings_menu.cam_min_zoom.input_box", allocator = persistent_slab_allocator() ) + { + using min_zoom_inputbox + layout.flags = {.Fixed_Width} + layout.margins.left = 5 + layout.padding.right = 5 + layout.size.min.x = 80 + style.corner_radii = { 3, 3, 3, 3 } + + if was_active + { + value, success := parse_f32(to_string(array_to_slice(input_str))) + if success { + value = clamp(value, 0.001, 9999.0) + config.cam_min_zoom = value + } + } + else + { + clear( input_str ) + append( & input_str, to_runes(str_fmt("%v", config.cam_min_zoom))) + } + } + } + + Max_Zoom: + { + 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, 25} + layout.flags = {.Fixed_Height} + layout.padding = to_ui_layout_side(4) + } + 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 + layout.font_size = 12 + } + + max_zoom_config: { + using max_zoom_inputbox + digits_only = true + disallow_leading_zeros = false + disallow_decimal = false + digit_min = 0.01 + digit_max = 9999 + max_length = 5 + ui_text_input_box( & max_zoom_inputbox, "settings_menu.cam_max_zoom.input_box", allocator = persistent_slab_allocator() ) + { + using max_zoom_inputbox + layout.flags = {.Fixed_Width} + layout.margins.left = 5 + layout.padding.right = 5 + layout.size.min.x = 80 + style.corner_radii = { 3, 3, 3, 3 } + + if was_active + { + value, success := parse_f32(to_string(array_to_slice(input_str))) + if success { + value = clamp(value, 0.001, 9999.0) + config.cam_max_zoom = value + } + } + else + { + clear( input_str ) + append( & input_str, to_runes(str_fmt("%v", config.cam_max_zoom))) + } + } + } + } + + Zoom_Mode: + { + scope( theme_table_row(is_even = true)) + hb := ui_hbox(.Left_To_Right, "settings_menu.cam_zoom_mode.hb"); { + using hb + + layout.size.min = {0, 35} + layout.flags = {.Fixed_Height} + layout.padding = to_ui_layout_side(4) + } + + scope(theme_text) + title := ui_text("settings_menu.cam_zoom_mode.title", str_intern("Camera: Zoom Mode")); { + using title + layout.anchor.ratio.x = 1.0 + layout.margins.left = 10 + layout.font_size = 12 + } + + // TODO(Ed): This is technically a manual drop-down as the vbox within ui_dropdown is unusuable for attaching the buttons + // This can be alleviated if we add an option for the drop-down to support a floating vbox (fixed position computed, following drop_down btn) + // For now its buttons are attached to app_config vbox + mode_selector := ui_drop_down( & zoom_mode_drop_down, "settings_menu.cam_zoom_mode.drop_down", str_intern_fmt("%s", config.cam_zoom_mode), vb_compute_layout = true ); + mode_selector_closed: + { + using mode_selector + btn.layout.size.min = { 80, btn.layout.size.min.y } + if ! is_open do break mode_selector_closed + + idx := 1 + for entry in CameraZoomMode + { + ui_parent(app_config.vbox) + scope(theme_button) + btn := ui_button(str_intern_fmt("settings_menu.cam_zoom_mode.%s.btn", entry).str) + { + using btn + layout.size.min = {100, 25} + layout.alignment = {1.0, 0} + layout.anchor.left = 1.0 + layout.flags = {.Fixed_Height} + layout.padding = to_ui_layout_side(4) + + ui_parent(btn) + scope(theme_text) + text_widget := ui_text(str_intern_fmt("settings_menu.cam_zoom_mode.%s.text", entry).str, str_intern_fmt("%s", entry)) + } + + if btn.pressed { + mode_selector.should_close = true + config.cam_zoom_mode = entry + screen_ui.active = 0 + } + } + } + } + + Cam_Zoom_Smooth_Snappiness: + { + ui_settings_entry_inputbox( & zoom_smooth_snappiness_input, false, "settings_menu.cam_zoom_smooth_snappiness", str_intern("Camera: Zoom Smooth Snappiness"), + UI_TextInput_Policy { + digits_only = true, + disallow_leading_zeros = false, + disallow_decimal = false, + digit_min = 0.01, + digit_max = 9999, + max_length = 5, + } + ) + using zoom_smooth_snappiness_input + + if was_active + { + value, success := parse_f32(to_string(array_to_slice(input_str))) + if success { + value = clamp(value, 0.001, 9999.0) + config.cam_zoom_smooth_snappiness = value + } + } + else + { + clear( input_str ) + append( & input_str, to_runes(str_fmt("%v", config.cam_zoom_smooth_snappiness))) + } + } + + Cam_Zoom_Sensitivity_Smooth: + { + ui_settings_entry_inputbox( & zoom_smooth_sensitivity_input, true, "settings_menu.cam_zoom_sensitivity_smooth", str_intern("Camera: Zoom Smooth Sensitivity"), + UI_TextInput_Policy { + digits_only = true, + disallow_leading_zeros = false, + disallow_decimal = false, + digit_min = 0.01, + digit_max = 9999, + max_length = 5, + } + ) + using zoom_smooth_sensitivity_input + + if was_active + { + value, success := parse_f32(to_string(array_to_slice(input_str))) + if success { + value = clamp(value, 0.001, 9999.0) + config.cam_zoom_sensitivity_smooth = value + } + } + else + { + clear( input_str ) + append( & input_str, to_runes(str_fmt("%v", config.cam_zoom_sensitivity_smooth))) + } + } + + Cam_Zoom_Sensitivity_Digital: + { + ui_settings_entry_inputbox( & zoom_digital_sensitivity_input, false, "settings_menu.cam_zoom_sensitivity_digital", str_intern("Camera: Zoom Digital Sensitivity"), + UI_TextInput_Policy { + digits_only = true, + disallow_leading_zeros = false, + disallow_decimal = false, + digit_min = 0.01, + digit_max = 9999, + max_length = 5, + } + ) + using zoom_digital_sensitivity_input + + if was_active + { + value, success := parse_f32(to_string(array_to_slice(input_str))) + if success { + value = clamp(value, 0.001, 9999.0) + config.cam_zoom_sensitivity_digital = value + } + } + else + { + clear( input_str ) + append( & input_str, to_runes(str_fmt("%v", config.cam_zoom_sensitivity_digital))) + } + } + + Cam_Zoom_Scroll_Delta_Scale: + { + ui_settings_entry_inputbox( & zoom_scroll_delta_scale_input, true, "settings_menu.cam_zoom_scroll_delta_scale", str_intern("Camera: Zoom Scroll Delta Scale"), + UI_TextInput_Policy { + digits_only = true, + disallow_leading_zeros = false, + disallow_decimal = false, + digit_min = 0.01, + digit_max = 9999, + max_length = 5, + } + ) + using zoom_scroll_delta_scale_input + + if was_active + { + value, success := parse_f32(to_string(array_to_slice(input_str))) + if success { + value = clamp(value, 0.001, 9999.0) + config.cam_zoom_scroll_delta_scale = value + } + } + else + { + clear( input_str ) + append( & input_str, to_runes(str_fmt("%v", config.cam_zoom_scroll_delta_scale))) + } + } + + Font_Size_Screen_Scalar: + { + ui_settings_entry_inputbox( & font_size_screen_scalar_input, false, "settings_menu.font_size_screen_scalar", str_intern("Font: Size Screen Scalar"), + UI_TextInput_Policy { + digits_only = true, + disallow_leading_zeros = false, + disallow_decimal = false, + digit_min = 0.01, + digit_max = 9999, + max_length = 5, + } + ) + using font_size_screen_scalar_input + + if was_active + { + value, success := parse_f32(to_string(array_to_slice(input_str))) + if success { + value = clamp(value, 0.001, 9999.0) + config.font_size_screen_scalar = value + } + } + else + { + clear( input_str ) + append( & input_str, to_runes(str_fmt("%v", config.font_size_screen_scalar))) + } + } + + Font_Size_Canvas_Scalar: + { + ui_settings_entry_inputbox( & font_size_canvas_scalar_input, false, "settings_menu.font_size_canvas_scalar", str_intern("Font: Size Canvas Scalar"), + UI_TextInput_Policy { + digits_only = true, + disallow_leading_zeros = false, + disallow_decimal = false, + digit_min = 0.01, + digit_max = 9999, + max_length = 5, + } + ) + using font_size_canvas_scalar_input + + if was_active + { + value, success := parse_f32(to_string(array_to_slice(input_str))) + if success { + value = clamp(value, 0.001, 9999.0) + config.font_size_canvas_scalar = value + } + } + else + { + clear( input_str ) + append( & input_str, to_runes(str_fmt("%v", config.font_size_canvas_scalar))) + } + } + } + } + ui_vbox_end(vbox, compute_layout = false ) + + ui_parent_pop() // container + return +} diff --git a/code/sectr/app/state.odin b/code/sectr/app/state.odin index 34d8cdb..d352032 100644 --- a/code/sectr/app/state.odin +++ b/code/sectr/app/state.odin @@ -188,6 +188,7 @@ FontData :: struct { FrameTime :: struct { sleep_is_granular : b32, + current_frame : u64, delta_seconds : f64, delta_ms : f64, delta_ns : Duration, @@ -233,17 +234,7 @@ State :: struct { monitor_id : i32, monitor_refresh_hz : i32, - // using frametime : FrameTime, - sleep_is_granular : b32, - - frame : u64, - frametime_delta_seconds : f64, - frametime_delta_ms : f64, - frametime_delta_ns : Duration, - frametime_target_ms : f64, - frametime_elapsed_ms : f64, - frametime_avg_ms : f64, - fps_avg : f64, + using frametime : FrameTime, // fonts : FontData, font_provider_ctx : FontProviderContext, @@ -278,15 +269,23 @@ State :: struct { sokol_context : runtime.Context, } +// NOTE: Avoid getting a mutable reference to state get_state :: #force_inline proc "contextless" () -> ^ State { return cast( ^ State ) Memory_App.persistent.reserve_start } -// get_frametime :: #force_inline proc "contextless" () -> FrameTime { -// return get_state().frametime -// } + +get_input_state :: #force_inline proc "contextless" () -> InputState { + return (get_state().input ^) +} + +frametime_delta32 :: #force_inline proc "contextless" () -> f32 { + return cast(f32) get_state().frametime.delta_ms +} 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 } +debug_data :: #force_inline proc "contextless" () -> DebugData { return get_state().debug } +get_frametime :: #force_inline proc "contextless" () -> FrameTime { return get_state().frametime } #endregion("State") diff --git a/code/sectr/math/math.odin b/code/sectr/math/math.odin index 4f99688..37c505a 100644 --- a/code/sectr/math/math.odin +++ b/code/sectr/math/math.odin @@ -135,8 +135,15 @@ equal_range2 :: #force_inline proc "contextless" ( a, b : Range2 ) -> b32 { return b32(result) } +// Will resolve the largest range possible given a & b. +join_range2 :: proc "contextless" ( a, b : Range2 ) -> (joined : Range2) { + joined.min = min( a.min, b.min ) + joined.max = max( a.max, b.max ) + return +} + size_range2 :: #force_inline proc "contextless" ( value : Range2 ) -> Vec2 { - return { value.p1.x - value.p0.x, value.p0.y - value.p1.y } + return { abs( value.p1.x - value.p0.x ), abs( value.p0.y - value.p1.y ) } } #endregion("Range2") diff --git a/code/sectr/ui/core/layout.odin b/code/sectr/ui/core/layout.odin index bd55a78..704d381 100644 --- a/code/sectr/ui/core/layout.odin +++ b/code/sectr/ui/core/layout.odin @@ -113,6 +113,11 @@ UI_LayoutFlag :: enum u32 { // For this to work, the children must have a minimum size set & their size overall must be greater than the parent's minimum size Size_To_Content, + // Will set minimum size to the child with the furthest bounds on X + Min_Size_To_Content_X, + // Will set minimum size to the child with the furthest bounds on Y + Min_Size_To_Content_Y, + // Will size the box to its text. Size_To_Text, diff --git a/code/sectr/ui/core/layout_compute.odin b/code/sectr/ui/core/layout_compute.odin index 8a34474..787877b 100644 --- a/code/sectr/ui/core/layout_compute.odin +++ b/code/sectr/ui/core/layout_compute.odin @@ -99,12 +99,36 @@ ui_box_compute_layout :: proc( box : ^UI_Box, adjusted_size.y = layout.size.min.y } + border_offset := Vec2 { layout.border_width, layout.border_width } + + // TODO(Ed): These are still WIP if .Size_To_Content in layout.flags { // Preemtively traverse the children of this parent and have them compute their layout. // This parent will just set its size to the max bounding area of those children. // This will recursively occur if child also depends on their content size from their children, etc. - ui_box_compute_layout_children(box) - //ui_compute_children_bounding_area(box) + // ui_box_compute_layout_children(box) + children_bounds := ui_compute_children_overall_bounds(box) + resolved_bounds := range2( + children_bounds.min - { layout.padding.left, layout.padding.bottom } - border_offset, + children_bounds.max + { layout.padding.right, layout.padding.top } + border_offset, + ) + adjusted_size = size_range2( resolved_bounds ) + } + if .Min_Size_To_Content_X in layout.flags { + children_bounds := ui_compute_children_overall_bounds(box) + resolved_bounds := range2( + children_bounds.min - { layout.padding.left, layout.padding.bottom } - border_offset, + children_bounds.max + { layout.padding.right, layout.padding.top } + border_offset, + ) + adjusted_size.x = size_range2( resolved_bounds ).x + } + if .Min_Size_To_Content_Y in layout.flags { + children_bounds := ui_compute_children_overall_bounds(box) + resolved_bounds := range2( + children_bounds.min - { layout.padding.left, layout.padding.bottom } - border_offset, + children_bounds.max + { layout.padding.right, layout.padding.top } + border_offset, + ) + adjusted_size.y = size_range2(resolved_bounds).y } // 5. Determine relative position @@ -146,8 +170,6 @@ ui_box_compute_layout :: proc( box : ^UI_Box, // 7. Padding & Content // Determine Padding's outer bounds - border_offset := Vec2 { layout.border_width, layout.border_width } - padding_bounds := range2( bounds.min + border_offset, bounds.min - border_offset, @@ -183,9 +205,19 @@ ui_box_compute_layout :: proc( box : ^UI_Box, computed.fresh = true && !dont_mark_fresh } -ui_compute_children_bounding_area :: proc ( box : ^UI_Box ) +ui_compute_children_overall_bounds :: proc ( box : ^UI_Box ) -> ( children_bounds : Range2 ) { - // TODO(Ed): Implement this so we can have the .Size_To_Content flag supported. + for current := box.first; current != nil && current.prev != box; current = ui_box_tranverse_next_depth_first( current ) + { + if current == box do return + if ! current.computed.fresh do ui_box_compute_layout( current ) + if current == box.first { + children_bounds = current.computed.bounds + continue + } + children_bounds = join_range2( current.computed.bounds, children_bounds ) + } + return } ui_box_compute_layout_children :: proc( box : ^UI_Box )