869 lines
46 KiB
C
869 lines
46 KiB
C
/*************************************************************************
|
|
*
|
|
* Orca
|
|
* Copyright 2023 Martin Fouilleul and the Orca project contributors
|
|
* See LICENSE.txt for licensing information
|
|
*
|
|
**************************************************************************/
|
|
#include "orca.h"
|
|
#include <math.h>
|
|
|
|
oc_vec2 frameSize = { 1200, 838 };
|
|
|
|
oc_surface surface;
|
|
oc_canvas canvas;
|
|
oc_font fontRegular;
|
|
oc_font fontBold;
|
|
oc_ui_context ui;
|
|
oc_arena textArena = { 0 };
|
|
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("Orca UI Demo"));
|
|
oc_window_set_size(frameSize);
|
|
|
|
surface = oc_surface_canvas();
|
|
canvas = oc_canvas_create();
|
|
oc_ui_init(&ui);
|
|
|
|
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(fontNames[i]), OC_FILE_ACCESS_READ, 0);
|
|
if(oc_file_last_error(file) != OC_IO_OK)
|
|
{
|
|
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);
|
|
oc_file_read(file, size, buffer);
|
|
oc_file_close(file);
|
|
oc_unicode_range ranges[5] = { OC_UNICODE_BASIC_LATIN,
|
|
OC_UNICODE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT,
|
|
OC_UNICODE_LATIN_EXTENDED_A,
|
|
OC_UNICODE_LATIN_EXTENDED_B,
|
|
OC_UNICODE_SPECIALS };
|
|
|
|
*fonts[i] = oc_font_create_from_memory(oc_str8_from_buffer(size, buffer), 5, ranges);
|
|
|
|
oc_scratch_end(scratch);
|
|
}
|
|
|
|
oc_arena_init(&textArena);
|
|
oc_arena_init(&logArena);
|
|
oc_list_init(&logLines.list);
|
|
}
|
|
|
|
ORCA_EXPORT void oc_on_raw_event(oc_event* event)
|
|
{
|
|
oc_ui_process_event(event);
|
|
}
|
|
|
|
void log_push(const char* line)
|
|
{
|
|
oc_str8_list_push(&logArena, &logLines, (oc_str8)OC_STR8(line));
|
|
}
|
|
|
|
void log_pushf(const char* format, ...)
|
|
{
|
|
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);
|
|
}
|
|
|
|
void column_begin(const char* header, f32 widthFraction)
|
|
{
|
|
oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, widthFraction, 1 },
|
|
.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, 1, 1 },
|
|
.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_resize(u32 width, u32 height)
|
|
{
|
|
frameSize.x = width;
|
|
frameSize.y = height;
|
|
}
|
|
|
|
void reset_next_radio_group_to_dark_theme(oc_arena* arena);
|
|
|
|
ORCA_EXPORT void oc_on_frame_refresh(void)
|
|
{
|
|
oc_arena_scope scratch = oc_scratch_begin();
|
|
|
|
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_ui_style defaultStyle = { .font = fontRegular };
|
|
oc_ui_style_mask defaultMask = OC_UI_STYLE_FONT;
|
|
oc_ui_frame(frameSize, &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_panel("main panel", OC_UI_FLAG_NONE)
|
|
{
|
|
oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 },
|
|
.size.height = { OC_UI_SIZE_PARENT, 1, 1 },
|
|
.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_AXIS
|
|
| OC_UI_STYLE_LAYOUT_MARGINS
|
|
| OC_UI_STYLE_LAYOUT_SPACING);
|
|
|
|
oc_ui_container("background", OC_UI_FLAG_DRAW_BACKGROUND)
|
|
{
|
|
column("Widgets", 1.0 / 3)
|
|
{
|
|
|
|
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_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_PARENT, 1, 1, .minSize = 200 },
|
|
.bgColor = ui.theme->bg2,
|
|
.borderColor = ui.theme->border,
|
|
.borderSize = 1,
|
|
.roundness = ui.theme->roundnessSmall },
|
|
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_panel("log", OC_UI_FLAG_DRAW_BACKGROUND | OC_UI_FLAG_DRAW_BORDER)
|
|
{
|
|
oc_ui_style_next(&(oc_ui_style){ .layout.margin.x = 16,
|
|
.layout.margin.y = 16 },
|
|
OC_UI_STYLE_LAYOUT_MARGINS
|
|
| OC_UI_STYLE_LAYOUT_SPACING);
|
|
|
|
oc_ui_container("contents", OC_UI_FLAG_NONE)
|
|
{
|
|
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++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
// 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)
|
|
{
|
|
static f32 unselectedWidth = 16;
|
|
static f32 unselectedHeight = 16;
|
|
static f32 unselectedRoundness = 8;
|
|
static oc_color unselectedBgColor = { 0.086, 0.086, 0.102, 1 };
|
|
static oc_color unselectedBorderColor = { 0.976, 0.976, 0.976, 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 oc_color selectedCenterColor = { 1, 1, 1, 1 };
|
|
static oc_color selectedBgColor = { 0.33, 0.66, 1, 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)
|
|
{
|
|
reset_next_radio_group_to_dark_theme(scratch.arena);
|
|
|
|
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") });
|
|
if(unselectedWhenStatus != OC_UI_NONE)
|
|
{
|
|
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 = unselectedBgColor,
|
|
.borderColor = unselectedBorderColor,
|
|
.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") });
|
|
if(selectedWhenStatus != OC_UI_NONE)
|
|
{
|
|
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 = selectedCenterColor,
|
|
.bgColor = selectedBgColor,
|
|
.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_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_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("unselected", OC_UI_FLAG_NONE)
|
|
{
|
|
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)
|
|
{
|
|
f32 widthSlider = (unselectedWidth - 8) / 16;
|
|
labeled_slider("Width", &widthSlider);
|
|
unselectedWidth = 8 + widthSlider * 16;
|
|
|
|
f32 heightSlider = (unselectedHeight - 8) / 16;
|
|
labeled_slider("Height", &heightSlider);
|
|
unselectedHeight = 8 + heightSlider * 16;
|
|
|
|
f32 roundnessSlider = (unselectedRoundness - 4) / 8;
|
|
labeled_slider("Roundness", &roundnessSlider);
|
|
unselectedRoundness = 4 + roundnessSlider * 8;
|
|
}
|
|
|
|
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", &unselectedBgColor.r);
|
|
labeled_slider("Background G", &unselectedBgColor.g);
|
|
labeled_slider("Background B", &unselectedBgColor.b);
|
|
labeled_slider("Background A", &unselectedBgColor.a);
|
|
}
|
|
|
|
oc_ui_style_next(&(oc_ui_style){ .layout.spacing = 4 },
|
|
OC_UI_STYLE_LAYOUT_SPACING);
|
|
oc_ui_container("border", OC_UI_FLAG_NONE)
|
|
{
|
|
labeled_slider("Border R", &unselectedBorderColor.r);
|
|
labeled_slider("Border G", &unselectedBorderColor.g);
|
|
labeled_slider("Border B", &unselectedBorderColor.b);
|
|
labeled_slider("Border A", &unselectedBorderColor.a);
|
|
}
|
|
|
|
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 active") };
|
|
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_ACTIVE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
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("selected", OC_UI_FLAG_NONE)
|
|
{
|
|
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)
|
|
{
|
|
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", &selectedCenterColor.r);
|
|
labeled_slider("Center G", &selectedCenterColor.g);
|
|
labeled_slider("Center B", &selectedCenterColor.b);
|
|
labeled_slider("Center A", &selectedCenterColor.a);
|
|
}
|
|
|
|
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", &selectedBgColor.r);
|
|
labeled_slider("Background G", &selectedBgColor.g);
|
|
labeled_slider("Background B", &selectedBgColor.b);
|
|
labeled_slider("Background A", &selectedBgColor.a);
|
|
}
|
|
|
|
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 active") };
|
|
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:
|
|
selectedWhenStatus = OC_UI_NONE;
|
|
break;
|
|
case 1:
|
|
selectedWhenStatus = OC_UI_HOVER;
|
|
break;
|
|
case 2:
|
|
selectedWhenStatus = OC_UI_ACTIVE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
oc_ui_style_next(&(oc_ui_style){ .fontSize = 16 },
|
|
OC_UI_STYLE_FONT_SIZE);
|
|
oc_ui_label("Label style");
|
|
|
|
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_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");
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
oc_canvas_select(canvas);
|
|
oc_surface_select(surface);
|
|
|
|
oc_set_color(ui.theme->bg0);
|
|
oc_clear();
|
|
|
|
oc_ui_draw();
|
|
oc_render(canvas);
|
|
oc_surface_present(surface);
|
|
|
|
oc_scratch_end(scratch);
|
|
}
|
|
|
|
// This makes sure the light theme doesn't break the styling overrides
|
|
// You won't need it in a real program as long as your colors come from ui.theme or ui.theme->palette
|
|
void reset_next_radio_group_to_dark_theme(oc_arena* arena)
|
|
{
|
|
oc_ui_tag defaultTag = oc_ui_tag_make("radio");
|
|
oc_ui_pattern defaultPattern = { 0 };
|
|
oc_ui_pattern_push(arena, &defaultPattern, (oc_ui_selector){ .kind = OC_UI_SEL_TAG, .tag = defaultTag });
|
|
oc_ui_style defaultStyle = { .borderColor = OC_UI_DARK_THEME.text3,
|
|
.borderSize = 1 };
|
|
oc_ui_style_mask defaultMask = OC_UI_STYLE_BORDER_COLOR
|
|
| OC_UI_STYLE_BORDER_SIZE;
|
|
oc_ui_style_match_after(defaultPattern, &defaultStyle, defaultMask);
|
|
|
|
oc_ui_pattern hoverPattern = { 0 };
|
|
oc_ui_pattern_push(arena, &hoverPattern, (oc_ui_selector){ .kind = OC_UI_SEL_TAG, .tag = defaultTag });
|
|
oc_ui_pattern_push(arena, &hoverPattern, (oc_ui_selector){ .op = OC_UI_SEL_AND, .kind = OC_UI_SEL_STATUS, .status = OC_UI_HOVER });
|
|
oc_ui_style hoverStyle = { .bgColor = OC_UI_DARK_THEME.fill0,
|
|
.borderColor = OC_UI_DARK_THEME.primary };
|
|
oc_ui_style_mask hoverMask = OC_UI_STYLE_BG_COLOR
|
|
| OC_UI_STYLE_BORDER_COLOR;
|
|
oc_ui_style_match_after(hoverPattern, &hoverStyle, hoverMask);
|
|
|
|
oc_ui_pattern activePattern = { 0 };
|
|
oc_ui_pattern_push(arena, &activePattern, (oc_ui_selector){ .kind = OC_UI_SEL_TAG, .tag = defaultTag });
|
|
oc_ui_pattern_push(arena, &activePattern, (oc_ui_selector){ .op = OC_UI_SEL_AND, .kind = OC_UI_SEL_STATUS, .status = OC_UI_ACTIVE });
|
|
oc_ui_style activeStyle = { .bgColor = OC_UI_DARK_THEME.fill1,
|
|
.borderColor = OC_UI_DARK_THEME.primary };
|
|
oc_ui_style_mask activeMask = OC_UI_STYLE_BG_COLOR
|
|
| OC_UI_STYLE_BORDER_COLOR;
|
|
oc_ui_style_match_after(activePattern, &activeStyle, activeMask);
|
|
|
|
oc_ui_tag selectedTag = oc_ui_tag_make("radio_selected");
|
|
oc_ui_pattern selectedPattern = { 0 };
|
|
oc_ui_pattern_push(arena, &selectedPattern, (oc_ui_selector){ .kind = OC_UI_SEL_TAG, .tag = selectedTag });
|
|
oc_ui_style selectedStyle = { .color = OC_UI_DARK_THEME.palette->white,
|
|
.bgColor = OC_UI_DARK_THEME.primary };
|
|
oc_ui_style_mask selectedMask = OC_UI_STYLE_COLOR
|
|
| OC_UI_STYLE_BG_COLOR;
|
|
oc_ui_style_match_after(selectedPattern, &selectedStyle, selectedMask);
|
|
|
|
oc_ui_pattern selectedHoverPattern = { 0 };
|
|
oc_ui_pattern_push(arena, &selectedHoverPattern, (oc_ui_selector){ .kind = OC_UI_SEL_TAG, .tag = selectedTag });
|
|
oc_ui_pattern_push(arena, &selectedHoverPattern, (oc_ui_selector){ .op = OC_UI_SEL_AND, .kind = OC_UI_SEL_STATUS, .status = OC_UI_HOVER });
|
|
oc_ui_style selectedHoverStyle = { .bgColor = OC_UI_DARK_THEME.primaryHover };
|
|
oc_ui_style_match_after(selectedHoverPattern, &selectedHoverStyle, OC_UI_STYLE_BG_COLOR);
|
|
|
|
oc_ui_pattern selectedActivePattern = { 0 };
|
|
oc_ui_pattern_push(arena, &selectedActivePattern, (oc_ui_selector){ .kind = OC_UI_SEL_TAG, .tag = selectedTag });
|
|
oc_ui_pattern_push(arena, &selectedActivePattern, (oc_ui_selector){ .op = OC_UI_SEL_AND, .kind = OC_UI_SEL_STATUS, .status = OC_UI_ACTIVE });
|
|
oc_ui_style selectedActiveStyle = { .bgColor = OC_UI_DARK_THEME.primaryActive };
|
|
oc_ui_style_match_after(selectedActivePattern, &selectedActiveStyle, OC_UI_STYLE_BG_COLOR);
|
|
}
|