diff --git a/program.odin b/program.odin index 46cc059..76433be 100644 --- a/program.odin +++ b/program.odin @@ -7,11 +7,13 @@ import "core:fmt" UiContainerType :: enum { Normal, Matrix, + Scroll, } UiElementData_Container :: struct { type: UiContainerType, thickness: f32, + scroll: f32, } UiElementData_Slider :: struct { @@ -61,6 +63,8 @@ Program :: struct { matrix_float_pool: []f32, matrix_value_string_pool: []InputFloatField, matrix_count: int, + matrix_scroll: f32, + matrix_scroll_speed: f32, grid: Grid, font_style: FontStyle, state: ProgramState, @@ -87,6 +91,7 @@ matrix_pool_get_mat3 :: proc() -> ^mat3 { program_init :: proc(allocator := context.allocator) { program.matrix_float_pool = make(type_of(program.matrix_float_pool), MATRIX_POOL_SIZE) program.matrix_value_string_pool = make(type_of(program.matrix_value_string_pool), MATRIX_POOL_SIZE) + program.matrix_scroll_speed = 32.0 program.font_style = { font = rl.GetFontDefault(), size = 16.0, @@ -129,7 +134,9 @@ program_build_ui :: proc() -> []ui.Element { ui.container_end() 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) + side_bar_container_data := new(UiElementData_Container, context.temp_allocator) + side_bar_container_data^ = {type = .Scroll, scroll = program.matrix_scroll} + matrix_container := ui.container_begin({ui.Size_Percentage(0.2), ui.Size_PercentageRemainder(1.0)}, side_bar_container_config, side_bar_container_data) for i in 0.. []ui.Element { ui_mat3(mat, value_strings, container_dimensions, container_config) } ui.container_end() - return ui.end() + elements := ui.end() + + mouse := rl.GetMousePosition() + if rect_has_point(rect2(matrix_container.area), mouse) { + program.matrix_scroll = max(0, program.matrix_scroll - rl.GetMouseWheelMove() * program.matrix_scroll_speed) + } + + return elements } ui_mat3 :: proc(mat: []f32, value_strings: []InputFloatField, dimensions: ui.Dimensions, config: ui.ElementConfiguration, allocator := context.temp_allocator) { @@ -161,8 +175,27 @@ ui_mat3 :: proc(mat: []f32, value_strings: []InputFloatField, dimensions: ui.Dim } program_render_ui :: proc(ctx: ^ui.Context, elements: []ui.Element) { - for element in elements { - area := rl.Rectangle(element.area) + scissor_container: ^ui.Element + + defer { + if scissor_container != nil { + rl.EndScissorMode() + scissor_container = nil + } + } + + for &element in elements { + offset: v2 + if scissor_container != nil { + if element.id.container_index < scissor_container.id.container_index { + rl.EndScissorMode() + scissor_container = nil + } else { + offset.y = -(cast(^UiElementData_Container)scissor_container.data).scroll + } + } + + area := rect_translate(rl.Rectangle(element.area), offset) switch element.type { case .Container: dim := rl.Color {0, 0, 0, 192} @@ -173,8 +206,7 @@ program_render_ui :: proc(ctx: ^ui.Context, elements: []ui.Element) { 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) + matrix_area := ui.rect_grow(ui.rect2(area), element.margin / 2.0) tl, tr, br, bl := ui.rect_get_corners(matrix_area) col := rl.WHITE hook_length: f32 = 4.0 @@ -184,6 +216,11 @@ program_render_ui :: proc(ctx: ^ui.Context, elements: []ui.Element) { 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) + case .Scroll: + rl.DrawRectangleRounded(area, 0.1, 4.0, dim) + rl.GuiGroupBox(area, element.label) + scissor_container = &element + rl.BeginScissorMode(**rect2_to_irect2(area)) } } else { rl.DrawRectangleRounded(area, 0.1, 4.0, dim) diff --git a/utils.odin b/utils.odin index c2290f4..286c318 100644 --- a/utils.odin +++ b/utils.odin @@ -91,6 +91,26 @@ enum_to_raygui_options_string :: proc($T: typeid, allocator: mem.Allocator) -> c /// ### RECTANGLES ### /// +rect2_to_irect2 :: proc "contextless" (rect: rect2) -> irect2 { + return {i32(rect.x), i32(rect.y), i32(rect.width), i32(rect.height)} +} + +irect2_to_rect2 :: proc "contextless" (rect: irect2) -> rect2 { + return {f32(rect.x), f32(rect.y), f32(rect.width), f32(rect.height)} +} + + +rect_has_point :: proc {rect2_has_point, irect2_has_point} + +@(private="file") rect2_has_point :: proc "contextless" (rect: rect2, p: v2) -> bool { + return p.x >= rect.x && p.x < rect.x + rect.width && p.y >= rect.y && p.y < rect.y + rect.height +} + +@(private="file") irect2_has_point :: proc "contextless" (rect: irect2, p: iv2) -> bool { + return p.x >= rect.x && p.x < rect.x + rect.width && p.y >= rect.y && p.y < rect.y + rect.height +} + + rect_translate :: proc {rect2_translate, irect2_translate} @(private="file") rect2_translate :: proc "contextless" (rect: rect2, translation: v2) -> rect2 {