From 3920dfd39a3f5d8bd422484b9d197ce53cf04d7c Mon Sep 17 00:00:00 2001 From: Synthasmagoria Date: Sun, 2 Aug 2026 14:09:48 +0200 Subject: [PATCH] Scale matrix add --- libraries/snths_ui/ui.odin | 24 ++++++--------- program.odin | 63 ++++++++++++++++++++++++++++++-------- 2 files changed, 60 insertions(+), 27 deletions(-) diff --git a/libraries/snths_ui/ui.odin b/libraries/snths_ui/ui.odin index 24b87ea..04a67d1 100644 --- a/libraries/snths_ui/ui.odin +++ b/libraries/snths_ui/ui.odin @@ -62,16 +62,7 @@ ElementType :: enum { InputFloat, Dropdown, Label, - Custom0, - Custom1, - Custom2, - Custom3, - Custom4, - Custom5, - Custom6, - Custom7, - Custom8, - Custom9, + Custom0, Custom1, Custom2, Custom3, Custom4, Custom5, Custom6, Custom7, Custom8, Custom9, } @rodata element_type_input := bit_set[ElementType] {.InputFloat} @@ -92,6 +83,11 @@ Dimensions :: struct { width, height: Size, } +dimensions_pixels :: proc(v: [2]f32) -> Dimensions {return {Size_Pixels(v.x), Size_Pixels(v.y)}} +dimensions_percentage :: proc(v: [2]f32) -> Dimensions {return {Size_Percentage(v.x), Size_Percentage(v.y)}} +dimensions_percentage_remainder :: proc(v: [2]f32) -> Dimensions {return {Size_PercentageRemainder(v.x), Size_PercentageRemainder(v.y)}} +dimensions_auto :: proc() -> Dimensions {return {SIZE_AUTO, SIZE_AUTO}} + Axis :: enum {X, Y} init :: proc(ctx: ^Context, element_capacity: int, measure_text_callback: MeasureTextProc, measure_text_callback_data: rawptr, allocator := context.allocator) { @@ -165,16 +161,16 @@ container_end :: proc() { br = {max(br.x, element_br.x), max(br.y, element_br.y)} } if width_is_auto { - container.area.width = br.x - container.area.x + container.area.width = br.x - container.area.x + container.padding.x } if height_is_auto { - container.area.height = br.y - container.area.y + container.area.height = br.y - container.area.y + container.padding.y } } ctx.same_line = false } -assert_auto_with_pixels :: proc(dimensions: Dimensions) { +assert_auto_dimension_with_pixels :: proc(dimensions: Dimensions) { container := _container_current() if _, is_auto := container.dimensions.width.(Size_Auto); is_auto { _, is_pixels := dimensions.width.(Size_Pixels) @@ -188,7 +184,7 @@ assert_auto_with_pixels :: proc(dimensions: Dimensions) { element :: proc(element_type: ElementType, dimensions: Dimensions, config: ElementConfiguration, data: rawptr = nil) -> ^Element { assert(element_type != .Container) - assert_auto_with_pixels(dimensions) + assert_auto_dimension_with_pixels(dimensions) element := Element{config = config, type = element_type, dimensions = dimensions, data = data} element.area = _resolve_element_area(element, is_text = (element.type == .Label)) return _append_element(element) diff --git a/program.odin b/program.odin index cf895ce..69d1f29 100644 --- a/program.odin +++ b/program.odin @@ -96,6 +96,19 @@ program: Program InputFloatField :: [32]byte MATRIX_POOL_SIZE :: 4096 +DIALOG_STATE_INPUT_FIELD_COUNT :: 16 +ProgramData_DialogState :: struct { + input_value_strings: [DIALOG_STATE_INPUT_FIELD_COUNT]InputFloatField, + input_values: [DIALOG_STATE_INPUT_FIELD_COUNT]f32, +} + +program_data_dialog_state_data_reset :: proc(data: ^ProgramData_DialogState) { + data^ = {} + for i in 0.. ^mat3 { } program_show_dialog :: proc(program: ^Program, dialog_type: ProgramDialogType) { + program_data_dialog_state_data_reset(&program.dialog_data) program.state = .Dialog program.dialog_type = dialog_type } @@ -187,20 +202,39 @@ program_update :: proc() { grid_inner_position := rect_get_tl(grid.inner_area) draw_grid(grid.area, {32.0, 32.0}, rl.GRAY) - program_render_ui(&program.ui_context, program.font_style, ui_elements) - program_render_ui(&program.ui_overlay_context, program.font_style, ui_overlay_elements) + program.ui_element_focus = program_render_ui_and_handle_focus(&program.ui_context, program.ui_element_focus, program.font_style, ui_elements) + program.ui_overlay_element_focus = program_render_ui_and_handle_focus(&program.ui_overlay_context, program.ui_overlay_element_focus, program.font_style, ui_overlay_elements) } program_build_dialog_ui :: proc(ctx: ^ui.Context) -> []ui.Element { size := v2{WINDOW_WIDTH, WINDOW_HEIGHT} - margin := size * 0.33 + container_margin := size * 0.33 + element_margin: f32 = 4.0 + dialog_data := &program.dialog_data ui.start(ctx, V2_ZERO, {WINDOW_WIDTH, WINDOW_HEIGHT}) - ui.container_begin({ui.Size_Percentage(1.0), ui.Size_Percentage(1.0)}, {margin = margin, padding = 4.0}) - ui.element(.Label, {}, {label = "Create a scale matrix", color = ui.col(rl.WHITE), margin = 4.0}) + ui.container_begin(ui.dimensions_auto(), {margin = container_margin, padding = 8.0}) + ui.element(.Label, {}, {label = "Create a scale matrix", color = ui.col(rl.WHITE), margin = element_margin}) + ui_labeled_input_float_element("X", 4.0, &dialog_data.input_values[0], &dialog_data.input_value_strings[0]) + ui_labeled_input_float_element("Y", 4.0, &dialog_data.input_values[0], &dialog_data.input_value_strings[0]) + ui_labeled_input_float_element("Z", 4.0, &dialog_data.input_values[0], &dialog_data.input_value_strings[0]) + + ui.element(.Button, ui.dimensions_pixels({96.0, 32.0}), {label = "Add", margin = element_margin}) + ui.same_line() + ui.element(.Button, ui.dimensions_pixels({96.0, 32.0}), {label = "Cancel", margin = element_margin}) ui.container_end() return ui.end() } +ui_labeled_input_float_element :: proc(label: cstring, margin: f32, value: ^f32, value_string: ^InputFloatField, allocator := context.temp_allocator) -> ^ui.Element { + label := fmt.ctprintf("%s: ", label) + label_element := ui.element(.Label, {}, {label = label, color = ui.col(rl.WHITE), margin = margin}) + dimensions := ui.Dimensions{ui.Size_Pixels(64.0), ui.dimensions_pixels(ui.rect_get_size(ui.get_element_outer_area(label_element^))).height} + ui.same_line() + input_data := new(UiElementData_FloatInput, context.temp_allocator) + input_data^ = {value = value, value_string = cstring(&value_string[0])} + return ui.element(.InputFloat, dimensions, {margin = margin}, input_data) +} + program_handle_mouse_workspace :: proc(mouse_state: MouseState, matrix_container: ^ui.Element) -> MouseState { mouse := rl.GetMousePosition() switch mouse_state { @@ -267,10 +301,11 @@ program_build_workspace_ui :: proc(ctx: ^ui.Context) -> (elements: []ui.Element, return } -program_render_ui :: proc(ctx: ^ui.Context, font_style: FontStyle, elements: []ui.Element) { +program_render_ui_and_handle_focus :: proc(ctx: ^ui.Context, focus_element_id: ui.ElementId, font_style: FontStyle, elements: []ui.Element) -> (focus: ui.ElementId) { scissor_container: ^ui.Element render_above: ui.Element render_above.id = ui.element_id_invalid() + focus_element_id := focus_element_id for &element in elements { offset: v2 @@ -322,20 +357,20 @@ program_render_ui :: proc(ctx: ^ui.Context, font_style: FontStyle, elements: []u rl.GuiSlider(area, element.label, "", data.value, data.min, data.max) case .InputFloat: data := cast(^UiElementData_FloatInput)element.data - if rl.GuiValueBoxFloat(area, element.label, data.value_string, data.value, program.ui_element_focus == element.id) == 1 { - program.ui_element_focus = element.id + if rl.GuiValueBoxFloat(area, element.label, data.value_string, data.value, focus_element_id == element.id) == 1 { + focus_element_id = element.id } case .Dropdown: assert(element.data != nil, "Element data cannot be nil when creating a dropdown") data := cast(^UiElementData_Dropdown)element.data - if program.ui_element_focus == element.id { + if focus_element_id == element.id { render_above = element } else { - if rl.GuiDropdownBox(area, element.label, data.value, program.ui_element_focus == element.id) { - if program.ui_element_focus == element.id { - program.ui_element_focus = ui.element_id_invalid() + if rl.GuiDropdownBox(area, element.label, data.value, focus_element_id == element.id) { + if focus_element_id == element.id { + focus_element_id = ui.element_id_invalid() } else { - program.ui_element_focus = element.id + focus_element_id = element.id } } } @@ -364,6 +399,8 @@ program_render_ui :: proc(ctx: ^ui.Context, font_style: FontStyle, elements: []u } } } + + return focus_element_id } ui_measure_text :: proc(str: cstring, font_data: rawptr) -> ui.v2 {