feat: selected's children
This commit is contained in:
@@ -2,7 +2,8 @@ const Model = struct {
|
||||
crash: bool = false,
|
||||
allocator: std.mem.Allocator,
|
||||
current_items_view: *vxfw.ListView,
|
||||
current_items_view_widget: vxfw.Widget,
|
||||
parent_items_view: *vxfw.ListView,
|
||||
current_children_view: *vxfw.ListView,
|
||||
app_common_model: *AppCommonModel,
|
||||
root_provider: *RootProvider,
|
||||
|
||||
@@ -19,7 +20,7 @@ const Model = struct {
|
||||
fn typeErasedEventHandler(ptr: *anyopaque, ctx: *vxfw.EventContext, event: vxfw.Event) anyerror!void {
|
||||
const vm: *Model = @ptrCast(@alignCast(ptr));
|
||||
switch (event) {
|
||||
.init => return ctx.requestFocus(vm.current_items_view_widget),
|
||||
.init => return ctx.requestFocus(vm.current_items_view.widget()),
|
||||
.key_press => |key| {
|
||||
if (key.matches('c', .{ .ctrl = true })) {
|
||||
ctx.quit = true;
|
||||
@@ -28,10 +29,10 @@ const Model = struct {
|
||||
if (key.matches('r', .{})) {
|
||||
// vm.crash = true;
|
||||
ctx.redraw = true;
|
||||
return ctx.requestFocus(vm.current_items_view_widget);
|
||||
return ctx.requestFocus(vm.current_items_view.widget());
|
||||
}
|
||||
},
|
||||
.focus_in => return ctx.requestFocus(vm.current_items_view_widget),
|
||||
.focus_in => return ctx.requestFocus(vm.current_items_view.widget()),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
@@ -61,6 +62,8 @@ const Model = struct {
|
||||
const max_size = ctx.max.size();
|
||||
|
||||
try createCurrentItems(ctx, vm);
|
||||
try createParentItems(ctx, vm);
|
||||
try createChildrenItems(ctx, vm);
|
||||
|
||||
{
|
||||
if (vm.current_items_view.children.slice.len == 0) {
|
||||
@@ -85,18 +88,46 @@ const Model = struct {
|
||||
const parentItemsWidth = max_size.width / 9;
|
||||
const childrenWidth = max_size.width * 4 / 9;
|
||||
const currentItemsWidth = max_size.width - parentItemsWidth - childrenWidth;
|
||||
|
||||
const currentItemsTop = 1;
|
||||
const list_surface: vxfw.SubSurface = .{
|
||||
.origin = .{ .row = currentItemsTop, .col = parentItemsWidth },
|
||||
.surface = try vm.current_items_view_widget
|
||||
.draw(ctx.withConstraints(ctx.min, .{
|
||||
.width = currentItemsWidth,
|
||||
.height = ctx.max.height.? - currentItemsTop,
|
||||
})),
|
||||
// .surface = try vm.current_items.widget().draw(ctx),
|
||||
};
|
||||
try rootWidgets.append(list_surface);
|
||||
|
||||
{
|
||||
const parent_items_list_surface: vxfw.SubSurface = .{
|
||||
.origin = .{ .row = currentItemsTop, .col = 0 },
|
||||
.surface = try vm.parent_items_view
|
||||
.widget()
|
||||
.draw(ctx.withConstraints(ctx.min, .{
|
||||
.width = parentItemsWidth,
|
||||
.height = ctx.max.height.? - currentItemsTop,
|
||||
})),
|
||||
};
|
||||
try rootWidgets.append(parent_items_list_surface);
|
||||
}
|
||||
|
||||
{
|
||||
const current_items_list_surface: vxfw.SubSurface = .{
|
||||
.origin = .{ .row = currentItemsTop, .col = parentItemsWidth + 1 },
|
||||
.surface = try vm.current_items_view
|
||||
.widget()
|
||||
.draw(ctx.withConstraints(ctx.min, .{
|
||||
.width = currentItemsWidth - 1,
|
||||
.height = ctx.max.height.? - currentItemsTop,
|
||||
})),
|
||||
};
|
||||
try rootWidgets.append(current_items_list_surface);
|
||||
}
|
||||
|
||||
{
|
||||
const current_children_list_surface: vxfw.SubSurface = .{
|
||||
.origin = .{ .row = currentItemsTop, .col = parentItemsWidth + currentItemsWidth + 1 },
|
||||
.surface = try vm.current_children_view
|
||||
.widget()
|
||||
.draw(ctx.withConstraints(ctx.min, .{
|
||||
.width = childrenWidth - 1,
|
||||
.height = ctx.max.height.? - currentItemsTop,
|
||||
})),
|
||||
};
|
||||
try rootWidgets.append(current_children_list_surface);
|
||||
}
|
||||
|
||||
const header = try ctx.arena.create(std.ArrayList(vxfw.Widget));
|
||||
header.* = std.ArrayList(vxfw.Widget).init(ctx.arena);
|
||||
@@ -182,20 +213,49 @@ const Model = struct {
|
||||
}
|
||||
|
||||
fn createCurrentItems(ctx: vxfw.DrawContext, vm: *Model) !void {
|
||||
if (vm.crash) @panic("asd123");
|
||||
const currentTab = vm.app_common_model.appState.currentTab;
|
||||
|
||||
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 ctx.arena.dupe(u8, currentItem.value.*.fullName.path) };
|
||||
} else null;
|
||||
|
||||
const widgets = try createItems(ctx, ¤tTab.currentItems, current_full_name);
|
||||
if (widgets) |w| {
|
||||
vm.current_items_view.children.slice = w;
|
||||
} else {
|
||||
vm.current_items_view.children.slice = &.{};
|
||||
}
|
||||
}
|
||||
|
||||
fn createParentItems(ctx: vxfw.DrawContext, vm: *Model) !void {
|
||||
const currentTab = vm.app_common_model.appState.currentTab;
|
||||
//TODO: current fullname
|
||||
const widgets = try createItems(ctx, ¤tTab.currentParentItems, null);
|
||||
if (widgets) |w| {
|
||||
vm.parent_items_view.children.slice = w;
|
||||
}
|
||||
}
|
||||
|
||||
fn createChildrenItems(ctx: vxfw.DrawContext, vm: *Model) !void {
|
||||
const currentTab = vm.app_common_model.appState.currentTab;
|
||||
//TODO: current fullname
|
||||
const widgets = try createItems(ctx, ¤tTab.currentChildren, null);
|
||||
if (widgets) |w| {
|
||||
vm.current_children_view.children.slice = w;
|
||||
}
|
||||
}
|
||||
fn createItems(
|
||||
ctx: vxfw.DrawContext,
|
||||
items1: *locked(?std.ArrayList(Arc(*models.Item))),
|
||||
current_full_name: ?models.FullName,
|
||||
) !?[]vxfw.Widget {
|
||||
const text_items = blk2: {
|
||||
const currentTab = vm.app_common_model.appState.currentTab;
|
||||
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 ctx.arena.dupe(u8, currentItem.value.*.fullName.path) };
|
||||
} else null;
|
||||
items1.mutex.lock();
|
||||
defer items1.mutex.unlock();
|
||||
|
||||
currentTab.currentItems.mutex.lock();
|
||||
defer currentTab.currentItems.mutex.unlock();
|
||||
|
||||
break :blk2 if (currentTab.currentItems.data) |items| blk: {
|
||||
break :blk2 if (items1.data) |items| blk: {
|
||||
const children = try ctx.arena.create(std.ArrayList(*vxfw.Text));
|
||||
children.* = std.ArrayList(*vxfw.Text).init(ctx.arena);
|
||||
|
||||
@@ -231,7 +291,8 @@ const Model = struct {
|
||||
break :colors .{ fg, bg };
|
||||
};
|
||||
|
||||
const text = try ctx.arena.dupe(u8, child.displayName);
|
||||
//NOTE: the right padding is wrong, if the text is too long, the remainder of the text and also the space will be clipped
|
||||
const text = try std.fmt.allocPrint(ctx.arena, " {s} ", .{child.displayName});
|
||||
const text_element = try ctx.arena.create(vxfw.Text);
|
||||
text_element.* = vxfw.Text{
|
||||
.text = text,
|
||||
@@ -243,13 +304,11 @@ const Model = struct {
|
||||
},
|
||||
};
|
||||
|
||||
// children[i] = text_element;
|
||||
try children.append(text_element);
|
||||
}
|
||||
break :blk children;
|
||||
} else {
|
||||
vm.current_items_view.children.slice = &.{};
|
||||
return;
|
||||
return null;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -258,7 +317,7 @@ const Model = struct {
|
||||
widgets[i] = t.widget();
|
||||
}
|
||||
|
||||
vm.current_items_view.children.slice = widgets;
|
||||
return widgets;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -313,14 +372,20 @@ pub fn main() !void {
|
||||
defer allocator.free(items);
|
||||
items[0] = empty_text_element.widget();
|
||||
|
||||
var list: vxfw.ListView = .{
|
||||
var current_items_list: vxfw.ListView = .{
|
||||
.draw_cursor = false,
|
||||
.children = .{ .slice = items },
|
||||
};
|
||||
|
||||
var parent_items_list: vxfw.ListView = .{
|
||||
.draw_cursor = false,
|
||||
.children = .{ .slice = items },
|
||||
};
|
||||
|
||||
var current_children_view: vxfw.ListView = .{
|
||||
.draw_cursor = false,
|
||||
.children = .{ .slice = items },
|
||||
};
|
||||
var list_widget = list.widget();
|
||||
list_widget.eventHandler = struct {
|
||||
fn a(_: *anyopaque, _: *vxfw.EventContext, _: vxfw.Event) anyerror!void {}
|
||||
}.a;
|
||||
|
||||
var appState: AppState = AppState.init(allocator);
|
||||
try appState.addTab(tab1);
|
||||
@@ -333,11 +398,13 @@ pub fn main() !void {
|
||||
try AppCommonModel.init(&app_common_model, allocator, appState);
|
||||
defer app_common_model.deinit();
|
||||
|
||||
|
||||
model.* = .{
|
||||
.allocator = allocator,
|
||||
.app_common_model = &app_common_model,
|
||||
.current_items_view = &list,
|
||||
.current_items_view_widget = list_widget,
|
||||
.current_items_view = ¤t_items_list,
|
||||
.parent_items_view = &parent_items_list,
|
||||
.current_children_view = ¤t_children_view,
|
||||
.root_provider = &rootProvider,
|
||||
};
|
||||
|
||||
@@ -346,6 +413,16 @@ pub fn main() !void {
|
||||
var app = try vxfw.App.init(allocator);
|
||||
defer app.deinit();
|
||||
|
||||
const asd = Observer(*Tab){
|
||||
.ctx = @ptrCast(@alignCast(&app)),
|
||||
.update = (struct{fn update(ctx: *anyopaque, _: *Tab)void {
|
||||
const app1: *vxfw.App = @ptrCast(@alignCast(ctx));
|
||||
_ = app1;
|
||||
}}).update,
|
||||
};
|
||||
|
||||
try app_common_model.appState.tabChildrenLoaded.attach(&asd);
|
||||
|
||||
try app.run(model.widget(), .{});
|
||||
|
||||
model.app_common_model.usage_number.data -= 1;
|
||||
@@ -370,3 +447,5 @@ const locked = @import("../core/sync.zig").locked;
|
||||
const AppCommonModel = @import("../app_common/Model.zig");
|
||||
const AppState = @import("../core/app_state.zig").AppState;
|
||||
const handle_key = @import("./action_map.zig").handle_key;
|
||||
const Arc = @import("zigrc").Arc;
|
||||
const Observer = @import("../core/observable.zig").Observer;
|
||||
|
||||
@@ -1,25 +1,30 @@
|
||||
pub const UnknownTabError = error.UnknownTab;
|
||||
|
||||
pub const AppState = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
currentTab: *Tab = undefined,
|
||||
tabs: std.ArrayList(*Tab),
|
||||
currentTabChanged: Observable(*Tab),
|
||||
tabPreCurrentItemsUnload: Observable(*Tab),
|
||||
tabChildrenLoaded: Observable(*Tab),
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator) AppState {
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.tabs = std.ArrayList(*Tab).init(allocator),
|
||||
.currentTabChanged = Observable(*Tab).init(allocator),
|
||||
.tabPreCurrentItemsUnload = Observable(*Tab).init(allocator),
|
||||
.tabChildrenLoaded = Observable(*Tab).init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn addTab(self: *AppState, tab: *Tab) !void {
|
||||
try self.tabs.append(tab);
|
||||
// tab.preCurrentItemsUnload.attach(.{
|
||||
// .ctx = @ptrCast(@alignCast(self)),
|
||||
// .update = preCurrentItemsUnload,
|
||||
// });
|
||||
const tabChildrenLoadedHandlerObserver = try tab.childrenLoaded.allocator.create(Observer(*Tab));
|
||||
tabChildrenLoadedHandlerObserver.* = Observer(*Tab){
|
||||
.ctx = @ptrCast(@alignCast(self)),
|
||||
.update = tabChildrenLoadedHandler,
|
||||
};
|
||||
|
||||
try tab.childrenLoaded.attach(tabChildrenLoadedHandlerObserver);
|
||||
}
|
||||
|
||||
pub fn setCurrentTab(self: *AppState, newTab: *Tab) !void {
|
||||
@@ -34,8 +39,20 @@ pub const AppState = struct {
|
||||
self.currentTabChanged.notify(newTab);
|
||||
}
|
||||
|
||||
pub fn removeTab(self: *AppState, tab: *Tab) void {
|
||||
const index = for (tab.childrenLoaded.observers, 0..) |observer, i| {
|
||||
if (observer.ctx == self) break i;
|
||||
} else null;
|
||||
|
||||
if (index) |i| {
|
||||
tab.childrenLoaded.observers.swapRemove(i);
|
||||
}
|
||||
|
||||
//TODO: remove from tabs
|
||||
}
|
||||
|
||||
pub fn deinit(self: *AppState) void {
|
||||
self.tabPreCurrentItemsUnload.deinit();
|
||||
self.tabChildrenLoaded.deinit();
|
||||
self.currentTabChanged.deinit();
|
||||
for (self.tabs.items) |tab| {
|
||||
tab.deinit();
|
||||
@@ -43,12 +60,13 @@ pub const AppState = struct {
|
||||
self.tabs.deinit();
|
||||
}
|
||||
|
||||
fn preCurrentItemsUnload(ctx: *anyopaque, tab: *Tab) void {
|
||||
const self: AppState = @ptrCast(@alignCast(ctx));
|
||||
self.tabPreCurrentItemsUnload.notify(tab);
|
||||
fn tabChildrenLoadedHandler(ctx: *anyopaque, tab: *Tab) void {
|
||||
const self: *AppState = @ptrCast(@alignCast(ctx));
|
||||
self.tabChildrenLoaded.notify(tab);
|
||||
}
|
||||
};
|
||||
|
||||
const std = @import("std");
|
||||
const Tab = @import("tab/tab.zig").Tab;
|
||||
const Observable = @import("observable.zig").Observable;
|
||||
const Observer = @import("observable.zig").Observer;
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
pub fn Observable(T: type) type {
|
||||
return struct {
|
||||
allocator: std.mem.Allocator,
|
||||
observers: std.ArrayList(*const Observer(T)),
|
||||
|
||||
const Self = @This();
|
||||
pub fn init(allocator: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.observers = std.ArrayList(*const Observer(T)).init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
for(self.observers)|o| {
|
||||
self.allocator.destroy(o);
|
||||
}
|
||||
self.observers.deinit();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ pub const Tab = struct {
|
||||
currentLocation: ?*Container,
|
||||
currentItems: locked(?std.ArrayList(Arc(*Item))),
|
||||
currentParentItems: locked(?std.ArrayList(Arc(*Item))),
|
||||
currentChildren: locked(?std.ArrayList(Arc(*Item))),
|
||||
childrenLoaded: Observable(*Tab),
|
||||
currentLocationChanged: Observable(?*Container),
|
||||
currentItemFullName: ?models.FullName,
|
||||
currentItem: ?Arc(*models.Item),
|
||||
@@ -21,7 +23,9 @@ pub const Tab = struct {
|
||||
.allocator = allocator,
|
||||
.currentItems = .{ .data = null },
|
||||
.currentParentItems = .{ .data = null },
|
||||
.currentChildren = .{ .data = null },
|
||||
.currentLocationChanged = Observable(?*Container).init(allocator),
|
||||
.childrenLoaded = Observable(*Tab).init(allocator),
|
||||
.currentLocation = null,
|
||||
.currentRequested = null,
|
||||
.currentItem = null,
|
||||
@@ -169,6 +173,13 @@ pub const Tab = struct {
|
||||
self.currentItemFullName = models.FullName{
|
||||
.path = try self.allocator.dupe(u8, arc.value.*.fullName.path),
|
||||
};
|
||||
|
||||
switch (arc.value.*.item) {
|
||||
.container => {
|
||||
std.Thread.Pool.spawn(self.threadPool, loadChildrenWrapper, .{ self, arc.retain() }) catch unreachable;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn loadItemsWrapper(self: *Tab, location: *Container) void {
|
||||
@@ -180,6 +191,7 @@ pub const Tab = struct {
|
||||
|
||||
fn loadParentItemsWrapper(self: *Tab, location: *Container) void {
|
||||
const parentAbsolutePath = location.item.parent orelse return;
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(self.allocator);
|
||||
defer arena.deinit();
|
||||
const allocator = arena.allocator();
|
||||
@@ -188,7 +200,7 @@ pub const Tab = struct {
|
||||
.path = allocator.dupe(u8, parentAbsolutePath.path.path) catch return,
|
||||
};
|
||||
|
||||
const resolvedParent = location.item.provider.getItemByFullName(parentFullName, &.{ .skipChildInit = true }, allocator) catch |e| {
|
||||
const resolvedParent = location.item.provider.getItemByFullName(parentFullName, &.{}, allocator) catch |e| {
|
||||
std.debug.print("error {} {s}\r\n", .{ e, parentFullName.path });
|
||||
return;
|
||||
};
|
||||
@@ -196,9 +208,47 @@ pub const Tab = struct {
|
||||
.container => |c| c,
|
||||
else => return,
|
||||
};
|
||||
loadItems(*Tab, self, parentContainer, &self.currentParentItems, (struct {
|
||||
fn a(_: *Tab) void {}
|
||||
}).a, self.allocator) catch {};
|
||||
loadItems(
|
||||
void,
|
||||
{},
|
||||
parentContainer,
|
||||
&self.currentParentItems,
|
||||
(struct {
|
||||
fn a(_: void) void {}
|
||||
}).a,
|
||||
self.allocator,
|
||||
) catch {};
|
||||
}
|
||||
|
||||
fn loadChildrenWrapper(self: *Tab, newSelectedItemArc: Arc(*models.Item)) void {
|
||||
defer if (newSelectedItemArc.releaseUnwrap()) |item| item.deinit();
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(self.allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const allocator = arena.allocator();
|
||||
|
||||
const resolvedChild = newSelectedItemArc.value.*.provider.getItemByFullName(newSelectedItemArc.value.*.fullName, &.{}, allocator) catch |e| {
|
||||
std.debug.print("error {} {s}\r\n", .{ e, newSelectedItemArc.value.*.fullName.path });
|
||||
return;
|
||||
};
|
||||
const childContainer = switch (resolvedChild.item) {
|
||||
.container => |c| c,
|
||||
else => return,
|
||||
};
|
||||
|
||||
loadItems(
|
||||
void,
|
||||
{},
|
||||
childContainer,
|
||||
&self.currentChildren,
|
||||
(struct {
|
||||
fn a(_: void) void {}
|
||||
}).a,
|
||||
self.allocator,
|
||||
) catch {};
|
||||
|
||||
self.childrenLoaded.notify(self);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Tab) void {
|
||||
@@ -217,10 +267,35 @@ pub const Tab = struct {
|
||||
currentItems.deinit();
|
||||
}
|
||||
|
||||
const data2 = self.currentParentItems.data;
|
||||
self.currentParentItems.data = null;
|
||||
if (data2) |currentItems| {
|
||||
for (currentItems.items) |arc_item| {
|
||||
if (arc_item.releaseUnwrap()) |item| {
|
||||
item.deinit();
|
||||
}
|
||||
}
|
||||
currentItems.deinit();
|
||||
}
|
||||
|
||||
const data3 = self.currentChildren.data;
|
||||
self.currentChildren.data = null;
|
||||
if (data3) |currentItems| {
|
||||
for (currentItems.items) |arc_item| {
|
||||
if (arc_item.releaseUnwrap()) |item| {
|
||||
item.deinit();
|
||||
}
|
||||
}
|
||||
currentItems.deinit();
|
||||
}
|
||||
|
||||
self.cleanCurrentItem();
|
||||
|
||||
self.cleanCurrentRequested();
|
||||
|
||||
self.currentLocationChanged.deinit();
|
||||
self.childrenLoaded.deinit();
|
||||
|
||||
self.allocator.destroy(self);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user