diff options
author | San Jacobs | 2023-10-15 14:59:33 +0200 |
---|---|---|
committer | San Jacobs | 2023-10-15 14:59:33 +0200 |
commit | 690d1102dedbbad955c34ba1a5ef9f4d15d82158 (patch) | |
tree | 887d6bea6a843952c7d8346a99131601f603e19f /src | |
parent | b6dab385dbf9a626970f3673d345d0e8e6a62e1e (diff) | |
parent | 2e3a7e10756954dc5a99d617a1c0eef327d3adbb (diff) | |
download | satscalc-690d1102dedbbad955c34ba1a5ef9f4d15d82158.tar.gz satscalc-690d1102dedbbad955c34ba1a5ef9f4d15d82158.tar.bz2 satscalc-690d1102dedbbad955c34ba1a5ef9f4d15d82158.zip |
Merge branch 'oui' into odin
Diffstat (limited to 'src')
-rw-r--r-- | src/main.odin | 256 | ||||
-rw-r--r-- | src/time.odin | 24 | ||||
-rw-r--r-- | src/ui_implementation.odin | 389 |
3 files changed, 628 insertions, 41 deletions
diff --git a/src/main.odin b/src/main.odin index 8199e65..698f044 100644 --- a/src/main.odin +++ b/src/main.odin @@ -1,11 +1,24 @@ package main +import "../lib/oui" import "core:fmt" import "core:math" import "core:slice" +import "core:runtime" import "core:strings" import rl "vendor:raylib" +UBUNTU_MONO := #load("../res/UbuntuMono-Regular.ttf") + +font : rl.Font +big_font : rl.Font +small_font : rl.Font + +FRACT_MIN : f32 = 0.0 +FRACT_MAX : f32 = 1.0 + +c0 : ^oui.Context + main :: proc() { // TODO: Replace the dynamic array of Workday-pointers with @@ -92,18 +105,20 @@ main :: proc() { SetWindowMinSize(width, height) // Loading fonts - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - font_size :: 18 - font: Font = LoadFontEx("res/UbuntuMono-Regular.ttf", font_size, nil, 0) - defer UnloadFont(font) - - small_font_size :: 14 - small_font: Font = LoadFontEx("res/UbuntuMono-Regular.ttf", small_font_size, nil, 0) - defer UnloadFont(small_font) - big_font_size :: 24 - big_font: Font = LoadFontEx("res/UbuntuMono-Regular.ttf", big_font_size, nil, 0) + small_font = LoadFontFromMemory(".ttf", raw_data(UBUNTU_MONO), i32(len(UBUNTU_MONO)), 14, nil, 0) + font = LoadFontFromMemory(".ttf", raw_data(UBUNTU_MONO), i32(len(UBUNTU_MONO)), 18, nil, 0) + big_font = LoadFontFromMemory(".ttf", raw_data(UBUNTU_MONO), i32(len(UBUNTU_MONO)), 24, nil, 0) defer UnloadFont(big_font) + defer UnloadFont(font) + defer UnloadFont(small_font) + + // oui stuff + c0 = new(oui.Context) + defer free(c0) + oui.context_init(c0, 2048, 2048 * 8) + defer oui.context_destroy(c0) // Setting up the timelines @@ -122,6 +137,8 @@ main :: proc() { for !WindowShouldClose() { // MAIN LOOP ---- MAIN LOOP ---- MAIN LOOP ---- MAIN LOOP + free_all(context.temp_allocator) + if IsWindowResized() { height = GetScreenHeight() width = GetScreenWidth() @@ -142,16 +159,194 @@ main :: proc() { // clicking will put a white border around the timeblock, // and display information about the block in the // bottom left of the screen. - + + mousePosition: = rl.GetMousePosition() + oui.set_cursor(c0, int(mousePosition.x), int(mousePosition.y)) + if rl.IsMouseButtonPressed(rl.MouseButton(0)) do oui.set_button(c0, .Left, true) + if rl.IsMouseButtonReleased(rl.MouseButton(0)) do oui.set_button(c0, .Left, false) // DRAW // ------------------------------------------ BeginDrawing() - ClearBackground(BGCOLOR) - DrawTextEx(font, "Date", {20, 8}, font_size, 0, RAYWHITE); - DrawTextEx(font, "Calltime", {105, 8}, font_size, 0, RAYWHITE); - DrawTextEx(font, "Wraptime", {f32(width)-83, 8}, font_size, 0, RAYWHITE); + ClearBackground(rl.RED) + +when true { + // hotloop + oui.begin_layout(c0) + + + master_container := panel() + master_container.id = oui.push_id(c0, "big_mr_boss_man") // Make ID for master thing just because. + // Does not need to be freed because master. + master_container.layout = .Absolute + master_container.sort_children = true + master_container.layout_size = {int(GetScreenWidth()), int(GetScreenHeight())} + + { + top_bar := panel_line(master_container, theme.background_bar, 30) + top_bar.id = oui.push_id(c0, "top_bar") // Make ID for anything that will have children. + defer oui.pop_id(c0) // They must be pop'ed before the next equal-in-hiarchy item + top_bar.layout_margin = 10 + + oui.item_insert(top_bar, label("Date", font, sizings.date, .Center)) + oui.item_insert(top_bar, label("Calltimes", font, sizings.call, .Center)) + + top_bar.layout_cut_children = .Right + oui.item_insert(top_bar, label("Price", font, sizings.price, .Center)) + oui.item_insert(top_bar, label("Wrap", font, sizings.wrap, .Center)) + + top_bar.layout_cut_children = .Fill + oui.item_insert(top_bar, label("Timeline", font, 0, .Center)) + } + + { + bottom_bar := panel(theme.background_bar) + bottom_bar.id = oui.push_id(c0, "bottom_bar") + defer oui.pop_id(c0) + bottom_bar.layout_cut_children = .Left + master_container.layout_cut_children = .Bottom + bottom_bar.z_index = 10 // Makes this render over/after the middle section + bottom_bar.layout_size.y = 50 + bottom_bar.layout_margin = 10 // Spacing from edges + bottom_bar.layout_cut_gap = 5 // Spacing between children + oui.item_insert(master_container, bottom_bar) + + price_reason := label("Reason for price of highlighted timeblock", font, 300,) + bottom_bar.layout_cut_children = .Left + oui.item_insert(bottom_bar, price_reason) + + totals := panel(theme.background_bar) + totals.layout_cut_children = .Top + totals.layout_size.x = 50 + bottom_bar.layout_cut_children = .Right + oui.item_insert(bottom_bar, totals) + + pre_sos_price := label("120 000 kr", small_font, 0, .Right) + pre_sos_price.layout_size.y = 11 + oui.item_insert(totals, pre_sos_price) + + post_sos_price := label("160 000 kr", big_font, 300, .Right) + post_sos_price.layout_size.y = 27 + oui.item_insert(totals, post_sos_price) + } + + { + middle_section := panel(theme.background) + middle_section.id = oui.push_id(c0, "middle_section") + defer oui.pop_id(c0) + middle_section.layout_margin = 10 // Spacing from edges + middle_section.layout_cut_gap = sizings.inter_timeline // Spacing between children + master_container.layout_cut_children = .Fill + oui.item_insert(master_container, middle_section) + + + // - - - - WORKDAYS - - - - + + FRACT_MAX = workdays[0].fractions[0].start + FRACT_MIN = FRACT_MAX // TODO: Optimize this. It doesn't need to re-calculated every frame + + for day, i in &workdays { + + for fract, i in day.fractions { + if fract.start < FRACT_MIN do FRACT_MIN = fract.start + if fract.end > FRACT_MAX do FRACT_MAX = fract.end + if i+1 == day.total_timeblocks do break + } + + line := panel_line(middle_section, theme.background) + line.layout_cut_children = .Left + line.layout_cut_gap = 0 + line.layout_margin = 0 + line.layout_size.y = sizings.timeline + oui.item_insert(line, label(dayprint(day.call), font, sizings.date, .Center)) + oui.item_insert(line, label(clockprint(day.call), font, sizings.call, .Center)) + + line.layout_cut_children = .Right + oui.item_insert(line, label("3500 kr", font, sizings.price, .Center)) + oui.item_insert(line, label(clockprint(day.wrap), font, sizings.wrap, .Center)) + + line.layout_cut_children = .Fill + timeline(line, &day) + } + new_workday := button("+", 100) + middle_section.layout_cut_children = .Top + oui.item_insert(middle_section, new_workday) + if oui.is_clicked(c0, new_workday) do fmt.println("NEW WORKDAY!") + + + + // - - - - SIZINGS EDITOR - - - - + { + oui.item_insert(middle_section, label("Sizings Editor", big_font, 100, .Center)) + + // To loop over the members of a struct you need to do this goofy shit: + info := runtime.type_info_base(type_info_of(Sizings)) + st := info.variant.(runtime.Type_Info_Struct) + root := uintptr(&sizings) + for offset, i in st.offsets { + + line := panel_line(middle_section, theme.background, 25) + line.id = oui.push_id(c0, fmt.tprintf("sizings_line_%d", i)) + defer oui.pop_id(c0) + + oui.item_insert(line, label(st.names[i], font, )) + + // To then access the member of the struct you're looping over + // you need to do this shit: + // v----------------------v + current_value := cast(^int) (root+offset) + + oui.item_insert(line, slider_int(fmt.tprintf("sizings-%d", i), fmt.tprintf("%d", current_value^), 300, current_value, 0, 200)) + } + output_button := button("output sizings", 100) + middle_section.layout_cut_children = .Top + oui.item_insert(middle_section, output_button) + if oui.is_clicked(c0, output_button) do fmt.printf("%#v", sizings) + } + + + // - - - - THEME EDITOR - - - - + { + oui.item_insert(middle_section, label("Theme Editor", big_font, 100, .Center)) + + // To loop over the members of a struct you need to do this goofy shit: + info := runtime.type_info_base(type_info_of(Theme)) + st := info.variant.(runtime.Type_Info_Struct) + root := uintptr(&theme) + for offset, i in st.offsets { + + line := panel_line(middle_section, theme.background, 25) + line.layout_cut_gap = 10 + line.id = oui.push_id(c0, fmt.tprintf("line_%d", i)) + defer oui.pop_id(c0) + + oui.item_insert(line, label(st.names[i], font, )) + + // To then access the member of the struct you're looping over + // you need to do this shit: + // v------------------------v + color_sliders(line, cast(^Color) (root+offset)) + } + output_theme_button := button("output theme", 100) + middle_section.layout_cut_children = .Top + oui.item_insert(middle_section, output_theme_button) + if oui.is_clicked(c0, output_theme_button) do fmt.printf("%#v", theme) + } + + } + + + oui.end_layout(c0) + + ui_draw(master_container) + + oui.process(c0) + +} else { + DrawTextEx(font, "Date", {20, 8}, f32(font.baseSize), 0, RAYWHITE); + DrawTextEx(font, "Calltime", {105, 8}, f32(font.baseSize), 0, RAYWHITE); + DrawTextEx(font, "Wraptime", {f32(width)-83, 8}, f32(font.baseSize), 0, RAYWHITE); for day, i in workdays { @@ -164,17 +359,17 @@ main :: proc() { // (At least, given how lunch breaks are currently implemented, // as holes in the workday) - DrawRectangle(10, DAY_HEIGHT*i32(i+1)-4, width-20, DAY_HEIGHT-1, PBGCOLOR) + DrawRectangle(10, DAY_HEIGHT*i32(i+1)-4, width-20, DAY_HEIGHT-1, theme.background_bar) for block, j in day.blocks { if j == day.total_timeblocks do break - block_color: = GREEN + block_color: = theme.price_100 switch { case block.value > 2.1: - block_color = PURPLE + block_color = theme.price_300 case block.value > 1.6: - block_color = RED + block_color = theme.price_200 case block.value > 1.1: - block_color = ORANGE + block_color = theme.price_150 } DrawRectangle(TIMELINE_START+i32(math.round(day.fractions[j].start*f32(width+TIMELINE_END-TIMELINE_START))), @@ -188,28 +383,21 @@ main :: proc() { copy(wrap_text, clockprint(day.wrap)) copy(date_text, toString(day.call)) - text_height = math.round(f32(i+1)*DAY_HEIGHT+(DAY_HEIGHT-font_size)*0.25) + text_height := math.round(f32(i+1)*DAY_HEIGHT+(DAY_HEIGHT-f32(font.baseSize))*0.25) - DrawTextEx(font, cstring(&date_text[0]), {20, text_height}, font_size, 0, RAYWHITE); - DrawTextEx(font, cstring(&wrap_text[0]), {f32(width)-70, text_height}, font_size, 0, RAYWHITE); + DrawTextEx(font, cstring(&date_text[0]), {20, text_height}, f32(font.baseSize), 0, RAYWHITE); + DrawTextEx(font, cstring(&wrap_text[0]), {f32(width)-70, text_height}, f32(font.baseSize), 0, RAYWHITE); if i == len(workdays)-1 { - DrawTextEx(big_font, "+", {20, DAY_HEIGHT*f32(i+2)}, big_font_size, 0, RAYWHITE) + DrawTextEx(big_font, "+", {20, DAY_HEIGHT*f32(i+2)}, f32(big_font.baseSize), 0, RAYWHITE) } } - DrawRectangle(0, height-50, width+10, 60, PBGCOLOR) - - DrawTextEx(small_font, total_sum, {f32(width)-120, f32(height)-43}, small_font_size, 0, RAYWHITE); - DrawTextEx(big_font, inc_soc, {f32(width)-120, f32(height)-29}, big_font_size, 0, RAYWHITE); + DrawRectangle(0, height-50, width+10, 60, theme.background_bar) + DrawTextEx(small_font, total_sum, {f32(width)-120, f32(height)-43}, f32(small_font.baseSize), 0, RAYWHITE); + DrawTextEx(big_font, inc_soc, {f32(width)-120, f32(height)-29}, f32(big_font.baseSize), 0, RAYWHITE); +} EndDrawing() } } - -BGCOLOR : rl.Color : {30, 30, 30, 255} -PBGCOLOR : rl.Color : {40, 40, 40, 255} - -DAY_HEIGHT :: 35 -TIMELINE_START :: 175 -TIMELINE_END :: -85 diff --git a/src/time.odin b/src/time.odin index 468f5d8..90dca49 100644 --- a/src/time.odin +++ b/src/time.odin @@ -90,7 +90,7 @@ new_workday :: proc(previous_wrap : Moment, // Paragraph 6.7 says that up to 2 hours of unused warned overtime counts as worktime, // though so that at least one hour of the unused overtime is not counted. // (It's unclear if an 8-hour day that ends 3 hours in counts as having 5 hours of unused overtime) - max(clamp(sub(planned_wrap, {0, 1, 0}), wrap, add(wrap, {0, 2, 0})), + time_max(time_clamp(sub(planned_wrap, {0, 1, 0}), wrap, add(wrap, {0, 2, 0})), add(call, {0, 4, 0})), 1, ""} // ^ Minimum 4 hour day ^ @@ -170,7 +170,7 @@ new_workday :: proc(previous_wrap : Moment, if getweekday(block.start) == .Sunday do upvalue(&block, 2, "Sunday") // Sundays are +100% if !(less(call, Moment{0, 7, call.day, call.month, call.year}) && - less(min(add(call, Delta{0,8,0}), wrap), Moment{0, 17, call.day, call.month, call.year} )) { + less(time_min(add(call, Delta{0,8,0}), wrap), Moment{0, 17, call.day, call.month, call.year} )) { // This was added for rule 6.11c, but in a world without a defined normal workday, // that rule is already covered already by 6.11g, so this is empty. } @@ -489,7 +489,7 @@ maxDelta :: proc(delta_a: Delta, delta_b: Delta) -> Delta { if sortable(delta_a) > sortable(delta_b) do return delta_a return delta_b } -max :: proc{maxDelta, maxMoment} +time_max :: proc{maxDelta, maxMoment} minMoment :: proc(moment_a: Moment, moment_b: Moment) -> Moment { if sortable(moment_a) < sortable(moment_b) do return moment_a @@ -499,15 +499,15 @@ minDelta :: proc(delta_a: Delta, delta_b: Delta) -> Delta { if sortable(delta_a) < sortable(delta_b) do return delta_a return delta_b } -min :: proc{minDelta, minMoment} +time_min :: proc{minDelta, minMoment} clampMoment :: proc(moment: Moment, moment_min: Moment, moment_max: Moment) -> Moment { - return min(max(moment, moment_min), moment_max) + return time_min(time_max(moment, moment_min), moment_max) } clampDelta :: proc(delta: Delta, delta_min: Delta, delta_max: Delta) -> Delta { - return min(max(delta, delta_min), delta_max) + return time_min(time_max(delta, delta_min), delta_max) } -clamp :: proc{clampMoment, clampDelta} +time_clamp :: proc{clampMoment, clampDelta} greatMoment :: proc(moment_a: Moment, moment_b: Moment) -> bool { return bool(sortable(moment_a) > sortable(moment_b)) @@ -702,6 +702,16 @@ clockprintTimeblock :: proc(block: Timeblock) -> string { } clockprint :: proc{clockprintTimeblock, clockprintMoment} +dayprintMoment :: proc(moment: Moment) -> string { + using moment + return fmt.tprintf("%4i-%2i-%2i", year, month, day) +} +dayprintTimeblock :: proc(block: Timeblock) -> string { + using block + return fmt.tprintf("%s -> %s", dayprint(start), dayprint(end)) +} +dayprint :: proc{dayprintTimeblock, dayprintMoment} + popBlock :: proc(workday: ^Workday, index: int, count: int = 1) { using workday when ODIN_DEBUG do fmt.printf("popBlock() running to remove %i block(s) from index %i\n", count, index) diff --git a/src/ui_implementation.odin b/src/ui_implementation.odin new file mode 100644 index 0000000..6839b57 --- /dev/null +++ b/src/ui_implementation.odin @@ -0,0 +1,389 @@ +package main + +import "../lib/oui" +import "core:strings" +import "core:fmt" +import rl "vendor:raylib" + + +Theme :: struct { + background: rl.Color, + background_bar: rl.Color, + button: rl.Color, + button_hover: rl.Color, + button_click: rl.Color, + base: rl.Color, + slider_bar: rl.Color, + text: rl.Color, + price_100: rl.Color, + price_150: rl.Color, + price_200: rl.Color, + price_300: rl.Color, +} + +theme : Theme = { + background = {25 , 27 , 29 , 255,}, + background_bar = {43 , 43 , 48 , 255,}, + button = {91 , 91 , 204, 255,}, + button_hover = {91 , 91 , 204, 255,}, + button_click = {91 , 91 , 204, 255,}, + base = {60 , 60 , 60 , 255,}, + slider_bar = {91 , 91 , 204, 255,}, + text = {255, 255, 255, 252,}, + price_100 = {30 , 240, 30 , 255,}, + price_150 = {240, 200, 30 , 255,}, + price_200 = {240, 30 , 30 , 255,}, + price_300 = {240, 30 , 240, 255,}, +} + +Sizings :: struct { + date: int, + call: int, + wrap: int, + price: int, + lunch: int, + timeline: int, + inter_timeline: int, +} +sizings : Sizings = { + date = 110, + call = 85, + wrap = 90, + price = 100, + lunch = 100, + timeline = 32, + inter_timeline = 5, +} + +DAY_HEIGHT :: 35 // Only here for legacy UI +TIMELINE_START :: 175 // Only here for legacy UI +TIMELINE_END :: -85 // Only here for legacy UI + +Item :: oui.Item +Call :: oui.Call + +Data_Element :: enum int { + Panel, + Button, + SliderU8, + SliderInt, + Label, + Text_Input, + Timeblock, + Timeline, +// ... +} + +Data_Head :: struct { + subtype: Data_Element, +} + +Data_Panel :: struct { + using _: Data_Head, + color: rl.Color, +} + +Data_Button :: struct { + using _: Data_Head, + text: string, + selected: bool, +} + +Data_SliderInt :: struct { + using _: Data_Head, + text: string, + value: ^int, + min: int, + max: int, +} + +Data_SliderU8 :: struct { + using _: Data_Head, + text: string, + value: ^u8, +} + +Data_Label :: struct { + using _: Data_Head, + text: string, + font: rl.Font, + font_size: i32, + alignment: Text_Alignment, +} + +Data_Timeline :: struct { + using _: Data_Head, + day: ^Workday, +} + +panel :: proc(color : rl.Color = rl.RED) -> ^Item { + item := oui.item_make(c0) + + data := oui.alloc_typed(c0, item, Data_Panel) + data.subtype = .Panel + data.color = color + + return item +} + +panel_line :: proc(parent: ^Item, color : rl.Color, height: int = 40) -> (item: ^Item) { + item = oui.item_make(c0) + item.layout_cut_children = .Left + item.layout_size.y = height + + old := parent.layout_cut_children + parent.layout_cut_children = .Top + oui.item_insert(parent, item) + parent.layout_cut_children = old + + data := oui.alloc_typed(c0, item, Data_Panel) + data.subtype = .Panel + data.color = color + + return +} + +button :: proc(text: string, width: int, selected := false) -> ^Item { + item := oui.item_make(c0) + item.layout_size = {width, 35} + item.callback = button_callback + item.id = oui.gen_id(c0, text) + + data := oui.alloc_typed(c0, item, Data_Button) + data.subtype = .Button + data.text = text + data.selected = selected + + return item +} +button_callback :: proc(ctxt: ^oui.Context, item: ^Item, event: Call) -> int { + data := cast(^Data_Button) item.handle + + #partial switch event { + case .Cursor_Handle: + //return int(Cursor_Type.Hand) + } + + return -1 +} + +slider_int :: proc(id: string, text: string, width: int, value: ^int, min: int, max: int) -> ^Item { + item := oui.item_make(c0) + item.layout_size = {width, 25} + item.id = oui.gen_id(c0, id) + item.callback = slider_int_callback + + data := oui.alloc_typed(c0, item, Data_SliderInt) + data.subtype = .SliderInt + data.text = text + data.value = value + data.min = min + data.max = max + + return item +} +slider_int_callback :: proc(ctxt: ^oui.Context, item: ^Item, event: Call) -> int { + data := cast(^Data_SliderInt) item.handle + rect := item.bounds + + #partial switch event { + case .Left_Capture: + cursor_position := clamp(oui.get_cursor(c0).x, rect.l, rect.r) + + data.value^ = int(f32(data.min) + (f32(data.max - data.min) * (f32(cursor_position - rect.l) / f32(rect.r - rect.l)))) + } + + return -1 +} + +slider_u8 :: proc(id: string, text: string, width: int, value: ^u8) -> ^Item { + item := oui.item_make(c0) + item.layout_size = {width, 25} + item.id = oui.gen_id(c0, id) + item.callback = slider_u8_callback + + data := oui.alloc_typed(c0, item, Data_SliderU8) + data.subtype = .SliderU8 + data.text = text + data.value = value + + return item +} +slider_u8_callback :: proc(ctxt: ^oui.Context, item: ^Item, event: Call) -> int { + data := cast(^Data_SliderU8) item.handle + rect := item.bounds + + #partial switch event { + case .Left_Capture: + cursor_position := clamp(oui.get_cursor(c0).x, rect.l, rect.r) + + data.value^ = u8(255*(f32(cursor_position - rect.l) / f32(rect.r - rect.l))) + } + + return -1 +} +color_sliders :: proc(parent: ^Item, color: ^rl.Color) { + width :: 167 + oui.item_insert(parent, slider_u8("slider_r", fmt.tprintf("%d", color.r), width, &color.r)) + oui.item_insert(parent, slider_u8("slider_g", fmt.tprintf("%d", color.g), width, &color.g)) + oui.item_insert(parent, slider_u8("slider_b", fmt.tprintf("%d", color.b), width, &color.b)) + oui.item_insert(parent, slider_u8("slider_a", fmt.tprintf("%d", color.a), width, &color.a)) +} + +timeline :: proc(parent: ^Item, day: ^Workday) -> ^Item { + item := oui.item_make(c0) + + data := oui.alloc_typed(c0, item, Data_Timeline) + data.subtype = .Timeline + data.day = day + + oui.item_insert(parent, item) + return item +} + +Text_Alignment :: enum int { + // Techically called justification, but text_alignment is more self-explanatory. + Left, + Right, + Center, +} +label :: proc(text: string, font: rl.Font, width: int = 150, alignment: Text_Alignment = .Left) -> ^Item { + item := oui.item_make(c0) + item.layout_size = {width, 25} + + data := oui.alloc_typed(c0, item, Data_Label) + data.subtype = .Label + data.text = text + data.font = font + data.alignment = alignment + + return item +} +calculate_text_alignment :: proc(text: cstring, font: rl.Font, alignment: Text_Alignment, rect: oui.RectI, spacing: f32 = 0) -> (output: [2]int) { + + measurement := rl.MeasureTextEx(font, text, f32(font.baseSize), spacing) + + switch alignment { + case .Left: + output.x = rect.l + case .Right: + output.x = rect.r - int(measurement.x) + case .Center: + output.x = (rect.l+(rect.r-rect.l)/2) - int(measurement.x/2) + } + + output.y = (rect.t+(rect.b-rect.t)/2) - int(measurement.y/2) + + return +} +i2f :: proc "contextless" (input: [2]int) -> rl.Vector2 { + return { f32(input.x), f32(input.y) } +} +f2i :: proc "contextless" (input: [2]f32) -> [2]int { + return { int(input.x), int(input.y) } +} + +// recursive loop +ui_draw_children :: proc(item: ^oui.Item) { + list := oui.children_list(c0, item) + for kid in list { + ui_draw(kid) + } +} + +ui_draw :: proc(item: ^oui.Item) { + head := cast(^Data_Head) item.handle + rect := item.bounds + + //fmt.println(rect, head, item) + + if head == nil { + ui_draw_children(item) + return + } + + #partial switch head.subtype { + //case .Panel_Root: + // ... render any type of item + case .Button: + data := cast(^Data_Button) item.handle + text_spacing := clamp(item.anim.hot - item.anim.active, 0, item.anim.hot)*2 + rl.DrawRectangle(i32(rect.l), i32(rect.t), i32(rect.r-rect.l), i32(rect.b-rect.t), theme.button) + + text := strings.clone_to_cstring(data.text, context.temp_allocator) + position := calculate_text_alignment(text, font, .Center, rect, text_spacing) + + rl.DrawTextEx(font, text, i2f(position), f32(font.baseSize), text_spacing, theme.text); + + //fmt.println(item.anim) + + case .SliderInt: + data := cast(^Data_SliderInt) head + rl.DrawRectangle(i32(rect.l), i32(rect.t), i32(rect.r-rect.l), i32(rect.b-rect.t), theme.base) + rl.DrawRectangle(i32(rect.l+1), i32(rect.t+1), i32(f32(rect.r-rect.l)*(f32(data.value^)/f32(data.max))-2), i32(rect.b-rect.t-2), theme.slider_bar) + + text := strings.clone_to_cstring(data.text, context.temp_allocator) + position := calculate_text_alignment(text, font, .Center, rect) + + rl.DrawTextEx(font, text, i2f(position), f32(font.baseSize), 0.0, theme.text); + + case .SliderU8: + data := cast(^Data_SliderU8) head + rl.DrawRectangle(i32(rect.l), i32(rect.t), i32(rect.r-rect.l), i32(rect.b-rect.t), theme.base) + rl.DrawRectangle(i32(rect.l+1), i32(rect.t+1), i32(f32(rect.r-rect.l)*(f32(data.value^)/255)-2), i32(rect.b-rect.t-2), theme.slider_bar) + + text := strings.clone_to_cstring(data.text, context.temp_allocator) + position := calculate_text_alignment(text, font, .Center, rect) + + rl.DrawTextEx(font, text, i2f(position), f32(font.baseSize), 0.0, theme.text); + + case .Panel: + data := cast(^Data_Panel) head + rl.DrawRectangle(i32(rect.l), i32(rect.t), i32(rect.r-rect.l), i32(rect.b-rect.t), data.color) + ui_draw_children(item) + + case .Label: + data := cast(^Data_Label) item.handle + text := strings.clone_to_cstring(data.text, context.temp_allocator) + position := calculate_text_alignment(text, data.font, data.alignment, rect) + + rl.DrawTextEx(data.font, text, i2f(position), f32(data.font.baseSize), 0.0, theme.text); + + case .Timeline: + data := cast(^Data_Timeline) item.handle + + width := int(f32(rect.r - rect.l)/(FRACT_MAX - FRACT_MIN)) + + for fracts, i in data.day.fractions { + + color := theme.price_100 + value := data.day.blocks[i].value + + switch { + case value>2.1: + color = theme.price_300 + case value>1.6: + color = theme.price_200 + case value>1.1: + color = theme.price_150 + } + + + + rl.DrawRectangle(i32(rect.l + int(f32(width)*fracts.start) - int(f32(width)*FRACT_MIN)), + i32(rect.t), + i32(f32(width) * (fracts.end - fracts.start)+0.99), + i32(rect.b - rect.t), + color) + // Dark middle of blocks, glowing edge. Disabled for now. + /*rl.DrawRectangle(i32(rect.l + int(f32(width)*fracts.start) - int(f32(width)*FRACT_MIN) + 1), + i32(rect.t) + 1, + i32(f32(width+1) * (fracts.end - fracts.start)-1.01), + i32(rect.b - rect.t)-2, + {0,0,0,100})*/ + if i+1 == data.day.total_timeblocks { + break + } + } + } +}
\ No newline at end of file |