diff --git a/libraries/snths_ui/ui.odin b/libraries/snths_ui/ui.odin index 66557fe..eebde26 100644 --- a/libraries/snths_ui/ui.odin +++ b/libraries/snths_ui/ui.odin @@ -11,16 +11,15 @@ 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}} +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 :: #force_inline 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 Context :: struct { origin: v2, - element_focus_id: int, + element_focus_id: ElementId, + container_count: u16, containers: [dynamic]int, container_last_element: [dynamic]int, elements: [dynamic]Element, @@ -29,15 +28,24 @@ Context :: struct { CONTAINER_STACK_SIZE :: 16 +ElementId :: bit_field(int) { + container_index: u16 | 16, + element_index: u16 | 16, +} + Element :: struct { area: rect2, - id: int, + id: ElementId, using config: ElementConfiguration, data: rawptr, type: ElementType, dimensions: Dimensions, } +element_id_invalid :: proc() -> ElementId { + return {container_index = max(u16), element_index = max(u16)} +} + ElementConfiguration :: struct { label: cstring, color: col, @@ -80,6 +88,7 @@ init :: proc(state: ^Context, element_capacity: int, allocator := context.alloca start :: proc(ui_context: ^Context, origin: v2, size: v2) { ctx = ui_context ctx.origin = origin + ctx.container_count = 0 clear(&ctx.elements) clear(&ctx.containers) clear(&ctx.container_last_element) @@ -105,7 +114,7 @@ focus_element :: proc(ctx: ^Context, element: Element) { } unfocus_element :: proc(ctx: ^Context) { - ctx.element_focus_id = -1 + ctx.element_focus_id = element_id_invalid() } is_element_focused :: proc(ctx: ^Context, element: Element) -> bool { @@ -113,25 +122,28 @@ is_element_focused :: proc(ctx: ^Context, element: Element) -> bool { } focus_next_element :: proc(ctx: ^Context, allowed_focus := element_type_input) { - if ctx.element_focus_id == -1 { + if ctx.element_focus_id == element_id_invalid() { return } - if ctx.element_focus_id + 1 >= len(ctx.elements) { - ctx.element_focus_id = -1 + element_index := int(ctx.element_focus_id.element_index) + if element_index + 1 >= len(ctx.elements) { + ctx.element_focus_id = element_id_invalid() return } - ctx.element_focus_id += 1 - for ctx.element_focus_id < len(ctx.elements) { - if ctx.elements[ctx.element_focus_id].type in allowed_focus { + element_index += 1 + for element_index < len(ctx.elements) { + if ctx.elements[element_index].type in allowed_focus { + ctx.element_focus_id = ctx.elements[element_index].id return } - ctx.element_focus_id += 1 + element_index += 1 } - ctx.element_focus_id = -1 + ctx.element_focus_id = element_id_invalid() } container_begin :: proc(dimensions: Dimensions, config: ElementConfiguration, data: rawptr = nil) -> ^Element { area := _resolve_element_area(dimensions, config.margin) + ctx.container_count += 1 element := _append_element({area = area, config = config, type = .Container, dimensions = dimensions, data = data}) container_index := len(ctx.elements) - 1 append(&ctx.containers, container_index) @@ -202,11 +214,11 @@ get_element_inner_area :: proc(element: Element) -> rect2 { _append_element :: proc(element: Element) -> ^Element { append(&ctx.elements, element) - last_element_index := len(ctx.elements) - 1 - last_element := &ctx.elements[last_element_index] - last_element.id = last_element_index - ctx.container_last_element[len(ctx.containers) - 1] = last_element_index - return last_element + element_index := len(ctx.elements) - 1 + element := &ctx.elements[element_index] + element.id = ElementId {container_index = ctx.container_count, element_index = u16(element_index)} + ctx.container_last_element[len(ctx.containers) - 1] = element_index + return element } _resolve_element_area :: proc(dimensions: Dimensions, margin: v2) -> rect2 { diff --git a/utils.odin b/utils.odin index b8f1433..c2290f4 100644 --- a/utils.odin +++ b/utils.odin @@ -91,11 +91,19 @@ enum_to_raygui_options_string :: proc($T: typeid, allocator: mem.Allocator) -> c /// ### RECTANGLES ### /// -rect_from :: proc { - rect2_from_v2, - irect2_from_iv2, +rect_translate :: proc {rect2_translate, irect2_translate} + +@(private="file") rect2_translate :: proc "contextless" (rect: rect2, translation: v2) -> rect2 { + return {rect.x + translation.x, rect.y + translation.y, rect.width, rect.height} } +@(private="file") irect2_translate :: proc "contextless" (rect: irect2, translation: iv2) -> irect2 { + return {rect.x + translation.x, rect.y + translation.y, rect.width, rect.height} +} + + +rect_from :: proc {rect2_from_v2, irect2_from_iv2} + @(private="file") rect2_from_v2 :: proc "contextless" (position, size: v2) -> rect2 { return {position.x, position.y, size.x, size.y} } @@ -104,10 +112,8 @@ rect_from :: proc { return {position.x, position.y, size.x, size.y} } -rect_scale :: proc{ - rect2_scale, - irect2_scale, -} + +rect_scale :: proc{rect2_scale, irect2_scale} @(private="file") rect2_scale :: proc "contextless" (rect: rect2, scalar: f32) -> rect2 { return {rect.x * scalar, rect.y * scalar, rect.width * scalar, rect.height * scalar} @@ -117,12 +123,8 @@ rect_scale :: proc{ return {rect.x * scalar, rect.y * scalar, rect.width * scalar, rect.height * scalar} } -rect_grow :: proc { - rect2_grow, - rect2_grow_v2, - irect2_grow, - rect2_grow_iv2, -} + +rect_grow :: proc {rect2_grow, rect2_grow_v2, irect2_grow, rect2_grow_iv2} @(private="file") rect2_grow :: proc "contextless" (rect: rect2, grow: f32) -> rect2 { return {rect.x - grow, rect.y - grow, rect.width + grow * 2.0, rect.height + grow * 2.0} @@ -141,10 +143,7 @@ rect_grow :: proc { } -rect_from_area :: proc { - rect_from_area_v2, - rect_from_area_iv2, -} +rect_from_area :: proc {rect_from_area_v2, rect_from_area_iv2} @(private="file") rect_from_area_v2 :: proc "contextless" (start, end: v2) -> rect2 { tl := linalg.min(start, end) @@ -156,10 +155,8 @@ rect_from_area :: proc { return {**tl, **(linalg.max(start, end) - tl)} } -rect_from_corners :: proc { - rect2_from_corners, - irect2_from_corners, -} + +rect_from_corners :: proc {rect2_from_corners, irect2_from_corners} @(private="file") rect2_from_corners :: proc "contextless" (tl, tr, br, bl: v2) -> rect2 { top_left := linalg.min(linalg.min(tl, tr, br), bl) @@ -173,10 +170,8 @@ rect_from_corners :: proc { return {**top_left, **(bottom_right - top_left)} } -rect_get_tl :: proc { - rect2_get_tl, - irect2_get_tl, -} + +rect_get_tl :: proc {rect2_get_tl, irect2_get_tl} @(private="file") rect2_get_tl :: proc(rect: rect2) -> v2 { return {rect.x, rect.y} @@ -186,10 +181,8 @@ rect_get_tl :: proc { return {rect.x, rect.y} } -rect_get_br :: proc { - rect2_get_br, - irect2_get_br, -} + +rect_get_br :: proc {rect2_get_br, irect2_get_br} @(private="file") rect2_get_br :: proc(rect: rect2) -> v2 { return {rect.x + rect.width, rect.y + rect.height} @@ -199,10 +192,8 @@ rect_get_br :: proc { return {rect.x + rect.width, rect.y + rect.height} } -rect_get_size :: proc { - rect2_get_size, - irect2_get_size, -} + +rect_get_size :: proc {rect2_get_size, irect2_get_size} @(private="file") rect2_get_size :: proc(rect: rect2) -> v2 { return {rect.width, rect.height}