diff --git a/samples/ui/data/OpenSans-Bold.ttf b/samples/ui/data/OpenSans-Bold.ttf new file mode 100644 index 0000000..4a5bc39 Binary files /dev/null and b/samples/ui/data/OpenSans-Bold.ttf differ diff --git a/samples/ui/data/OpenSans-Regular.ttf b/samples/ui/data/OpenSans-Regular.ttf new file mode 100644 index 0000000..29e9e60 Binary files /dev/null and b/samples/ui/data/OpenSans-Regular.ttf differ diff --git a/samples/ui/data/OpenSansLatinSubset.ttf b/samples/ui/data/OpenSansLatinSubset.ttf deleted file mode 100644 index acfe2d8..0000000 Binary files a/samples/ui/data/OpenSansLatinSubset.ttf and /dev/null differ diff --git a/samples/ui/src/main.c b/samples/ui/src/main.c index 18fe195..bb729f5 100644 --- a/samples/ui/src/main.c +++ b/samples/ui/src/main.c @@ -6,32 +6,47 @@ * **************************************************************************/ #include "orca.h" +#include -oc_vec2 frameSize = { 100, 100 }; +oc_vec2 frameSize = { 1200, 838 }; oc_surface surface; oc_canvas canvas; -oc_font font; +oc_font fontRegular; +oc_font fontBold; oc_ui_context ui; oc_arena textArena = { 0 }; -oc_ui_theme* theme = &OC_UI_DARK_THEME; +oc_arena logArena = { 0 }; +oc_str8_list logLines; + +typedef enum cmd +{ + CMD_NONE, + CMD_SET_DARK_THEME, + CMD_SET_LIGHT_THEME +} cmd; + +cmd command = CMD_NONE; ORCA_EXPORT void oc_on_init(void) { - oc_window_set_title(OC_STR8("ui")); + oc_window_set_title(OC_STR8("Orca UI Demo")); + oc_window_set_size(frameSize); surface = oc_surface_canvas(); canvas = oc_canvas_create(); oc_ui_init(&ui); - //NOTE: load font + oc_font* fonts[2] = { &fontRegular, &fontBold }; + const char* fontNames[2] = { "/OpenSans-Regular.ttf", "/OpenSans-Bold.ttf" }; + for(int i = 0; i < 2; i++) { oc_arena_scope scratch = oc_scratch_begin(); - oc_file file = oc_file_open(OC_STR8("/OpenSansLatinSubset.ttf"), OC_FILE_ACCESS_READ, 0); + oc_file file = oc_file_open(OC_STR8(fontNames[i]), OC_FILE_ACCESS_READ, 0); if(oc_file_last_error(file) != OC_IO_OK) { - oc_log_error("Couldn't open file OpenSansLatinSubset.ttf\n"); + oc_log_error("Couldn't open file %s\n", fontNames[i]); } u64 size = oc_file_size(file); char* buffer = (char*)oc_arena_push(scratch.arena, size); @@ -43,19 +58,14 @@ ORCA_EXPORT void oc_on_init(void) OC_UNICODE_LATIN_EXTENDED_B, OC_UNICODE_SPECIALS }; - font = oc_font_create_from_memory(oc_str8_from_buffer(size, buffer), 5, ranges); + *fonts[i] = oc_font_create_from_memory(oc_str8_from_buffer(size, buffer), 5, ranges); oc_scratch_end(scratch); } oc_arena_init(&textArena); -} - -ORCA_EXPORT void oc_on_resize(u32 width, u32 height) -{ - oc_log_info("frame resize %u, %u", width, height); - frameSize.x = width; - frameSize.y = height; + oc_arena_init(&logArena); + oc_list_init(&logLines.list); } ORCA_EXPORT void oc_on_raw_event(oc_event* event) @@ -63,324 +73,715 @@ ORCA_EXPORT void oc_on_raw_event(oc_event* event) oc_ui_process_event(event); } -void widget_begin_view(char* str) +void log_push(const char* line) { - oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_Y, - .layout.spacing = 10, - .layout.margin.x = 10, - .layout.margin.y = 10, - .layout.align.x = OC_UI_ALIGN_CENTER, - .layout.align.y = OC_UI_ALIGN_START }, - OC_UI_STYLE_LAYOUT); - - oc_ui_box_begin(str, OC_UI_FLAG_DRAW_BORDER); - oc_ui_label(str); + oc_str8_list_push(&logArena, &logLines, (oc_str8)OC_STR8(line)); } -void widget_end_view(void) +void log_pushf(const char* format, ...) { - oc_ui_box_end(); + va_list args; + va_start(args, format); + oc_str8 str = oc_str8_pushfv(&logArena, format, args); + va_end(args); + oc_str8_list_push(&logArena, &logLines, str); } -#define widget_view(s) oc_defer_loop(widget_begin_view(s), widget_end_view()) +void column_begin(const char* header, f32 widthFraction) +{ + oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, widthFraction }, + .size.height = { OC_UI_SIZE_PARENT, 1 }, + .layout.axis = OC_UI_AXIS_Y, + .layout.margin.y = 8, + .layout.spacing = 24, + .bgColor = ui.theme->bg1, + .borderColor = ui.theme->border, + .borderSize = 1, + .roundness = ui.theme->roundnessSmall }, + OC_UI_STYLE_SIZE + | OC_UI_STYLE_LAYOUT_AXIS + | OC_UI_STYLE_LAYOUT_MARGIN_Y + | OC_UI_STYLE_LAYOUT_SPACING + | OC_UI_STYLE_BG_COLOR + | OC_UI_STYLE_BORDER_COLOR + | OC_UI_STYLE_BORDER_SIZE + | OC_UI_STYLE_ROUNDNESS); + oc_ui_box_begin(header, OC_UI_FLAG_DRAW_BACKGROUND | OC_UI_FLAG_DRAW_BORDER); + + oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 }, + .layout.align.x = OC_UI_ALIGN_CENTER }, + OC_UI_STYLE_SIZE_WIDTH + | OC_UI_STYLE_LAYOUT_ALIGN_X); + oc_ui_container("header", OC_UI_FLAG_NONE) + { + oc_ui_style_next(&(oc_ui_style){ .fontSize = 18 }, + OC_UI_STYLE_FONT_SIZE); + oc_ui_label(header); + } + + oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 }, + .size.height = { OC_UI_SIZE_PARENT, 0.8 }, + .layout.align.x = OC_UI_ALIGN_START, + .layout.margin.x = 16, + .layout.spacing = 24 }, + OC_UI_STYLE_SIZE + | OC_UI_STYLE_LAYOUT_ALIGN_X + | OC_UI_STYLE_LAYOUT_MARGIN_X + | OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_box_begin("contents", OC_UI_FLAG_NONE); +} + +void column_end() +{ + oc_ui_box_end(); // contents + oc_ui_box_end(); // column +} + +#define column(h, w) oc_defer_loop(column_begin(h, w), column_end()) + +void labeled_slider(const char* label, f32* value) +{ + oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_X, + .layout.spacing = 8 }, + OC_UI_STYLE_LAYOUT_AXIS + | OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container(label, OC_UI_FLAG_NONE) + { + oc_ui_style_match_after(oc_ui_pattern_owner(), + &(oc_ui_style){ .size.width = { OC_UI_SIZE_PIXELS, 100 } }, + OC_UI_STYLE_SIZE_WIDTH); + oc_ui_label(label); + + oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PIXELS, 100 } }, + OC_UI_STYLE_SIZE_WIDTH); + oc_ui_slider("slider", value); + } +} ORCA_EXPORT void oc_on_frame_refresh(void) { + switch(command) + { + case CMD_SET_DARK_THEME: + oc_ui_set_theme(&OC_UI_DARK_THEME); + break; + case CMD_SET_LIGHT_THEME: + oc_ui_set_theme(&OC_UI_LIGHT_THEME); + break; + default: + break; + } + command = CMD_NONE; + oc_arena_scope scratch = oc_scratch_begin(); - oc_ui_set_theme(theme); - - oc_ui_style defaultStyle = { .font = font }; - + oc_ui_style defaultStyle = { .font = fontRegular }; oc_ui_style_mask defaultMask = OC_UI_STYLE_FONT; - oc_ui_frame(frameSize, &defaultStyle, defaultMask) { - oc_ui_style_match_before(oc_ui_pattern_all(), &defaultStyle, defaultMask); + //-------------------------------------------------------------------------------------------- + // Menu bar + //-------------------------------------------------------------------------------------------- + oc_ui_menu_bar("menu_bar") + { + oc_ui_menu("File") + { + if(oc_ui_menu_button("Quit").pressed) + { + oc_request_quit(); + } + } + + oc_ui_menu("Theme") + { + if(oc_ui_menu_button("Dark theme").pressed) + { + command = CMD_SET_DARK_THEME; + } + if(oc_ui_menu_button("Light theme").pressed) + { + command = CMD_SET_LIGHT_THEME; + } + } + } oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 }, - .size.height = { OC_UI_SIZE_PARENT, 1 }, - .layout.axis = OC_UI_AXIS_Y, - .layout.align.x = OC_UI_ALIGN_CENTER, - .layout.align.y = OC_UI_ALIGN_START, - .layout.spacing = 10 }, + .size.height = { OC_UI_SIZE_PARENT_MINUS_PIXELS, 28 }, + .layout.axis = OC_UI_AXIS_X, + .layout.margin.x = 16, + .layout.margin.y = 16, + .layout.spacing = 16 }, OC_UI_STYLE_SIZE - | OC_UI_STYLE_LAYOUT); - + | OC_UI_STYLE_LAYOUT_AXIS + | OC_UI_STYLE_LAYOUT_MARGINS + | OC_UI_STYLE_LAYOUT_SPACING); oc_ui_container("background", OC_UI_FLAG_DRAW_BACKGROUND) { - oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 }, - .size.height = { OC_UI_SIZE_CHILDREN }, - .layout.align.x = OC_UI_ALIGN_CENTER, - .layout.margin.x = 10, - .layout.margin.y = 10 }, - OC_UI_STYLE_SIZE - | OC_UI_STYLE_LAYOUT_ALIGN_X - | OC_UI_STYLE_LAYOUT_MARGINS); - oc_ui_container("title", OC_UI_FLAG_NONE) + column("Widgets", 1.0 / 3) { - oc_ui_style_next(&(oc_ui_style){ .fontSize = 26 }, OC_UI_STYLE_FONT_SIZE); - oc_ui_label("Orca UI Demo"); - if(oc_ui_box_sig(oc_ui_box_top()).hovering) + oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 }, + .layout.axis = OC_UI_AXIS_X, + .layout.spacing = 32 }, + OC_UI_STYLE_SIZE_WIDTH + | OC_UI_STYLE_LAYOUT_AXIS + | OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("top", OC_UI_FLAG_NONE) { - oc_ui_tooltip("That is a tooltip!"); + oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_Y, + .layout.spacing = 24 }, + OC_UI_STYLE_LAYOUT_AXIS + | OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("top_left", OC_UI_FLAG_NONE) + { + //----------------------------------------------------------------------------- + // Label + //----------------------------------------------------------------------------- + oc_ui_label("Label"); + + //----------------------------------------------------------------------------- + // Button + //----------------------------------------------------------------------------- + if(oc_ui_button("Button").clicked) + { + log_push("Button clicked"); + } + + oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_X, + .layout.align.y = OC_UI_ALIGN_CENTER, + .layout.spacing = 8 }, + OC_UI_STYLE_LAYOUT_AXIS + | OC_UI_STYLE_LAYOUT_ALIGN_Y + | OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("checkbox", OC_UI_FLAG_NONE) + { + //------------------------------------------------------------------------- + // Checkbox + //------------------------------------------------------------------------- + static bool checked = false; + if(oc_ui_checkbox("checkbox", &checked).clicked) + { + if(checked) + { + log_push("Checkbox checked"); + } + else + { + log_push("Checkbox unchecked"); + } + } + + oc_ui_label("Checkbox"); + } + } + + //--------------------------------------------------------------------------------- + // Vertical slider + //--------------------------------------------------------------------------------- + static float vSliderValue = 0; + static float vSliderLoggedValue = 0; + static f64 vSliderLogTime = 0; + oc_ui_style_next(&(oc_ui_style){ .size.height = { OC_UI_SIZE_PIXELS, 130 } }, + OC_UI_STYLE_SIZE_HEIGHT); + oc_ui_slider("v_slider", &vSliderValue); + f64 now = oc_clock_time(OC_CLOCK_MONOTONIC); + if((now - vSliderLogTime) >= 0.2 && vSliderValue != vSliderLoggedValue) + { + log_pushf("Vertical slider moved to %f", vSliderValue); + vSliderLoggedValue = vSliderValue; + vSliderLogTime = now; + } + + oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_Y, + .layout.spacing = 24 }, + OC_UI_STYLE_LAYOUT_AXIS + | OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("top_right", OC_UI_FLAG_NONE) + { + //----------------------------------------------------------------------------- + // Tooltip + //----------------------------------------------------------------------------- + if(oc_ui_label("Tooltip").hovering) + { + oc_ui_tooltip("Hi"); + } + + //----------------------------------------------------------------------------- + // Radio group + //----------------------------------------------------------------------------- + static int radioSelected = 0; + oc_str8 options[] = { OC_STR8("Radio 1"), + OC_STR8("Radio 2") }; + oc_ui_radio_group_info radioGroupInfo = { .selectedIndex = radioSelected, + .optionCount = 2, + .options = options }; + oc_ui_radio_group_info result = oc_ui_radio_group("radio_group", &radioGroupInfo); + radioSelected = result.selectedIndex; + if(result.changed) + { + log_pushf("Selected Radio %i", result.selectedIndex + 1); + } + + //----------------------------------------------------------------------------- + // Horizontal slider + //----------------------------------------------------------------------------- + static float hSliderValue = 0; + static float hSliderLoggedValue = 0; + static f64 hSliderLogTime = 0; + oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PIXELS, 130 } }, + OC_UI_STYLE_SIZE_WIDTH); + oc_ui_slider("h_slider", &hSliderValue); + f64 now = oc_clock_time(OC_CLOCK_MONOTONIC); + if((now - hSliderLogTime) >= 0.2 && hSliderValue != hSliderLoggedValue) + { + log_pushf("Slider moved to %f", hSliderValue); + hSliderLoggedValue = hSliderValue; + hSliderLogTime = now; + } + } + } + + //------------------------------------------------------------------------------------- + // Text box + //------------------------------------------------------------------------------------- + oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PIXELS, 305 }, + .size.height = { OC_UI_SIZE_TEXT } }, + OC_UI_STYLE_SIZE); + static oc_str8 text = OC_STR8_LIT("Text box"); + oc_ui_text_box_result res = oc_ui_text_box("text", scratch.arena, text); + if(res.changed) + { + oc_arena_clear(&textArena); + text = oc_str8_push_copy(&textArena, res.text); + } + if(res.accepted) + { + log_pushf("Entered text \"%s\"", text.ptr); + } + + //------------------------------------------------------------------------------------- + // Select + //------------------------------------------------------------------------------------- + static int selected = -1; + oc_str8 options[] = { OC_STR8("Option 1"), + OC_STR8("Option 2") }; + oc_ui_select_popup_info info = { .selectedIndex = selected, + .optionCount = 2, + .options = options, + .placeholder = OC_STR8_LIT("Select") }; + oc_ui_select_popup_info result = oc_ui_select_popup("select", &info); + if(result.selectedIndex != selected) + { + log_pushf("Selected %s", options[result.selectedIndex].ptr); + } + selected = result.selectedIndex; + + //------------------------------------------------------------------------------------- + // Scrollable panel + //------------------------------------------------------------------------------------- + oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 }, + .size.height = { OC_UI_SIZE_PIXELS, 430 }, + .layout.margin.x = 16, + .layout.margin.y = 16, + .layout.spacing = 8, + .bgColor = ui.theme->bg2, + .borderColor = ui.theme->border, + .borderSize = 1, + .roundness = ui.theme->roundnessSmall }, + OC_UI_STYLE_SIZE + | OC_UI_STYLE_LAYOUT_MARGINS + | OC_UI_STYLE_LAYOUT_SPACING + | OC_UI_STYLE_BG_COLOR + | OC_UI_STYLE_BORDER_COLOR + | OC_UI_STYLE_BORDER_SIZE + | OC_UI_STYLE_ROUNDNESS); + oc_ui_panel("log", OC_UI_FLAG_DRAW_BACKGROUND | OC_UI_FLAG_DRAW_BORDER) + { + if(oc_list_empty(&logLines.list)) + { + oc_ui_style_next(&(oc_ui_style){ .color = ui.theme->text2 }, + OC_UI_STYLE_COLOR); + oc_ui_label("Log"); + } + + i32 i = 0; + oc_list_for(&logLines.list, logLine, oc_str8_elt, listElt) + { + char id[15]; + snprintf(id, sizeof(id), "%d", i); + oc_ui_container(id, OC_UI_FLAG_NONE) + { + oc_ui_label_str8(logLine->string); + } + i++; + } } } - oc_ui_menu_bar("Menu bar") + //----------------------------------------------------------------------------------------- + // Styling + //----------------------------------------------------------------------------------------- + // Initial values here are hardcoded from the dark theme and everything is overridden all + // the time. In a real program you'd only override what you need and supply the values from + // ui.theme or ui.theme->palette. + // + // Rule-based styling is described at + // https://www.forkingpaths.dev/posts/23-03-10/rule_based_styling_imgui.html + column("Styling", 2.0 / 3) { - oc_ui_menu("Menu 1") + static f32 unselectedWidth = 16; + static f32 unselectedHeight = 16; + static f32 unselectedRoundness = 8; + static f32 unselectedBgR = 0.086; + static f32 unselectedBgG = 0.086; + static f32 unselectedBgB = 0.102; + static f32 unselectedBgA = 1; + static f32 unselectedBorderR = 0.976; + static f32 unselectedBorderG = 0.976; + static f32 unselectedBorderB = 0.976; + static f32 unselectedBorderA = 0.35; + static f32 unselectedBorderSize = 1; + static oc_ui_status unselectedWhenStatus = OC_UI_NONE; + + static f32 selectedWidth = 16; + static f32 selectedHeight = 16; + static f32 selectedRoundness = 8; + static f32 selectedR = 1; + static f32 selectedG = 1; + static f32 selectedB = 1; + static f32 selectedA = 1; + static f32 selectedBgR = 0.33; + static f32 selectedBgG = 0.66; + static f32 selectedBgB = 1; + static f32 selectedBgA = 1; + static oc_ui_status selectedWhenStatus = OC_UI_NONE; + + static oc_color labelFontColor = { 0.976, 0.976, 0.976, 1 }; + static oc_font* labelFont = &fontRegular; + static f32 labelFontSize = 14; + + oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 }, + .size.height = { OC_UI_SIZE_PIXELS, 152 }, + .layout.margin.x = 320, + .layout.margin.y = 16, + .bgColor = OC_UI_DARK_THEME.bg0, + .roundness = OC_UI_DARK_THEME.roundnessSmall }, + OC_UI_STYLE_SIZE + | OC_UI_STYLE_LAYOUT_MARGINS + | OC_UI_STYLE_BG_COLOR + | OC_UI_STYLE_ROUNDNESS); + oc_ui_container("styled_radios", OC_UI_FLAG_DRAW_BACKGROUND | OC_UI_FLAG_DRAW_BORDER) { - if(oc_ui_menu_button("Option 1.1").pressed) - { - oc_log_info("Pressed option 1.1\n"); - } - oc_ui_menu_button("Option 1.2"); - oc_ui_menu_button("Option 1.3"); - oc_ui_menu_button("Option 1.4"); + oc_ui_pattern unselectedPattern = { 0 }; + oc_ui_pattern_push(scratch.arena, + &unselectedPattern, + (oc_ui_selector){ .kind = OC_UI_SEL_TAG, + .tag = oc_ui_tag_make("radio") }); + oc_ui_pattern_push(scratch.arena, + &unselectedPattern, + (oc_ui_selector){ .op = OC_UI_SEL_AND, + .kind = OC_UI_SEL_STATUS, + .status = unselectedWhenStatus }); + oc_ui_style_match_after(unselectedPattern, + &(oc_ui_style){ .size.width = { OC_UI_SIZE_PIXELS, unselectedWidth }, + .size.height = { OC_UI_SIZE_PIXELS, unselectedHeight }, + .bgColor = { unselectedBgR, unselectedBgG, unselectedBgB, unselectedBgA }, + .borderColor = { unselectedBorderR, unselectedBorderG, unselectedBorderB, unselectedBorderA }, + .borderSize = unselectedBorderSize, + .roundness = unselectedRoundness }, + OC_UI_STYLE_SIZE + | OC_UI_STYLE_BG_COLOR + | OC_UI_STYLE_BORDER_COLOR + | OC_UI_STYLE_BORDER_SIZE + | OC_UI_STYLE_ROUNDNESS); + + oc_ui_pattern selectedPattern = { 0 }; + oc_ui_pattern_push(scratch.arena, + &selectedPattern, + (oc_ui_selector){ .kind = OC_UI_SEL_TAG, + .tag = oc_ui_tag_make("radio_selected") }); + oc_ui_pattern_push(scratch.arena, + &selectedPattern, + (oc_ui_selector){ .op = OC_UI_SEL_AND, + .kind = OC_UI_SEL_STATUS, + .status = selectedWhenStatus }); + oc_ui_style_match_after(selectedPattern, + &(oc_ui_style){ .size.width = { OC_UI_SIZE_PIXELS, selectedWidth }, + .size.height = { OC_UI_SIZE_PIXELS, selectedHeight }, + .color = { selectedR, selectedG, selectedB, selectedA }, + .bgColor = { selectedBgR, selectedBgG, selectedBgB, selectedBgA }, + .roundness = selectedRoundness }, + OC_UI_STYLE_SIZE + | OC_UI_STYLE_COLOR + | OC_UI_STYLE_BG_COLOR + | OC_UI_STYLE_ROUNDNESS); + + oc_ui_pattern labelPattern = { 0 }; + oc_ui_tag labelTag = oc_ui_tag_make("label"); + oc_ui_pattern_push(scratch.arena, &labelPattern, (oc_ui_selector){ .kind = OC_UI_SEL_TAG, .tag = labelTag }); + oc_ui_style_match_after(labelPattern, + &(oc_ui_style){ .color = labelFontColor, + .font = *labelFont, + .fontSize = labelFontSize }, + OC_UI_STYLE_COLOR + | OC_UI_STYLE_FONT + | OC_UI_STYLE_FONT_SIZE); + + static int selectedIndex = 0; + oc_str8 options[] = { OC_STR8("I"), + OC_STR8("Am"), + OC_STR8("Stylish") }; + oc_ui_radio_group_info radioGroupInfo = { .selectedIndex = selectedIndex, + .optionCount = oc_array_size(options), + .options = options }; + oc_ui_radio_group_info result = oc_ui_radio_group("radio_group", &radioGroupInfo); + selectedIndex = result.selectedIndex; } - oc_ui_menu("Menu 2") + oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_X, + .layout.spacing = 32 }, + OC_UI_STYLE_LAYOUT_AXIS + | OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("controls", OC_UI_FLAG_NONE) { - oc_ui_menu_button("Option 2.1"); - oc_ui_menu_button("Option 2.2"); - oc_ui_menu_button("Option 2.3"); - oc_ui_menu_button("Option 2.4"); - } - - oc_ui_menu("Menu 3") - { - oc_ui_menu_button("Option 3.1"); - oc_ui_menu_button("Option 3.2"); - oc_ui_menu_button("Option 3.3"); - oc_ui_menu_button("Option 3.4"); - } - } - - oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 }, - .size.height = { OC_UI_SIZE_PARENT, 1, 1 }, - .layout.margin.x = 10, - .layout.margin.y = 10 }, - OC_UI_STYLE_SIZE | OC_UI_STYLE_LAYOUT_MARGINS); - - oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_X }, OC_UI_STYLE_LAYOUT_AXIS); - oc_ui_container("contents", OC_UI_FLAG_NONE) - { - oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 0.5 }, - .size.height = { OC_UI_SIZE_PARENT, 1 } }, - OC_UI_STYLE_SIZE); - - oc_ui_container("left", OC_UI_FLAG_NONE) - { - oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_X, - .layout.spacing = 10, - .layout.margin.x = 10, - .layout.margin.y = 10, - .size.width = { OC_UI_SIZE_PARENT, 1 }, - .size.height = { OC_UI_SIZE_PARENT, 0.5 } }, + oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_Y, + .layout.spacing = 16 }, OC_UI_STYLE_LAYOUT_AXIS - | OC_UI_STYLE_LAYOUT_SPACING - | OC_UI_STYLE_LAYOUT_MARGIN_X - | OC_UI_STYLE_LAYOUT_MARGIN_Y - | OC_UI_STYLE_SIZE); - - oc_ui_container("up", OC_UI_FLAG_NONE) + | OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("unselected", OC_UI_FLAG_NONE) { - oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 0.33 }, - .size.height = { OC_UI_SIZE_PARENT, 1 } }, - OC_UI_STYLE_SIZE); - widget_view("Buttons") + oc_ui_style_next(&(oc_ui_style){ .fontSize = 16 }, + OC_UI_STYLE_FONT_SIZE); + oc_ui_label("Radio style"); + + oc_ui_style_next(&(oc_ui_style){ .layout.spacing = 4 }, + OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("size", OC_UI_FLAG_NONE) { - if(oc_ui_button("Button A").clicked) - { - oc_log_info("A clicked"); - } + f32 widthSlider = (unselectedWidth - 8) / 16; + labeled_slider("Width", &widthSlider); + unselectedWidth = 8 + widthSlider * 16; - if(oc_ui_button("Button B").clicked) - { - oc_log_info("B clicked"); - } + f32 heightSlider = (unselectedHeight - 8) / 16; + labeled_slider("Height", &heightSlider); + unselectedHeight = 8 + heightSlider * 16; - if(oc_ui_button("Button C").clicked) - { - oc_log_info("C clicked"); - } + f32 roundnessSlider = (unselectedRoundness - 4) / 8; + labeled_slider("Roundness", &roundnessSlider); + unselectedRoundness = 4 + roundnessSlider * 8; } - oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 0.33 }, - .size.height = { OC_UI_SIZE_PARENT, 1 } }, - OC_UI_STYLE_SIZE); - - widget_view("checkboxes") + oc_ui_style_next(&(oc_ui_style){ .layout.spacing = 4 }, + OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("background", OC_UI_FLAG_NONE) { - static bool check1 = true; - static bool check2 = false; - static bool check3 = false; - - oc_ui_checkbox("check1", &check1); - oc_ui_checkbox("check2", &check2); - oc_ui_checkbox("check3", &check3); + labeled_slider("Background R", &unselectedBgR); + labeled_slider("Background G", &unselectedBgG); + labeled_slider("Background B", &unselectedBgB); + labeled_slider("Background A", &unselectedBgA); } - oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 0.33 }, - .size.height = { OC_UI_SIZE_PARENT, 1 } }, - OC_UI_STYLE_SIZE); - - widget_view("Radio group") + oc_ui_style_next(&(oc_ui_style){ .layout.spacing = 4 }, + OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("border", OC_UI_FLAG_NONE) { - static int radioSelected = 0; - oc_str8 options[] = { OC_STR8("Dark theme"), - OC_STR8("Light theme") }; - oc_ui_radio_group_info info = { .selectedIndex = radioSelected, - .optionCount = 2, - .options = options }; + labeled_slider("Border R", &unselectedBorderR); + labeled_slider("Border G", &unselectedBorderG); + labeled_slider("Border B", &unselectedBorderB); + labeled_slider("Border A", &unselectedBorderA); + } - oc_ui_radio_group_info result = oc_ui_radio_group("radio_group", &info); - radioSelected = result.selectedIndex; - theme = radioSelected == 0 ? &OC_UI_DARK_THEME : &OC_UI_LIGHT_THEME; + f32 borderSizeSlider = unselectedBorderSize / 5; + labeled_slider("Border size", &borderSizeSlider); + unselectedBorderSize = borderSizeSlider * 5; + + oc_ui_style_next(&(oc_ui_style){ .layout.spacing = 10 }, + OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("status_override", OC_UI_FLAG_NONE) + { + oc_ui_label("Override"); + + static int statusIndex = 0; + oc_str8 statusOptions[] = { OC_STR8("Always"), + OC_STR8("When hovering"), + OC_STR8("When dragging") }; + oc_ui_radio_group_info statusInfo = { .selectedIndex = statusIndex, + .optionCount = oc_array_size(statusOptions), + .options = statusOptions }; + oc_ui_radio_group_info result = oc_ui_radio_group("status", &statusInfo); + statusIndex = result.selectedIndex; + switch(statusIndex) + { + case 0: + unselectedWhenStatus = OC_UI_NONE; + break; + case 1: + unselectedWhenStatus = OC_UI_HOVER; + break; + case 2: + unselectedWhenStatus = OC_UI_DRAGGING; + break; + default: + break; + } } } - oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_X, - .size.width = { OC_UI_SIZE_PARENT, 1 }, - .size.height = { OC_UI_SIZE_PARENT, 0.5 } }, + oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_Y, + .layout.spacing = 16 }, OC_UI_STYLE_LAYOUT_AXIS - | OC_UI_STYLE_SIZE); - - oc_ui_container("down", OC_UI_FLAG_NONE) + | OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("selected", OC_UI_FLAG_NONE) { - widget_view("Vertical Sliders") + oc_ui_style_next(&(oc_ui_style){ .fontSize = 16 }, + OC_UI_STYLE_FONT_SIZE); + oc_ui_label("Radio selected style"); + + oc_ui_style_next(&(oc_ui_style){ .layout.spacing = 4 }, + OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("size", OC_UI_FLAG_NONE) { - oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_X, - .layout.spacing = 10 }, - OC_UI_STYLE_LAYOUT_AXIS - | OC_UI_STYLE_LAYOUT_SPACING); - oc_ui_container("contents", OC_UI_FLAG_NONE) + f32 widthSlider = (selectedWidth - 8) / 16; + labeled_slider("Width", &widthSlider); + selectedWidth = 8 + widthSlider * 16; + + f32 heightSlider = (selectedHeight - 8) / 16; + labeled_slider("Height", &heightSlider); + selectedHeight = 8 + heightSlider * 16; + + f32 roundnessSlider = (selectedRoundness - 4) / 8; + labeled_slider("Roundness", &roundnessSlider); + selectedRoundness = 4 + roundnessSlider * 8; + } + + oc_ui_style_next(&(oc_ui_style){ .layout.spacing = 4 }, + OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("color", OC_UI_FLAG_NONE) + { + labeled_slider("Center R", &selectedR); + labeled_slider("Center G", &selectedG); + labeled_slider("Center B", &selectedB); + labeled_slider("Center A", &selectedA); + } + + oc_ui_style_next(&(oc_ui_style){ .layout.spacing = 4 }, + OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("background", OC_UI_FLAG_NONE) + { + labeled_slider("Background R", &selectedBgR); + labeled_slider("Background G", &selectedBgG); + labeled_slider("Background B", &selectedBgB); + labeled_slider("Background A", &selectedBgA); + } + + oc_ui_style_next(&(oc_ui_style){ .layout.spacing = 10 }, + OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("status_override", OC_UI_FLAG_NONE) + { + oc_ui_style_next(&(oc_ui_style){ .size.height = { OC_UI_SIZE_PIXELS, 30 } }, + OC_UI_STYLE_SIZE_HEIGHT); + oc_ui_box_make("spacer", OC_UI_FLAG_NONE); + + oc_ui_label("Override"); + + static int statusIndex = 0; + oc_str8 statusOptions[] = { OC_STR8("Always"), + OC_STR8("When hovering"), + OC_STR8("When dragging") }; + oc_ui_radio_group_info statusInfo = { .selectedIndex = statusIndex, + .optionCount = oc_array_size(statusOptions), + .options = statusOptions }; + oc_ui_radio_group_info result = oc_ui_radio_group("status", &statusInfo); + statusIndex = result.selectedIndex; + switch(statusIndex) { - oc_ui_style_next(&(oc_ui_style){ .size.height = { OC_UI_SIZE_PIXELS, 200 } }, - OC_UI_STYLE_SIZE_HEIGHT); - static f32 slider1 = 0; - oc_ui_slider("slider1", &slider1); - - oc_ui_style_next(&(oc_ui_style){ .size.height = { OC_UI_SIZE_PIXELS, 200 } }, - OC_UI_STYLE_SIZE_HEIGHT); - static f32 slider2 = 0; - oc_ui_slider("slider2", &slider2); - - oc_ui_style_next(&(oc_ui_style){ .size.height = { OC_UI_SIZE_PIXELS, 200 } }, - OC_UI_STYLE_SIZE_HEIGHT); - static f32 slider3 = 0; - oc_ui_slider("slider3", &slider3); + case 0: + selectedWhenStatus = OC_UI_NONE; + break; + case 1: + selectedWhenStatus = OC_UI_HOVER; + break; + case 2: + selectedWhenStatus = OC_UI_DRAGGING; + break; + default: + break; } } - - widget_view("Horizontal Sliders") - { - oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PIXELS, 200 } }, - OC_UI_STYLE_SIZE_WIDTH); - static f32 slider1 = 0; - oc_ui_slider("slider1", &slider1); - - oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PIXELS, 200 } }, - OC_UI_STYLE_SIZE_WIDTH); - static f32 slider2 = 0; - oc_ui_slider("slider2", &slider2); - - oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PIXELS, 200 } }, - OC_UI_STYLE_SIZE_WIDTH); - static f32 slider3 = 0; - oc_ui_slider("slider3", &slider3); - } - } - } - - oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 0.5 }, - .size.height = { OC_UI_SIZE_PARENT, 1 } }, - OC_UI_STYLE_SIZE); - - oc_ui_container("right", 0) - { - - oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 }, - .size.height = { OC_UI_SIZE_PARENT, 0.33 } }, - OC_UI_STYLE_SIZE); - widget_view("Text box") - { - oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PIXELS, 300 }, - .size.height = { OC_UI_SIZE_TEXT } }, - OC_UI_STYLE_SIZE); - static oc_str8 text = { 0 }; - oc_ui_text_box_result res = oc_ui_text_box("textbox", scratch.arena, text); - if(res.changed) - { - oc_arena_clear(&textArena); - text = oc_str8_push_copy(&textArena, res.text); - } } - oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 }, - .size.height = { OC_UI_SIZE_PARENT, 0.33 } }, - OC_UI_STYLE_SIZE); - widget_view("Test") + oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_Y, + .layout.spacing = 16 }, + OC_UI_STYLE_LAYOUT_AXIS + | OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("label", OC_UI_FLAG_NONE) { - static int selected = 0; - oc_str8 options[] = { OC_STR8("Option 1"), - OC_STR8("Option 2"), - OC_STR8("Long option 3"), - OC_STR8("Option 4"), - OC_STR8("Option 5") }; - oc_ui_select_popup_info info = { .selectedIndex = selected, - .optionCount = 5, - .options = options }; + oc_ui_style_next(&(oc_ui_style){ .fontSize = 16 }, + OC_UI_STYLE_FONT_SIZE); + oc_ui_label("Label style"); - oc_ui_select_popup_info result = oc_ui_select_popup("popup", &info); - selected = result.selectedIndex; - } - - oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 }, - .size.height = { OC_UI_SIZE_PARENT, 0.33 } }, - OC_UI_STYLE_SIZE); - widget_view("Color") - { - oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 }, - .size.height = { OC_UI_SIZE_PARENT, 0.7 }, - .layout.axis = OC_UI_AXIS_X }, - OC_UI_STYLE_SIZE - | OC_UI_STYLE_LAYOUT_AXIS); - - oc_ui_panel("Panel", OC_UI_FLAG_DRAW_BORDER) + oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_X, + .layout.spacing = 8 }, + OC_UI_STYLE_LAYOUT_AXIS + | OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("font_color", OC_UI_FLAG_NONE) { - oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_X }, - OC_UI_STYLE_LAYOUT_AXIS); - oc_ui_container("contents", 0) - { - oc_ui_style_next(&(oc_ui_style){ .layout.spacing = 20 }, - OC_UI_STYLE_LAYOUT_SPACING); - oc_ui_container("buttons", 0) - { - if(oc_ui_button("Break the law").clicked) - { - oc_clipboard_set_string((oc_str8)OC_STR8_LIT("Check out my cool website")); - } - oc_ui_button("Button B"); - oc_ui_button("Button C"); - oc_ui_button("Button D"); - } + oc_ui_style_match_after(oc_ui_pattern_owner(), + &(oc_ui_style){ .size.width = { OC_UI_SIZE_PIXELS, 100 } }, + OC_UI_STYLE_SIZE_WIDTH); + oc_ui_label("Font color"); - oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_X, - .layout.spacing = 20 }, - OC_UI_STYLE_LAYOUT_SPACING - | OC_UI_STYLE_LAYOUT_AXIS); - - oc_ui_container("buttons2", 0) - { - oc_ui_button("Button A"); - oc_ui_button("Button B"); - oc_ui_button("Button C"); - oc_ui_button("Button D"); - } - } + static int colorSelected = 0; + oc_str8 colorNames[] = { OC_STR8("Default"), + OC_STR8("Red"), + OC_STR8("Orange"), + OC_STR8("Amber"), + OC_STR8("Yellow"), + OC_STR8("Lime"), + OC_STR8("Light Green"), + OC_STR8("Green") }; + oc_color colors[] = { OC_UI_DARK_THEME.text0, + OC_UI_DARK_THEME.palette->red5, + OC_UI_DARK_THEME.palette->orange5, + OC_UI_DARK_THEME.palette->amber5, + OC_UI_DARK_THEME.palette->yellow5, + OC_UI_DARK_THEME.palette->lime5, + OC_UI_DARK_THEME.palette->lightGreen5, + OC_UI_DARK_THEME.palette->green5 }; + oc_ui_select_popup_info colorInfo = { .selectedIndex = colorSelected, + .optionCount = oc_array_size(colorNames), + .options = colorNames }; + oc_ui_select_popup_info colorResult = oc_ui_select_popup("color", &colorInfo); + colorSelected = colorResult.selectedIndex; + labelFontColor = colors[colorSelected]; } + + oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_X, + .layout.spacing = 8 }, + OC_UI_STYLE_LAYOUT_AXIS + | OC_UI_STYLE_LAYOUT_SPACING); + oc_ui_container("font", OC_UI_FLAG_NONE) + { + oc_ui_style_match_after(oc_ui_pattern_owner(), + &(oc_ui_style){ .size.width = { OC_UI_SIZE_PIXELS, 100 } }, + OC_UI_STYLE_SIZE_WIDTH); + oc_ui_label("Font"); + + static int fontSelected = 0; + oc_str8 fontNames[] = { OC_STR8("Regular"), + OC_STR8("Bold") }; + oc_font* fonts[] = { &fontRegular, + &fontBold }; + oc_ui_select_popup_info fontInfo = { .selectedIndex = fontSelected, + .optionCount = oc_array_size(fontNames), + .options = fontNames }; + oc_ui_select_popup_info fontResult = oc_ui_select_popup("font_style", &fontInfo); + fontSelected = fontResult.selectedIndex; + labelFont = fonts[fontSelected]; + } + + f32 fontSizeSlider = (labelFontSize - 8) / 16; + labeled_slider("Font size", &fontSizeSlider); + labelFontSize = 8 + fontSizeSlider * 16; } } } diff --git a/src/libc-shim/include/string.h b/src/libc-shim/include/string.h index 5204d64..ae0161f 100644 --- a/src/libc-shim/include/string.h +++ b/src/libc-shim/include/string.h @@ -10,4 +10,5 @@ int strcmp(const char* s1, const char* s2); int strncmp(const char* s1, const char* s2, size_t n); char* strcpy(char* __restrict s1, const char* __restrict s2); +#define snprintf stbsp_snprintf #define vsnprintf stbsp_vsnprintf diff --git a/src/ui/ui.c b/src/ui/ui.c index 9ba16ad..8eff843 100644 --- a/src/ui/ui.c +++ b/src/ui/ui.c @@ -1620,7 +1620,7 @@ oc_ui_sig oc_ui_button_str8(oc_str8 label) .layout.margin.y = 6, .color = theme->primary, .bgColor = theme->fill0, - .roundness = 3 }; + .roundness = theme->roundnessSmall }; oc_ui_style_mask defaultMask = OC_UI_STYLE_SIZE_WIDTH | OC_UI_STYLE_SIZE_HEIGHT @@ -1701,7 +1701,7 @@ oc_ui_sig oc_ui_checkbox(const char* name, bool* checked) .size.height = { OC_UI_SIZE_PIXELS, 16 }, .bgColor = theme->primary, .color = theme->white, - .roundness = 3 }; + .roundness = theme->roundnessSmall }; oc_ui_style_mask defaultMask = OC_UI_STYLE_SIZE_WIDTH | OC_UI_STYLE_SIZE_HEIGHT @@ -1740,7 +1740,7 @@ oc_ui_sig oc_ui_checkbox(const char* name, bool* checked) .bgColor = { 0 }, .borderColor = theme->text3, .borderSize = 1, - .roundness = 3 }; + .roundness = theme->roundnessSmall }; oc_ui_style_mask defaultMask = OC_UI_STYLE_SIZE_WIDTH | OC_UI_STYLE_SIZE_HEIGHT @@ -2241,7 +2241,7 @@ void oc_ui_tooltip(const char* label) .floatTarget = { 24, 0 }, .bgColor = theme->palette->grey7, .color = theme->bg0, - .roundness = 6 }; + .roundness = theme->roundnessMedium }; oc_ui_style_mask contentsMask = OC_UI_STYLE_SIZE | OC_UI_STYLE_LAYOUT_MARGINS | OC_UI_STYLE_FLOAT @@ -2532,7 +2532,7 @@ oc_ui_select_popup_info oc_ui_select_popup(const char* name, oc_ui_select_popup_ .layout.margin.x = 12, .layout.margin.y = 6, .bgColor = theme->fill0, - .roundness = 3 }, + .roundness = theme->roundnessSmall }, OC_UI_STYLE_SIZE | OC_UI_STYLE_LAYOUT_MARGIN_X | OC_UI_STYLE_LAYOUT_MARGIN_Y @@ -2543,7 +2543,16 @@ oc_ui_select_popup_info oc_ui_select_popup(const char* name, oc_ui_select_popup_ { oc_ui_container("selected_option", 0) { - oc_ui_label_str8(info->options[info->selectedIndex]); + if(info->selectedIndex == -1) + { + oc_ui_style_next(&(oc_ui_style){ .color = theme->text2 }, + OC_UI_STYLE_COLOR); + oc_ui_label_str8(info->placeholder); + } + else + { + oc_ui_label_str8(info->options[info->selectedIndex]); + } } oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PIXELS, button->rect.h }, @@ -2589,7 +2598,7 @@ oc_ui_select_popup_info oc_ui_select_popup(const char* name, oc_ui_select_popup_ .bgColor = theme->bg3, .borderColor = theme->elevatedBorder, .borderSize = 1, - .roundness = 6 }, + .roundness = theme->roundnessMedium }, OC_UI_STYLE_SIZE | OC_UI_STYLE_FLOAT | OC_UI_STYLE_LAYOUT @@ -2717,9 +2726,11 @@ oc_ui_radio_group_info oc_ui_radio_group(const char* name, oc_ui_radio_group_inf for(int i = 0; i < info->optionCount; i++) { oc_ui_style_next(&(oc_ui_style){ .layout.axis = OC_UI_AXIS_X, - .layout.spacing = 8 }, + .layout.spacing = 8, + .layout.align.y = OC_UI_ALIGN_CENTER }, OC_UI_STYLE_LAYOUT_AXIS - | OC_UI_STYLE_LAYOUT_SPACING); + | OC_UI_STYLE_LAYOUT_SPACING + | OC_UI_STYLE_LAYOUT_ALIGN_Y); oc_ui_box* row = oc_ui_box_begin_str8(info->options[i], OC_UI_FLAG_CLICKABLE); oc_ui_flags flags = OC_UI_FLAG_DRAW_BACKGROUND | OC_UI_FLAG_DRAW_BORDER | OC_UI_FLAG_DRAW_PROC; oc_ui_box* radio = oc_ui_box_make("radio", flags); @@ -2798,6 +2809,7 @@ oc_ui_radio_group_info oc_ui_radio_group(const char* name, oc_ui_radio_group_inf oc_ui_container("label", 0) { + oc_ui_tag_next("label"); oc_ui_label_str8(info->options[i]); } @@ -3599,7 +3611,7 @@ oc_ui_text_box_result oc_ui_text_box(const char* name, oc_arena* arena, oc_str8 oc_ui_style frameStyle = { .layout.margin.x = 12, .layout.margin.y = 6, .bgColor = theme->fill0, - .roundness = 3 }; + .roundness = theme->roundnessSmall }; oc_ui_style_mask frameMask = OC_UI_STYLE_LAYOUT_MARGIN_X | OC_UI_STYLE_LAYOUT_MARGIN_Y | OC_UI_STYLE_BG_COLOR @@ -4083,6 +4095,7 @@ oc_ui_theme OC_UI_DARK_THEME = { .primary = { 0.33, 0.66, 1, 1 }, // blue5 .primaryHover = { 0.5, 0.757, 1, 1 }, // blue6 .primaryActive = { 0.66, 0.84, 1, 1 }, // blue7 + .border = { 1, 1, 1, 0.08 }, .fill0 = { 1, 1, 1, 0.12 }, .fill1 = { 1, 1, 1, 0.16 }, .fill2 = { 1, 1, 1, 0.2 }, @@ -4096,7 +4109,11 @@ oc_ui_theme OC_UI_DARK_THEME = { .text2 = { 0.976, 0.976, 0.976, 0.6 }, // grey9 .text3 = { 0.976, 0.976, 0.976, 0.35 }, // grey9 .sliderThumbBorder = { 0, 0, 0, 0.075 }, - .elevatedBorder = { 1, 1, 1, 0.1 } + .elevatedBorder = { 1, 1, 1, 0.1 }, + + .roundnessSmall = 3, + .roundnessMedium = 6, + .roundnessLarge = 9 }; oc_ui_palette OC_UI_LIGHT_PALETTE = { @@ -4269,6 +4286,7 @@ oc_ui_theme OC_UI_LIGHT_THEME = { .primary = { 0.000, 0.392, 0.980, 1 }, // blue5 .primaryHover = { 0.000, 0.384, 0.839, 1 }, // blue6 .primaryActive = { 0.000, 0.310, 0.702, 1 }, // blue7 + .border = { 0.110, 0.122, 0.137, 0.08 }, // grey9 .fill0 = { 0.180, 0.196, 0.220, 0.05 }, // grey8 .fill1 = { 0.180, 0.196, 0.220, 0.09 }, // grey8 .fill2 = { 0.180, 0.196, 0.220, 0.13 }, // grey8 @@ -4281,6 +4299,10 @@ oc_ui_theme OC_UI_LIGHT_THEME = { .text1 = { 0.110, 0.122, 0.137, 0.8 }, // grey9 .text2 = { 0.110, 0.122, 0.137, 0.62 }, // grey9 .text3 = { 0.110, 0.122, 0.137, 0.35 }, // grey9 - .sliderThumbBorder = { 0, 0, 0, 0.075 }, - .elevatedBorder = { 0, 0, 0, 0.075 } + .sliderThumbBorder = { 0, 0, 0, 0.125 }, + .elevatedBorder = { 0, 0, 0, 0.075 }, + + .roundnessSmall = 3, + .roundnessMedium = 6, + .roundnessLarge = 9 }; diff --git a/src/ui/ui.h b/src/ui/ui.h index d2e6d9a..92f7ee5 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -349,6 +349,7 @@ typedef struct oc_ui_theme oc_color primary; oc_color primaryHover; oc_color primaryActive; + oc_color border; oc_color fill0; oc_color fill1; oc_color fill2; @@ -364,6 +365,10 @@ typedef struct oc_ui_theme oc_color sliderThumbBorder; oc_color elevatedBorder; + f32 roundnessSmall; + f32 roundnessMedium; + f32 roundnessLarge; + oc_ui_palette* palette; } oc_ui_theme; @@ -623,7 +628,7 @@ typedef struct oc_ui_context oc_ui_edit_move editSelectionMode; i32 editWordSelectionInitialCursor; i32 editWordSelectionInitialMark; - + bool clipboardRegistered; oc_ui_theme* theme; @@ -771,9 +776,10 @@ ORCA_API oc_ui_text_box_result oc_ui_text_box(const char* name, oc_arena* arena, typedef struct oc_ui_select_popup_info { bool changed; - int selectedIndex; + int selectedIndex; // -1 if nothing is selected int optionCount; oc_str8* options; + oc_str8 placeholder; } oc_ui_select_popup_info; ORCA_API oc_ui_select_popup_info oc_ui_select_popup(const char* name, oc_ui_select_popup_info* info);