feat(gui): base project
This commit is contained in:
44
build.zig
44
build.zig
@@ -10,10 +10,20 @@ pub fn build(b: *std.Build) void {
|
|||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
const console_exe = b.addExecutable(.{
|
const console_exe = b.addExecutable(.{
|
||||||
.name = "FileTime3",
|
.name = "ftime",
|
||||||
.root_module = console_exe_mod,
|
.root_module = console_exe_mod,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const gui_exe_mod = b.createModule(.{
|
||||||
|
.root_source_file = b.path("src/gui_main.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
const gui_exe = b.addExecutable(.{
|
||||||
|
.name = "filetime",
|
||||||
|
.root_module = gui_exe_mod,
|
||||||
|
});
|
||||||
|
|
||||||
const vaxis = b.dependency("vaxis", .{
|
const vaxis = b.dependency("vaxis", .{
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
@@ -22,22 +32,38 @@ pub fn build(b: *std.Build) void {
|
|||||||
console_exe.root_module.addImport("vaxis", vaxis.module("vaxis"));
|
console_exe.root_module.addImport("vaxis", vaxis.module("vaxis"));
|
||||||
b.installArtifact(console_exe);
|
b.installArtifact(console_exe);
|
||||||
|
|
||||||
|
const dvui = b.dependency("dvui", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.backend = .raylib,
|
||||||
|
});
|
||||||
|
|
||||||
|
gui_exe.root_module.addImport("dvui", dvui.module("dvui_raylib"));
|
||||||
|
b.installArtifact(gui_exe);
|
||||||
|
|
||||||
const run_console_cmd = b.addRunArtifact(console_exe);
|
const run_console_cmd = b.addRunArtifact(console_exe);
|
||||||
run_console_cmd.step.dependOn(b.getInstallStep());
|
run_console_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
|
||||||
|
const run_gui_cmd = b.addRunArtifact(gui_exe);
|
||||||
|
run_gui_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
|
||||||
if (b.args) |args| {
|
if (b.args) |args| {
|
||||||
run_console_cmd.addArgs(args);
|
run_console_cmd.addArgs(args);
|
||||||
|
run_gui_cmd.addArgs(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
const run_console_step = b.step("run", "Run the console app");
|
const run_console_step = b.step("run:console", "Run the console app");
|
||||||
run_console_step.dependOn(&run_console_cmd.step);
|
run_console_step.dependOn(&run_console_cmd.step);
|
||||||
|
|
||||||
const console_unit_tests = b.addTest(.{
|
const run_gui_step = b.step("run:gui", "Run the gui app");
|
||||||
.root_module = console_exe_mod,
|
run_gui_step.dependOn(&run_gui_cmd.step);
|
||||||
});
|
|
||||||
|
|
||||||
const run_console_unit_tests = b.addRunArtifact(console_unit_tests);
|
// const console_unit_tests = b.addTest(.{
|
||||||
|
// .root_module = console_exe_mod,
|
||||||
const test_step = b.step("test", "Run unit console tests");
|
// });
|
||||||
test_step.dependOn(&run_console_unit_tests.step);
|
//
|
||||||
|
// const run_console_unit_tests = b.addRunArtifact(console_unit_tests);
|
||||||
|
//
|
||||||
|
// const test_step = b.step("test", "Run unit console tests");
|
||||||
|
// test_step.dependOn(&run_console_unit_tests.step);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,10 @@
|
|||||||
.url = "git+https://github.com/rockorager/libvaxis.git#ae71b6545c099e73d45df7e5dd7c7a3081839468",
|
.url = "git+https://github.com/rockorager/libvaxis.git#ae71b6545c099e73d45df7e5dd7c7a3081839468",
|
||||||
.hash = "vaxis-0.1.0-BWNV_JEMCQBskZQsnlzh6GoyHSDgOi41bCoZIB2pW-E7",
|
.hash = "vaxis-0.1.0-BWNV_JEMCQBskZQsnlzh6GoyHSDgOi41bCoZIB2pW-E7",
|
||||||
},
|
},
|
||||||
|
.dvui = .{
|
||||||
|
.url = "git+https://github.com/david-vanderson/dvui.git#5703f8f02fb8e1bf2c866517f208745e4d7af869",
|
||||||
|
.hash = "dvui-0.2.0-AQFJmXGezQAwyj44yNdQ3oZ2XkMybh9r6ltiMEOKIwT6",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
.paths = .{
|
.paths = .{
|
||||||
"build.zig",
|
"build.zig",
|
||||||
|
|||||||
14
src/app_common/Model.zig
Normal file
14
src/app_common/Model.zig
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const models = @import("../core/models.zig");
|
||||||
|
const Tab = @import("../core/tab/tab.zig").Tab;
|
||||||
|
const locked = @import("../core/sync.zig").locked;
|
||||||
|
|
||||||
|
running: bool = true,
|
||||||
|
usage_number: locked(u16) = .{ .data = 0 },
|
||||||
|
current_items: locked(?[]*models.Item) = .{ .data = null },
|
||||||
|
current_items_allocator: std.heap.ArenaAllocator,
|
||||||
|
tab: *Tab,
|
||||||
|
|
||||||
|
pub fn deinit(self: *@This()) void {
|
||||||
|
self.current_items_allocator.deinit();
|
||||||
|
}
|
||||||
44
src/app_common/root.zig
Normal file
44
src/app_common/root.zig
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const models = @import("../core/models.zig");
|
||||||
|
const Model = @import("Model.zig");
|
||||||
|
|
||||||
|
pub fn data_loop(vm: *Model) void {
|
||||||
|
vm.usage_number.data += 1;
|
||||||
|
while (vm.running) {
|
||||||
|
inner_loop(vm) catch {};
|
||||||
|
std.Thread.sleep(100 * std.time.ns_per_ms);
|
||||||
|
}
|
||||||
|
vm.usage_number.data -= 1;
|
||||||
|
}
|
||||||
|
fn inner_loop(vm: *Model) !void {
|
||||||
|
if (vm.tab.currentItemsChanged) {
|
||||||
|
std.Thread.sleep(10 * std.time.ns_per_ms);
|
||||||
|
|
||||||
|
vm.tab.currentItems.mutex.lock();
|
||||||
|
defer vm.tab.currentItems.mutex.unlock();
|
||||||
|
|
||||||
|
if (vm.tab.currentItems.data) |current_items| {
|
||||||
|
_ = vm.current_items_allocator.reset(.retain_capacity);
|
||||||
|
const allocator = vm.current_items_allocator.allocator();
|
||||||
|
|
||||||
|
const items = try allocator.alloc(*models.Item, current_items.items.len);
|
||||||
|
for (current_items.items, 0..) |item, i| {
|
||||||
|
items[i] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
std.mem.sort(*models.Item, items, {}, struct {
|
||||||
|
fn sort(_: void, lhs: *models.Item, rhs: *models.Item) bool {
|
||||||
|
if (lhs.item == .container and rhs.item == .element) return true;
|
||||||
|
if (lhs.item == .element and rhs.item == .container) return false;
|
||||||
|
return std.mem.order(u8, lhs.displayName, rhs.displayName) == .lt;
|
||||||
|
}
|
||||||
|
}.sort);
|
||||||
|
|
||||||
|
vm.current_items.mutex.lock();
|
||||||
|
defer vm.current_items.mutex.unlock();
|
||||||
|
vm.current_items.data = items;
|
||||||
|
|
||||||
|
vm.tab.currentItemsChanged = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,19 +7,15 @@ const provider = @import("../core/provider/provider.zig");
|
|||||||
const local_provider = @import("../core/provider/local.zig");
|
const local_provider = @import("../core/provider/local.zig");
|
||||||
const Tab = @import("../core/tab/tab.zig").Tab;
|
const Tab = @import("../core/tab/tab.zig").Tab;
|
||||||
const locked = @import("../core/sync.zig").locked;
|
const locked = @import("../core/sync.zig").locked;
|
||||||
|
const CoreModel = @import("../app_common/Model.zig");
|
||||||
|
const core = @import("../app_common/root.zig");
|
||||||
|
|
||||||
/// Our main application state
|
/// Our main application state
|
||||||
const Model = struct {
|
const Model = struct {
|
||||||
crash: bool = false,
|
crash: bool = false,
|
||||||
usage_number: locked(u16) = .{ .data = 0 },
|
|
||||||
running: bool = true,
|
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
current_items: locked(?[]*models.Item) = .{ .data = null },
|
|
||||||
current_items_view: *vxfw.ListView,
|
current_items_view: *vxfw.ListView,
|
||||||
current_items_allocator: std.heap.ArenaAllocator,
|
core_model: CoreModel,
|
||||||
tab: *Tab,
|
|
||||||
/// State of the counter
|
|
||||||
count: usize = 0,
|
|
||||||
|
|
||||||
/// Helper function to return a vxfw.Widget struct
|
/// Helper function to return a vxfw.Widget struct
|
||||||
pub fn widget(self: *Model) vxfw.Widget {
|
pub fn widget(self: *Model) vxfw.Widget {
|
||||||
@@ -97,7 +93,7 @@ const Model = struct {
|
|||||||
};
|
};
|
||||||
try rootWidgets.append(list_surface);
|
try rootWidgets.append(list_surface);
|
||||||
|
|
||||||
const current_location_text = if (vm.tab.currentLocation) |loc| loc.item.fullName.path else "";
|
const current_location_text = if (vm.core_model.tab.currentLocation) |loc| loc.item.fullName.path else "";
|
||||||
const current_location_text_element = try ctx.arena.create(vxfw.Text);
|
const current_location_text_element = try ctx.arena.create(vxfw.Text);
|
||||||
current_location_text_element.* = vxfw.Text{
|
current_location_text_element.* = vxfw.Text{
|
||||||
.text = current_location_text,
|
.text = current_location_text,
|
||||||
@@ -126,9 +122,9 @@ const Model = struct {
|
|||||||
fn createCurrentItems(ctx: vxfw.DrawContext, vm: *Model) !void {
|
fn createCurrentItems(ctx: vxfw.DrawContext, vm: *Model) !void {
|
||||||
if (vm.crash) @panic("asd123");
|
if (vm.crash) @panic("asd123");
|
||||||
|
|
||||||
vm.current_items.mutex.lock();
|
vm.core_model.current_items.mutex.lock();
|
||||||
defer vm.current_items.mutex.unlock();
|
defer vm.core_model.current_items.mutex.unlock();
|
||||||
const text_items = if (vm.current_items.data) |items| blk: {
|
const text_items = if (vm.core_model.current_items.data) |items| blk: {
|
||||||
const children = try ctx.arena.alloc(*vxfw.Text, items.len);
|
const children = try ctx.arena.alloc(*vxfw.Text, items.len);
|
||||||
for (0.., items[0..children.len]) |i, child| {
|
for (0.., items[0..children.len]) |i, child| {
|
||||||
const is_active = i == vm.current_items_view.cursor;
|
const is_active = i == vm.current_items_view.cursor;
|
||||||
@@ -179,60 +175,8 @@ const Model = struct {
|
|||||||
|
|
||||||
vm.current_items_view.children.slice = widgets;
|
vm.current_items_view.children.slice = widgets;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn onClick(maybe_ptr: ?*anyopaque, ctx: *vxfw.EventContext) anyerror!void {
|
|
||||||
const ptr = maybe_ptr orelse return;
|
|
||||||
const self: *Model = @ptrCast(@alignCast(ptr));
|
|
||||||
self.count +|= 1;
|
|
||||||
return ctx.consumeAndRedraw();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn data_loop(vm: *Model) void {
|
|
||||||
vm.usage_number.data += 1;
|
|
||||||
while (vm.running) {
|
|
||||||
inner_loop(vm) catch {};
|
|
||||||
std.Thread.sleep(100 * std.time.ns_per_ms);
|
|
||||||
}
|
|
||||||
vm.usage_number.data -= 1;
|
|
||||||
}
|
|
||||||
fn inner_loop(vm: *Model) !void {
|
|
||||||
if (vm.tab.currentItemsChanged) {
|
|
||||||
std.Thread.sleep(10 * std.time.ns_per_ms);
|
|
||||||
|
|
||||||
vm.tab.currentItems.mutex.lock();
|
|
||||||
defer vm.tab.currentItems.mutex.unlock();
|
|
||||||
|
|
||||||
if (vm.tab.currentItems.data) |current_items| {
|
|
||||||
_ = vm.current_items_allocator.reset(.retain_capacity);
|
|
||||||
const allocator = vm.current_items_allocator.allocator();
|
|
||||||
|
|
||||||
const items = try allocator.alloc(*models.Item, current_items.items.len);
|
|
||||||
for (current_items.items, 0..) |item, i| {
|
|
||||||
items[i] = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
std.mem.sort(*models.Item, items, {}, struct {
|
|
||||||
fn sort(_: void, lhs: *models.Item, rhs: *models.Item) bool {
|
|
||||||
if (lhs.item == .container and rhs.item == .element) return true;
|
|
||||||
if (lhs.item == .element and rhs.item == .container) return false;
|
|
||||||
return std.mem.order(u8, lhs.displayName, rhs.displayName) == .lt;
|
|
||||||
}
|
|
||||||
}.sort);
|
|
||||||
|
|
||||||
vm.current_items.mutex.lock();
|
|
||||||
defer vm.current_items.mutex.unlock();
|
|
||||||
vm.current_items.data = items;
|
|
||||||
|
|
||||||
vm.tab.currentItemsChanged = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vm.tab.currentItems.mutex.lock();
|
|
||||||
defer vm.tab.currentItems.mutex.unlock();
|
|
||||||
vm.count = if (vm.tab.currentItems.data) |c| c.items.len else 999;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
const DebugAllocator = std.heap.DebugAllocator(.{});
|
const DebugAllocator = std.heap.DebugAllocator(.{});
|
||||||
var gpa = DebugAllocator{};
|
var gpa = DebugAllocator{};
|
||||||
@@ -277,7 +221,6 @@ pub fn main() !void {
|
|||||||
|
|
||||||
const homeFullName: models.FullName = .{ .path = "/home/adam" };
|
const homeFullName: models.FullName = .{ .path = "/home/adam" };
|
||||||
const homeItem = try localContentProvider.getItemByFullName(homeFullName, &.{}, allocator);
|
const homeItem = try localContentProvider.getItemByFullName(homeFullName, &.{}, allocator);
|
||||||
// defer homeItem.deinit();
|
|
||||||
const c = switch (homeItem.item) {
|
const c = switch (homeItem.item) {
|
||||||
.container => |c| c,
|
.container => |c| c,
|
||||||
.element => unreachable,
|
.element => unreachable,
|
||||||
@@ -294,6 +237,7 @@ pub fn main() !void {
|
|||||||
const model = try allocator.create(Model);
|
const model = try allocator.create(Model);
|
||||||
defer allocator.destroy(model);
|
defer allocator.destroy(model);
|
||||||
|
|
||||||
|
// TODO: remove
|
||||||
std.Thread.sleep(1 * std.time.ns_per_s);
|
std.Thread.sleep(1 * std.time.ns_per_s);
|
||||||
|
|
||||||
const empty_text_element = try allocator.create(vxfw.Text);
|
const empty_text_element = try allocator.create(vxfw.Text);
|
||||||
@@ -318,16 +262,17 @@ pub fn main() !void {
|
|||||||
};
|
};
|
||||||
model.* = .{
|
model.* = .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
|
.core_model = .{
|
||||||
.current_items_allocator = std.heap.ArenaAllocator.init(allocator),
|
.current_items_allocator = std.heap.ArenaAllocator.init(allocator),
|
||||||
.current_items_view = &list,
|
|
||||||
.tab = tab1,
|
.tab = tab1,
|
||||||
.count = 0,
|
},
|
||||||
|
.current_items_view = &list,
|
||||||
};
|
};
|
||||||
defer model.current_items_allocator.deinit();
|
defer model.core_model.deinit();
|
||||||
|
|
||||||
model.usage_number.data += 1;
|
model.core_model.usage_number.data += 1;
|
||||||
|
|
||||||
try pool.spawn(data_loop, .{model});
|
try pool.spawn(core.data_loop, .{&model.core_model});
|
||||||
|
|
||||||
var app = try vxfw.App.init(allocator);
|
var app = try vxfw.App.init(allocator);
|
||||||
defer app.deinit();
|
defer app.deinit();
|
||||||
@@ -335,10 +280,10 @@ pub fn main() !void {
|
|||||||
try app.run(model.widget(), .{});
|
try app.run(model.widget(), .{});
|
||||||
// std.Thread.sleep(10 * std.time.ns_per_s);
|
// std.Thread.sleep(10 * std.time.ns_per_s);
|
||||||
|
|
||||||
model.usage_number.data -= 1;
|
model.core_model.usage_number.data -= 1;
|
||||||
model.running = false;
|
model.core_model.running = false;
|
||||||
|
|
||||||
while (model.usage_number.data > 0) {
|
while (model.core_model.usage_number.data > 0) {
|
||||||
std.Thread.sleep(10 * std.time.ns_per_ms);
|
std.Thread.sleep(10 * std.time.ns_per_ms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
194
src/gui/main.zig
Normal file
194
src/gui/main.zig
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const CoreModel = @import("../app_common/Model.zig");
|
||||||
|
const models = @import("../core/models.zig");
|
||||||
|
const provider = @import("../core/provider/provider.zig");
|
||||||
|
const local_provider = @import("../core/provider/local.zig");
|
||||||
|
const Tab = @import("../core/tab/tab.zig").Tab;
|
||||||
|
const core = @import("../app_common/root.zig");
|
||||||
|
|
||||||
|
const dvui = @import("dvui");
|
||||||
|
const RaylibBackend = dvui.backend;
|
||||||
|
comptime {
|
||||||
|
std.debug.assert(@hasDecl(RaylibBackend, "RaylibBackend"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const vsync = true;
|
||||||
|
var scale_val: f32 = 1.0;
|
||||||
|
|
||||||
|
var show_dialog_outside_frame: bool = false;
|
||||||
|
|
||||||
|
pub const c = RaylibBackend.c;
|
||||||
|
|
||||||
|
const Model = struct {
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
core_model: CoreModel,
|
||||||
|
selected_item: u32 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// This example shows how to use the dvui for a normal application:
|
||||||
|
/// - dvui renders the whole application
|
||||||
|
/// - render frames only when needed
|
||||||
|
pub fn main() !void {
|
||||||
|
var gpa_instance = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
const gpa = gpa_instance.allocator();
|
||||||
|
defer {
|
||||||
|
_ = gpa_instance.detectLeaks();
|
||||||
|
_ = gpa_instance.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
var tsa = std.heap.ThreadSafeAllocator{ .child_allocator = gpa };
|
||||||
|
const allocator = tsa.allocator();
|
||||||
|
|
||||||
|
var pool: std.Thread.Pool = undefined;
|
||||||
|
try pool.init(.{
|
||||||
|
.allocator = allocator,
|
||||||
|
});
|
||||||
|
defer pool.deinit();
|
||||||
|
|
||||||
|
var localContentProvider = local_provider.LocalContentProvider{ .threadPool = &pool };
|
||||||
|
|
||||||
|
const homeFullName: models.FullName = .{ .path = "/home/adam" };
|
||||||
|
const homeItem = try localContentProvider.getItemByFullName(homeFullName, &.{}, allocator);
|
||||||
|
const startLocation = switch (homeItem.item) {
|
||||||
|
.container => |c1| c1,
|
||||||
|
.element => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
|
var tab1 = try allocator.create(Tab);
|
||||||
|
defer allocator.destroy(tab1);
|
||||||
|
|
||||||
|
tab1.init(&pool, allocator);
|
||||||
|
defer tab1.deinit();
|
||||||
|
|
||||||
|
tab1.setCurrentLocation(startLocation);
|
||||||
|
|
||||||
|
const model = try allocator.create(Model);
|
||||||
|
defer allocator.destroy(model);
|
||||||
|
|
||||||
|
model.* = .{
|
||||||
|
.allocator = allocator,
|
||||||
|
.core_model = .{
|
||||||
|
.current_items_allocator = std.heap.ArenaAllocator.init(allocator),
|
||||||
|
.tab = tab1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
defer model.core_model.deinit();
|
||||||
|
try pool.spawn(core.data_loop, .{&model.core_model});
|
||||||
|
|
||||||
|
// init Raylib backend (creates OS window)
|
||||||
|
// initWindow() means the backend calls CloseWindow for you in deinit()
|
||||||
|
var backend = try RaylibBackend.initWindow(.{
|
||||||
|
.gpa = gpa,
|
||||||
|
.size = .{ .w = 800.0, .h = 600.0 },
|
||||||
|
.vsync = vsync,
|
||||||
|
.title = "DVUI Raylib Standalone Example",
|
||||||
|
// .icon = window_icon_png, // can also call setIconFromFileContent()
|
||||||
|
});
|
||||||
|
defer backend.deinit();
|
||||||
|
backend.log_events = true;
|
||||||
|
|
||||||
|
// init dvui Window (maps onto a single OS window)
|
||||||
|
var win = try dvui.Window.init(@src(), gpa, backend.backend(), .{});
|
||||||
|
defer win.deinit();
|
||||||
|
|
||||||
|
main_loop: while (true) {
|
||||||
|
c.BeginDrawing();
|
||||||
|
|
||||||
|
// Raylib does not support waiting with event interruption, so dvui
|
||||||
|
// can't do variable framerate. So can't call win.beginWait() or
|
||||||
|
// win.waitTime().
|
||||||
|
try win.begin(std.time.nanoTimestamp());
|
||||||
|
|
||||||
|
// send all events to dvui for processing
|
||||||
|
const quit = try backend.addAllEvents(&win);
|
||||||
|
if (quit) break :main_loop;
|
||||||
|
|
||||||
|
// if dvui widgets might not cover the whole window, then need to clear
|
||||||
|
// the previous frame's render
|
||||||
|
backend.clear();
|
||||||
|
|
||||||
|
for (dvui.events()) |*e| {
|
||||||
|
switch (e.evt) {
|
||||||
|
.key => |ke| {
|
||||||
|
if (ke.action == .down or ke.action == .repeat) {
|
||||||
|
switch (ke.code) {
|
||||||
|
.down => model.selected_item +|= 1,
|
||||||
|
.up => model.selected_item -|= 1,
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try dvui_frame(model);
|
||||||
|
|
||||||
|
// marks end of dvui frame, don't call dvui functions after this
|
||||||
|
// - sends all dvui stuff to backend for rendering, must be called before renderPresent()
|
||||||
|
_ = try win.end(.{});
|
||||||
|
|
||||||
|
// cursor management
|
||||||
|
backend.setCursor(win.cursorRequested());
|
||||||
|
|
||||||
|
// render frame to OS
|
||||||
|
c.EndDrawing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dvui_frame(model: *Model) !void {
|
||||||
|
{
|
||||||
|
model.core_model.current_items.mutex.lock();
|
||||||
|
defer model.core_model.current_items.mutex.unlock();
|
||||||
|
|
||||||
|
if (model.core_model.current_items.data) |current_items| {
|
||||||
|
for (0.., current_items) |i, item| {
|
||||||
|
const is_active = i == model.selected_item;
|
||||||
|
const fg, const bg = colors: {
|
||||||
|
var fg: dvui.Color = .{ .r = 100, .g = 100, .b = 100 };
|
||||||
|
var bg: dvui.Color = .{ .r = 100, .g = 100, .b = 100 };
|
||||||
|
if (is_active) {
|
||||||
|
fg = switch (item.item) {
|
||||||
|
.container => .{ .r = 100, .g = 100, .b = 100 },
|
||||||
|
.element => .{ .r = 100, .g = 100, .b = 100 },
|
||||||
|
};
|
||||||
|
bg = switch (item.item) {
|
||||||
|
.container => .{ .r = 200, .g = 200, .b = 200 },
|
||||||
|
.element => .{ .r = 200, .g = 200, .b = 200 },
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
fg = switch (item.item) {
|
||||||
|
.container => .{ .r = 100, .g = 100, .b = 100 },
|
||||||
|
.element => .{ .r = 100, .g = 100, .b = 100 },
|
||||||
|
};
|
||||||
|
bg = .{ .r = 100, .g = 100, .b = 100 };
|
||||||
|
}
|
||||||
|
break :colors .{ fg, bg };
|
||||||
|
};
|
||||||
|
|
||||||
|
_ = fg;
|
||||||
|
|
||||||
|
var tl = try dvui.textLayout(@src(), .{}, .{
|
||||||
|
.id_extra = i,
|
||||||
|
.expand = .horizontal,
|
||||||
|
.font_style = .title_4,
|
||||||
|
.color_fill = .{ .color = bg },
|
||||||
|
});
|
||||||
|
|
||||||
|
const text = try dvui.currentWindow().arena().dupe(u8, item.displayName);
|
||||||
|
try tl.addText(text, .{});
|
||||||
|
tl.deinit();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var tl = try dvui.textLayout(@src(), .{}, .{
|
||||||
|
.expand = .horizontal,
|
||||||
|
.font_style = .title_4,
|
||||||
|
.color_fill = .{ .color = .{ .r = 100, .g = 100, .b = 100 } },
|
||||||
|
});
|
||||||
|
|
||||||
|
const lorem = "This example shows how to use dvui in a normal application.";
|
||||||
|
try tl.addText(lorem, .{});
|
||||||
|
tl.deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/gui_main.zig
Normal file
5
src/gui_main.zig
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const run = @import("gui/main.zig").main;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
try run();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user