diff --git a/src/heavens-net/App.zig b/src/heavens-net/App.zig index e256cf8..e1babad 100644 --- a/src/heavens-net/App.zig +++ b/src/heavens-net/App.zig @@ -2,49 +2,42 @@ const std = @import("std"); const dvui = @import("dvui"); const hncore = @import("hncore"); -const win = @import("./win/root.zig"); +const compo = @import("./compo/root.zig"); const Self = @This(); -alloc: std.mem.Allocator, -today: win.today.Mock, +stage: compo.stage.Mock, +search: compo.search.Mock, +taskedit: compo.taskedit.Mock, pub fn init(alloc: std.mem.Allocator) !Self { return Self { - .alloc = alloc, - .today = try win.today.Mock.init(alloc), + .search = try compo.search.Mock.init(alloc), + .stage = try compo.stage.Mock.init(alloc), + .taskedit = try compo.taskedit.Mock.init(alloc), }; } pub fn deinit(self: *Self) void { - self.today.deinit(); + self.taskedit.deinit(); + self.stage.deinit(); + self.search.deinit(); } pub fn gui(self: *Self) !void { - // ---- menu + try compo.menu.gui(.{}); + + // background { - var root = try dvui.menu(@src(), .horizontal, .{ .background = true, .expand = .horizontal }); - defer root.deinit(); - - if (try dvui.menuItemLabel(@src(), "File", .{ .submenu = true }, .{})) |r| { - var float = try dvui.floatingMenu( - @src(), .{.from = dvui.Rect.fromPoint(dvui.Point{ .x = r.x, .y = r.y + r.h })}, .{}); - defer float.deinit(); - - if (try dvui.menuItemLabel(@src(), "Open", .{}, .{})) |_| { - } - } - } - - // ---- project tabs - { - var tbox = try dvui.box(@src(), .vertical, .{ + var box = try dvui.box(@src(), .vertical, .{ .expand = .both, .background = true, - .color_fill = .{ .name = .fill_window }, + .color_fill = .{ .color = dvui.Color.white, }, }); - defer tbox.deinit(); + defer box.deinit(); } // ---- windows - try win.today.gui(&self.today); + try compo.search.gui(&self.search); + try compo.stage.gui(&self.stage); + try compo.taskedit.gui(&self.taskedit); } diff --git a/src/heavens-net/compo/menu.zig b/src/heavens-net/compo/menu.zig new file mode 100644 index 0000000..c829b22 --- /dev/null +++ b/src/heavens-net/compo/menu.zig @@ -0,0 +1,36 @@ +const std = @import("std"); +const dvui = @import("dvui"); + +pub fn gui(ctx: anytype) !void { + _ = ctx; + + var root = try dvui.menu(@src(), .horizontal, .{ .background = true, .expand = .horizontal }); + defer root.deinit(); + + if (try dvui.menuItemLabel(@src(), "Workspace", .{ .submenu = true }, .{})) |r| { + var float = try dvui.floatingMenu( + @src(), .{.from = dvui.Rect.fromPoint(dvui.Point{ .x = r.x, .y = r.y + r.h })}, .{}); + defer float.deinit(); + + if (try dvui.menuItemLabel(@src(), "New", .{}, .{})) |_| { + } + if (try dvui.menuItemLabel(@src(), "Open", .{}, .{})) |_| { + } + + try dvui.separator(@src(), .{}); + + if (try dvui.menuItemLabel(@src(), "Save", .{}, .{})) |_| { + } + if (try dvui.menuItemLabel(@src(), "Save as", .{}, .{})) |_| { + } + } + + if (try dvui.menuItemLabel(@src(), "Task", .{ .submenu = true }, .{})) |r| { + var float = try dvui.floatingMenu( + @src(), .{.from = dvui.Rect.fromPoint(dvui.Point{ .x = r.x, .y = r.y + r.h })}, .{}); + defer float.deinit(); + + if (try dvui.menuItemLabel(@src(), "New", .{}, .{})) |_| { + } + } +} diff --git a/src/heavens-net/compo/root.zig b/src/heavens-net/compo/root.zig new file mode 100644 index 0000000..04e4791 --- /dev/null +++ b/src/heavens-net/compo/root.zig @@ -0,0 +1,4 @@ +pub const menu = @import("./menu.zig"); +pub const search = @import("./search.zig"); +pub const stage = @import("./stage.zig"); +pub const taskedit = @import("./taskedit.zig"); diff --git a/src/heavens-net/compo/search.zig b/src/heavens-net/compo/search.zig new file mode 100644 index 0000000..49ad3e7 --- /dev/null +++ b/src/heavens-net/compo/search.zig @@ -0,0 +1,102 @@ +const std = @import("std"); +const dvui = @import("dvui"); + +const ui = @import("../ui/root.zig"); + +pub const Task = struct { + id: usize, + name: [:0]const u8, +}; + +pub fn gui(ctx: anytype) !void { + var win = try dvui.floatingWindow(@src(), .{}, .{}); + defer win.deinit(); + + const cw = dvui.currentWindow(); + + try dvui.windowHeader("Search", "", null); + + // task adder + { + var adder = try dvui.textEntry(@src(), .{}, .{ + .expand = .horizontal, + }); + defer adder.deinit(); + + if (dvui.focusedWidgetId() == adder.data().id) { + if (ui.event.keyPress("activate")) { + std.debug.print("hello\n", .{}); + } + } + } + + // task list + { + var scrollArea = try dvui.scrollArea(@src(), .{}, .{ + .expand = .both, + }); + defer scrollArea.deinit(); + + var list = try dvui.box(@src(), .vertical, .{ + .expand = .both, + .padding = dvui.Rect.all(4), + }); + defer list.deinit(); + + for (0.., ctx.tasks()) |idx, task| { + if (idx > 0) { + _ = try dvui.spacer(@src(), .{ .w = 0, .h = 1}, .{ + .id_extra = idx, + .expand = .horizontal, + }); + } + var hbox = try dvui.box(@src(), .horizontal, .{ + .id_extra = idx, + .expand = .horizontal, + .background = true, + .border = dvui.Rect.all(1), + }); + defer hbox.deinit(); + + try dvui.label(@src(), "#{d} {s}", .{ task.id, task.name, }, .{}); + + if (hbox.data().borderRect().contains(cw.mouse_pt)) { + var icons = try dvui.box(@src(), .horizontal, .{ + .expand = .vertical, + .gravity_x = 1, + }); + defer icons.deinit(); + + dvui. + } + } + + try dvui.labelNoFmt(@src(), "no tasks anymore :)", .{ .gravity_x = 0.5 }); + } +} + +pub const Mock = struct { + const Self = @This(); + const TaskList = std.ArrayList(Task); + + _tasks: TaskList, + + pub fn init(alloc: std.mem.Allocator) !Self { + var ts = TaskList.init(alloc); + errdefer ts.deinit(); + + try ts.append(Task { .id = 0, .name = "helloworld", }); + try ts.append(Task { .id = 1, .name = "goodbye", }); + + return Mock { + ._tasks = ts, + }; + } + pub fn deinit(self: *Self) void { + self._tasks.deinit(); + } + + fn tasks(self: *const Self) []const Task { + return self._tasks.items; + } +}; diff --git a/src/heavens-net/win/today.zig b/src/heavens-net/compo/stage.zig similarity index 82% rename from src/heavens-net/win/today.zig rename to src/heavens-net/compo/stage.zig index 5e87406..5579911 100644 --- a/src/heavens-net/win/today.zig +++ b/src/heavens-net/compo/stage.zig @@ -2,6 +2,7 @@ const std = @import("std"); const dvui = @import("dvui"); pub const Task = struct { + id: usize, name: [:0]const u8, mark: bool, }; @@ -10,7 +11,7 @@ pub fn gui(ctx: anytype) !void { var win = try dvui.floatingWindow(@src(), .{}, .{}); defer win.deinit(); - try dvui.windowHeader("Today", "", null); + try dvui.windowHeader("Stage", "", null); var scrollArea = try dvui.scrollArea(@src(), .{}, .{ .expand = .both, @@ -46,7 +47,7 @@ pub fn gui(ctx: anytype) !void { ctx.mark(idx, mark); } - try dvui.label(@src(), "{s}", .{ task.name, }, .{}); + try dvui.label(@src(), "#{d} {s}", .{ task.id, task.name, }, .{}); _ = try dvui.ReorderWidget.draggable(@src(), .{ .reorderable = reorderable, }, .{ .expand = .vertical, @@ -68,8 +69,8 @@ pub const Mock = struct { var tasks = TaskList.init(alloc); errdefer tasks.deinit(); - try tasks.append(Task { .name = "helloworld", .mark = true, }); - try tasks.append(Task { .name = "goodbye", .mark = false, }); + try tasks.append(Task { .id = 0, .name = "helloworld", .mark = true, }); + try tasks.append(Task { .id = 1, .name = "goodbye", .mark = false, }); return Mock { .tasks = tasks, @@ -79,10 +80,10 @@ pub const Mock = struct { self.tasks.deinit(); } - fn mark(self: *Self, idx: usize, check: bool) void { + pub fn mark(self: *Self, idx: usize, check: bool) void { self.tasks.items[idx].mark = check; } - fn get_tasks(self: *const Self) []const Task { + pub fn get_tasks(self: *const Self) []const Task { return self.tasks.items; } }; diff --git a/src/heavens-net/compo/taskedit.zig b/src/heavens-net/compo/taskedit.zig new file mode 100644 index 0000000..7ee5518 --- /dev/null +++ b/src/heavens-net/compo/taskedit.zig @@ -0,0 +1,158 @@ +const std = @import("std"); +const dvui = @import("dvui"); + +const ui = @import("../ui/root.zig"); + +pub const Tab = enum { + info, + detail, + network, + gantt, +}; + +pub fn gui(ctx: anytype) !void { + var win = try dvui.floatingWindow(@src(), .{}, .{}); + defer win.deinit(); + + // window header + { + var buf: [128]u8 = undefined; + const subtitle = std.fmt.bufPrint(&buf, "#{d}", .{ctx.taskId()}) catch unreachable; + try dvui.windowHeader("Task", subtitle, null); + } + + // task summary + { + var hbox = try dvui.box(@src(), .horizontal, .{ .expand = .horizontal, }); + defer hbox.deinit(); + + var mark: bool = false; + if (try dvui.checkbox(@src(), &mark, null, .{ .gravity_y = 0.5, })) { + } + + var summary = try dvui.textEntry(@src(), .{}, .{ + .expand = .horizontal, + }); + defer summary.deinit(); + } + + // tabs + { + const shown = ctx.shownTab(); + + var tbox = try dvui.box(@src(), .vertical, .{ .expand = .both, }); + defer tbox.deinit(); + + { + var tabs = dvui.TabsWidget.init(@src(), .{ .dir = .horizontal }, .{ + .expand = .horizontal, + }); + try tabs.install(); + defer tabs.deinit(); + + inline for (std.meta.fields(Tab)) |tabMeta| { + const tab = @field(Tab, tabMeta.name); + if (try tabs.addTabLabel(shown == tab, tabMeta.name)) { + ctx.switchTab(tab); + } + } + } + + var vbox = try dvui.box(@src(), .vertical, .{ .expand = .both, }); + defer vbox.deinit(); + + switch (shown) { + .info => try tabInfo(ctx), + .detail => try tabDetail(ctx), + else => try dvui.labelNoFmt(@src(), "NOT IMPLEMENTED YET :(", .{ + .gravity_x = 0.5, + .gravity_y = 0.5, + }), + } + } +} + +fn tabInfo(ctx: anytype) !void { + _ = ctx; + + var vbox = try dvui.box(@src(), .vertical, .{ .expand = .both, }); + defer vbox.deinit(); + + const fields = [_][:0]const u8 {"foo", "baz", "bar"}; + for (0.., fields) |idx, name| { + var hbox = try dvui.box(@src(), .horizontal, .{ + .id_extra = idx, + .expand = .horizontal, + }); + defer hbox.deinit(); + + { + var box = try dvui.box(@src(), .horizontal, .{ + .min_size_content = .{ .w = 64, .h = 0, }, + }); + defer box.deinit(); + try dvui.label(@src(), "{s}", .{name}, .{ + .gravity_x = 1, + }); + } + { + var box = try dvui.box(@src(), .horizontal, .{ + .expand = .horizontal, + }); + defer box.deinit(); + try dvui.labelNoFmt(@src(), "this is a field value", .{}); + } + } +} + +fn tabDetail(ctx: anytype) !void { + _ = ctx; + // const task = ctx.task(); + + var vbox = try dvui.box(@src(), .vertical, .{ .expand = .both, }); + defer vbox.deinit(); + + // detail + { + var detail = try dvui.textEntry(@src(), .{ + .break_lines = true, + .scroll_vertical = true, + .scroll_horizontal = true, + .multiline = true, + }, .{ + .expand = .both, + }); + defer detail.deinit(); + } +} + +pub const Mock = struct { + const Self = @This(); + + _taskId: usize, + _summary: []const u8, + + _shownTab: Tab, + + pub fn init(alloc: std.mem.Allocator) !Self { + _ = alloc; + return Mock { + ._taskId = 0, + ._summary = "hello", + ._shownTab = .info, + }; + } + pub fn deinit(self: *Self) void { + _ = self; + } + + fn switchTab(self: *Self, tab: Tab) void { + self._shownTab = tab; + } + + fn taskId(self: *const Self) usize { return self._taskId; } + fn summary(self: *const Self) []const u8 { return self._summary; } + + fn shownTab(self: *const Self) Tab { return self._shownTab; } +}; + diff --git a/src/heavens-net/ui/event.zig b/src/heavens-net/ui/event.zig new file mode 100644 index 0000000..072a38b --- /dev/null +++ b/src/heavens-net/ui/event.zig @@ -0,0 +1,21 @@ +const dvui = @import("dvui"); + +pub fn key(bind: []const u8) ?*const dvui.Event.Key { + for (dvui.events()) |e| { + if (e.evt == .key) { + if (e.evt.key.matchBind(bind)) { + return &e.evt.key; + } + } + } + return null; +} +pub fn keyDown(bind: []const u8) bool { + return if (key(bind)) |k| k.action == .down else false; +} +pub fn keyPress(bind: []const u8) bool { + return if (key(bind)) |k| (k.action == .down or k.action == .repeat) else false; +} +pub fn keyUp(bind: []const u8) bool { + return if (key(bind)) |k| k.action == .up else false; +} diff --git a/src/heavens-net/ui/root.zig b/src/heavens-net/ui/root.zig new file mode 100644 index 0000000..417fce6 --- /dev/null +++ b/src/heavens-net/ui/root.zig @@ -0,0 +1 @@ +pub const event = @import("./event.zig"); diff --git a/src/heavens-net/win/root.zig b/src/heavens-net/win/root.zig deleted file mode 100644 index e53fb68..0000000 --- a/src/heavens-net/win/root.zig +++ /dev/null @@ -1 +0,0 @@ -pub const today = @import("./today.zig");