diff --git a/code/sectr/app/scratch.odin b/code/sectr/app/scratch.odin index f4baf2e..5c7aac3 100644 --- a/code/sectr/app/scratch.odin +++ b/code/sectr/app/scratch.odin @@ -39,5 +39,7 @@ DebugData :: struct { pipeline : sokol_gfx.Pipeline, bindings : sokol_gfx.Bindings, pass_action : sokol_gfx.Pass_Action, - } + }, + + last_invalid_input_time : Time, } diff --git a/code/sectr/app/screen.odin b/code/sectr/app/screen.odin index 3d31ed6..1ba15c3 100644 --- a/code/sectr/app/screen.odin +++ b/code/sectr/app/screen.odin @@ -231,6 +231,7 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b title.layout.font_size = 12 } + iter_next :: next input_box := ui_widget("settings_menu.engine_refresh.input_box", {.Mouse_Clickable, .Focusable, .Click_To_Focus}); { using input_box layout.flags = {.Fixed_Width} @@ -243,6 +244,8 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b else if input_box.hot do style.bg_color = app_color.input_box_bg_hot else do style.bg_color = app_color.input_box_bg + @static max_value_length : u64 = 4 + @static value_str : Array(rune) if value_str.header == nil { error : AllocatorError @@ -255,13 +258,65 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b } if input_box.active { - append( & value_str, input_events.codes_pressed ) + if ! input_box.was_active { + debug.last_invalid_input_time._nsec = 0 + } + + iter_obj := iterator( & input_events.key_events ); iter := & iter_obj + for event := iter_next( iter ); event != nil; event = iter_next( iter ) + { + if event.frame_id != state.frame do break + + if event.key == .backspace && event.type == .Key_Pressed { + if value_str.num > 0 { + pop( value_str) + break + } + } + + if event.key == .enter && event.type == .Key_Pressed { + screen_ui.active = 0 + } + } + + // append( & value_str, input_events.codes_pressed ) + for code in to_slice(input_events.codes_pressed) { + if value_str.num == 0 && code == '0' { + debug.last_invalid_input_time = time_now() + continue + } + + if value_str.num >= max_value_length { + debug.last_invalid_input_time = time_now() + continue + } + + // Only accept characters 0-9 + if '0' <= code && code <= '9' { + + append(&value_str, code) + } + else { + debug.last_invalid_input_time = time_now() + continue + } + } clear( input_events.codes_pressed ) + + invalid_color := RGBA8 { 70, 50, 50, 255} + + // Visual feedback - change background color briefly when invalid input occurs + feedback_duration :: 0.2 // seconds + curr_duration := duration_seconds( time_diff( debug.last_invalid_input_time, time_now() )) + if debug.last_invalid_input_time._nsec != 0 && curr_duration < feedback_duration { + input_box.style.bg_color = invalid_color // Or a specific error color from your theme + } } else if input_box.was_active { value, success := parse_uint(to_string(array_to_slice(value_str))) if success { + value = clamp(value, 1, 9999) config.engine_refresh_hz = value } } diff --git a/code/sectr/engine/client_api.odin b/code/sectr/engine/client_api.odin index 2cb1236..7d04261 100644 --- a/code/sectr/engine/client_api.odin +++ b/code/sectr/engine/client_api.odin @@ -60,6 +60,7 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem // Any persistent allocations are explicitly specified. context.allocator = transient_allocator() context.temp_allocator = transient_allocator() + } state := new( State, persistent_allocator() ) @@ -332,9 +333,9 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem ui_startup( & workspace.ui, cache_allocator = persistent_slab_allocator() ) } - debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum (197).txt", allocator = persistent_slab_allocator()) + // debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum (197).txt", allocator = persistent_slab_allocator()) // debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum (1022).txt", allocator = persistent_slab_allocator()) - // debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/sokol_gp.h", allocator = persistent_slab_allocator()) + debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/sokol_gp.h", allocator = persistent_slab_allocator()) // debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/ve_fontcache.h", allocator = persistent_slab_allocator()) alloc_error : AllocatorError; success : bool diff --git a/code/sectr/engine/update.odin b/code/sectr/engine/update.odin index 68d78d0..145068f 100644 --- a/code/sectr/engine/update.odin +++ b/code/sectr/engine/update.odin @@ -341,7 +341,7 @@ update :: proc( delta_time : f64 ) -> b32 // test_draggable() // test_text_box() // test_parenting( & default_layout, & frame_style_default ) - test_whitespace_ast( & default_layout, & frame_style_default ) + // test_whitespace_ast( & default_layout, & frame_style_default ) } //endregion Workspace Imgui Tick diff --git a/code/sectr/grime/mappings.odin b/code/sectr/grime/mappings.odin index 28b2242..700263d 100644 --- a/code/sectr/grime/mappings.odin +++ b/code/sectr/grime/mappings.odin @@ -120,6 +120,9 @@ import "core:time" duration_seconds :: time.duration_seconds duration_ms :: time.duration_milliseconds thread_sleep :: time.sleep + time_diff :: time.diff + time_now :: time.now + Time :: time.Time import "core:unicode" is_white_space :: unicode.is_white_space @@ -173,6 +176,7 @@ import "codebase:grime" array_clear :: grime.array_clear array_free :: grime.array_free array_grow_formula :: grime.array_grow_formula + array_pop :: grime.array_pop array_remove_at :: grime.array_remove_at array_resize :: grime.array_resize @@ -453,6 +457,7 @@ points_to_pixels :: proc { } pop :: proc { + array_pop, stack_pop, stack_allocator_pop, } @@ -560,6 +565,10 @@ to_runes :: proc { string_to_runes, } +to_slice :: proc { + array_to_slice, +} + to_string :: proc { runes_to_string, str_builder_to_string,