From 26407a14b121adfcaaee212ad5ee6a50892a9a90 Mon Sep 17 00:00:00 2001 From: Synthasmagoria Date: Sat, 1 Aug 2026 16:01:17 +0200 Subject: [PATCH] label work part 1 --- example/main.odin | 6 +++++- ui.odin | 48 +++++++++++++++++++++++++++++++---------------- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/example/main.odin b/example/main.odin index 2f0dfe0..9268b0b 100644 --- a/example/main.odin +++ b/example/main.odin @@ -39,6 +39,10 @@ UiElementData_FloatInput :: struct { value_string: cstring, } +ui_measure_text :: proc(str: cstring) -> ui.v2 { + return rl.MeasureTextEx(rl.GetFontDefault(), str, 18.0, 1.0) +} + main :: proc() { back.register_segfault_handler() _register_illegal_instruction_handler() @@ -49,7 +53,7 @@ main :: proc() { rl.SetTargetFPS(WINDOW_FRAMERATE) ctx: ui.Context - ui.init(&ctx, 4000) + ui.init(&ctx, 4000, ui_measure_text) outer_container_config := ui.ElementConfiguration {margin = {4.0, 8.0}, padding = {12.0, 24.0}, color = ui.col(rl.RED), label = ""} outer_container_margin_value_string_x := cstring(make([^]u8, INPUT_FLOAT_CHARACTERS)) diff --git a/ui.odin b/ui.odin index cae15df..5ee2bc4 100644 --- a/ui.odin +++ b/ui.odin @@ -16,6 +16,8 @@ rect_grow :: #force_inline proc(rect: rect2, amount: v2) -> rect2 {return {rect. ctx: ^Context +MeasureTextProc :: proc(cstring) -> v2 + Context :: struct { origin: v2, container_count: u16, @@ -23,6 +25,7 @@ Context :: struct { container_last_element: [dynamic]int, elements: [dynamic]Element, same_line: bool, + measure_text: MeasureTextProc, } CONTAINER_STACK_SIZE :: 16 @@ -39,6 +42,7 @@ Element :: struct { data: rawptr, type: ElementType, dimensions: Dimensions, + is_text: bool, } element_id_invalid :: proc() -> ElementId { @@ -57,6 +61,7 @@ ElementType :: enum { Slider, InputFloat, Dropdown, + Label, Custom0, Custom1, Custom2, @@ -89,10 +94,11 @@ Dimensions :: struct { Axis :: enum {X, Y} -init :: proc(state: ^Context, element_capacity: int, allocator := context.allocator) { - state.containers = make(type_of(state.containers), 0, CONTAINER_STACK_SIZE, allocator) - state.container_last_element = make(type_of(state.container_last_element), 0, CONTAINER_STACK_SIZE, allocator) - state.elements = make(type_of(state.elements), 0, element_capacity, allocator) +init :: proc(ctx: ^Context, element_capacity: int, measure_text_callback: MeasureTextProc, allocator := context.allocator) { + ctx.containers = make(type_of(ctx.containers), 0, CONTAINER_STACK_SIZE, allocator) + ctx.container_last_element = make(type_of(ctx.container_last_element), 0, CONTAINER_STACK_SIZE, allocator) + ctx.elements = make(type_of(ctx.elements), 0, element_capacity, allocator) + ctx.measure_text = measure_text_callback } start :: proc(ui_context: ^Context, origin: v2, size: v2) { @@ -134,13 +140,14 @@ focus_next_element :: proc(id: ElementId, elements: []Element, allowed_focus: bi } container_begin :: proc(dimensions: Dimensions, config: ElementConfiguration, data: rawptr = nil) -> ^Element { - area := _resolve_element_area(dimensions, config.margin) + element := Element{config = config, type = .Container, dimensions = dimensions, data = data} + element.area = _resolve_element_area(element) ctx.container_count += 1 - element := _append_element({area = area, config = config, type = .Container, dimensions = dimensions, data = data}) + element_ref := _append_element(element) container_index := len(ctx.elements) - 1 append(&ctx.containers, container_index) append(&ctx.container_last_element, -1) - return element + return element_ref } container_end :: proc() { @@ -166,8 +173,7 @@ container_end :: proc() { ctx.same_line = false } -element :: proc(element_type: ElementType, dimensions: Dimensions, config: ElementConfiguration, data: rawptr = nil) -> ^Element { - assert(element_type != .Container) +assert_auto_with_pixels :: proc(dimensions: Dimensions) { container := _container_current() if _, is_auto := container.dimensions.width.(Size_Auto); is_auto { _, is_pixels := dimensions.width.(Size_Pixels) @@ -177,9 +183,15 @@ element :: proc(element_type: ElementType, dimensions: Dimensions, config: Eleme _, is_pixels := dimensions.height.(Size_Pixels) assert(is_pixels, "Any height that is not Size_Pixels is disallowed in a container using Size_Auto for height") } +} - area := _resolve_element_area(dimensions, config.margin) - return _append_element({area = area, config = config, type = element_type, dimensions = dimensions, data = data}) +element :: proc(element_type: ElementType, dimensions: Dimensions, config: ElementConfiguration, data: rawptr = nil) -> ^Element { + assert(element_type != .Container) + assert_auto_with_pixels(dimensions) + element := Element{config = config, type = element_type, dimensions = dimensions, data = data} + element.is_text = element.type == .Label + element.area = _resolve_element_area(element) + return _append_element(element) } get_element_outer_area :: proc(element: Element) -> rect2 { @@ -199,10 +211,14 @@ _append_element :: proc(element: Element) -> ^Element { return element } -_resolve_element_area :: proc(dimensions: Dimensions, margin: v2) -> rect2 { +_resolve_element_area :: proc(element: Element) -> rect2 { outer_position := _resolve_element_outer_position() - outer_size := _resolve_element_outer_size(dimensions) - return rect_grow(rect2{**outer_position, **outer_size}, -margin * 2.0) + if !element.is_text { + outer_size := _resolve_element_outer_size(element.dimensions) + return rect_grow(rect2{**outer_position, **outer_size}, -element.margin * 2.0) + } + inner_position := ctx.measure_text(element.label) + return {**outer_position, **(inner_position + element.margin * 2.0)} } _resolve_element_outer_position :: proc() -> v2 { @@ -221,10 +237,10 @@ _resolve_element_outer_position :: proc() -> v2 { } _resolve_element_outer_size :: proc(dimensions: Dimensions) -> v2 { - return {_resolve_elemment_outer_size_axis(dimensions.width, .X), _resolve_elemment_outer_size_axis(dimensions.height, .Y)} + return {_resolve_element_outer_size_axis(dimensions.width, .X), _resolve_element_outer_size_axis(dimensions.height, .Y)} } -_resolve_elemment_outer_size_axis :: proc(size: Size, axis: Axis) -> f32 { +_resolve_element_outer_size_axis :: proc(size: Size, axis: Axis) -> f32 { switch value in size { case Size_Pixels: return f32(value)