Zig UI demo

This commit is contained in:
Ilia Demianenko 2023-09-29 18:15:04 -07:00
parent 47cba86c03
commit fd308f9a3a
12 changed files with 2633 additions and 108 deletions

View File

@ -73,6 +73,12 @@ ORCA_EXPORT void oc_on_raw_event(oc_event* event)
oc_ui_process_event(event);
}
ORCA_EXPORT void oc_on_resize(u32 width, u32 height)
{
frameSize.x = width;
frameSize.y = height;
}
void log_push(const char* line)
{
oc_str8_list_push(&logArena, &logLines, (oc_str8)OC_STR8(line));
@ -158,12 +164,6 @@ void labeled_slider(const char* label, f32* 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)
@ -330,7 +330,7 @@ ORCA_EXPORT void oc_on_frame_refresh(void)
radioSelected = result.selectedIndex;
if(result.changed)
{
log_pushf("Selected Radio %i", result.selectedIndex + 1);
log_pushf("Selected %s", options[result.selectedIndex].ptr);
}
//-----------------------------------------------------------------------------
@ -359,13 +359,13 @@ ORCA_EXPORT void oc_on_frame_refresh(void)
.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_ui_text_box_result result = oc_ui_text_box("text", scratch.arena, text);
if(result.changed)
{
oc_arena_clear(&textArena);
text = oc_str8_push_copy(&textArena, res.text);
text = oc_str8_push_copy(&textArena, result.text);
}
if(res.accepted)
if(result.accepted)
{
log_pushf("Entered text \"%s\"", text.ptr);
}
@ -465,7 +465,7 @@ ORCA_EXPORT void oc_on_frame_refresh(void)
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.x = 310,
.layout.margin.y = 16,
.bgColor = OC_UI_DARK_THEME.bg0,
.roundness = OC_UI_DARK_THEME.roundnessSmall },
@ -527,8 +527,8 @@ ORCA_EXPORT void oc_on_frame_refresh(void)
| 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 labelPattern = { 0 };
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,
@ -818,32 +818,32 @@ ORCA_EXPORT void oc_on_frame_refresh(void)
// 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_tag unselectedTag = oc_ui_tag_make("radio");
oc_ui_pattern unselectedPattern = { 0 };
oc_ui_pattern_push(arena, &unselectedPattern, (oc_ui_selector){ .kind = OC_UI_SEL_TAG, .tag = unselectedTag });
oc_ui_style unselectedStyle = { .borderColor = OC_UI_DARK_THEME.text3,
.borderSize = 1 };
oc_ui_style_mask unselectedMask = OC_UI_STYLE_BORDER_COLOR
| OC_UI_STYLE_BORDER_SIZE;
oc_ui_style_match_after(unselectedPattern, &unselectedStyle, unselectedMask);
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_pattern unselectedHoverPattern = { 0 };
oc_ui_pattern_push(arena, &unselectedHoverPattern, (oc_ui_selector){ .kind = OC_UI_SEL_TAG, .tag = unselectedTag });
oc_ui_pattern_push(arena, &unselectedHoverPattern, (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_style_match_after(unselectedHoverPattern, &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_pattern unselectedActivePattern = { 0 };
oc_ui_pattern_push(arena, &unselectedActivePattern, (oc_ui_selector){ .kind = OC_UI_SEL_TAG, .tag = unselectedTag });
oc_ui_pattern_push(arena, &unselectedActivePattern, (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_style_match_after(unselectedActivePattern, &activeStyle, activeMask);
oc_ui_tag selectedTag = oc_ui_tag_make("radio_selected");
oc_ui_pattern selectedPattern = { 0 };

View File

@ -9,6 +9,5 @@ These two commands build the runtime - the native host executable - and the samp
### Warning
Zig bindings for Orca are in-progress and experimental. You may encounter bugs since not all the bound APIs have been tested extensively - this sample is currently the only code doing so! Additionally, not all APIs have zig coverage yet, notably:
* `oc_ui`
* `gles`
As more APIs get tested, there is a possibility of breaking changes. Please report any bugs you find on the Handmade discord in the #orca channel.

View File

@ -205,7 +205,7 @@ export fn oc_on_frame_refresh() void {
const text_rect = text_metrics.ink;
const center_x = frame_size.x / 2;
const text_begin_x = center_x - text_rect.Flat.w / 2;
const text_begin_x = center_x - text_rect.w / 2;
Mat2x3.push(Mat2x3.translate(text_begin_x, 100));
defer Mat2x3.pop();

6
samples/zig-ui/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
UI
zig-out
zig-cache
liborca.a
profile.dtrace
profile.spall

13
samples/zig-ui/README.md Normal file
View File

@ -0,0 +1,13 @@
### Build and run
Zig version `0.11.0` or greater is required for this sample. To build and run:
```
orca dev build-runtime
zig build run
```
These two commands build the runtime - the native host executable - and the sample as a loadable wasm library, then runs it. To only build the sample without running it, use `zig build bundle`.
### Warning
Zig bindings for Orca are in-progress and experimental. You may encounter bugs since not all the bound APIs have been tested extensively - this sample is currently the only code doing so! Additionally, not all APIs have zig coverage yet, notably:
* `gles`
As more APIs get tested, there is a possibility of breaking changes. Please report any bugs you find on the Handmade discord in the #orca channel.

107
samples/zig-ui/build.zig Normal file
View File

@ -0,0 +1,107 @@
const std = @import("std");
const builtin = @import("builtin");
fn addSourceString(str: []const u8, strings: *std.ArrayList(u8), sources: *std.ArrayList([]const u8)) !void {
var begin = strings.items.len;
try strings.appendSlice(str);
var realstring = strings.items[begin..];
try sources.append(realstring);
}
pub fn build(b: *std.Build) !void {
const optimize = b.standardOptimizeOption(.{});
var wasm_target = std.zig.CrossTarget{
.cpu_arch = .wasm32,
.os_tag = .freestanding,
};
wasm_target.cpu_features_add.addFeature(@intFromEnum(std.Target.wasm.Feature.bulk_memory));
var orca_source_strings = try std.ArrayList(u8).initCapacity(b.allocator, 1024 * 4);
var orca_sources = try std.ArrayList([]const u8).initCapacity(b.allocator, 128);
defer orca_source_strings.deinit();
defer orca_sources.deinit();
{
try addSourceString("../../src/orca.c", &orca_source_strings, &orca_sources);
var libc_shim_dir = try std.fs.cwd().openIterableDir("../../src/libc-shim/src", .{});
var walker = try libc_shim_dir.walk(b.allocator);
defer walker.deinit();
while (try walker.next()) |entry| {
const extension = std.fs.path.extension(entry.path);
if (std.mem.eql(u8, extension, ".c")) {
var path_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
var abs_path = try libc_shim_dir.dir.realpath(entry.path, &path_buffer);
try addSourceString(abs_path, &orca_source_strings, &orca_sources);
}
}
}
const orca_compile_opts = [_][]const u8{
"-D__ORCA__",
"--no-standard-libraries",
"-fno-builtin",
"-g",
"-O2",
"-mexec-model=reactor",
"-fno-sanitize=undefined",
"-isystem ../../src/libc-shim/include",
"-I../../src",
"-I../../src/ext",
"-Wl,--export-dynamic",
};
var orca_lib = b.addStaticLibrary(.{
.name = "orca",
.target = wasm_target,
.optimize = optimize,
});
orca_lib.rdynamic = true;
orca_lib.addIncludePath(.{ .path = "../../src" });
orca_lib.addIncludePath(.{ .path = "../../src/libc-shim/include" });
orca_lib.addIncludePath(.{ .path = "../../src/ext" });
orca_lib.addCSourceFiles(orca_sources.items, &orca_compile_opts);
// builds the wasm module out of the orca C sources and main.zig
const orca_module: *std.Build.Module = b.createModule(.{
.source_file = .{ .path = "../../src/orca.zig" },
});
const wasm_lib = b.addSharedLibrary(.{
.name = "module",
.root_source_file = .{ .path = "src/main.zig" },
.target = wasm_target,
.optimize = optimize,
});
wasm_lib.rdynamic = true;
wasm_lib.addIncludePath(.{ .path = "../../src" });
wasm_lib.addIncludePath(.{ .path = "../../src/libc-shim/include" });
wasm_lib.addIncludePath(.{ .path = "../../ext" });
wasm_lib.addModule("orca", orca_module);
wasm_lib.linkLibrary(orca_lib);
// copies the wasm module into zig-out/wasm_lib
b.installArtifact(wasm_lib);
// Runs the orca build command
const bundle_cmd_str = [_][]const u8{ "orca", "bundle", "--orca-dir", "../..", "--name", "UI", "--resource-dir", "data", "zig-out/lib/module.wasm" };
var bundle_cmd = b.addSystemCommand(&bundle_cmd_str);
bundle_cmd.step.dependOn(b.getInstallStep());
const bundle_step = b.step("bundle", "Runs the orca toolchain to bundle the wasm module into an orca app.");
bundle_step.dependOn(&bundle_cmd.step);
// Runs the app
const run_cmd_windows = [_][]const u8{"UI/bin/UI.exe"};
const run_cmd_macos = [_][]const u8{ "open", "UI.app" };
const run_cmd_str: []const []const u8 = switch (builtin.os.tag) {
.windows => &run_cmd_windows,
.macos => &run_cmd_macos,
else => @compileError("unsupported platform"),
};
var run_cmd = b.addSystemCommand(run_cmd_str);
run_cmd.step.dependOn(&bundle_cmd.step);
const run_step = b.step("run", "Runs the bundled app using the Orca runtime.");
run_step.dependOn(&run_cmd.step);
}

Binary file not shown.

Binary file not shown.

870
samples/zig-ui/src/main.zig Normal file
View File

@ -0,0 +1,870 @@
const std = @import("std");
const oc = @import("orca");
var frame_size: oc.Vec2 = .{ .x = 1200, .y = 838 };
var surface: oc.Surface = undefined;
var canvas: oc.Canvas = undefined;
var font_regular: oc.Font = undefined;
var font_bold: oc.Font = undefined;
var ui: oc.UiContext = undefined;
var text_arena: oc.Arena = undefined;
var log_arena: oc.Arena = undefined;
var log_lines: oc.Str8List = undefined;
const Cmd = enum {
None,
SetDarkTheme,
SetLightTheme,
};
var cmd: Cmd = .None;
export fn oc_on_init() void {
oc.windowSetTitle("Orca Zig UI Demo");
oc.windowSetSize(frame_size);
surface = oc.Surface.canvas();
canvas = oc.Canvas.create();
ui.init();
var fonts = [_]*oc.Font{ &font_regular, &font_bold };
var font_names = [_][]const u8{ "/OpenSans-Regular.ttf", "/OpenSans-Bold.ttf" };
for (fonts, font_names) |font, name| {
var scratch = oc.Arena.scratchBegin();
defer scratch.end();
var file = oc.File.open(oc.Str8.fromSlice(name), .{ .read = true }, .{});
if (file.lastError() != oc.io.Error.Ok) {
oc.log.err("Couldn't open file {s}", .{name}, @src());
}
var size = file.getSize();
var buffer = scratch.arena.push(size) catch {
oc.log.err("Out of memory", .{}, @src());
return;
};
_ = file.read(size, buffer);
file.close();
var ranges = oc.UnicodeRange.range(&[_]oc.UnicodeRange.Enum{
.BasicLatin,
.C1ControlsAndLatin1Supplement,
.LatinExtendedA,
.LatinExtendedB,
.Specials,
});
font.* = oc.Font.createFromMemory(buffer[0..size], &ranges);
}
text_arena = oc.Arena.init();
log_arena = oc.Arena.init();
log_lines = oc.Str8List.init();
}
export fn oc_on_raw_event(event: *oc.CEvent) void {
oc.uiProcessCEvent(event);
}
export fn oc_on_resize(width: u32, height: u32) void {
frame_size.x = @floatFromInt(width);
frame_size.y = @floatFromInt(height);
}
export fn oc_on_frame_refresh() void {
var scratch = oc.Arena.scratchBegin();
defer scratch.end();
switch (cmd) {
.SetDarkTheme => oc.uiSetTheme(oc.ui_dark_theme),
.SetLightTheme => oc.uiSetTheme(oc.ui_light_theme),
.None => {},
}
cmd = .None;
var default_style = oc.UiStyle{ .font = font_regular };
{
oc.uiBeginFrame(frame_size, &default_style);
defer oc.uiEndFrame();
//--------------------------------------------------------------------------------------------
// Menu bar
//--------------------------------------------------------------------------------------------
{
oc.uiMenuBarBegin("menu_bar");
defer oc.uiMenuBarEnd();
{
oc.uiMenuBegin("File");
defer oc.uiMenuEnd();
if (oc.uiMenuButton("Quit").pressed) {
oc.requestQuit();
}
}
{
oc.uiMenuBegin("Theme");
defer oc.uiMenuEnd();
if (oc.uiMenuButton("Dark theme").pressed) {
cmd = .SetDarkTheme;
}
if (oc.uiMenuButton("Light theme").pressed) {
cmd = .SetLightTheme;
}
}
}
{
oc.uiPanelBegin("main panel", .{});
defer oc.uiPanelEnd();
{
oc.uiStyleNext(.{
.size = .{
.width = .fill_parent,
.height = .{ .custom = .{ .kind = .Parent, .value = 1, .relax = 1 } },
},
.layout = .{
.axis = .X,
.margin = .{ .x = 16, .y = 16 },
.spacing = 16,
},
});
_ = oc.uiBoxBegin("Background", .{ .draw_background = true });
defer _ = oc.uiBoxEnd();
widgets(scratch.arena);
styling(scratch.arena);
}
}
}
_ = canvas.select();
surface.select();
oc.Canvas.setColor(ui.theme.bg0);
oc.Canvas.clear();
oc.uiDraw();
canvas.render();
surface.present();
}
var checkbox_checked: bool = false;
var v_slider_value: f32 = 0;
var v_slider_logged_value: f32 = 0;
var v_slider_log_time: f64 = 0;
var radio_selected: usize = 0;
var h_slider_value: f32 = 0;
var h_slider_logged_value: f32 = 0;
var h_slider_log_time: f64 = 0;
var text: []const u8 = "Text box";
var selected: ?usize = null;
fn widgets(arena: *oc.Arena) void {
columnBegin("Widgets", 1.0 / 3.0);
defer columnEnd();
{
oc.uiStyleNext(.{
.size = .{
.width = .fill_parent,
},
.layout = .{
.axis = .X,
.spacing = 32,
},
});
_ = oc.uiBoxBegin("top", .{});
defer _ = oc.uiBoxEnd();
{
oc.uiStyleNext(.{
.layout = .{
.axis = .Y,
.spacing = 24,
},
});
_ = oc.uiBoxBegin("top_left", .{});
defer _ = oc.uiBoxEnd();
//-----------------------------------------------------------------------------
// Label
//-----------------------------------------------------------------------------
_ = oc.uiLabel("Label");
//-----------------------------------------------------------------------------
// Button
//-----------------------------------------------------------------------------
if (oc.uiButton("Button").clicked) {
logPush("Button clicked");
}
{
oc.uiStyleNext(.{
.layout = .{
.axis = .X,
.alignment = .{ .y = .Center },
.spacing = 8,
},
});
_ = oc.uiBoxBegin("checkbox", .{});
defer _ = oc.uiBoxEnd();
//-------------------------------------------------------------------------
// Checkbox
//-------------------------------------------------------------------------
if (oc.uiCheckbox("checkbox", &checkbox_checked).clicked) {
if (checkbox_checked) {
logPush("Checkbox checked");
} else {
logPush("Checkbox unhecked");
}
}
_ = oc.uiLabel("Checkbox");
}
}
//---------------------------------------------------------------------------------
// Vertical slider
//---------------------------------------------------------------------------------
oc.uiStyleNext(.{ .size = .{ .height = .{ .pixels = 130 } } });
_ = oc.uiSlider("v_slider", &v_slider_value);
var now = oc.clock.time(.Monotonic);
if ((now - v_slider_log_time) >= 0.2 and v_slider_value != v_slider_logged_value) {
logPushf("Vertical slider moved to {d:.3}", .{v_slider_value});
v_slider_logged_value = v_slider_value;
v_slider_log_time = now;
}
{
oc.uiStyleNext(.{
.layout = .{
.axis = .Y,
.spacing = 24,
},
});
_ = oc.uiBoxBegin("top right", .{});
defer _ = oc.uiBoxEnd();
//-----------------------------------------------------------------------------
// Tooltip
//-----------------------------------------------------------------------------
if (oc.uiLabel("Tooltip").hovering) {
oc.uiTooltip("Hi");
}
//-----------------------------------------------------------------------------
// Radio group
//-----------------------------------------------------------------------------
var options = [_][]const u8{
"Radio 1",
"Radio 2",
};
var radio_group_info = oc.UiRadioGroupInfo{
.selected_index = radio_selected,
.options = &options,
};
var result = oc.uiRadioGroup("radio_group", &radio_group_info);
radio_selected = result.selected_index.?;
if (result.changed) {
logPushf("Selected {s}", .{options[radio_selected]});
}
//-----------------------------------------------------------------------------
// Horizontal slider
//-----------------------------------------------------------------------------
oc.uiStyleNext(.{ .size = .{ .width = .{ .pixels = 130 } } });
_ = oc.uiSlider("h_slider", &h_slider_value);
if ((now - h_slider_log_time) >= 0.2 and h_slider_value != h_slider_logged_value) {
logPushf("Slider moved to {d:.3}", .{h_slider_value});
h_slider_logged_value = h_slider_value;
h_slider_log_time = now;
}
}
}
//-------------------------------------------------------------------------------------
// Text box
//-------------------------------------------------------------------------------------
oc.uiStyleNext(.{
.size = .{
.width = .{ .pixels = 305 },
.height = .text,
},
});
var textResult = oc.uiTextBox("text", arena.*, text);
if (textResult.changed) {
text_arena.clear();
text = text_arena.pushStr(textResult.text) catch {
oc.log.err("Out of memory", .{}, @src());
oc.requestQuit();
return;
};
}
if (textResult.accepted) {
logPushf("Entered text {s}", .{text});
}
//-------------------------------------------------------------------------------------
// Select
//-------------------------------------------------------------------------------------
var options = [_][]const u8{
"Option 1",
"Option 2",
};
var select_popup_info = oc.UiSelectPopupInfo{
.selected_index = selected,
.options = &options,
.placeholder = "Select",
};
var selectResult = oc.uiSelectPopup("select", &select_popup_info);
if (selectResult.selected_index != selected) {
logPushf("Selected {s}", .{options[selectResult.selected_index.?]});
}
selected = selectResult.selected_index;
//-------------------------------------------------------------------------------------
// Scrollable panel
//-------------------------------------------------------------------------------------
{
oc.uiStyleNext(.{
.size = .{
.width = .fill_parent,
.height = .{
.custom = .{ .kind = .Parent, .value = 1, .relax = 1, .min_size = 200 },
},
},
.bg_color = ui.theme.bg2,
.border_color = ui.theme.border,
.border_size = 1,
.roundness = ui.theme.roundness_small,
});
_ = oc.uiPanelBegin("log", .{ .draw_background = true, .draw_border = true });
defer oc.uiPanelEnd();
{
oc.uiStyleNext(.{
.layout = .{
.margin = .{ .x = 16, .y = 16 },
},
});
_ = oc.uiBoxBegin("contents", .{});
defer _ = oc.uiBoxEnd();
if (log_lines.list.empty()) {
oc.uiStyleNext(.{ .color = ui.theme.text2 });
_ = oc.uiLabel("Log");
}
var i: i32 = 0;
var log_lines_iter = log_lines.iter();
while (log_lines_iter.next()) |log_line| {
var buf: [15]u8 = undefined;
var id = std.fmt.bufPrint(&buf, "{d}", .{i}) catch unreachable;
_ = oc.uiBoxBegin(id, .{});
defer _ = oc.uiBoxEnd();
_ = oc.uiLabel(log_line.string.slice());
i += 1;
}
}
}
}
var styling_selected_radio: ?usize = 0;
var unselected_width: f32 = 16;
var unselected_height: f32 = 16;
var unselected_roundness: f32 = 8;
var unselected_bg_color: oc.Color = oc.Color.rgba(0.086, 0.086, 0.102, 1);
var unselected_border_color: oc.Color = oc.Color.rgba(0.976, 0.976, 0.976, 0.35);
var unselected_border_size: f32 = 1;
var unselected_when_status: oc.UiStatus = .{};
var unselected_status_index: ?usize = 0;
var selected_width: f32 = 16;
var selected_height: f32 = 16;
var selected_roundness: f32 = 8;
var selected_center_color: oc.Color = oc.Color.rgba(1, 1, 1, 1);
var selected_bg_color: oc.Color = oc.Color.rgba(0.33, 0.66, 1, 1);
var selected_when_status: oc.UiStatus = .{};
var selected_status_index: ?usize = 0;
var label_font_color: oc.Color = oc.Color.rgba(0.976, 0.976, 0.976, 1);
var label_font_color_selected: ?usize = 0;
var label_font: *oc.Font = &font_regular;
var label_font_selected: ?usize = 0;
var label_font_size: f32 = 14;
fn styling(arena: *oc.Arena) void {
//-----------------------------------------------------------------------------------------
// 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
columnBegin("Styling", 2.0 / 3.0);
defer columnEnd();
{
oc.uiStyleNext(.{
.size = .{
.width = .fill_parent,
.height = .{ .pixels = 152 },
},
.layout = .{
.margin = .{ .x = 310, .y = 16 },
},
.bg_color = oc.ui_dark_theme.bg0,
.roundness = oc.ui_dark_theme.roundness_small,
});
_ = oc.uiBoxBegin("styled_radios", .{ .draw_background = true, .draw_border = true });
defer _ = oc.uiBoxEnd();
resetNextRadioGroupToDarkTheme(arena);
var unselected_tag = oc.uiTagMake("radio");
var unselected_pattern = oc.UiPattern.init();
unselected_pattern.push(arena, .{ .sel = .{ .tag = unselected_tag } });
if (!unselected_when_status.empty()) {
unselected_pattern.push(arena, .{ .op = .And, .sel = .{ .status = unselected_when_status } });
}
oc.uiStyleMatchAfter(unselected_pattern, .{
.size = .{
.width = .{ .pixels = unselected_width },
.height = .{ .pixels = unselected_height },
},
.bg_color = unselected_bg_color,
.border_color = unselected_border_color,
.border_size = unselected_border_size,
.roundness = unselected_roundness,
});
var selected_tag = oc.uiTagMake("radio_selected");
var selected_pattern = oc.UiPattern.init();
selected_pattern.push(arena, .{ .sel = .{ .tag = selected_tag } });
if (!selected_when_status.empty()) {
selected_pattern.push(arena, .{ .op = .And, .sel = .{ .status = selected_when_status } });
}
oc.uiStyleMatchAfter(selected_pattern, .{
.size = .{
.width = .{ .pixels = selected_width },
.height = .{ .pixels = selected_height },
},
.color = selected_center_color,
.bg_color = selected_bg_color,
.roundness = selected_roundness,
});
var label_tag = oc.uiTagMake("label");
var label_pattern = oc.UiPattern.init();
label_pattern.push(arena, .{ .sel = .{ .tag = label_tag } });
oc.uiStyleMatchAfter(label_pattern, .{
.color = label_font_color,
.font = label_font.*,
.font_size = label_font_size,
});
var options = [_][]const u8{
"I",
"Am",
"Stylish",
};
var radio_group_info = oc.UiRadioGroupInfo{
.selected_index = styling_selected_radio,
.options = &options,
};
var result = oc.uiRadioGroup("radio_group", &radio_group_info);
styling_selected_radio = result.selected_index;
}
{
oc.uiStyleNext(.{ .layout = .{ .axis = .X, .spacing = 32 } });
_ = oc.uiBoxBegin("controls", .{});
defer _ = oc.uiBoxEnd();
{
oc.uiStyleNext(.{ .layout = .{ .axis = .Y, .spacing = 16 } });
_ = oc.uiBoxBegin("unselected", .{});
defer _ = oc.uiBoxEnd();
oc.uiStyleNext(.{ .font_size = 16 });
_ = oc.uiLabel("Radio style");
{
oc.uiStyleNext(.{ .layout = .{ .spacing = 4 } });
_ = oc.uiBoxBegin("size", .{});
defer _ = oc.uiBoxEnd();
var width_slider = (unselected_width - 8) / 16;
labeledSlider("Width", &width_slider);
unselected_width = 8 + width_slider * 16;
var height_slider = (unselected_height - 8) / 16;
labeledSlider("Height", &height_slider);
unselected_height = 8 + height_slider * 16;
var roundness_slider = (unselected_roundness - 4) / 8;
labeledSlider("Roundness", &roundness_slider);
unselected_roundness = 4 + roundness_slider * 8;
}
{
oc.uiStyleNext(.{ .layout = .{ .spacing = 4 } });
_ = oc.uiBoxBegin("background", .{});
defer _ = oc.uiBoxEnd();
labeledSlider("Background R", &unselected_bg_color.r);
labeledSlider("Background G", &unselected_bg_color.g);
labeledSlider("Background B", &unselected_bg_color.b);
labeledSlider("Background A", &unselected_bg_color.a);
}
{
oc.uiStyleNext(.{ .layout = .{ .spacing = 4 } });
_ = oc.uiBoxBegin("border", .{});
defer _ = oc.uiBoxEnd();
labeledSlider("Border R", &unselected_border_color.r);
labeledSlider("Border G", &unselected_border_color.g);
labeledSlider("Border B", &unselected_border_color.b);
labeledSlider("Border A", &unselected_border_color.a);
}
var border_size_slider = unselected_border_size / 5;
labeledSlider("Border size", &border_size_slider);
unselected_border_size = border_size_slider * 5;
{
oc.uiStyleNext(.{ .layout = .{ .spacing = 10 } });
_ = oc.uiBoxBegin("status_override", .{});
defer _ = oc.uiBoxEnd();
_ = oc.uiLabel("Override");
var status_options = [_][]const u8{
"Always",
"When hovering",
"When active",
};
var status_info = oc.UiRadioGroupInfo{
.selected_index = unselected_status_index,
.options = &status_options,
};
var status_result = oc.uiRadioGroup("status", &status_info);
unselected_status_index = status_result.selected_index;
unselected_when_status = switch (unselected_status_index.?) {
0 => .{},
1 => .{ .hover = true },
2 => .{ .active = true },
else => unreachable,
};
}
}
{
oc.uiStyleNext(.{ .layout = .{ .axis = .Y, .spacing = 16 } });
_ = oc.uiBoxBegin("selected", .{});
defer _ = oc.uiBoxEnd();
oc.uiStyleNext(.{ .font_size = 16 });
_ = oc.uiLabel("Radio selected style");
{
oc.uiStyleNext(.{ .layout = .{ .spacing = 4 } });
_ = oc.uiBoxBegin("size", .{});
defer _ = oc.uiBoxEnd();
var width_slider = (selected_width - 8) / 16;
labeledSlider("Width", &width_slider);
selected_width = 8 + width_slider * 16;
var height_slider = (selected_height - 8) / 16;
labeledSlider("Height", &height_slider);
selected_height = 8 + height_slider * 16;
var roundness_slider = (selected_roundness - 4) / 8;
labeledSlider("Roundness", &roundness_slider);
selected_roundness = 4 + roundness_slider * 8;
}
{
oc.uiStyleNext(.{ .layout = .{ .spacing = 4 } });
_ = oc.uiBoxBegin("color", .{});
defer _ = oc.uiBoxEnd();
labeledSlider("Center R", &selected_center_color.r);
labeledSlider("Center G", &selected_center_color.g);
labeledSlider("Center B", &selected_center_color.b);
labeledSlider("Center A", &selected_center_color.a);
}
{
oc.uiStyleNext(.{ .layout = .{ .spacing = 4 } });
_ = oc.uiBoxBegin("background", .{});
defer _ = oc.uiBoxEnd();
labeledSlider("Background R", &selected_bg_color.r);
labeledSlider("Background G", &selected_bg_color.g);
labeledSlider("Background B", &selected_bg_color.b);
labeledSlider("Background A", &selected_bg_color.a);
}
{
oc.uiStyleNext(.{ .layout = .{ .spacing = 10 } });
_ = oc.uiBoxBegin("status_override", .{});
defer _ = oc.uiBoxEnd();
oc.uiStyleNext(.{ .size = .{ .height = .{ .pixels = 30 } } });
_ = oc.uiBoxMake("spacer", .{});
_ = oc.uiLabel("Override");
var status_options = [_][]const u8{
"Always",
"When hovering",
"When active",
};
var status_info = oc.UiRadioGroupInfo{
.selected_index = selected_status_index,
.options = &status_options,
};
var status_result = oc.uiRadioGroup("status", &status_info);
selected_status_index = status_result.selected_index;
selected_when_status = switch (selected_status_index.?) {
0 => .{},
1 => .{ .hover = true },
2 => .{ .active = true },
else => unreachable,
};
}
}
{
oc.uiStyleNext(.{ .layout = .{ .axis = .Y, .spacing = 10 } });
_ = oc.uiBoxBegin("label", .{});
defer _ = oc.uiBoxEnd();
oc.uiStyleNext(.{ .font_size = 16 });
_ = oc.uiLabel("Label style");
{
oc.uiStyleNext(.{ .layout = .{ .axis = .X, .spacing = 8 } });
_ = oc.uiBoxBegin("font_color", .{});
defer _ = oc.uiBoxEnd();
oc.uiStyleMatchAfter(oc.UiPattern.owner(), .{
.size = .{ .width = .{ .pixels = 100 } },
});
_ = oc.uiLabel("Font color");
var color_names = [_][]const u8{
"Default",
"Red",
"Orange",
"Amber",
"Yellow",
"Lime",
"Light green",
"Green",
};
var colors = [_]oc.Color{
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.light_green5,
oc.ui_dark_theme.palette.green5,
};
var color_info = oc.UiSelectPopupInfo{
.selected_index = label_font_color_selected,
.options = &color_names,
};
var color_result = oc.uiSelectPopup("color", &color_info);
label_font_color_selected = color_result.selected_index;
label_font_color = colors[label_font_color_selected.?];
}
{
oc.uiStyleNext(.{ .layout = .{ .axis = .X, .spacing = 8 } });
_ = oc.uiBoxBegin("font", .{});
defer _ = oc.uiBoxEnd();
oc.uiStyleMatchAfter(oc.UiPattern.owner(), .{
.size = .{ .width = .{ .pixels = 100 } },
});
_ = oc.uiLabel("Font");
var font_names = [_][]const u8{
"Regular",
"Bold",
};
var fonts = [_]*oc.Font{
&font_regular,
&font_bold,
};
var font_info = oc.UiSelectPopupInfo{
.selected_index = label_font_selected,
.options = &font_names,
};
var font_result = oc.uiSelectPopup("font_style", &font_info);
label_font_selected = font_result.selected_index;
label_font = fonts[label_font_selected.?];
}
var font_size_slider = (label_font_size - 8) / 16;
labeledSlider("Font size", &font_size_slider);
label_font_size = 8 + font_size_slider * 16;
}
}
}
fn columnBegin(header: []const u8, widthFraction: f32) void {
oc.uiStyleNext(.{
.size = .{
.width = .{
.custom = .{ .kind = .Parent, .value = widthFraction, .relax = 1 },
},
.height = .fill_parent,
},
.layout = .{
.axis = .Y,
.margin = .{ .y = 8 },
.spacing = 24,
},
.bg_color = ui.theme.bg1,
.border_color = ui.theme.border,
.border_size = 1,
.roundness = ui.theme.roundness_small,
});
_ = oc.uiBoxBegin(header, .{ .draw_background = true, .draw_border = true });
{
oc.uiStyleNext(.{
.size = .{ .width = .fill_parent },
.layout = .{ .alignment = .{ .x = .Center } },
});
_ = oc.uiBoxBegin("header", .{});
defer _ = oc.uiBoxEnd();
oc.uiStyleNext(.{ .font_size = 18 });
_ = oc.uiLabel(header);
}
oc.uiStyleNext(.{
.size = .{
.width = .fill_parent,
.height = .{
.custom = .{ .kind = .Parent, .value = 1, .relax = 1 },
},
},
.layout = .{
.alignment = .{ .x = .Start },
.margin = .{ .x = 16 },
.spacing = 24,
},
});
_ = oc.uiBoxBegin("contents", .{});
}
fn columnEnd() void {
_ = oc.uiBoxEnd(); // contents
_ = oc.uiBoxEnd(); // column
}
fn labeledSlider(label: []const u8, value: *f32) void {
oc.uiStyleNext(.{ .layout = .{ .axis = .X, .spacing = 8 } });
_ = oc.uiBoxBegin(label, .{});
defer _ = oc.uiBoxEnd();
oc.uiStyleMatchAfter(oc.UiPattern.owner(), .{
.size = .{ .width = .{ .pixels = 100 } },
});
_ = oc.uiLabel(label);
oc.uiStyleNext(.{
.size = .{ .width = .{ .pixels = 100 } },
});
_ = oc.uiSlider("slider", value);
}
fn logPush(line: []const u8) void {
log_lines.push(&log_arena, oc.Str8.fromSlice(line)) catch {
oc.log.err("Out of memory", .{}, @src());
oc.requestQuit();
return;
};
}
fn logPushf(comptime fmt: []const u8, args: anytype) void {
var str = oc.Str8.pushf(&log_arena, fmt, args) catch {
oc.log.err("Out of memory", .{}, @src());
oc.requestQuit();
return;
};
log_lines.push(&log_arena, str) catch {
oc.log.err("Out of memory", .{}, @src());
oc.requestQuit();
return;
};
}
/// 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
fn resetNextRadioGroupToDarkTheme(arena: *oc.Arena) void {
var unselected_tag = oc.uiTagMake("radio");
var unselected_pattern = oc.UiPattern.init();
unselected_pattern.push(arena, .{ .sel = .{ .tag = unselected_tag } });
oc.uiStyleMatchAfter(unselected_pattern, .{
.border_color = oc.ui_dark_theme.text3,
.border_size = 1,
});
var unselected_hover_pattern = oc.UiPattern.init();
unselected_hover_pattern.push(arena, .{ .sel = .{ .tag = unselected_tag } });
unselected_hover_pattern.push(arena, .{ .op = .And, .sel = .{ .status = .{ .hover = true } } });
oc.uiStyleMatchAfter(unselected_hover_pattern, .{
.bg_color = oc.ui_dark_theme.fill0,
.border_color = oc.ui_dark_theme.primary,
});
var unselected_active_pattern = oc.UiPattern.init();
unselected_active_pattern.push(arena, .{ .sel = .{ .tag = unselected_tag } });
unselected_active_pattern.push(arena, .{ .op = .And, .sel = .{ .status = .{ .active = true } } });
oc.uiStyleMatchAfter(unselected_active_pattern, .{
.bg_color = oc.ui_dark_theme.fill1,
.border_color = oc.ui_dark_theme.primary,
});
var selected_tag = oc.uiTagMake("radio_selected");
var selected_pattern = oc.UiPattern.init();
selected_pattern.push(arena, .{ .sel = .{ .tag = selected_tag } });
oc.uiStyleMatchAfter(selected_pattern, .{
.color = oc.ui_dark_theme.palette.white,
.bg_color = oc.ui_dark_theme.primary,
});
var selected_hover_pattern = oc.UiPattern.init();
selected_hover_pattern.push(arena, .{ .sel = .{ .tag = selected_tag } });
selected_hover_pattern.push(arena, .{ .op = .And, .sel = .{ .status = .{ .hover = true } } });
oc.uiStyleMatchAfter(selected_hover_pattern, .{
.bg_color = oc.ui_dark_theme.primary_hover,
});
var selected_active_pattern = oc.UiPattern.init();
selected_active_pattern.push(arena, .{ .sel = .{ .tag = selected_tag } });
selected_active_pattern.push(arena, .{ .op = .And, .sel = .{ .status = .{ .active = true } } });
oc.uiStyleMatchAfter(selected_active_pattern, .{
.bg_color = oc.ui_dark_theme.primary_active,
});
}

File diff suppressed because it is too large Load Diff

View File

@ -1778,7 +1778,7 @@ oc_ui_sig oc_ui_button_behavior(oc_ui_box* box)
{
oc_ui_box_set_hot(box, false);
}
if(!sig.hovering && !sig.dragging)
if(!sig.hovering || !sig.dragging)
{
oc_ui_box_deactivate(box);
}
@ -1873,7 +1873,7 @@ void oc_ui_checkbox_draw(oc_ui_box* box, void* data)
oc_matrix_pop();
}
oc_ui_sig oc_ui_checkbox(const char* name, bool* checked)
oc_ui_sig oc_ui_checkbox_str8(oc_str8 name, bool* checked)
{
oc_ui_context* ui = oc_ui_get_context();
oc_ui_theme* theme = ui->theme;
@ -1918,7 +1918,7 @@ oc_ui_sig oc_ui_checkbox(const char* name, bool* checked)
| OC_UI_FLAG_HOT_ANIMATION
| OC_UI_FLAG_ACTIVE_ANIMATION;
box = oc_ui_box_make(name, flags);
box = oc_ui_box_make_str8(name, flags);
oc_ui_tag_box(box, "checkbox");
oc_ui_box_set_draw_proc(box, oc_ui_checkbox_draw, 0);
@ -1968,7 +1968,7 @@ oc_ui_sig oc_ui_checkbox(const char* name, bool* checked)
| OC_UI_FLAG_HOT_ANIMATION
| OC_UI_FLAG_ACTIVE_ANIMATION;
box = oc_ui_box_make(name, flags);
box = oc_ui_box_make_str8(name, flags);
oc_ui_tag_box(box, "checkbox");
}
@ -1981,16 +1981,21 @@ oc_ui_sig oc_ui_checkbox(const char* name, bool* checked)
return (sig);
}
oc_ui_sig oc_ui_checkbox(const char* name, bool* checked)
{
return oc_ui_checkbox_str8(OC_STR8(name), checked);
}
//------------------------------------------------------------------------------
// slider / scrollbar
//------------------------------------------------------------------------------
oc_ui_box* oc_ui_slider(const char* label, f32* value)
oc_ui_box* oc_ui_slider_str8(oc_str8 label, f32* value)
{
oc_ui_context* ui = oc_ui_get_context();
oc_ui_theme* theme = ui->theme;
oc_ui_style_match_before(oc_ui_pattern_all(), &(oc_ui_style){ 0 }, OC_UI_STYLE_LAYOUT);
oc_ui_box* frame = oc_ui_box_begin(label, 0);
oc_ui_box* frame = oc_ui_box_begin_str8(label, 0);
{
oc_ui_axis trackAxis = (frame->rect.w > frame->rect.h) ? OC_UI_AXIS_X : OC_UI_AXIS_Y;
oc_ui_axis secondAxis = (trackAxis == OC_UI_AXIS_Y) ? OC_UI_AXIS_X : OC_UI_AXIS_Y;
@ -2161,12 +2166,17 @@ oc_ui_box* oc_ui_slider(const char* label, f32* value)
return (frame);
}
oc_ui_box* oc_ui_scrollbar(const char* label, f32 thumbRatio, f32* scrollValue)
oc_ui_box* oc_ui_slider(const char* label, f32* value)
{
return oc_ui_slider_str8(OC_STR8(label), value);
}
oc_ui_box* oc_ui_scrollbar_str8(oc_str8 label, f32 thumbRatio, f32* scrollValue)
{
oc_ui_context* ui = oc_ui_get_context();
oc_ui_theme* theme = ui->theme;
oc_ui_style_match_before(oc_ui_pattern_all(), &(oc_ui_style){ 0 }, OC_UI_STYLE_LAYOUT);
oc_ui_box* frame = oc_ui_box_begin(label, 0);
oc_ui_box* frame = oc_ui_box_begin_str8(label, 0);
{
f32 minThumbRatio = 17. / oc_max(frame->rect.w, frame->rect.h);
thumbRatio = oc_min(oc_max(thumbRatio, minThumbRatio), 1.);
@ -2292,10 +2302,15 @@ oc_ui_box* oc_ui_scrollbar(const char* label, f32 thumbRatio, f32* scrollValue)
return (frame);
}
oc_ui_box* oc_ui_scrollbar(const char* label, f32 thumbRatio, f32* scrollValue)
{
return oc_ui_scrollbar_str8(OC_STR8(label), thumbRatio, scrollValue);
}
//------------------------------------------------------------------------------
// panels
//------------------------------------------------------------------------------
void oc_ui_panel_begin(const char* str, oc_ui_flags flags)
void oc_ui_panel_begin_str8(oc_str8 str, oc_ui_flags flags)
{
flags = flags
| OC_UI_FLAG_CLIP
@ -2311,7 +2326,7 @@ void oc_ui_panel_begin(const char* str, oc_ui_flags flags)
.layout.margin.y = 0 },
OC_UI_STYLE_SIZE
| OC_UI_STYLE_LAYOUT_MARGINS);
oc_ui_box_begin(str, flags);
oc_ui_box_begin_str8(str, flags);
oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 },
.size.height = { OC_UI_SIZE_PARENT, 1 } },
@ -2320,6 +2335,11 @@ void oc_ui_panel_begin(const char* str, oc_ui_flags flags)
oc_ui_box_begin("contents", 0);
}
void oc_ui_panel_begin(const char* str, oc_ui_flags flags)
{
oc_ui_panel_begin_str8(OC_STR8(str), flags);
}
void oc_ui_panel_end(void)
{
oc_ui_box_end(); // contents
@ -2413,7 +2433,7 @@ void oc_ui_tooltip_arrow_draw(oc_ui_box* box, void* data)
oc_matrix_pop();
}
void oc_ui_tooltip(const char* label)
void oc_ui_tooltip_str8(oc_str8 label)
{
oc_ui_context* ui = oc_ui_get_context();
oc_ui_theme* theme = ui->theme;
@ -2424,7 +2444,7 @@ void oc_ui_tooltip(const char* label)
.floatTarget.x = p.x,
.floatTarget.y = p.y };
oc_ui_style_next(&containerStyle, OC_UI_STYLE_FLOAT);
oc_ui_container(label, OC_UI_FLAG_OVERLAY)
oc_ui_container_str8(label, OC_UI_FLAG_OVERLAY)
{
oc_ui_style arrowStyle = { .size.width = { OC_UI_SIZE_PIXELS, 24 },
.size.height = { OC_UI_SIZE_PIXELS, 24 },
@ -2460,17 +2480,22 @@ void oc_ui_tooltip(const char* label)
oc_ui_box* contents = oc_ui_box_begin("contents", OC_UI_FLAG_DRAW_BACKGROUND);
oc_ui_label(label);
oc_ui_label_str8(label);
oc_ui_box_end();
}
}
void oc_ui_tooltip(const char* label)
{
oc_ui_tooltip_str8(OC_STR8(label));
}
//------------------------------------------------------------------------------
// Menus
//------------------------------------------------------------------------------
void oc_ui_menu_bar_begin(const char* name)
void oc_ui_menu_bar_begin_str8(oc_str8 name)
{
oc_ui_style style = {
.size.width = { OC_UI_SIZE_PARENT, 1, 0 },
@ -2481,7 +2506,7 @@ void oc_ui_menu_bar_begin(const char* name)
| OC_UI_STYLE_LAYOUT_AXIS;
oc_ui_style_next(&style, mask);
oc_ui_box* bar = oc_ui_box_begin(name, OC_UI_FLAG_DRAW_BACKGROUND);
oc_ui_box* bar = oc_ui_box_begin_str8(name, OC_UI_FLAG_DRAW_BACKGROUND);
oc_ui_sig sig = oc_ui_box_sig(bar);
oc_ui_context* ui = oc_ui_get_context();
@ -2491,16 +2516,21 @@ void oc_ui_menu_bar_begin(const char* name)
}
}
void oc_ui_menu_bar_begin(const char* name)
{
oc_ui_menu_bar_begin_str8(OC_STR8(name));
}
void oc_ui_menu_bar_end(void)
{
oc_ui_box_end(); // menu bar
}
void oc_ui_menu_begin(const char* label)
void oc_ui_menu_begin_str8(oc_str8 label)
{
oc_ui_context* ui = oc_ui_get_context();
oc_ui_theme* theme = ui->theme;
oc_ui_box* container = oc_ui_box_make(label, 0);
oc_ui_box* container = oc_ui_box_make_str8(label, 0);
oc_ui_box_push(container);
oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_CHILDREN },
@ -2525,7 +2555,7 @@ void oc_ui_menu_begin(const char* label)
oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_TEXT },
.size.height = { OC_UI_SIZE_TEXT } },
OC_UI_STYLE_SIZE);
oc_ui_box* buttonLabel = oc_ui_box_make(label, OC_UI_FLAG_DRAW_TEXT);
oc_ui_box* buttonLabel = oc_ui_box_make_str8(label, OC_UI_FLAG_DRAW_TEXT);
oc_ui_box_end(); // button
@ -2592,13 +2622,18 @@ void oc_ui_menu_begin(const char* label)
oc_ui_box_push(menu);
}
void oc_ui_menu_begin(const char* label)
{
oc_ui_menu_begin_str8(OC_STR8(label));
}
void oc_ui_menu_end(void)
{
oc_ui_box_pop(); // menu
oc_ui_box_pop(); // container
}
oc_ui_sig oc_ui_menu_button(const char* name)
oc_ui_sig oc_ui_menu_button_str8(oc_str8 name)
{
oc_ui_context* ui = oc_ui_get_context();
oc_ui_theme* theme = ui->theme;
@ -2627,11 +2662,16 @@ oc_ui_sig oc_ui_menu_button(const char* name)
| OC_UI_FLAG_DRAW_TEXT
| OC_UI_FLAG_DRAW_BACKGROUND;
oc_ui_box* box = oc_ui_box_make(name, flags);
oc_ui_box* box = oc_ui_box_make_str8(name, flags);
oc_ui_sig sig = oc_ui_box_sig(box);
return (sig);
}
oc_ui_sig oc_ui_menu_button(const char* name)
{
return oc_ui_menu_button_str8(OC_STR8(name));
}
//------------------------------------------------------------------------------
// Select
//------------------------------------------------------------------------------
@ -2689,14 +2729,14 @@ void oc_ui_select_popup_draw_checkmark(oc_ui_box* box, void* data)
oc_matrix_pop();
}
oc_ui_select_popup_info oc_ui_select_popup(const char* name, oc_ui_select_popup_info* info)
oc_ui_select_popup_info oc_ui_select_popup_str8(oc_str8 name, oc_ui_select_popup_info* info)
{
oc_ui_select_popup_info result = *info;
oc_ui_context* ui = oc_ui_get_context();
oc_ui_theme* theme = ui->theme;
oc_ui_container(name, 0)
oc_ui_container_str8(name, 0)
{
oc_ui_pattern hoverPattern = { 0 };
oc_ui_pattern_push(&ui->frameArena, &hoverPattern, (oc_ui_selector){ .kind = OC_UI_SEL_STATUS, .status = OC_UI_HOVER });
@ -2908,6 +2948,11 @@ oc_ui_select_popup_info oc_ui_select_popup(const char* name, oc_ui_select_popup_
return (result);
}
oc_ui_select_popup_info oc_ui_select_popup(const char* name, oc_ui_select_popup_info* info)
{
return oc_ui_select_popup_str8(OC_STR8(name), info);
}
//------------------------------------------------------------------------------
// Radio group
//------------------------------------------------------------------------------
@ -2926,7 +2971,7 @@ void oc_ui_radio_indicator_draw(oc_ui_box* box, void* data)
oc_matrix_pop();
}
oc_ui_radio_group_info oc_ui_radio_group(const char* name, oc_ui_radio_group_info* info)
oc_ui_radio_group_info oc_ui_radio_group_str8(oc_str8 name, oc_ui_radio_group_info* info)
{
oc_ui_radio_group_info result = *info;
@ -2937,7 +2982,7 @@ oc_ui_radio_group_info oc_ui_radio_group(const char* name, oc_ui_radio_group_inf
.layout.spacing = 12 },
OC_UI_STYLE_LAYOUT_AXIS
| OC_UI_STYLE_LAYOUT_SPACING);
oc_ui_container(name, 0)
oc_ui_container_str8(name, 0)
{
for(int i = 0; i < info->optionCount; i++)
{
@ -3036,6 +3081,11 @@ oc_ui_radio_group_info oc_ui_radio_group(const char* name, oc_ui_radio_group_inf
return (result);
}
oc_ui_radio_group_info oc_ui_radio_group(const char* name, oc_ui_radio_group_info* info)
{
return oc_ui_radio_group_str8(OC_STR8(name), info);
}
//------------------------------------------------------------------------------
// text box
//------------------------------------------------------------------------------
@ -3817,7 +3867,7 @@ void oc_ui_text_box_render(oc_ui_box* box, void* data)
}
}
oc_ui_text_box_result oc_ui_text_box(const char* name, oc_arena* arena, oc_str8 text)
oc_ui_text_box_result oc_ui_text_box_str8(oc_str8 name, oc_arena* arena, oc_str8 text)
{
oc_ui_context* ui = oc_ui_get_context();
oc_ui_theme* theme = ui->theme;
@ -3853,7 +3903,7 @@ oc_ui_text_box_result oc_ui_text_box(const char* name, oc_arena* arena, oc_str8
oc_ui_flags frameFlags = OC_UI_FLAG_CLICKABLE
| OC_UI_FLAG_DRAW_BACKGROUND
| OC_UI_FLAG_DRAW_BORDER;
oc_ui_box* frame = oc_ui_box_begin(name, frameFlags);
oc_ui_box* frame = oc_ui_box_begin_str8(name, frameFlags);
oc_ui_tag_box(frame, "frame");
oc_font font = frame->style.font;
f32 fontSize = frame->style.fontSize;
@ -4136,6 +4186,11 @@ oc_ui_text_box_result oc_ui_text_box(const char* name, oc_arena* arena, oc_str8
return (result);
}
oc_ui_text_box_result oc_ui_text_box(const char* name, oc_arena* arena, oc_str8 text)
{
return oc_ui_text_box_str8(OC_STR8(name), arena, text);
}
//------------------------------------------------------------------------------
// Themes
// doc/UIColors.md has them visualized

View File

@ -518,7 +518,6 @@ struct oc_ui_box
oc_list beforeRules;
oc_list afterRules;
//oc_ui_style_tag tag;
oc_ui_style* targetStyle;
oc_ui_style style;
u32 z;
@ -632,8 +631,6 @@ typedef struct oc_ui_context
i32 editWordSelectionInitialCursor;
i32 editWordSelectionInitialMark;
bool clipboardRegistered;
oc_ui_theme* theme;
} oc_ui_context;
@ -731,17 +728,6 @@ ORCA_API void oc_ui_style_match_after(oc_ui_pattern pattern, oc_ui_style* style,
//-------------------------------------------------------------------------
// Basic widget helpers
//-------------------------------------------------------------------------
enum
{
OC_UI_STYLE_TAG_USER_MAX = 1 << 16,
OC_UI_STYLE_TAG_LABEL,
OC_UI_STYLE_TAG_BUTTON,
OC_UI_STYLE_TAG_SCROLLBAR,
OC_UI_STYLE_TAG_PANEL,
OC_UI_STYLE_TAG_TOOLTIP,
OC_UI_STYLE_TAG_MENU
};
ORCA_API oc_ui_sig oc_ui_label(const char* label);
ORCA_API oc_ui_sig oc_ui_label_str8(oc_str8 label);