diff options
Diffstat (limited to 'pick.zig')
-rw-r--r-- | pick.zig | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/pick.zig b/pick.zig new file mode 100644 index 0000000..76b1213 --- /dev/null +++ b/pick.zig @@ -0,0 +1,184 @@ +const std = @import("std"); +const dvui = @import("dvui"); +const entypo = dvui.entypo; +const Backend = @import("SDLBackend"); + +var gpa_instance = std.heap.GeneralPurposeAllocator(.{}){}; +const gpa = gpa_instance.allocator(); +const vsync = true; + +pub fn main() !void { + var backend = try Backend.init(.{ + .width = 480, + .height = 360, + .vsync = vsync, + .title = "File Picker", + }); + defer backend.deinit(); + + var win = try dvui.Window.init(@src(), 0, gpa, backend.backend()); + defer win.deinit(); + win.theme = &dvui.Adwaita.light; + + var ctx = try Ctx.init(); + + loop: while (true) { + var nstime = win.beginWait(backend.hasEvent()); + try win.begin(nstime); + backend.clear(); + + const quit = try backend.addAllEvents(&win); + if (quit or .exit == try ctx.frame()) break :loop; + + const end_micros = try win.end(.{}); + backend.setCursor(win.cursorRequested()); + backend.renderPresent(); + + const wait_event_micros = win.waitTime(end_micros, null); + backend.waitEventTimeout(wait_event_micros); + } +} + +pub const Ctx = struct { + path: []u8 = "", + filename: []u8 = "", + entries: std.ArrayListUnmanaged(std.fs.IterableDir.Entry) = .{}, + + pub fn init() !Ctx { + var ret = Ctx{}; + try ret.list_files(); + return ret; + } + + pub const ExitStatus = enum { ok, exit }; + pub fn frame(ctx: *Ctx) !ExitStatus { + const bg = dvui.Options{ + .background = true, + .expand = .horizontal, + .corner_radius = dvui.Rect.all(0), + }; + + const opts = dvui.Options{ + .corner_radius = dvui.Rect.all(0), + }; + + var box = try dvui.box(@src(), .vertical, bg.override(.{ + .expand = .both, + })); + defer box.deinit(); + + { + var top = try dvui.box(@src(), .horizontal, bg); + defer top.deinit(); + + if (try dvui.button(@src(), "..", opts)) { + try std.os.chdir(".."); + try ctx.list_files(); + } + + const te = try dvui.textEntry(@src(), .{ .text = ctx.path }, bg); + defer te.deinit(); + } + { + var bottom = try dvui.box(@src(), .horizontal, opts.override(.{ + .expand = .horizontal, + .gravity_y = 1, + })); + defer bottom.deinit(); + + const button_enabled = ctx.filename.len != 0; + var button_opts = opts.override(.{ .gravity_x = 1 }); + if (button_enabled) { + button_opts.color_style = .accent; + } else { + button_opts.color_style = .control; + button_opts.color_hover = button_opts.color(.fill); + } + if (try dvui.button(@src(), "ok", button_opts) and button_enabled) { + std.debug.print("{s}/{s}\n", .{ ctx.path, ctx.filename }); + return .exit; + } + + const tl = try dvui.textEntry(@src(), .{ .text = ctx.filename }, opts.override(.{ + .expand = .horizontal, + })); + defer tl.deinit(); + } + { + var scroll = try dvui.scrollArea(@src(), .{}, .{ .expand = .both }); + defer scroll.deinit(); + + for (ctx.entries.items, 0..) |entry, i| { + const name, const icon, const color_style: dvui.Theme.ColorStyle = switch (entry.kind) { + .directory => .{ "folder", entypo.folder, .window }, + .file => .{ "file", entypo.text_document, .control }, + else => .{ "other", entypo.help, .content }, + }; + + const id = opts.override(.{ .id_extra = i }); + const wide = id.override(.{ + .color_style = color_style, + .expand = .horizontal, + .margin = dvui.Rect.all(0), + }); + + var bw = dvui.ButtonWidget.init(@src(), .{}, wide); + try bw.install(); + bw.processEvents(); + try bw.drawBackground(); + + const m = try dvui.menu(@src(), .horizontal, id); + try dvui.icon(@src(), name, icon, id.override(.{ .gravity_y = 0.4 })); + try dvui.labelNoFmt(@src(), entry.name, id); + m.deinit(); + + var clicked = bw.clicked(); + try bw.drawFocus(); + bw.deinit(); + + if (clicked) switch (entry.kind) { + .directory => { + try std.os.chdir(entry.name); + try ctx.list_files(); + }, + else => { + gpa.free(ctx.filename); + ctx.filename = try gpa.dupe(u8, entry.name); + }, + }; + } + } + + return .ok; + } + + pub fn list_files(ctx: *Ctx) !void { + var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + const path = try std.os.realpath(".", &buf); + ctx.path = try gpa.dupe(u8, path); + + const cwd = std.fs.cwd(); + const iterable = try cwd.openIterableDir(".", .{}); + var iterator = iterable.iterate(); + + ctx.entries.clearRetainingCapacity(); + + while (try iterator.next()) |entry| { + const name = try gpa.dupe(u8, entry.name); + try ctx.entries.append(gpa, .{ .name = name, .kind = entry.kind }); + } + + const Entry = std.fs.IterableDir.Entry; + const items = ctx.entries.items; + const closures = struct { + pub fn less_than_0(_: void, l: Entry, r: Entry) bool { + return std.mem.lessThan(u8, l.name, r.name); + } + pub fn less_than_1(_: void, l: Entry, r: Entry) bool { + return @intFromEnum(l.kind) < @intFromEnum(r.kind); + } + }; + std.mem.sort(Entry, items, {}, closures.less_than_0); + std.mem.sort(Entry, items, {}, closures.less_than_1); + } +}; |