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 dayrate : f64 = 3500 c0 : ^oui.Context main :: proc() { // TODO: Replace the dynamic array of Workday-pointers with // an actual array of Workdays, plus a length variable // for cache reasons, and to simplify the process of // adding new Workdays to the array. workdays : [dynamic]Workday //resize(&workdays, 3) the_big_sum : f64 = 0 { // No need to keep this array in memory forever c, _ := importICS("res/test.ics") for thing, i in c { fmt.println("\n\nAdding workday nr", i, "\n", toString(thing), "\n") append(&workdays, new_workday({00, 00, 1, 1, 1850}, thing.start, thing.end, thing.end)) for each_block in workdays[i].blocks { the_big_sum += f64(each_block.value) * (dayrate/7.5) * f64(hourcount(each_block)) } } } /*workday0: = new_workday({10, 22, 3, 5, 2023}, {00, 08, 4, 5, 2023}, {00, 22, 4, 5, 2023}, {30, 21, 4, 5, 2023}) workdays[0] = &workday0 workday1: = new_workday(workday0.wrap, {00, 08, 5, 5, 2023}, {30, 15, 5, 5, 2023}, {30, 16, 5, 5, 2023}) workdays[1] = &workday1 workday2: = new_workday(workday1.wrap, {00, 12, 6, 5, 2023}, {15, 17, 6, 5, 2023}, {00, 17, 6, 5, 2023}) workdays[2] = &workday2 */ slice.sort_by(workdays[:], lessWorkday) //call_text: cstring = "00:00" call_text: = make([]byte, 6) defer delete(call_text) call_text[len(call_text)-1] = 0 //wrap_text: cstring = "00:00" wrap_text: = make([]byte, 6) defer delete(wrap_text) wrap_text[len(wrap_text)-1] = 0 date_text: = make([]byte, len(toString(workdays[0].call))+1 ) defer delete(date_text) wrap_text[len(wrap_text)-1] = 0 total_sum: cstring = f64_to_cstring(the_big_sum) defer delete(total_sum) inc_soc: cstring = f64_to_cstring(the_big_sum*1.26) defer delete(inc_soc) text_height: f32 using rl width: i32 = 900 height: i32 = 500 InitWindow(width, height, "satscalc") defer CloseWindow() SetTargetFPS(60) SetWindowState({.WINDOW_RESIZABLE}) SetWindowMinSize(width, height) // Loading fonts - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 for day, f in &workdays { beginning: Moment = {0, 0, day.call.day, day.call.month, day.call.year} fmt.println("\nNew day!") for each_block, i in day.blocks { if i == day.total_timeblocks do break start := daycount(diff(beginning, each_block.start)) end := daycount(diff(beginning, each_block.end)) day.fractions[i].start = start day.fractions[i].end = end if start < FRACT_MIN do FRACT_MIN = start if end > FRACT_MAX do FRACT_MAX = end fmt.println(day.fractions[i]) } if f == 0 { // First time through we set the normalization anchors to something we know is real FRACT_MAX = workdays[0].fractions[0].start FRACT_MIN = FRACT_MAX } } for !WindowShouldClose() { // MAIN LOOP ---- MAIN LOOP ---- MAIN LOOP ---- MAIN LOOP free_all(context.temp_allocator) if IsWindowResized() { height = GetScreenHeight() width = GetScreenWidth() fmt.println("Resized to:", width, 'x', height) } pre_sos_price : f64 = 0 for each_day in workdays { pre_sos_price += f64(each_day.price) } post_sos_price : f64 = pre_sos_price * 1.26 // TODO: Find a good way to calculate the size and location // of all the timeblocks in every day. // // I know I want them to scale with the window, and // that the width of them should be normalized. // If you add a day that lasts until 4 AM the morning // after, all the other days should scale down to keep // the vertical alignment of time accurate // // TODO: Hovering over a timeblock should make it pulse softly // 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(theme.background) 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("Calltime", 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 := label(fmt.tprintf("%.2f Kr", pre_sos_price), small_font, 0, .Right) pre_sos_price_label.layout_size.y = 11 oui.item_insert(totals, pre_sos_price_label) post_sos_price_label := label(fmt.tprintf("%.2f Kr", post_sos_price), big_font, 300, .Right) post_sos_price_label.layout_size.y = 27 oui.item_insert(totals, post_sos_price_label) } { 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 - - - - for day, i in &workdays { 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(fmt.tprintf("%.2f Kr", day.price), font, sizings.price, .Center)) oui.item_insert(line, label(clockprint(day.wrap), font, sizings.wrap, .Center)) line.layout_cut_children = .Fill { a_timeline := timeline(line, &day) /*x_offset := i32(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)*/ } } 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 { // TODO: The fractions held inside Workday-s needs to come in pairs, // just like moments come as pairs in timeblocks. // Because that will let us store both the beginning and ending // of timeblocks, which is a simple way to take care of reading // out-of-bounds and will make it possible to render lunch breaks // // (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, theme.background_bar) for block, j in day.blocks { if j == day.total_timeblocks do break block_color: = theme.price_100 switch { case block.value > 2.1: block_color = theme.price_300 case block.value > 1.6: block_color = theme.price_200 case block.value > 1.1: block_color = theme.price_150 } DrawRectangle(TIMELINE_START+i32(math.round(day.fractions[j].start*f32(width+TIMELINE_END-TIMELINE_START))), DAY_HEIGHT*i32(i+1)-4, i32(math.round(f32(width+TIMELINE_END-TIMELINE_START)*(day.fractions[j].end-day.fractions[j].start)+0.5)), DAY_HEIGHT-1, block_color) } copy(call_text, clockprint(day.call)) copy(wrap_text, clockprint(day.wrap)) copy(date_text, toString(day.call)) 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}, 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)}, f32(big_font.baseSize), 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() } }