summaryrefslogtreecommitdiff
path: root/pick.zig
diff options
context:
space:
mode:
authorKitty-Cricket Piapiac <kitty@piapiac.org>2023-11-13 05:39:45 +0000
committerKitty-Cricket Piapiac <kitty@piapiac.org>2023-11-13 05:39:45 +0000
commitb43906514a78b8491ef3c25f828e23a64edc526e (patch)
treea158985fd88634ab4fad411a07ceae78e3d80be4 /pick.zig
init
Diffstat (limited to 'pick.zig')
-rw-r--r--pick.zig184
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);
+ }
+};