Zig UI demo
This commit is contained in:
parent
47cba86c03
commit
fd308f9a3a
|
@ -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 };
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
UI
|
||||
zig-out
|
||||
zig-cache
|
||||
liborca.a
|
||||
profile.dtrace
|
||||
profile.spall
|
|
@ -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.
|
|
@ -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.
|
@ -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,
|
||||
});
|
||||
}
|
1563
src/orca.zig
1563
src/orca.zig
File diff suppressed because it is too large
Load Diff
107
src/ui/ui.c
107
src/ui/ui.c
|
@ -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
|
||||
|
|
14
src/ui/ui.h
14
src/ui/ui.h
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue