From 44d408583ab8811f2b89d8fcb9e21b98f1409b7d Mon Sep 17 00:00:00 2001 From: San Jacobs Date: Sat, 14 Oct 2023 16:19:16 +0200 Subject: There is a theme editor now??? --- src/main.odin | 65 +++++++++++---------- src/time.odin | 14 ++--- src/ui_implementation.odin | 139 +++++++++++++++++++++++++++++++++------------ 3 files changed, 145 insertions(+), 73 deletions(-) diff --git a/src/main.odin b/src/main.odin index fcb425d..bed835a 100644 --- a/src/main.odin +++ b/src/main.odin @@ -4,6 +4,7 @@ import "../lib/oui" import "core:fmt" import "core:math" import "core:slice" +import "core:runtime" import "core:strings" import rl "vendor:raylib" @@ -136,7 +137,8 @@ main :: proc() { mousePosition: = rl.GetMousePosition() oui.set_cursor(c0, int(mousePosition.x), int(mousePosition.y)) - oui.set_button(c0, .Left, rl.IsMouseButtonPressed(rl.MouseButton(0))) + 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 // ------------------------------------------ @@ -150,22 +152,24 @@ when true { master_container := panel() - master_container.id = oui.push_id(c0, "big_mr_boss_man") + 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.layout_size = {int(GetScreenWidth()), int(GetScreenHeight())} { - top_bar := panel_line(master_container, theme.background_top, 30) - top_bar.id = oui.push_id(c0, "small_boie") - defer oui.pop_id(c0) + top_bar := panel_line(master_container, theme.background_bar, 30) + top_bar.id = oui.push_id(c0, "small_boie") // Make ID for anything that will have children. + defer oui.pop_id(c0) // These need to be pop'ed before the next item at the same level in the hierachy. top_bar.layout_margin = 6 - date_label := label("Date", font, .Left) - oui.item_insert(top_bar, date_label) + oui.item_insert(top_bar, label("Date", font, .Left)) + oui.item_insert(top_bar, label("Calltime", font, .Left)) + oui.item_insert(top_bar, label("Lunch", font, .Left)) } { - bottom_bar := panel(theme.background_bottom) + bottom_bar := panel(theme.background_bar) bottom_bar.id = oui.push_id(c0, "not_small_boie") defer oui.pop_id(c0) bottom_bar.layout_cut_children = .Left @@ -178,32 +182,35 @@ when true { 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 = 5 // Spacing between children master_container.layout_cut_children = .Fill oui.item_insert(master_container, middle_section) - { - line := panel_line(middle_section, theme.background, 40) - line.id = oui.push_id(c0, "a_line") + // 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) - { - a_button := button("Testor", 100) - oui.item_insert(line, a_button) - } + + 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)) } - } - - - -/* a_button := button("Testerino", 50) - if oui.latest_clicked() { - fmt.println("CLICKO BOIO") + output_theme_button := button("output theme", 100) + oui.item_insert(middle_section, output_theme_button) + if oui.is_clicked(c0, output_theme_button) do fmt.printf("%#v", theme) } - oui.set_cut(a_panel, .Left) - oui.set_height(a_button, 50) - oui.set_offset(a_button, 20, 20) - - oui.item_insert(a_panel, a_button)*/ + oui.end_layout(c0) @@ -227,7 +234,7 @@ when true { // (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_top) for block, j in day.blocks { if j == day.total_timeblocks do break block_color: = GREEN @@ -261,7 +268,7 @@ when true { } } - DrawRectangle(0, height-50, width+10, 60, PBGCOLOR) + DrawRectangle(0, height-50, width+10, 60, theme.background_top) 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); diff --git a/src/time.odin b/src/time.odin index 44c810a..b607e51 100644 --- a/src/time.odin +++ b/src/time.odin @@ -89,7 +89,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 ^ @@ -169,7 +169,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. } @@ -389,7 +389,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 @@ -399,15 +399,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)) diff --git a/src/ui_implementation.odin b/src/ui_implementation.odin index 3e9b913..6b0947d 100644 --- a/src/ui_implementation.odin +++ b/src/ui_implementation.odin @@ -8,32 +8,43 @@ import rl "vendor:raylib" Theme :: struct { background: rl.Color, - background_top: rl.Color, - background_bottom: rl.Color, + background_bar: rl.Color, button: rl.Color, + base: rl.Color, + slider_bar: rl.Color, text: rl.Color, } -theme : Theme = { +/*theme : Theme = { background = {20, 25, 25, 255}, background_top = {30, 35, 35, 255}, background_bottom = {40, 40, 40, 255}, button = {80, 80, 80, 255}, + base = {60, 60, 60, 255}, + slider_bar = {170, 170, 170, 255}, text = rl.RAYWHITE, +}*/ + +theme : Theme = { + background = {25 , 27 , 29 , 255,}, + background_bar = {43 , 43 , 48 , 255,}, + button = {91 , 91 , 204, 255,}, + base = {60 , 60 , 60 , 255,}, + slider_bar = {91 , 91 , 204, 255,}, + text = {255, 255, 255, 252,}, } DAY_HEIGHT :: 35 TIMELINE_START :: 175 TIMELINE_END :: -85 - - Item :: oui.Item Call :: oui.Call Data_Element :: enum int { Panel, Button, + Slider, Label, Text_Input, Timeblock, @@ -55,6 +66,12 @@ Data_Button :: struct { selected: bool, } +Data_Slider :: struct { + using _: Data_Head, + text: string, + value: ^u8, +} + Data_Label :: struct { using _: Data_Head, text: string, @@ -63,17 +80,6 @@ Data_Label :: struct { alignment: Text_Alignment, } -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 -} - panel :: proc(color : rl.Color = rl.RED) -> ^Item { item := oui.item_make(c0) @@ -105,6 +111,7 @@ 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 @@ -113,6 +120,50 @@ button :: proc(text: string, width: int, selected := false) -> ^Item { 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 :: 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_callback + + data := oui.alloc_typed(c0, item, Data_Slider) + data.subtype = .Slider + data.text = text + data.value = value + + return item +} +slider_callback :: proc(ctxt: ^oui.Context, item: ^Item, event: Call) -> int { + data := cast(^Data_Slider) 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("slider_r", fmt.tprintf("%d", color.r), width, &color.r)) + oui.item_insert(parent, slider("slider_g", fmt.tprintf("%d", color.g), width, &color.g)) + oui.item_insert(parent, slider("slider_b", fmt.tprintf("%d", color.b), width, &color.b)) + oui.item_insert(parent, slider("slider_a", fmt.tprintf("%d", color.a), width, &color.a)) +} Text_Alignment :: enum int { // Techically called justification, but text_alignment is more self-explanatory. @@ -122,6 +173,7 @@ Text_Alignment :: enum int { } label :: proc(text: string, font: rl.Font, alignment: Text_Alignment = .Left) -> ^Item { item := oui.item_make(c0) + item.layout_size = {150, 25} data := oui.alloc_typed(c0, item, Data_Label) data.subtype = .Label @@ -175,26 +227,39 @@ ui_draw :: proc(item: ^oui.Item) { } #partial switch head.subtype { - //case .Panel_Root: - // ... render any type of item - case .Button: - data := cast(^Data_Button) item.handle - 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) - - 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 .Panel_Root: + // ... render any type of item + case .Button: + data := cast(^Data_Button) item.handle + 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) + + rl.DrawTextEx(font, text, i2f(position), f32(font.baseSize), 0.0, theme.text); + + //fmt.println(item.anim) + + case .Slider: + data := cast(^Data_Slider) 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); } } \ No newline at end of file -- cgit v1.2.1