diff --git a/src/gui/action_map.zig b/src/gui/action_map.zig new file mode 100644 index 0000000..ab93081 --- /dev/null +++ b/src/gui/action_map.zig @@ -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; diff --git a/src/gui/main.zig b/src/gui/main.zig index e217d74..63ab73c 100644 --- a/src/gui/main.zig +++ b/src/gui/main.zig @@ -13,7 +13,6 @@ 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: @@ -90,7 +89,10 @@ pub fn main() !void { var win = try dvui.Window.init(@src(), allocator, backend.backend(), .{}); defer win.deinit(); + var arena_allocator = std.heap.ArenaAllocator.init(allocator); + const arena = arena_allocator.allocator(); main_loop: while (true) { + defer _ = arena_allocator.reset(.free_all); c.BeginDrawing(); // Raylib does not support waiting with event interruption, so dvui @@ -109,47 +111,57 @@ pub fn main() !void { 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 => {}, - } - } + _ = handle_map(ke, &model.core_model.appState, arena) catch ActionResult.None; }, 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 // - sends all dvui stuff to backend for rendering, must be called before renderPresent() - _ = try win.end(.{}); + const end_micros = try win.end(.{}); // cursor management backend.setCursor(win.cursorRequested()); - // render frame to OS - c.EndDrawing(); + // waitTime and beginWait combine to achieve variable framerates + 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; - currentTab.currentItems.mutex.lock(); - defer currentTab.currentItems.mutex.unlock(); + currentTab.currentParentItems.mutex.lock(); + 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| { const arc_item = source_arc_item.retain(); defer if (arc_item.releaseUnwrap()) |item| item.deinit(); const item = arc_item.value.*; - const is_active = i == model.selected_item; + 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 }; @@ -185,16 +197,121 @@ fn dvui_frame(model: *Model) !void { 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 } }, - }); + } + } + { + var items_box = try dvui.box(@src(), .vertical, .{}); + defer items_box.deinit(); + const currentTab = model.core_model.appState.currentTab; - const lorem = "This example shows how to use dvui in a normal application."; - try tl.addText(lorem, .{}); - tl.deinit(); + 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 { + 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(); + } + } + } + { + 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(); + } } } } @@ -209,3 +326,5 @@ const Tab = @import("../core/tab/tab.zig").Tab; const AppState = @import("../core/app_state.zig").AppState; const dvui = @import("dvui"); +const handle_map = @import("action_map.zig").handle_key; +const ActionResult = @import("../core/action/action.zig").ActionResult;