Zig bindings for orca (still WIP) #140
|
@ -29,15 +29,17 @@ oc_ui_sig oc_ui_label(const char* label);
|
|||
oc_ui_sig oc_ui_label_str8(oc_str8 label);
|
||||
oc_ui_sig oc_ui_button(const char* label);
|
||||
oc_ui_sig oc_ui_checkbox(const char* name, bool* checked);
|
||||
oc_ui_box* oc_ui_slider(const char* label, f32 thumbRatio, f32* scrollValue);
|
||||
oc_ui_box* oc_ui_slider(const char* name, f32* value);
|
||||
oc_ui_box* oc_ui_scrollbar(const char* name, f32 thumbRatio, f32* scrollValue);
|
||||
oc_ui_text_box_result oc_ui_text_box(const char* name, oc_arena* arena, oc_str8 text);
|
||||
oc_ui_select_popup_info oc_ui_select_popup(const char* name, oc_ui_select_popup_info* info);
|
||||
oc_ui_radio_group_info oc_ui_radio_group(const char* name, oc_ui_radio_group_info* info);
|
||||
|
||||
void oc_ui_panel_begin(const char* name, oc_ui_flags flags);
|
||||
void oc_ui_panel_end(void);
|
||||
#define oc_ui_panel(s, f)
|
||||
|
||||
void oc_ui_menu_bar_begin(const char* label);
|
||||
void oc_ui_menu_bar_begin(const char* name);
|
||||
void oc_ui_menu_bar_end(void);
|
||||
#define oc_ui_menu_bar(name)
|
||||
|
||||
|
@ -45,11 +47,11 @@ void oc_ui_menu_begin(const char* label);
|
|||
void oc_ui_menu_end(void);
|
||||
#define oc_ui_menu(name)
|
||||
|
||||
oc_ui_sig oc_ui_menu_button(const char* name);
|
||||
oc_ui_sig oc_ui_menu_button(const char* label);
|
||||
|
||||
oc_ui_sig oc_ui_tooltip_begin(const char* name);
|
||||
oc_ui_sig oc_ui_tooltip_begin(const char* label);
|
||||
void oc_ui_tooltip_end(void);
|
||||
#define oc_ui_tooltip(name)
|
||||
#define oc_ui_tooltip(label)
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Styling
|
||||
|
|
|
@ -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,
|
||||
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 defaultMask = OC_UI_STYLE_BORDER_COLOR
|
||||
oc_ui_style_mask unselectedMask = OC_UI_STYLE_BORDER_COLOR
|
||||
| OC_UI_STYLE_BORDER_SIZE;
|
||||
oc_ui_style_match_after(defaultPattern, &defaultStyle, defaultMask);
|
||||
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 };
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
Sample
|
||||
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", "Sample", "--icon", "icon.png", "--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{"Sample/bin/Sample.exe"};
|
||||
const run_cmd_macos = [_][]const u8{ "open", "Sample.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);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
T E P I D M O N K E Y F O N T S
|
||||
freeware fonts for a freeware world
|
||||
|
||||
Site: http://www.tepidmonkey.com/
|
||||
E-mail: brandon@tepidmonkey.com
|
||||
|
||||
Thanks for your interest in my fonts!
|
||||
|
||||
For help on how to unzip, unstuff or install one of my
|
||||
fonts, please visit my site at
|
||||
www.tepidmonkey.com and go to the Help section.
|
||||
If you have any comments or questions, you can e-mail
|
||||
me at brandon@tepidmonkey.com and I'll try to reply as
|
||||
soon as possible.
|
||||
|
||||
Every week, I present a brand new original font for
|
||||
your downloading pleasure, so be sure to visit my web
|
||||
site every Sunday.
|
||||
|
||||
You may use this font(s) for non-commercial and
|
||||
commercial purposes. You are not allowed to sell this
|
||||
font for any fee at all. You are allowed to
|
||||
redistribute it as long as you don't charge ANYTHING
|
||||
for it (at all) and if you include this unaltered
|
||||
Read Me file. You may not change any aspect of the font
|
||||
file or this file.
|
||||
For the full set of terms of use (which override what
|
||||
is listed here), go to www.tepidmonkey.com
|
||||
and visit the Terms section.
|
Binary file not shown.
After Width: | Height: | Size: 153 KiB |
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
|
@ -0,0 +1,289 @@
|
|||
const std = @import("std");
|
||||
const oc = @import("orca");
|
||||
|
||||
const lerp = std.math.lerp;
|
||||
|
||||
const Vec2 = oc.Vec2;
|
||||
const Mat2x3 = oc.Mat2x3;
|
||||
const Str8 = oc.Str8;
|
||||
|
||||
var surface: oc.Surface = undefined;
|
||||
var canvas: oc.Canvas = undefined;
|
||||
var font: oc.Font = undefined;
|
||||
var orca_image: oc.Image = undefined;
|
||||
var gradient_image: oc.Image = undefined;
|
||||
|
||||
var counter: u32 = 0;
|
||||
var last_seconds: f64 = 0;
|
||||
var frame_size: Vec2 = .{ .x = 0, .y = 0 };
|
||||
|
||||
var rotation_demo: f32 = 0;
|
||||
|
||||
export fn oc_on_init() void {
|
||||
oc.windowSetTitle("zig sample");
|
||||
oc.windowSetSize(Vec2{ .x = 480, .y = 640 });
|
||||
|
||||
oc.log.info("current platform: {}", .{oc.getHostPlatform()}, @src());
|
||||
|
||||
surface = oc.Surface.canvas();
|
||||
canvas = oc.Canvas.create();
|
||||
|
||||
oc.assert(oc.Canvas.nil().isNil() == true, "nil canvas should be nil", .{}, @src());
|
||||
oc.assert(canvas.isNil() == false, "created canvas should not be nil", .{}, @src());
|
||||
|
||||
const ranges = oc.UnicodeRange.range(&[_]oc.UnicodeRange.Enum{
|
||||
.BasicLatin,
|
||||
.C1ControlsAndLatin1Supplement,
|
||||
.LatinExtendedA,
|
||||
.LatinExtendedB,
|
||||
.Specials,
|
||||
});
|
||||
font = oc.Font.createFromPath("/zig.ttf", &ranges);
|
||||
oc.assert(oc.Font.nil().isNil() == true, "nil font should be nil", .{}, @src());
|
||||
oc.assert(font.isNil() == false, "created font should not be nil", .{}, @src());
|
||||
|
||||
orca_image = oc.Image.createFromPath(surface, Str8.fromSlice("/orca_jumping.jpg"), false);
|
||||
oc.assert(oc.Image.nil().isNil() == true, "nil image should be nil", .{}, @src());
|
||||
oc.assert(orca_image.isNil() == false, "created image should not be nil", .{}, @src());
|
||||
|
||||
// generate a gradient and upload it to an image
|
||||
{
|
||||
const width = 256;
|
||||
const height = 128;
|
||||
|
||||
const tl = oc.Color{ .r = 70.0 / 255.0, .g = 13.0 / 255.0, .b = 108.0 / 255.0 };
|
||||
const bl = oc.Color{ .r = 251.0 / 255.0, .g = 167.0 / 255.0, .b = 87.0 / 255.0 };
|
||||
const tr = oc.Color{ .r = 48.0 / 255.0, .g = 164.0 / 255.0, .b = 219.0 / 255.0 };
|
||||
const br = oc.Color{ .r = 151.0 / 255.0, .g = 222.0 / 255.0, .b = 150.0 / 255.0 };
|
||||
|
||||
var pixels: [width * height]u32 = undefined;
|
||||
for (0..height) |y| {
|
||||
for (0..width) |x| {
|
||||
const h: f32 = @floatFromInt(height - 1);
|
||||
const w: f32 = @floatFromInt(width - 1);
|
||||
const y_norm: f32 = @as(f32, @floatFromInt(y)) / h;
|
||||
const x_norm: f32 = @as(f32, @floatFromInt(x)) / w;
|
||||
|
||||
const tl_weight = (1 - x_norm) * (1 - y_norm);
|
||||
const bl_weight = (1 - x_norm) * y_norm;
|
||||
const tr_weight = x_norm * (1 - y_norm);
|
||||
const br_weight = x_norm * y_norm;
|
||||
|
||||
const r: f32 = tl_weight * tl.r + bl_weight * bl.r + tr_weight * tr.r + br_weight * br.r;
|
||||
const g: f32 = tl_weight * tl.g + bl_weight * bl.g + tr_weight * tr.g + br_weight * br.g;
|
||||
const b: f32 = tl_weight * tl.b + bl_weight * bl.b + tr_weight * tr.b + br_weight * br.b;
|
||||
const color = oc.Color{ .r = r, .g = g, .b = b, .a = 1.0 };
|
||||
pixels[y * width + x] = color.toRgba8();
|
||||
}
|
||||
}
|
||||
|
||||
gradient_image = oc.Image.create(surface, width, height);
|
||||
gradient_image.uploadRegionRgba8(oc.Rect.xywh(0, 0, width, height), @ptrCast((&pixels).ptr));
|
||||
}
|
||||
}
|
||||
|
||||
export fn oc_on_resize(width: u32, height: u32) void {
|
||||
frame_size = Vec2{ .x = @floatFromInt(width), .y = @floatFromInt(height) };
|
||||
oc.log.info("frame resize: {d:.2}, {d:.2}", .{ frame_size.x, frame_size.y }, @src());
|
||||
}
|
||||
|
||||
export fn oc_on_mouse_down(button: oc.MouseButton) void {
|
||||
oc.log.info("mouse down! {}", .{button}, @src());
|
||||
}
|
||||
|
||||
export fn oc_on_mouse_up(button: oc.MouseButton) void {
|
||||
oc.log.info("mouse up! {}", .{button}, @src());
|
||||
}
|
||||
|
||||
export fn oc_on_mouse_wheel(dx: f32, dy: f32) void {
|
||||
oc.log.info("mouse wheel! dx: {d:.2}, dy: {d:.2}", .{ dx, dy }, @src());
|
||||
}
|
||||
|
||||
export fn oc_on_key_down(scan: oc.ScanCode, key: oc.KeyCode) void {
|
||||
oc.log.info("key down: {} {}", .{ scan, key }, @src());
|
||||
}
|
||||
|
||||
export fn oc_on_key_up(scan: oc.ScanCode, key: oc.KeyCode) void {
|
||||
oc.log.info("key up: {} {}", .{ scan, key }, @src());
|
||||
|
||||
switch (key) {
|
||||
oc.KeyCode.Escape => oc.requestQuit(),
|
||||
oc.KeyCode.B => oc.abort("aborting", .{}, @src()),
|
||||
oc.KeyCode.A => oc.assert(false, "test assert failed", .{}, @src()),
|
||||
oc.KeyCode.W => oc.log.warn("logging a test warning", .{}, @src()),
|
||||
oc.KeyCode.E => oc.log.err("logging a test error", .{}, @src()),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
export fn oc_on_frame_refresh() void {
|
||||
counter += 1;
|
||||
|
||||
const secs: f64 = oc.clock.time(.Date);
|
||||
|
||||
if (last_seconds != @floor(secs)) {
|
||||
last_seconds = @floor(secs);
|
||||
oc.log.info("seconds since Jan 1, 1970: {d:.0}", .{secs}, @src());
|
||||
}
|
||||
|
||||
_ = canvas.select();
|
||||
oc.Canvas.setColorRgba(0.05, 0.05, 0.05, 1.0);
|
||||
oc.Canvas.clear();
|
||||
|
||||
oc.Canvas.setColorRgba(1.0, 0.05, 0.05, 1.0);
|
||||
|
||||
{
|
||||
const translation: Mat2x3 = .{ .m = [_]f32{ 1, 0, 50, 0, 1, 50 } };
|
||||
Mat2x3.push(translation);
|
||||
defer Mat2x3.pop();
|
||||
|
||||
oc.assert(std.meta.eql(Mat2x3.top(), translation), "top of matrix stack should be what we pushed", .{}, @src());
|
||||
oc.Canvas.setWidth(1);
|
||||
oc.Canvas.rectangleFill(50, 0, 10, 10);
|
||||
oc.Canvas.rectangleStroke(70, 0, 10, 10);
|
||||
oc.Canvas.roundedRectangleFill(90, 0, 10, 10, 3);
|
||||
oc.Canvas.roundedRectangleStroke(110, 0, 10, 10, 3);
|
||||
|
||||
const green = oc.Color{ .r = 0.05, .g = 1, .b = 0.05, .a = 1 };
|
||||
oc.Canvas.setColor(green);
|
||||
oc.assert(std.meta.eql(oc.Canvas.getColor(), green), "color should be green", .{}, @src());
|
||||
|
||||
oc.Canvas.setTolerance(1);
|
||||
oc.Canvas.setJoint(.Bevel);
|
||||
oc.Canvas.ellipseFill(140, 5, 10, 5);
|
||||
oc.Canvas.ellipseStroke(170, 5, 10, 5);
|
||||
oc.Canvas.circleFill(195, 5, 5);
|
||||
oc.Canvas.circleStroke(215, 5, 5);
|
||||
|
||||
oc.Canvas.arc(230, 5, 5, 0, std.math.pi);
|
||||
}
|
||||
|
||||
{
|
||||
rotation_demo += 0.03;
|
||||
|
||||
const rot = Mat2x3.rotate(rotation_demo);
|
||||
const trans = Mat2x3.translate(285, 55);
|
||||
Mat2x3.push(Mat2x3.mul_m(trans, rot));
|
||||
defer Mat2x3.pop();
|
||||
|
||||
oc.Canvas.rectangleFill(-5, -5, 10, 10);
|
||||
}
|
||||
|
||||
{
|
||||
var scratch_scope = oc.Arena.scratchBegin();
|
||||
defer scratch_scope.end();
|
||||
|
||||
var scratch: *oc.Arena = scratch_scope.arena;
|
||||
|
||||
var str1: Str8 = Str8.collate(scratch, &[_][]const u8{ "Hello", "from", "Zig!" }, ">> ", " ", " <<") catch |e| fatal(e, @src());
|
||||
|
||||
var str2_list = oc.Str8List.init();
|
||||
str2_list.push(scratch, Str8.fromSlice("All")) catch |e| fatal(e, @src());
|
||||
str2_list.pushf(scratch, "your", .{}) catch |e| fatal(e, @src());
|
||||
str2_list.pushSlice(scratch, "base!!") catch |e| fatal(e, @src());
|
||||
|
||||
oc.assert(str2_list.containsSlice("All"), "str2_list should have the string we just pushed", .{}, @src());
|
||||
|
||||
{
|
||||
var elt_first = str2_list.list.first;
|
||||
var elt_last = str2_list.list.last;
|
||||
oc.assert(elt_first != null, "list checks", .{}, @src());
|
||||
oc.assert(elt_last != null, "list checks", .{}, @src());
|
||||
oc.assert(elt_first != elt_last, "list checks", .{}, @src());
|
||||
oc.assert(elt_first.?.next != null, "list checks", .{}, @src());
|
||||
oc.assert(elt_first.?.prev == null, "list checks", .{}, @src());
|
||||
oc.assert(elt_last.?.next == null, "list checks", .{}, @src());
|
||||
oc.assert(elt_last.?.prev != null, "list checks", .{}, @src());
|
||||
oc.assert(elt_first.?.next != elt_last, "list checks", .{}, @src());
|
||||
oc.assert(elt_last.?.prev != elt_first, "list checks", .{}, @src());
|
||||
}
|
||||
|
||||
var str2: Str8 = str2_list.collate(scratch, Str8.fromSlice("<< "), Str8.fromSlice("-"), Str8.fromSlice(" >>")) catch |e| fatal(e, @src());
|
||||
|
||||
const font_size = 18;
|
||||
const text_metrics = font.textMetrics(font_size, str1);
|
||||
const text_rect = text_metrics.ink;
|
||||
|
||||
const center_x = frame_size.x / 2;
|
||||
const text_begin_x = center_x - text_rect.w / 2;
|
||||
|
||||
Mat2x3.push(Mat2x3.translate(text_begin_x, 100));
|
||||
defer Mat2x3.pop();
|
||||
|
||||
oc.Canvas.setColorRgba(1.0, 0.05, 0.05, 1.0);
|
||||
oc.Canvas.setFont(font);
|
||||
oc.Canvas.setFontSize(font_size);
|
||||
oc.Canvas.moveTo(0, 0);
|
||||
oc.Canvas.textOutlines(str1);
|
||||
oc.Canvas.moveTo(0, 35);
|
||||
oc.Canvas.textOutlines(str2);
|
||||
oc.Canvas.fill();
|
||||
}
|
||||
|
||||
{
|
||||
var scratch_scope = oc.Arena.scratchBegin();
|
||||
defer scratch_scope.end();
|
||||
|
||||
var scratch: *oc.Arena = scratch_scope.arena;
|
||||
|
||||
var separators = oc.Str8List.init();
|
||||
separators.pushSlice(scratch, " ") catch |e| fatal(e, @src());
|
||||
separators.pushSlice(scratch, "|") catch |e| fatal(e, @src());
|
||||
separators.pushSlice(scratch, "-") catch |e| fatal(e, @src());
|
||||
|
||||
const big_string = Str8.fromSlice("This is |a one-word string that | has no spaces in it");
|
||||
var strings: oc.Str8List = big_string.split(scratch, separators) catch |e| fatal(e, @src());
|
||||
var collated = strings.join(scratch) catch |e| fatal(e, @src());
|
||||
|
||||
oc.Canvas.setFontSize(12);
|
||||
oc.Canvas.moveTo(0, 170);
|
||||
oc.Canvas.textOutlines(collated);
|
||||
oc.Canvas.fill();
|
||||
}
|
||||
|
||||
{
|
||||
const orca_size = orca_image.size();
|
||||
|
||||
{
|
||||
const trans = Mat2x3.translate(0, 200);
|
||||
const scale = Mat2x3.scaleUniform(0.25);
|
||||
Mat2x3.push(Mat2x3.mul_m(trans, scale));
|
||||
defer Mat2x3.pop();
|
||||
|
||||
orca_image.draw(oc.Rect.xywh(0, 0, orca_size.x, orca_size.y));
|
||||
|
||||
var half_size = orca_size;
|
||||
half_size.x /= 2;
|
||||
orca_image.drawRegion(oc.Rect.xywh(0, 0, half_size.x, half_size.y), oc.Rect.xywh(orca_size.x + 10, 0, half_size.x, half_size.y));
|
||||
}
|
||||
|
||||
{
|
||||
const x_offset = orca_size.x * 0.25 + orca_size.x * 0.25 * 0.5 + 5;
|
||||
const gradient_size = gradient_image.size();
|
||||
|
||||
const trans = Mat2x3.translate(x_offset, 200);
|
||||
const scale = Mat2x3.scaleUniform((orca_size.y * 0.25) / gradient_size.y);
|
||||
Mat2x3.push(Mat2x3.mul_m(trans, scale));
|
||||
defer Mat2x3.pop();
|
||||
|
||||
gradient_image.draw(oc.Rect.xywh(0, 0, gradient_size.x, gradient_size.y));
|
||||
}
|
||||
}
|
||||
|
||||
surface.select();
|
||||
canvas.render();
|
||||
surface.present();
|
||||
}
|
||||
|
||||
export fn oc_on_terminate() void {
|
||||
oc.log.info("byebye {}", .{counter}, @src());
|
||||
}
|
||||
|
||||
fn fatal(err: anyerror, source: std.builtin.SourceLocation) noreturn {
|
||||
oc.abort("Caught fatal {}", .{err}, source);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
fn oneMinusLerp(a: anytype, b: anytype, t: anytype) @TypeOf(a, b, t) {
|
||||
return 1.0 - lerp(a, b, t);
|
||||
}
|
|
@ -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,871 @@
|
|||
const std = @import("std");
|
||||
const oc = @import("orca");
|
||||
const ui = oc.ui;
|
||||
|
||||
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_ctx: ui.Context = 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(&ui_ctx);
|
||||
|
||||
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 {
|
||||
ui.processCEvent(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 => ui.setTheme(ui.dark_theme),
|
||||
.SetLightTheme => ui.setTheme(ui.light_theme),
|
||||
.None => {},
|
||||
}
|
||||
cmd = .None;
|
||||
|
||||
var default_style = ui.Style{ .font = font_regular };
|
||||
{
|
||||
ui.beginFrame(frame_size, &default_style);
|
||||
defer ui.endFrame();
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
// Menu bar
|
||||
//--------------------------------------------------------------------------------------------
|
||||
{
|
||||
ui.menuBarBegin("menu_bar");
|
||||
defer ui.menuBarEnd();
|
||||
|
||||
{
|
||||
ui.menuBegin("File");
|
||||
defer ui.menuEnd();
|
||||
|
||||
if (ui.menuButton("Quit").pressed) {
|
||||
oc.requestQuit();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ui.menuBegin("Theme");
|
||||
defer ui.menuEnd();
|
||||
|
||||
if (ui.menuButton("Dark theme").pressed) {
|
||||
cmd = .SetDarkTheme;
|
||||
}
|
||||
if (ui.menuButton("Light theme").pressed) {
|
||||
cmd = .SetLightTheme;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ui.panelBegin("main panel", .{});
|
||||
defer ui.panelEnd();
|
||||
|
||||
{
|
||||
ui.styleNext(.{
|
||||
.size = .{
|
||||
.width = .fill_parent,
|
||||
.height = .{ .custom = .{ .kind = .Parent, .value = 1, .relax = 1 } },
|
||||
},
|
||||
.layout = .{
|
||||
.axis = .X,
|
||||
.margin = .{ .x = 16, .y = 16 },
|
||||
.spacing = 16,
|
||||
},
|
||||
});
|
||||
_ = ui.boxBegin("Background", .{ .draw_background = true });
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
widgets(scratch.arena);
|
||||
|
||||
styling(scratch.arena);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ = canvas.select();
|
||||
surface.select();
|
||||
|
||||
oc.Canvas.setColor(ui_ctx.theme.bg0);
|
||||
oc.Canvas.clear();
|
||||
|
||||
ui.draw();
|
||||
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();
|
||||
|
||||
{
|
||||
ui.styleNext(.{
|
||||
.size = .{
|
||||
.width = .fill_parent,
|
||||
},
|
||||
.layout = .{
|
||||
.axis = .X,
|
||||
.spacing = 32,
|
||||
},
|
||||
});
|
||||
_ = ui.boxBegin("top", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
{
|
||||
ui.styleNext(.{
|
||||
.layout = .{
|
||||
.axis = .Y,
|
||||
.spacing = 24,
|
||||
},
|
||||
});
|
||||
_ = ui.boxBegin("top_left", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Label
|
||||
//-----------------------------------------------------------------------------
|
||||
_ = ui.makeLabel("Label");
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Button
|
||||
//-----------------------------------------------------------------------------
|
||||
if (ui.button("Button").clicked) {
|
||||
logPush("Button clicked");
|
||||
}
|
||||
|
||||
{
|
||||
ui.styleNext(.{
|
||||
.layout = .{
|
||||
.axis = .X,
|
||||
.alignment = .{ .y = .Center },
|
||||
.spacing = 8,
|
||||
},
|
||||
});
|
||||
_ = ui.boxBegin("checkbox", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Checkbox
|
||||
//-------------------------------------------------------------------------
|
||||
if (ui.checkbox("checkbox", &checkbox_checked).clicked) {
|
||||
if (checkbox_checked) {
|
||||
logPush("Checkbox checked");
|
||||
} else {
|
||||
logPush("Checkbox unhecked");
|
||||
}
|
||||
}
|
||||
|
||||
_ = ui.makeLabel("Checkbox");
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Vertical slider
|
||||
//---------------------------------------------------------------------------------
|
||||
ui.styleNext(.{ .size = .{ .height = .{ .pixels = 130 } } });
|
||||
_ = ui.slider("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;
|
||||
}
|
||||
|
||||
{
|
||||
ui.styleNext(.{
|
||||
.layout = .{
|
||||
.axis = .Y,
|
||||
.spacing = 24,
|
||||
},
|
||||
});
|
||||
_ = ui.boxBegin("top right", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Tooltip
|
||||
//-----------------------------------------------------------------------------
|
||||
if (ui.makeLabel("Tooltip").hovering) {
|
||||
ui.tooltip("Hi");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Radio group
|
||||
//-----------------------------------------------------------------------------
|
||||
var options = [_][]const u8{
|
||||
"Radio 1",
|
||||
"Radio 2",
|
||||
};
|
||||
var radio_group_info = ui.RadioGroupInfo{
|
||||
.selected_index = radio_selected,
|
||||
.options = &options,
|
||||
};
|
||||
var result = ui.radioGroup("radio_group", &radio_group_info);
|
||||
radio_selected = result.selected_index.?;
|
||||
if (result.changed) {
|
||||
logPushf("Selected {s}", .{options[radio_selected]});
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Horizontal slider
|
||||
//-----------------------------------------------------------------------------
|
||||
ui.styleNext(.{ .size = .{ .width = .{ .pixels = 130 } } });
|
||||
_ = ui.slider("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
|
||||
//-------------------------------------------------------------------------------------
|
||||
ui.styleNext(.{
|
||||
.size = .{
|
||||
.width = .{ .pixels = 305 },
|
||||
.height = .text,
|
||||
},
|
||||
});
|
||||
var textResult = ui.textBox("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 = ui.SelectPopupInfo{
|
||||
.selected_index = selected,
|
||||
.options = &options,
|
||||
.placeholder = "Select",
|
||||
};
|
||||
var selectResult = ui.selectPopup("select", &select_popup_info);
|
||||
if (selectResult.selected_index != selected) {
|
||||
logPushf("Selected {s}", .{options[selectResult.selected_index.?]});
|
||||
}
|
||||
selected = selectResult.selected_index;
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Scrollable panel
|
||||
//-------------------------------------------------------------------------------------
|
||||
{
|
||||
ui.styleNext(.{
|
||||
.size = .{
|
||||
.width = .fill_parent,
|
||||
.height = .{
|
||||
.custom = .{ .kind = .Parent, .value = 1, .relax = 1, .min_size = 200 },
|
||||
},
|
||||
},
|
||||
.bg_color = ui_ctx.theme.bg2,
|
||||
.border_color = ui_ctx.theme.border,
|
||||
.border_size = 1,
|
||||
.roundness = ui_ctx.theme.roundness_small,
|
||||
});
|
||||
_ = ui.panelBegin("log", .{ .draw_background = true, .draw_border = true });
|
||||
defer ui.panelEnd();
|
||||
|
||||
{
|
||||
ui.styleNext(.{
|
||||
.layout = .{
|
||||
.margin = .{ .x = 16, .y = 16 },
|
||||
},
|
||||
});
|
||||
_ = ui.boxBegin("contents", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
if (log_lines.list.empty()) {
|
||||
ui.styleNext(.{ .color = ui_ctx.theme.text2 });
|
||||
_ = ui.makeLabel("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;
|
||||
_ = ui.boxBegin(id, .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
_ = ui.makeLabel(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: ui.Status = .{};
|
||||
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: ui.Status = .{};
|
||||
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_ctx.theme or ui_ctx.theme.palette.
|
||||
//
|
||||
// Rule-based styling is described at
|
||||
// https://www.forkingpaths.dev/posts/23-03-10/rule_based_styling_imgui_ctx.html
|
||||
columnBegin("Styling", 2.0 / 3.0);
|
||||
defer columnEnd();
|
||||
|
||||
{
|
||||
ui.styleNext(.{
|
||||
.size = .{
|
||||
.width = .fill_parent,
|
||||
.height = .{ .pixels = 152 },
|
||||
},
|
||||
.layout = .{
|
||||
.margin = .{ .x = 310, .y = 16 },
|
||||
},
|
||||
.bg_color = ui.dark_theme.bg0,
|
||||
.roundness = ui.dark_theme.roundness_small,
|
||||
});
|
||||
_ = ui.boxBegin("styled_radios", .{ .draw_background = true, .draw_border = true });
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
resetNextRadioGroupToDarkTheme(arena);
|
||||
|
||||
var unselected_tag = ui.Tag.make("radio");
|
||||
var unselected_pattern = ui.Pattern.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 } });
|
||||
}
|
||||
ui.styleMatchAfter(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 = ui.Tag.make("radio_selected");
|
||||
var selected_pattern = ui.Pattern.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 } });
|
||||
}
|
||||
ui.styleMatchAfter(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 = ui.Tag.make("label");
|
||||
var label_pattern = ui.Pattern.init();
|
||||
label_pattern.push(arena, .{ .sel = .{ .tag = label_tag } });
|
||||
ui.styleMatchAfter(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 = ui.RadioGroupInfo{
|
||||
.selected_index = styling_selected_radio,
|
||||
.options = &options,
|
||||
};
|
||||
var result = ui.radioGroup("radio_group", &radio_group_info);
|
||||
styling_selected_radio = result.selected_index;
|
||||
}
|
||||
|
||||
{
|
||||
ui.styleNext(.{ .layout = .{ .axis = .X, .spacing = 32 } });
|
||||
_ = ui.boxBegin("controls", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
{
|
||||
ui.styleNext(.{ .layout = .{ .axis = .Y, .spacing = 16 } });
|
||||
_ = ui.boxBegin("unselected", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
ui.styleNext(.{ .font_size = 16 });
|
||||
_ = ui.makeLabel("Radio style");
|
||||
|
||||
{
|
||||
ui.styleNext(.{ .layout = .{ .spacing = 4 } });
|
||||
_ = ui.boxBegin("size", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
{
|
||||
ui.styleNext(.{ .layout = .{ .spacing = 4 } });
|
||||
_ = ui.boxBegin("background", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
{
|
||||
ui.styleNext(.{ .layout = .{ .spacing = 4 } });
|
||||
_ = ui.boxBegin("border", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
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;
|
||||
|
||||
{
|
||||
ui.styleNext(.{ .layout = .{ .spacing = 10 } });
|
||||
_ = ui.boxBegin("status_override", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
_ = ui.makeLabel("Override");
|
||||
|
||||
var status_options = [_][]const u8{
|
||||
"Always",
|
||||
"When hovering",
|
||||
"When active",
|
||||
};
|
||||
var status_info = ui.RadioGroupInfo{
|
||||
.selected_index = unselected_status_index,
|
||||
.options = &status_options,
|
||||
};
|
||||
var status_result = ui.radioGroup("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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ui.styleNext(.{ .layout = .{ .axis = .Y, .spacing = 16 } });
|
||||
_ = ui.boxBegin("selected", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
ui.styleNext(.{ .font_size = 16 });
|
||||
_ = ui.makeLabel("Radio selected style");
|
||||
|
||||
{
|
||||
ui.styleNext(.{ .layout = .{ .spacing = 4 } });
|
||||
_ = ui.boxBegin("size", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
{
|
||||
ui.styleNext(.{ .layout = .{ .spacing = 4 } });
|
||||
_ = ui.boxBegin("color", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
{
|
||||
ui.styleNext(.{ .layout = .{ .spacing = 4 } });
|
||||
_ = ui.boxBegin("background", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
{
|
||||
ui.styleNext(.{ .layout = .{ .spacing = 10 } });
|
||||
_ = ui.boxBegin("status_override", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
ui.styleNext(.{ .size = .{ .height = .{ .pixels = 30 } } });
|
||||
_ = ui.boxMake("spacer", .{});
|
||||
|
||||
_ = ui.makeLabel("Override");
|
||||
|
||||
var status_options = [_][]const u8{
|
||||
"Always",
|
||||
"When hovering",
|
||||
"When active",
|
||||
};
|
||||
var status_info = ui.RadioGroupInfo{
|
||||
.selected_index = selected_status_index,
|
||||
.options = &status_options,
|
||||
};
|
||||
var status_result = ui.radioGroup("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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ui.styleNext(.{ .layout = .{ .axis = .Y, .spacing = 10 } });
|
||||
_ = ui.boxBegin("label", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
ui.styleNext(.{ .font_size = 16 });
|
||||
_ = ui.makeLabel("Label style");
|
||||
|
||||
{
|
||||
ui.styleNext(.{ .layout = .{ .axis = .X, .spacing = 8 } });
|
||||
_ = ui.boxBegin("font_color", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
ui.styleMatchAfter(ui.Pattern.owner(), .{
|
||||
.size = .{ .width = .{ .pixels = 100 } },
|
||||
});
|
||||
_ = ui.makeLabel("Font color");
|
||||
|
||||
var color_names = [_][]const u8{
|
||||
"Default",
|
||||
"Red",
|
||||
"Orange",
|
||||
"Amber",
|
||||
"Yellow",
|
||||
"Lime",
|
||||
"Light green",
|
||||
"Green",
|
||||
};
|
||||
var colors = [_]oc.Color{
|
||||
ui.dark_theme.text0,
|
||||
ui.dark_theme.palette.red5,
|
||||
ui.dark_theme.palette.orange5,
|
||||
ui.dark_theme.palette.amber5,
|
||||
ui.dark_theme.palette.yellow5,
|
||||
ui.dark_theme.palette.lime5,
|
||||
ui.dark_theme.palette.light_green5,
|
||||
ui.dark_theme.palette.green5,
|
||||
};
|
||||
var color_info = ui.SelectPopupInfo{
|
||||
.selected_index = label_font_color_selected,
|
||||
.options = &color_names,
|
||||
};
|
||||
var color_result = ui.selectPopup("color", &color_info);
|
||||
label_font_color_selected = color_result.selected_index;
|
||||
label_font_color = colors[label_font_color_selected.?];
|
||||
}
|
||||
|
||||
{
|
||||
ui.styleNext(.{ .layout = .{ .axis = .X, .spacing = 8 } });
|
||||
_ = ui.boxBegin("font", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
ui.styleMatchAfter(ui.Pattern.owner(), .{
|
||||
.size = .{ .width = .{ .pixels = 100 } },
|
||||
});
|
||||
_ = ui.makeLabel("Font");
|
||||
|
||||
var font_names = [_][]const u8{
|
||||
"Regular",
|
||||
"Bold",
|
||||
};
|
||||
var fonts = [_]*oc.Font{
|
||||
&font_regular,
|
||||
&font_bold,
|
||||
};
|
||||
var font_info = ui.SelectPopupInfo{
|
||||
.selected_index = label_font_selected,
|
||||
.options = &font_names,
|
||||
};
|
||||
var font_result = ui.selectPopup("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 {
|
||||
ui.styleNext(.{
|
||||
.size = .{
|
||||
.width = .{
|
||||
.custom = .{ .kind = .Parent, .value = widthFraction, .relax = 1 },
|
||||
},
|
||||
.height = .fill_parent,
|
||||
},
|
||||
.layout = .{
|
||||
.axis = .Y,
|
||||
.margin = .{ .y = 8 },
|
||||
.spacing = 24,
|
||||
},
|
||||
.bg_color = ui_ctx.theme.bg1,
|
||||
.border_color = ui_ctx.theme.border,
|
||||
.border_size = 1,
|
||||
.roundness = ui_ctx.theme.roundness_small,
|
||||
});
|
||||
_ = ui.boxBegin(header, .{ .draw_background = true, .draw_border = true });
|
||||
|
||||
{
|
||||
ui.styleNext(.{
|
||||
.size = .{ .width = .fill_parent },
|
||||
.layout = .{ .alignment = .{ .x = .Center } },
|
||||
});
|
||||
_ = ui.boxBegin("header", .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
ui.styleNext(.{ .font_size = 18 });
|
||||
_ = ui.makeLabel(header);
|
||||
}
|
||||
|
||||
ui.styleNext(.{
|
||||
.size = .{
|
||||
.width = .fill_parent,
|
||||
.height = .{
|
||||
.custom = .{ .kind = .Parent, .value = 1, .relax = 1 },
|
||||
},
|
||||
},
|
||||
.layout = .{
|
||||
.alignment = .{ .x = .Start },
|
||||
.margin = .{ .x = 16 },
|
||||
.spacing = 24,
|
||||
},
|
||||
});
|
||||
_ = ui.boxBegin("contents", .{});
|
||||
}
|
||||
|
||||
fn columnEnd() void {
|
||||
_ = ui.boxEnd(); // contents
|
||||
_ = ui.boxEnd(); // column
|
||||
}
|
||||
|
||||
fn labeledSlider(label: []const u8, value: *f32) void {
|
||||
ui.styleNext(.{ .layout = .{ .axis = .X, .spacing = 8 } });
|
||||
_ = ui.boxBegin(label, .{});
|
||||
defer _ = ui.boxEnd();
|
||||
|
||||
ui.styleMatchAfter(ui.Pattern.owner(), .{
|
||||
.size = .{ .width = .{ .pixels = 100 } },
|
||||
});
|
||||
_ = ui.makeLabel(label);
|
||||
|
||||
ui.styleNext(.{
|
||||
.size = .{ .width = .{ .pixels = 100 } },
|
||||
});
|
||||
_ = ui.slider("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_ctx.theme or ui_ctx.theme.palette
|
||||
fn resetNextRadioGroupToDarkTheme(arena: *oc.Arena) void {
|
||||
var unselected_tag = ui.Tag.make("radio");
|
||||
var unselected_pattern = ui.Pattern.init();
|
||||
unselected_pattern.push(arena, .{ .sel = .{ .tag = unselected_tag } });
|
||||
ui.styleMatchAfter(unselected_pattern, .{
|
||||
.border_color = ui.dark_theme.text3,
|
||||
.border_size = 1,
|
||||
});
|
||||
|
||||
var unselected_hover_pattern = ui.Pattern.init();
|
||||
unselected_hover_pattern.push(arena, .{ .sel = .{ .tag = unselected_tag } });
|
||||
unselected_hover_pattern.push(arena, .{ .op = .And, .sel = .{ .status = .{ .hover = true } } });
|
||||
ui.styleMatchAfter(unselected_hover_pattern, .{
|
||||
.bg_color = ui.dark_theme.fill0,
|
||||
.border_color = ui.dark_theme.primary,
|
||||
});
|
||||
|
||||
var unselected_active_pattern = ui.Pattern.init();
|
||||
unselected_active_pattern.push(arena, .{ .sel = .{ .tag = unselected_tag } });
|
||||
unselected_active_pattern.push(arena, .{ .op = .And, .sel = .{ .status = .{ .active = true } } });
|
||||
ui.styleMatchAfter(unselected_active_pattern, .{
|
||||
.bg_color = ui.dark_theme.fill1,
|
||||
.border_color = ui.dark_theme.primary,
|
||||
});
|
||||
|
||||
var selected_tag = ui.Tag.make("radio_selected");
|
||||
var selected_pattern = ui.Pattern.init();
|
||||
selected_pattern.push(arena, .{ .sel = .{ .tag = selected_tag } });
|
||||
ui.styleMatchAfter(selected_pattern, .{
|
||||
.color = ui.dark_theme.palette.white,
|
||||
.bg_color = ui.dark_theme.primary,
|
||||
});
|
||||
|
||||
var selected_hover_pattern = ui.Pattern.init();
|
||||
selected_hover_pattern.push(arena, .{ .sel = .{ .tag = selected_tag } });
|
||||
selected_hover_pattern.push(arena, .{ .op = .And, .sel = .{ .status = .{ .hover = true } } });
|
||||
ui.styleMatchAfter(selected_hover_pattern, .{
|
||||
.bg_color = ui.dark_theme.primary_hover,
|
||||
});
|
||||
|
||||
var selected_active_pattern = ui.Pattern.init();
|
||||
selected_active_pattern.push(arena, .{ .sel = .{ .tag = selected_tag } });
|
||||
selected_active_pattern.push(arena, .{ .op = .And, .sel = .{ .status = .{ .active = true } } });
|
||||
ui.styleMatchAfter(selected_active_pattern, .{
|
||||
.bg_color = ui.dark_theme.primary_active,
|
||||
});
|
||||
}
|
|
@ -188,7 +188,7 @@ oc_key_code oc_scancode_to_keycode(oc_scan_code scanCode)
|
|||
return (oc_appData.keyMap[scanCode]);
|
||||
}
|
||||
|
||||
#define OC_DEFAULT_KEYMAP_ENTRY(sc, sv, ...) [(int) sc] = (oc_key_code)sc,
|
||||
#define OC_DEFAULT_KEYMAP_ENTRY(sc, sv, kc, ...) [(int) sc] = OC_VA_NOPT(sv, ##__VA_ARGS__) __VA_ARGS__,
|
||||
|
||||
oc_key_code oc_defaultKeyMap[OC_SCANCODE_COUNT] = {
|
||||
OC_KEY_TABLE(OC_DEFAULT_KEYMAP_ENTRY)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,11 +8,10 @@
|
|||
#include "platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
oc_host_platform oc_get_host_platform()
|
||||
oc_host_platform oc_get_host_platform(void)
|
||||
{
|
||||
return OC_HOST_PLATFORM_MACOS;
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ typedef enum
|
|||
OC_HOST_PLATFORM_WINDOWS,
|
||||
} oc_host_platform;
|
||||
|
||||
ORCA_API oc_host_platform oc_get_host_platform();
|
||||
ORCA_API oc_host_platform oc_get_host_platform(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
@ -8,11 +8,10 @@
|
|||
#include "platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
oc_host_platform oc_get_host_platform()
|
||||
oc_host_platform oc_get_host_platform(void)
|
||||
{
|
||||
return OC_HOST_PLATFORM_WINDOWS;
|
||||
}
|
||||
|
|
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 name, 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(name, 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* name, f32* value)
|
||||
{
|
||||
return oc_ui_slider_str8(OC_STR8(name), value);
|
||||
}
|
||||
|
||||
oc_ui_box* oc_ui_scrollbar_str8(oc_str8 name, 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(name, 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* name, f32 thumbRatio, f32* scrollValue)
|
||||
{
|
||||
return oc_ui_scrollbar_str8(OC_STR8(name), 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 label)
|
||||
{
|
||||
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(label, flags);
|
||||
oc_ui_sig sig = oc_ui_box_sig(box);
|
||||
return (sig);
|
||||
}
|
||||
|
||||
oc_ui_sig oc_ui_menu_button(const char* label)
|
||||
{
|
||||
return oc_ui_menu_button_str8(OC_STR8(label));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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
|
||||
|
|
24
src/ui/ui.h
24
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,39 +728,28 @@ 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);
|
||||
|
||||
ORCA_API oc_ui_sig oc_ui_button(const char* label);
|
||||
ORCA_API oc_ui_sig oc_ui_checkbox(const char* name, bool* checked);
|
||||
ORCA_API oc_ui_box* oc_ui_slider(const char* label, f32* value);
|
||||
ORCA_API oc_ui_box* oc_ui_scrollbar(const char* label, f32 thumbRatio, f32* scrollValue);
|
||||
ORCA_API oc_ui_box* oc_ui_slider(const char* name, f32* value);
|
||||
ORCA_API oc_ui_box* oc_ui_scrollbar(const char* name, f32 thumbRatio, f32* scrollValue);
|
||||
ORCA_API void oc_ui_tooltip(const char* label);
|
||||
|
||||
ORCA_API void oc_ui_panel_begin(const char* name, oc_ui_flags flags);
|
||||
ORCA_API void oc_ui_panel_end(void);
|
||||
#define oc_ui_panel(s, f) oc_defer_loop(oc_ui_panel_begin(s, f), oc_ui_panel_end())
|
||||
|
||||
ORCA_API void oc_ui_menu_bar_begin(const char* label);
|
||||
ORCA_API void oc_ui_menu_bar_begin(const char* name);
|
||||
ORCA_API void oc_ui_menu_bar_end(void);
|
||||
#define oc_ui_menu_bar(name) oc_defer_loop(oc_ui_menu_bar_begin(name), oc_ui_menu_bar_end())
|
||||
|
||||
ORCA_API void oc_ui_menu_begin(const char* label);
|
||||
ORCA_API void oc_ui_menu_end(void);
|
||||
#define oc_ui_menu(name) oc_defer_loop(oc_ui_menu_begin(name), oc_ui_menu_end())
|
||||
#define oc_ui_menu(label) oc_defer_loop(oc_ui_menu_begin(label), oc_ui_menu_end())
|
||||
|
||||
ORCA_API oc_ui_sig oc_ui_menu_button(const char* name);
|
||||
ORCA_API oc_ui_sig oc_ui_menu_button(const char* label);
|
||||
|
||||
typedef struct oc_ui_text_box_result
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue