From 31422d95921f5363c404b993b4d472991fffb6c8 Mon Sep 17 00:00:00 2001 From: Synthasmagoria Date: Fri, 31 Jul 2026 11:51:09 +0200 Subject: [PATCH] Matrix container --- libraries/snths_ui/ui.odin | 51 ++++++---------------- program.odin | 87 ++++++++++++++++++++++++++++---------- utils.odin | 4 ++ 3 files changed, 80 insertions(+), 62 deletions(-) diff --git a/libraries/snths_ui/ui.odin b/libraries/snths_ui/ui.odin index 5ffad7f..66557fe 100644 --- a/libraries/snths_ui/ui.odin +++ b/libraries/snths_ui/ui.odin @@ -11,6 +11,9 @@ rect_get_tr :: #force_inline proc(rect: rect2) -> v2 {return {rect.x + rect.widt rect_get_br :: #force_inline proc(rect: rect2) -> v2 {return {rect.x + rect.width, rect.y + rect.height}} rect_get_bl :: #force_inline proc(rect: rect2) -> v2 {return {rect.x, rect.y + rect.height}} rect_get_size :: #force_inline proc(rect: rect2) -> v2 {return {rect.width, rect.height}} +rect_get_corners :: #force_inline proc(rect: rect2) -> (tl, tr, br, bl: v2) { + return rect_get_tl(rect), rect_get_tr(rect), rect_get_br(rect), rect_get_bl(rect) +} rect_grow :: proc(rect: rect2, amount: v2) -> rect2 {return {rect.x - amount.x / 2.0, rect.y - amount.y / 2.0, rect.width + amount.x, rect.height + amount.y}} ctx: ^Context @@ -30,7 +33,7 @@ Element :: struct { area: rect2, id: int, using config: ElementConfiguration, - data: ElementData, + data: rawptr, type: ElementType, dimensions: Dimensions, } @@ -41,22 +44,6 @@ ElementConfiguration :: struct { margin, padding: v2, } -ElementData :: struct { - min, max: f32, - value: ^f32, - value_string: cstring, -} - -ElementData_Slider :: struct { - min, max: f32, - value: ^f32, -} - -ElementData_FloatInput :: struct { - value: ^f32, - value_string: cstring, -} - ElementType :: enum { Container, Button, @@ -143,9 +130,9 @@ focus_next_element :: proc(ctx: ^Context, allowed_focus := element_type_input) { ctx.element_focus_id = -1 } -container_begin :: proc(dimensions: Dimensions, config: ElementConfiguration) -> ^Element { +container_begin :: proc(dimensions: Dimensions, config: ElementConfiguration, data: rawptr = nil) -> ^Element { area := _resolve_element_area(dimensions, config.margin) - element := _append_element({area = area, config = config, type = .Container, dimensions = dimensions}) + element := _append_element({area = area, config = config, type = .Container, dimensions = dimensions, data = data}) container_index := len(ctx.elements) - 1 append(&ctx.containers, container_index) append(&ctx.container_last_element, -1) @@ -187,36 +174,22 @@ assert_no_dimensions_percentage_in_auto_container :: proc(dimensions: Dimensions } } -button :: proc(dimensions: Dimensions, config: ElementConfiguration) -> ^Element { +button :: proc(dimensions: Dimensions, config: ElementConfiguration, data: rawptr = nil) -> ^Element { assert_no_dimensions_percentage_in_auto_container(dimensions) area := _resolve_element_area(dimensions, config.margin) - return _append_element({ - area = area, - config = config, - type = .Button, - dimensions = dimensions}) + return _append_element({area = area, config = config, type = .Button, dimensions = dimensions, data = data}) } -slider :: proc(dimensions: Dimensions, config: ElementConfiguration, data: ElementData_Slider) -> ^Element { +slider :: proc(dimensions: Dimensions, config: ElementConfiguration, data: rawptr = nil) -> ^Element { assert_no_dimensions_percentage_in_auto_container(dimensions) area := _resolve_element_area(dimensions, config.margin) - return _append_element({ - area = area, - config = config, - type = .Slider, - data = {max = data.max, min = data.min, value = data.value}, - dimensions = dimensions}) + return _append_element({area = area, config = config, type = .Slider, dimensions = dimensions, data = data}) } -input_float :: proc(dimensions: Dimensions, config: ElementConfiguration, data: ElementData_FloatInput) -> ^Element { +input_float :: proc(dimensions: Dimensions, config: ElementConfiguration, data: rawptr = nil) -> ^Element { assert_no_dimensions_percentage_in_auto_container(dimensions) area := _resolve_element_area(dimensions, config.margin) - return _append_element({ - area = area, - config = config, - type = .InputFloat, - data = {value = data.value, value_string = data.value_string}, - dimensions = dimensions}) + return _append_element({area = area, config = config, type = .InputFloat, dimensions = dimensions, data = data}) } get_element_outer_area :: proc(element: Element) -> rect2 { diff --git a/program.odin b/program.odin index de6ad66..46cc059 100644 --- a/program.odin +++ b/program.odin @@ -4,6 +4,26 @@ import rl "libraries/raylib" import ui "libraries/snths_ui" import "core:fmt" +UiContainerType :: enum { + Normal, + Matrix, +} + +UiElementData_Container :: struct { + type: UiContainerType, + thickness: f32, +} + +UiElementData_Slider :: struct { + min, max: f32, + value: ^f32, +} + +UiElementData_FloatInput :: struct { + value: ^f32, + value_string: cstring, +} + FontStyle :: struct { font: rl.Font, size, spacing: f32 @@ -92,13 +112,9 @@ program_update :: proc() { } program_build_ui :: proc() -> []ui.Element { - container_margin: f32 = 4.0 - container_config := ui.ElementConfiguration { - margin = V2_ONE * container_margin, - } - ui.start(&program.ui_context, {0, 0}, {WINDOW_WIDTH, WINDOW_HEIGHT}) - top_bar_container := ui.container_begin({ui.Size_Percentage(1.0), ui.Size_Pixels(48.0)}, container_config) + top_bar_container_config := ui.ElementConfiguration {margin = V2_ONE * 4.0} + top_bar_container := ui.container_begin({ui.Size_Percentage(1.0), ui.Size_Pixels(48.0)}, top_bar_container_config) top_bar_inner_height := ui.get_element_inner_area(top_bar_container^).height top_bar_button_dimensions := ui.Dimensions {ui.Size_Pixels(top_bar_inner_height), ui.Size_Pixels(top_bar_inner_height)} top_bar_button_config := ui.ElementConfiguration {margin = V2_ONE * 4} @@ -112,11 +128,12 @@ program_build_ui :: proc() -> []ui.Element { } ui.container_end() - ui.container_begin({ui.Size_Percentage(0.2), ui.Size_PercentageRemainder(1.0)}, container_config) + side_bar_container_config := ui.ElementConfiguration {margin = V2_ONE * 4.0} + ui.container_begin({ui.Size_Percentage(0.2), ui.Size_PercentageRemainder(1.0)}, side_bar_container_config) for i in 0.. []ui.Element { return ui.end() } -ui_mat3 :: proc(mat: ^mat3, value_strings: []InputFloatField, dimensions: ui.Dimensions, config: ui.ElementConfiguration) { - ui.container_begin(dimensions, config) +ui_mat3 :: proc(mat: []f32, value_strings: []InputFloatField, dimensions: ui.Dimensions, config: ui.ElementConfiguration, allocator := context.temp_allocator) { + container_data := new(UiElementData_Container, allocator) + container_data^ = {type = .Matrix, thickness = 2.0} + ui.container_begin(dimensions, config, container_data) matrix_input_config := ui.ElementConfiguration {margin = V2_ONE * 4.0} matrix_input_dimensions := ui.Dimensions {ui.Size_Percentage(1.0 / 3.0), ui.Size_Percentage(1.0 / 3.0)} #unroll for i in 0..<3 { - data: ui.ElementData_FloatInput - data = {value = &mat[i, 0], value_string = input_float_field_as_cstring(&value_strings[i * 3 + 0])} - ui.input_float(matrix_input_dimensions, matrix_input_config, data) - ui.same_line() - data = {value = &mat[i, 1], value_string = input_float_field_as_cstring(&value_strings[i * 3 + 1])} - ui.input_float(matrix_input_dimensions, matrix_input_config, data) - ui.same_line() - data = {value = &mat[i, 2], value_string = input_float_field_as_cstring(&value_strings[i * 3 + 2])} - ui.input_float(matrix_input_dimensions, matrix_input_config, data) + #unroll for j in 0..<3 { + data := new(UiElementData_FloatInput, allocator) + index := i * 3 + j + data^ = {value = &mat[index], value_string = input_float_field_as_cstring(&value_strings[index])} + ui.input_float(matrix_input_dimensions, matrix_input_config, data) + ui.same_line() + } + program.ui_context.same_line = false } ui.container_end() } @@ -147,14 +165,37 @@ program_render_ui :: proc(ctx: ^ui.Context, elements: []ui.Element) { area := rl.Rectangle(element.area) switch element.type { case .Container: - rl.GuiGroupBox(area, element.label) + dim := rl.Color {0, 0, 0, 192} + if element.data != nil { + data := cast(^UiElementData_Container)element.data + switch data.type { + case .Normal: + rl.DrawRectangleRounded(area, 0.1, 4.0, dim) + rl.GuiGroupBox(area, element.label) + case .Matrix: + + matrix_area := ui.rect_grow(element.area, element.margin / 2.0) + tl, tr, br, bl := ui.rect_get_corners(matrix_area) + col := rl.WHITE + hook_length: f32 = 4.0 + rl.DrawLineEx(tl, bl, data.thickness, col) + rl.DrawLineEx(tl, tl + V2_RIGHT * hook_length, data.thickness, col) + rl.DrawLineEx(bl, bl + V2_RIGHT * hook_length, data.thickness, col) + rl.DrawLineEx(tr, br, data.thickness, col) + rl.DrawLineEx(tr, tr + V2_LEFT * hook_length, data.thickness, col) + rl.DrawLineEx(br, br + V2_LEFT * hook_length, data.thickness, col) + } + } else { + rl.DrawRectangleRounded(area, 0.1, 4.0, dim) + rl.GuiGroupBox(area, element.label) + } case .Button: rl.GuiButton(area, element.label) case .Slider: - data := element.data + data := cast(^UiElementData_Slider)element.data rl.GuiSlider(area, element.label, "", data.value, data.min, data.max) case .InputFloat: - data := element.data + data := cast(^UiElementData_FloatInput)element.data if rl.GuiValueBoxFloat(area, element.label, data.value_string, data.value, ui.is_element_focused(ctx, element)) == 1 { ui.focus_element(ctx, element) } diff --git a/utils.odin b/utils.odin index 07b27e9..b8f1433 100644 --- a/utils.odin +++ b/utils.odin @@ -71,6 +71,10 @@ tri2 :: [3]v2 Bezier :: [3]v2 V2_ONE :: v2{1.0, 1.0} +V2_LEFT :: v2{-1.0, 0.0} +V2_RIGHT :: v2{1.0, 0.0} +V2_UP :: v2{0.0, -1.0} +V2_DOWN :: v2{0.0, 1.0} /// ### MISCELANIOUS ### /// enum_to_raygui_options_string :: proc($T: typeid, allocator: mem.Allocator) -> cstring where intrinsics.type_is_enum(T) {