diff --git a/example/main.odin b/example/main.odin index 3699dde..fb4da07 100644 --- a/example/main.odin +++ b/example/main.odin @@ -9,8 +9,11 @@ WINDOW_HEIGHT :: 720 WINDOW_CAPTION :: "Immediate mode GUI" WINDOW_FRAMERATE :: 60 +v2 :: [2]f32 +V2_ONE :: v2{1.0, 1.0} + main :: proc() { - rl.SetTraceLogLevel(.WARNING) + // rl.SetTraceLogLevel(.WARNING) rl.InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_CAPTION) defer rl.CloseWindow() rl.SetTargetFPS(WINDOW_FRAMERATE) @@ -18,46 +21,74 @@ main :: proc() { ctx: ui.Context ui.init(&ctx, 4000) + outer_container_config := ui.ElementConfiguration {margin = {4.0, 8.0}, padding = {12.0, 24.0}, color = ui.col(rl.RED), label = ""} + inner_container_config := ui.ElementConfiguration {color = cast(ui.col)rl.GREEN, label = "", margin = {4.0, 4.0}} + button_config := ui.ElementConfiguration {margin = {4.0, 4.0}} + for !rl.WindowShouldClose() { - ui.start(&ctx, {0, 0}, {WINDOW_WIDTH, WINDOW_HEIGHT}) - outer_container := ui.container_begin( - dimensions = {ui.Size_Pixels(WINDOW_WIDTH), ui.Size_Pixels(WINDOW_HEIGHT)}, - config = { - margin = {4.0, 8.0}, - padding = {12.0, 24.0}, - color = cast([4]u8)rl.RED, - label = "", - }, - ) - inner_container_config := ui.ElementConfiguration {color = cast([4]u8)rl.GREEN, label = "", margin = {16.0, 8.0}} - inner_container_dimensions := ui.Dimensions {ui.Size_Percentage(1.0), ui.Size_Percentage(0.1)} - for i in 0..<10 { - ui.container_begin(dimensions = inner_container_dimensions, config = inner_container_config) - ui.container_end() - } - // inner_container_dimensions := ui.Dimensions {ui.Size_Percentage(1.0), ui.Size_Percentage(1.0)} - // ui.container_begin(dimensions = inner_container_dimensions, config = inner_container_config) - // ui.container_end() - ui.container_end() + + ui.start(&ctx, origin = {0, 0}, size = {WINDOW_WIDTH, WINDOW_HEIGHT}) + for i in 0..<10 { + ui.container_begin(dimensions = {ui.Size_Percentage(1.0), ui.Size_Percentage(0.1)}, config = inner_container_config) + for j in 0..<10 { + config := button_config + config.label = fmt.ctprintf("%d", i * 10 + j) + ui.button(dimensions = {ui.Size_Percentage(0.1), ui.Size_Percentage(1.0)}, config = config) + ui.same_line() + } + ui.container_end() + } elements := ui.end() rl.BeginDrawing() defer rl.EndDrawing() rl.ClearBackground(rl.BLACK) - rl.DrawRectangleRec(rl.Rectangle(ui.get_element_inner_area(outer_container^)), rl.GRAY) + render_ui_elements(elements) - for element in elements { - switch element.type { - case .Container: - area := rl.Rectangle(element.area) - if len(element.label) == 0 { - rl.DrawRectangleRoundedLinesEx(area, 0.1, 4.0, 1.0, rl.Color(element.color)) - } else { - rl.GuiLabel(area, element.label) - } - case .Button: + ui.start(&ctx, {0, 0}, {WINDOW_WIDTH, WINDOW_HEIGHT}) + config := ui.ElementConfiguration{margin = V2_ONE * 4, padding = V2_ONE * 4, color = ui.col(rl.MAGENTA)} + ui.container_begin({ui.Size_Percentage(0.3), ui.Size_Percentage(0.3)}, config) + slider_config := config + slider_config.label = "Outer container margin" + ui_slider_2d(1.0, 0.2, slider_config, &outer_container_config.margin, 0.0, 32.0) + slider_config.label = "Inner container margin" + ui_slider_2d(1.0, 0.2, slider_config, &inner_container_config.margin, 0.0, 32.0) + slider_config.label = "Button margin" + ui_slider_2d(1.0, 0.2, slider_config, &button_config.margin, 0.0, 32.0) + ui.container_end() + debug_elements := ui.end() + + render_ui_elements(debug_elements) + } +} + +ui_slider_2d :: proc(width, height: ui.Size_Percentage, config: ui.ElementConfiguration, value: ^v2, min: f32, max: f32) -> ^ui.Element { + container := ui.container_begin(dimensions = {width, height}, config = config) + dimensions := ui.Dimensions {ui.Size_Percentage(0.5), ui.Size_Percentage(1.0)} + ui.slider(dimensions, {margin = config.margin}, {value = &value.x, min = min, max = max}) + ui.same_line() + ui.slider(dimensions, {margin = config.margin}, {value = &value.y, min = min, max = max}) + ui.container_end() + return container +} + +render_ui_elements :: proc(elements: []ui.Element) { + for element in elements { + area := rl.Rectangle(element.area) + switch element.type { + case .Container: + rl.DrawRectangleRounded(area, 0.1, 4.0, {0, 0, 0, 192}) + if len(element.label) == 0 { + rl.DrawRectangleRoundedLinesEx(area, 0.1, 4.0, 1.0, rl.Color(element.color)) + } else { + rl.GuiGroupBox(area, element.label) } + case .Button: + rl.GuiButton(area, element.label) + case .Slider: + data := element.data.float_input_data + rl.GuiSlider(area, "", "", data.value, data.min, data.max) } } } diff --git a/ui.odin b/ui.odin index af4ddba..82dda43 100644 --- a/ui.odin +++ b/ui.odin @@ -2,6 +2,7 @@ package synthas_ui v2 :: [2]f32 rect2 :: struct {x, y, width, height: f32} +col :: [4]u8 rect_get_tl :: #force_inline proc(rect: rect2) -> v2 {return {rect.x, rect.y}} rect_get_tr :: #force_inline proc(rect: rect2) -> v2 {return {rect.x + rect.width, rect.y}} @@ -27,18 +28,29 @@ CONTAINER_STACK_SIZE :: 16 Element :: struct { area: rect2, using config: ElementConfiguration, + data: ElementData, type: ElementType, } ElementConfiguration :: struct { label: cstring, - color: [4]u8, + color: col, margin, padding: v2, } +ElementData :: struct { + using float_input_data: ElementData_FloatInput, +} + +ElementData_FloatInput :: struct { + min, max: f32, + value: ^f32, +} + ElementType :: enum { Container, Button, + Slider, } Size_Pixels :: distinct f32 @@ -85,7 +97,7 @@ end :: proc() -> []Element { assert(len(ctx.containers) > 0, "Closed base container before ending UI layout mode") elements := ctx.elements[:] ctx = nil - return elements + return elements[1:] } same_line :: proc() { @@ -94,7 +106,7 @@ same_line :: proc() { container_begin :: proc(dimensions: Dimensions, config: ElementConfiguration) -> ^Element { area := _resolve_element_area(dimensions, config.margin) - element := _append_element(Element{area = area, config = config, type = .Container}) + element := _append_element({area = area, config = config, type = .Container}) container_index := len(ctx.elements) - 1 append(&ctx.containers, container_index) append(&ctx.container_last_element, -1) @@ -105,11 +117,18 @@ container_end :: proc() { container := ctx.elements[pop(&ctx.containers)] pop(&ctx.container_last_element) // TODO: Set flex + ctx.same_line = false outer := get_element_outer_area(container) } -button :: proc(dimensions: Dimensions) -> ^Element { - return nil +button :: proc(dimensions: Dimensions, config: ElementConfiguration) -> ^Element { + area := _resolve_element_area(dimensions, config.margin) + return _append_element({area = area, config = config, type = .Button}) +} + +slider :: proc(dimensions: Dimensions, config: ElementConfiguration, data: ElementData_FloatInput) -> ^Element { + area := _resolve_element_area(dimensions, config.margin) + return _append_element({area = area, config = config, type = .Slider, data = {float_input_data = data}}) } _append_element :: proc(element: Element) -> ^Element { @@ -134,7 +153,14 @@ _resolve_element_area :: proc(dimensions: Dimensions, margin: v2) -> rect2 { _resolve_element_outer_position :: proc() -> v2 { if alignment_element := _element_container_previous(); alignment_element != nil { - return rect_get_bl(get_element_outer_area(alignment_element^)) + area: v2 + if ctx.same_line { + area = rect_get_tr(get_element_outer_area(alignment_element^)) + } else { + area = rect_get_bl(get_element_outer_area(alignment_element^)) + } + ctx.same_line = false + return area } return rect_get_tl(get_element_inner_area(_element_previous()^)) }