feat: gui 3 column

This commit is contained in:
2025-06-07 15:12:24 +02:00
parent f6a9a15f2e
commit 9a09048570
2 changed files with 168 additions and 26 deletions

23
src/gui/action_map.zig Normal file
View File

@@ -0,0 +1,23 @@
pub fn handle_key(key: dvui.Event.Key, appState: *AppState, arena: std.mem.Allocator) !ActionResult {
if (key.action == .down or key.action == .repeat) {
if (key.code == .left) {
return try handle_action(Action.GoUp, appState, arena);
} else if (key.code == .right) {
return try handle_action(Action.Enter, appState, arena);
} else if (key.code == .up) {
return try handle_action(Action.SelectPrevious, appState, arena);
} else if (key.code == .down) {
return try handle_action(Action.SelectNext, appState, arena);
}
}
return ActionResult.None;
}
const std = @import("std");
const dvui = @import("dvui");
const ActionResult = @import("../core/action/action.zig").ActionResult;
const handle_action = @import("../core/action/action_handler.zig").handle;
const Action = @import("../core/action/action.zig").Action;
const AppState = @import("../core/app_state.zig").AppState;
const RootProvider = @import("../core/provider/root.zig").RootProvider;

View File

@@ -13,7 +13,6 @@ pub const c = RaylibBackend.c;
const Model = struct { const Model = struct {
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
core_model: CoreModel, core_model: CoreModel,
selected_item: u32 = 0,
}; };
/// This example shows how to use the dvui for a normal application: /// This example shows how to use the dvui for a normal application:
@@ -90,7 +89,10 @@ pub fn main() !void {
var win = try dvui.Window.init(@src(), allocator, backend.backend(), .{}); var win = try dvui.Window.init(@src(), allocator, backend.backend(), .{});
defer win.deinit(); defer win.deinit();
var arena_allocator = std.heap.ArenaAllocator.init(allocator);
const arena = arena_allocator.allocator();
main_loop: while (true) { main_loop: while (true) {
defer _ = arena_allocator.reset(.free_all);
c.BeginDrawing(); c.BeginDrawing();
// Raylib does not support waiting with event interruption, so dvui // Raylib does not support waiting with event interruption, so dvui
@@ -109,47 +111,57 @@ pub fn main() !void {
for (dvui.events()) |*e| { for (dvui.events()) |*e| {
switch (e.evt) { switch (e.evt) {
.key => |ke| { .key => |ke| {
if (ke.action == .down or ke.action == .repeat) { _ = handle_map(ke, &model.core_model.appState, arena) catch ActionResult.None;
switch (ke.code) {
.down => model.selected_item +|= 1,
.up => model.selected_item -|= 1,
else => {},
}
}
}, },
else => {}, else => {},
} }
} }
try dvui_frame(model); try dvui_frame(model, arena);
// // 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();
// marks end of dvui frame, don't call dvui functions after this // 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() // - sends all dvui stuff to backend for rendering, must be called before renderPresent()
_ = try win.end(.{}); const end_micros = try win.end(.{});
// cursor management // cursor management
backend.setCursor(win.cursorRequested()); backend.setCursor(win.cursorRequested());
// render frame to OS // waitTime and beginWait combine to achieve variable framerates
c.EndDrawing(); const wait_event_micros = win.waitTime(end_micros, null);
backend.EndDrawingWaitEventTimeout(wait_event_micros);
} }
} }
fn dvui_frame(model: *Model) !void { fn dvui_frame(model: *Model, arena: std.mem.Allocator) !void {
var hbox = try dvui.box(@src(), .horizontal, .{});
defer hbox.deinit();
{ {
var parent_items_box = try dvui.box(@src(), .vertical, .{});
defer parent_items_box.deinit();
const currentTab = model.core_model.appState.currentTab; const currentTab = model.core_model.appState.currentTab;
currentTab.currentItems.mutex.lock(); currentTab.currentParentItems.mutex.lock();
defer currentTab.currentItems.mutex.unlock(); defer currentTab.currentParentItems.mutex.unlock();
if (currentTab.currentItems.data) |current_items| { if (currentTab.currentParentItems.data) |current_items| {
for (0.., current_items.items) |i, *source_arc_item| { for (0.., current_items.items) |i, *source_arc_item| {
const arc_item = source_arc_item.retain(); const arc_item = source_arc_item.retain();
defer if (arc_item.releaseUnwrap()) |item| item.deinit(); defer if (arc_item.releaseUnwrap()) |item| item.deinit();
const item = arc_item.value.*; const item = arc_item.value.*;
const is_active = i == model.selected_item; const is_active = false; // TODO
const fg, const bg = colors: { const fg, const bg = colors: {
var fg: dvui.Color = .{ .r = 100, .g = 100, .b = 100 }; var fg: dvui.Color = .{ .r = 100, .g = 100, .b = 100 };
var bg: dvui.Color = .{ .r = 100, .g = 100, .b = 100 }; var bg: dvui.Color = .{ .r = 100, .g = 100, .b = 100 };
@@ -185,18 +197,123 @@ fn dvui_frame(model: *Model) !void {
try tl.addText(text, .{}); try tl.addText(text, .{});
tl.deinit(); tl.deinit();
} }
}
}
{
var items_box = try dvui.box(@src(), .vertical, .{});
defer items_box.deinit();
const currentTab = model.core_model.appState.currentTab;
currentTab.currentItems.mutex.lock();
defer currentTab.currentItems.mutex.unlock();
if (currentTab.currentItems.data) |current_items| {
const current_full_name = if (currentTab.currentItem) |currentItem| blk: {
const arc_copy = currentItem.retain();
defer if (arc_copy.releaseUnwrap()) |item| item.deinit();
break :blk models.FullName{ .path = try arena.dupe(u8, currentItem.value.*.fullName.path) };
} else null;
for (0.., current_items.items) |i, *source_arc_item| {
const arc_item = source_arc_item.retain();
defer if (arc_item.releaseUnwrap()) |item| item.deinit();
const item = arc_item.value.*;
const is_active = if (current_full_name) |c_full_name|
models.FullName.eql(&c_full_name, &item.fullName)
else
false;
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 { } 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(), .{}, .{ var tl = try dvui.textLayout(@src(), .{}, .{
.id_extra = i,
.expand = .horizontal, .expand = .horizontal,
.font_style = .title_4, .font_style = .title_4,
.color_fill = .{ .color = .{ .r = 100, .g = 100, .b = 100 } }, .color_fill = .{ .color = bg },
}); });
const lorem = "This example shows how to use dvui in a normal application."; const text = try dvui.currentWindow().arena().dupe(u8, item.displayName);
try tl.addText(lorem, .{}); try tl.addText(text, .{});
tl.deinit(); tl.deinit();
} }
} }
}
{
var selected_children_box = try dvui.box(@src(), .vertical, .{});
defer selected_children_box.deinit();
const currentTab = model.core_model.appState.currentTab;
currentTab.currentChildren.mutex.lock();
defer currentTab.currentChildren.mutex.unlock();
if (currentTab.currentChildren.data) |current_items| {
for (0.., current_items.items) |i, *source_arc_item| {
const arc_item = source_arc_item.retain();
defer if (arc_item.releaseUnwrap()) |item| item.deinit();
const item = arc_item.value.*;
const is_active = false; //TODO
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();
}
}
}
} }
const std = @import("std"); const std = @import("std");
@@ -209,3 +326,5 @@ const Tab = @import("../core/tab/tab.zig").Tab;
const AppState = @import("../core/app_state.zig").AppState; const AppState = @import("../core/app_state.zig").AppState;
const dvui = @import("dvui"); const dvui = @import("dvui");
const handle_map = @import("action_map.zig").handle_key;
const ActionResult = @import("../core/action/action.zig").ActionResult;