369 lines
13 KiB
Zig
369 lines
13 KiB
Zig
const Model = struct {
|
|
crash: bool = false,
|
|
allocator: std.mem.Allocator,
|
|
current_items_view: *vxfw.ListView,
|
|
current_items_view_widget: vxfw.Widget,
|
|
app_common_model: *AppCommonModel,
|
|
root_provider: *RootProvider,
|
|
|
|
/// Helper function to return a vxfw.Widget struct
|
|
pub fn widget(self: *Model) vxfw.Widget {
|
|
return .{
|
|
.userdata = self,
|
|
.eventHandler = Model.typeErasedEventHandler,
|
|
.captureHandler = Model.typeErasedCaptureHandler,
|
|
.drawFn = Model.typeErasedDrawFn,
|
|
};
|
|
}
|
|
|
|
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),
|
|
.key_press => |key| {
|
|
if (key.matches('c', .{ .ctrl = true })) {
|
|
ctx.quit = true;
|
|
return;
|
|
}
|
|
if (key.matches('r', .{})) {
|
|
// vm.crash = true;
|
|
ctx.redraw = true;
|
|
return ctx.requestFocus(vm.current_items_view_widget);
|
|
}
|
|
},
|
|
.focus_in => return ctx.requestFocus(vm.current_items_view_widget),
|
|
else => {},
|
|
}
|
|
}
|
|
fn typeErasedCaptureHandler(ptr: *anyopaque, ctx: *vxfw.EventContext, event: vxfw.Event) anyerror!void {
|
|
const vm: *Model = @ptrCast(@alignCast(ptr));
|
|
switch (event) {
|
|
.key_press => |key| {
|
|
var arena = std.heap.ArenaAllocator.init(vm.allocator);
|
|
defer arena.deinit();
|
|
|
|
const result = handle_key(key, &vm.app_common_model.appState, arena.allocator()) catch null;
|
|
if (result) |r| {
|
|
if (r == ActionResult.Handled) {
|
|
ctx.consumeAndRedraw();
|
|
}
|
|
}
|
|
},
|
|
else => {},
|
|
}
|
|
}
|
|
|
|
fn typeErasedDrawFn(ptr: *anyopaque, ctx: vxfw.DrawContext) std.mem.Allocator.Error!vxfw.Surface {
|
|
const vm: *Model = @ptrCast(@alignCast(ptr));
|
|
const rootWidgets = try ctx.arena.create(std.ArrayList(vxfw.SubSurface));
|
|
rootWidgets.* = std.ArrayList(vxfw.SubSurface).init(ctx.arena);
|
|
|
|
const max_size = ctx.max.size();
|
|
|
|
try createCurrentItems(ctx, vm);
|
|
|
|
{
|
|
if (vm.current_items_view.children.slice.len == 0) {
|
|
const empty_text_element = try ctx.arena.create(vxfw.Text);
|
|
empty_text_element.* = vxfw.Text{
|
|
.text = "Empty",
|
|
.overflow = .clip,
|
|
.softwrap = false,
|
|
// .style = .{
|
|
// .bg = bg,
|
|
// .fg = fg,
|
|
// },
|
|
};
|
|
|
|
const items = try ctx.arena.alloc(vxfw.Widget, 1);
|
|
items[0] = empty_text_element.widget();
|
|
|
|
vm.current_items_view.children.slice = items;
|
|
}
|
|
}
|
|
|
|
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 header = try ctx.arena.create(std.ArrayList(vxfw.Widget));
|
|
header.* = std.ArrayList(vxfw.Widget).init(ctx.arena);
|
|
|
|
{
|
|
const current_location_text = if (vm.app_common_model.appState.currentTab.currentLocation) |loc|
|
|
try std.fmt.allocPrint(ctx.arena, "{s} ", .{loc.item.fullName.path})
|
|
else
|
|
"";
|
|
const current_location_text_element = try ctx.arena.create(vxfw.Text);
|
|
current_location_text_element.* = vxfw.Text{
|
|
.text = current_location_text,
|
|
.overflow = .clip,
|
|
.softwrap = false,
|
|
.style = .{
|
|
.fg = .{ .index = 4 },
|
|
},
|
|
};
|
|
try header.append(current_location_text_element.widget());
|
|
}
|
|
|
|
{
|
|
const currentTab = vm.app_common_model.appState.currentTab;
|
|
if (currentTab.currentItem) |currentItem| {
|
|
currentTab.currentItems.mutex.lock();
|
|
defer currentTab.currentItems.mutex.unlock();
|
|
|
|
if (currentTab.currentItems.data) |currentItems| {
|
|
const current_item_text =
|
|
for (currentItems.items) |item| {
|
|
const arc_item = item.retain();
|
|
defer if (arc_item.releaseUnwrap()) |i| i.deinit();
|
|
|
|
if (models.FullName.eql(&arc_item.value.*.fullName, ¤tItem)) {
|
|
break try std.fmt.allocPrint(ctx.arena, "{s} ", .{arc_item.value.*.displayName});
|
|
}
|
|
} else "";
|
|
|
|
const current_item_text_element = try ctx.arena.create(vxfw.Text);
|
|
current_item_text_element.* = vxfw.Text{
|
|
.text = current_item_text,
|
|
.overflow = .clip,
|
|
.softwrap = false,
|
|
.style = .{
|
|
.fg = .{ .index = 4 },
|
|
},
|
|
};
|
|
try header.append(current_item_text_element.widget());
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
const head_items = try ctx.arena.alloc(vxfw.FlexItem, header.items.len);
|
|
|
|
for (0.., header.items) |i, item| {
|
|
head_items[i] = vxfw.FlexItem{
|
|
.widget = item,
|
|
.flex = 0,
|
|
};
|
|
}
|
|
|
|
const header_element = try ctx.arena.create(vxfw.FlexRow);
|
|
header_element.* = .{ .children = head_items };
|
|
|
|
const flex_column_surface: vxfw.SubSurface = .{
|
|
.origin = .{ .row = 0, .col = 0 },
|
|
.surface = try header_element.widget().draw(ctx),
|
|
};
|
|
|
|
try rootWidgets.append(flex_column_surface);
|
|
}
|
|
|
|
return .{
|
|
.size = max_size,
|
|
.widget = vm.widget(),
|
|
.buffer = &.{},
|
|
.children = rootWidgets.items,
|
|
};
|
|
}
|
|
|
|
fn createCurrentItems(ctx: vxfw.DrawContext, vm: *Model) !void {
|
|
if (vm.crash) @panic("asd123");
|
|
|
|
const text_items = blk2: {
|
|
const currentTab = vm.app_common_model.appState.currentTab;
|
|
const current_full_name = if (currentTab.currentItem) |currentItem|
|
|
models.FullName{ .path = try ctx.arena.dupe(u8, currentItem.path) }
|
|
else
|
|
null;
|
|
|
|
currentTab.currentItems.mutex.lock();
|
|
defer currentTab.currentItems.mutex.unlock();
|
|
|
|
break :blk2 if (currentTab.currentItems.data) |items| blk: {
|
|
const children = try ctx.arena.create(std.ArrayList(*vxfw.Text));
|
|
children.* = std.ArrayList(*vxfw.Text).init(ctx.arena);
|
|
|
|
for (items.items) |*original_arc_child| {
|
|
const arc_child = original_arc_child.retain();
|
|
defer if (arc_child.releaseUnwrap()) |item| item.deinit();
|
|
|
|
const child = arc_child.value.*;
|
|
const is_active = if (current_full_name) |c_full_name|
|
|
models.FullName.eql(&c_full_name, &child.fullName)
|
|
else
|
|
false;
|
|
|
|
const fg, const bg = colors: {
|
|
var fg: vaxis.Color = .default;
|
|
var bg: vaxis.Color = .default;
|
|
if (is_active) {
|
|
fg = switch (child.item) {
|
|
.container => .{ .index = 0 },
|
|
.element => .{ .index = 0 },
|
|
};
|
|
bg = switch (child.item) {
|
|
.container => .{ .index = 4 },
|
|
.element => .{ .index = 7 },
|
|
};
|
|
} else {
|
|
fg = switch (child.item) {
|
|
.container => .{ .index = 4 },
|
|
.element => .default,
|
|
};
|
|
bg = .default;
|
|
}
|
|
break :colors .{ fg, bg };
|
|
};
|
|
|
|
const text = try ctx.arena.dupe(u8, child.displayName);
|
|
const text_element = try ctx.arena.create(vxfw.Text);
|
|
text_element.* = vxfw.Text{
|
|
.text = text,
|
|
.overflow = .clip,
|
|
.softwrap = false,
|
|
.style = .{
|
|
.bg = bg,
|
|
.fg = fg,
|
|
},
|
|
};
|
|
|
|
// children[i] = text_element;
|
|
try children.append(text_element);
|
|
}
|
|
break :blk children;
|
|
} else {
|
|
vm.current_items_view.children.slice = &.{};
|
|
return;
|
|
};
|
|
};
|
|
|
|
const widgets = try ctx.arena.alloc(vxfw.Widget, text_items.items.len);
|
|
for (text_items.items, 0..) |t, i| {
|
|
widgets[i] = t.widget();
|
|
}
|
|
|
|
vm.current_items_view.children.slice = widgets;
|
|
}
|
|
};
|
|
|
|
pub fn main() !void {
|
|
const DebugAllocator = std.heap.DebugAllocator(.{});
|
|
var gpa = DebugAllocator{};
|
|
const gp_allocator = gpa.allocator();
|
|
defer {
|
|
_ = gpa.detectLeaks();
|
|
_ = gpa.deinit();
|
|
}
|
|
|
|
var tsa = std.heap.ThreadSafeAllocator{ .child_allocator = gp_allocator };
|
|
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 };
|
|
var localContentProv = localContentProvider.provider();
|
|
|
|
var rootProvider = RootProvider.init(allocator);
|
|
defer rootProvider.deinit();
|
|
|
|
try rootProvider.providers.append(&localContentProv);
|
|
|
|
const current_path = try std.fs.cwd().realpathAlloc(allocator, ".");
|
|
defer allocator.free(current_path);
|
|
|
|
const start_full_name = try local_provider.getFullNameByNativePath(allocator, models.NativePath{ .path = current_path });
|
|
defer allocator.free(start_full_name.path);
|
|
|
|
var tab1 = try allocator.create(Tab);
|
|
|
|
tab1.init(&pool, &rootProvider, allocator);
|
|
|
|
try tab1.setCurrentLocation(start_full_name);
|
|
|
|
// TODO: remove
|
|
std.Thread.sleep(1 * std.time.ns_per_s);
|
|
|
|
const empty_text_element = try allocator.create(vxfw.Text);
|
|
defer allocator.destroy(empty_text_element);
|
|
empty_text_element.* = vxfw.Text{
|
|
.text = "Empty",
|
|
};
|
|
|
|
const items = try allocator.alloc(vxfw.Widget, 1);
|
|
defer allocator.free(items);
|
|
items[0] = empty_text_element.widget();
|
|
|
|
var list: 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);
|
|
try appState.setCurrentTab(tab1);
|
|
|
|
const model = try allocator.create(Model);
|
|
defer allocator.destroy(model);
|
|
|
|
var app_common_model: AppCommonModel = undefined;
|
|
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,
|
|
.root_provider = &rootProvider,
|
|
};
|
|
|
|
model.app_common_model.usage_number.data += 1;
|
|
|
|
var app = try vxfw.App.init(allocator);
|
|
defer app.deinit();
|
|
|
|
try app.run(model.widget(), .{});
|
|
|
|
model.app_common_model.usage_number.data -= 1;
|
|
model.app_common_model.running = false;
|
|
|
|
while (model.app_common_model.usage_number.data > 0) {
|
|
std.Thread.sleep(10 * std.time.ns_per_ms);
|
|
}
|
|
}
|
|
|
|
const std = @import("std");
|
|
const vaxis = @import("vaxis");
|
|
const vxfw = vaxis.vxfw;
|
|
|
|
const models = @import("../core/models.zig");
|
|
const ActionResult = @import("../core/action/action.zig").ActionResult;
|
|
const provider = @import("../core/provider/provider.zig");
|
|
const RootProvider = @import("../core/provider/root.zig").RootProvider;
|
|
const local_provider = @import("../core/provider/local.zig");
|
|
const Tab = @import("../core/tab/tab.zig").Tab;
|
|
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;
|