diff --git a/src/main.zig b/src/main.zig index 1b0b628..03bd454 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,6 +1,7 @@ const std = @import("std"); const sdl = @import("sdl.zig"); const ttf = @import("ttf.zig"); +const dirent = @cImport(@cInclude("dirent.h")); const Ui = struct { window: sdl.Window, @@ -9,7 +10,7 @@ const Ui = struct { uiFont: ttf.Font, codeFont: ttf.Font, - treeWidget: TreeWidget, + treeWidget: TreeView, pub fn init() !Ui { try sdl.init(); @@ -20,7 +21,7 @@ const Ui = struct { var uiFont = try ttf.Font.init("/usr/share/fonts/ubuntu/Ubuntu-R.ttf", 16); var codeFont = try ttf.Font.init("/usr/share/fonts/TTF/Cascadia.ttf", 16); - var treeWidget = TreeWidget.init(); + var treeWidget = TreeView.init(); return Ui{ .window = window, @@ -45,44 +46,120 @@ const Ui = struct { sdl.quit(); } - pub fn update(self: Ui) !void { + pub fn update(self: *Ui) !void { while (sdl.Event.poll()) |event| { var type_ = event.type_(); // std.debug.warn("event: {}\n", .{@tagName(type_)}); switch (type_) { .Quit => return error.Exiting, + .MouseMotion => { + var motion = event.mouseMotion().?; + self.treeWidget.mouseMotion(motion); + }, else => {}, } } } - pub fn render(self: Ui) !void { + pub fn render(self: *Ui) !void { try self.renderer.setDrawColor(.{ .r = 30, .g = 30, .b = 30 }); try self.renderer.clear(); - try self.treeWidget.render(self); + try self.treeWidget.render(self.*); self.renderer.present(); } }; -const TreeWidget = struct { - pub fn init() TreeWidget { - return .{}; +const TreeView = struct { + const Entry = struct { + name: []const u8, + texture: ?sdl.Texture = null, + y: i32, + width: i32 = 0, + height: i32 = 0, + + highlighted: bool = false, + + fn prerender(self: *Entry, ui: Ui) !void { + var surface = try ui.uiFont.renderBlended(self.name, .{ .r = 255, .g = 255, .b = 255 }); + self.texture = try ui.renderer.createTextureFromSurface(surface); + self.width = surface.width(); + self.height = surface.height(); + + // We don't need the surface anymore. + surface.deinit(); + } + + pub fn render(self: *Entry, ui: Ui) !void { + if (self.texture == null) { + try self.prerender(ui); + } + + if (self.highlighted) { + try ui.renderer.setDrawColor(.{ .r = 42, .g = 45, .b = 46 }); + try ui.renderer.fillRect(sdl.Rect{ .x = 0, .y = self.y, .w = 200, .h = 25 }); + } + + var y = @divTrunc(25 - self.height, 2); + var dst = sdl.Rect{ .x = 10, .y = self.y + y, .w = self.width, .h = self.height }; + try ui.renderer.copy(self.texture.?, null, dst); + } + + pub fn mouseMotion(self: *Entry, event: sdl.MouseMotionEvent) void { + self.highlighted = event.y > self.y and event.y < self.y + 20; + } + }; + + cursorHand: *sdl.c.SDL_Cursor, + count: u64 = 0, + + // Temporary, std.heap.c_allocator was broken, so this for now + entries: [256]Entry = undefined, + + pub fn init() TreeView { + var cursorHand = sdl.c.SDL_CreateSystemCursor(@intToEnum(sdl.c.SDL_SystemCursor, sdl.c.SDL_SYSTEM_CURSOR_HAND)).?; + sdl.c.SDL_SetCursor(cursorHand); + var self = TreeView{ .cursorHand = cursorHand }; + + self.refresh() catch unreachable; + return self; } - pub fn deinit(self: TreeWidget) void {} + pub fn deinit(self: TreeView) void { + sdl.c.SDL_FreeCursor(self.cursorHand); + for (self.entries[0..self.count]) |entry| { + if (entry.texture) |texture| { + texture.deinit(); + } + } + } - pub fn render(self: TreeWidget, ui: Ui) !void { - var surface = try ui.uiFont.renderBlended("Hello world", .{ .r = 255, .g = 255, .b = 255 }); - defer surface.deinit(); + pub fn render(self: *TreeView, ui: Ui) !void { + try ui.renderer.setDrawColor(.{ .r = 38, .g = 38, .b = 38 }); + try ui.renderer.fillRect(sdl.Rect{ .x = 0, .y = 0, .w = 200, .h = 720 }); - var texture = try ui.renderer.createTextureFromSurface(surface); - defer texture.deinit(); + for (self.entries[0..self.count]) |*entry, i| { + try entry.render(ui); + } + } - var dst = sdl.Rect{ .w = surface.width(), .h = surface.height() }; - try ui.renderer.copy(texture, null, dst); + pub fn refresh(self: *TreeView) !void { + var dir = try std.fs.cwd().openDir("./", .{ .iterate = true }); + var iterator = dir.iterate(); + var index: u31 = 0; + while (try iterator.next()) |file| { + self.entries[index] = Entry{ .name = file.name, .y = index * 25 + 10 }; + index += 1; + } + self.count = index; + } + + pub fn mouseMotion(self: *TreeView, event: sdl.MouseMotionEvent) void { + for (self.entries[0..self.count]) |*entry, i| { + entry.mouseMotion(event); + } } }; diff --git a/src/sdl.zig b/src/sdl.zig index e0ff5ed..46a496d 100644 --- a/src/sdl.zig +++ b/src/sdl.zig @@ -84,6 +84,13 @@ pub const Renderer = struct { return error.SdlError; } } + + pub fn fillRect(self: Renderer, rect: ?Rect) !void { + var dst = if (rect) |inner| &inner.c() else null; + if (c.SDL_RenderFillRect(self.renderer, dst) != 0) { + return error.SdlError; + } + } }; pub const Texture = struct { @@ -238,6 +245,17 @@ pub const EventType = enum(u32) { _, }; +pub const MouseMotionEvent = struct { + timestamp: u32, + windowId: u32, + which: u32, + state: u32, + x: i32, + y: i32, + xrel: i32, + yrel: i32, +}; + pub const Event = struct { event: c.SDL_Event, @@ -252,4 +270,22 @@ pub const Event = struct { pub fn type_(self: Event) EventType { return @intToEnum(EventType, self.event.type); } + + pub fn mouseMotion(self: Event) ?MouseMotionEvent { + if (self.type_() != .MouseMotion) { + return null; + } + + var inner = self.event.motion; + return MouseMotionEvent{ + .timestamp = inner.timestamp, + .windowId = inner.windowID, + .which = inner.which, + .state = inner.state, + .x = inner.x, + .y = inner.y, + .xrel = inner.xrel, + .yrel = inner.yrel, + }; + } }; diff --git a/src/ttf.zig b/src/ttf.zig index 4787c79..86cf83b 100644 --- a/src/ttf.zig +++ b/src/ttf.zig @@ -36,7 +36,7 @@ pub const Font = struct { c.TTF_CloseFont(self.font); } - pub fn renderBlended(self: Font, text: [:0]const u8, color: sdl.Color) !sdl.Surface { + pub fn renderBlended(self: Font, text: []const u8, color: sdl.Color) !sdl.Surface { var cText = @ptrCast([*c]const u8, text); if (c.TTF_RenderUTF8_Blended(self.font, cText, @bitCast(c.SDL_Color, color))) |surface| { return sdl.Surface{ .surface = @ptrCast(*sdl.c.SDL_Surface, surface) };