Implement TreeView (aka TreeWidget)

This commit is contained in:
Sijmen 2020-05-21 22:37:11 +02:00
parent 0569bb5de7
commit cfde59e2f4
Signed by: vijfhoek
GPG Key ID: DAF7821E067D9C48
3 changed files with 130 additions and 17 deletions

View File

@ -1,6 +1,7 @@
const std = @import("std"); const std = @import("std");
const sdl = @import("sdl.zig"); const sdl = @import("sdl.zig");
const ttf = @import("ttf.zig"); const ttf = @import("ttf.zig");
const dirent = @cImport(@cInclude("dirent.h"));
const Ui = struct { const Ui = struct {
window: sdl.Window, window: sdl.Window,
@ -9,7 +10,7 @@ const Ui = struct {
uiFont: ttf.Font, uiFont: ttf.Font,
codeFont: ttf.Font, codeFont: ttf.Font,
treeWidget: TreeWidget, treeWidget: TreeView,
pub fn init() !Ui { pub fn init() !Ui {
try sdl.init(); 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 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 codeFont = try ttf.Font.init("/usr/share/fonts/TTF/Cascadia.ttf", 16);
var treeWidget = TreeWidget.init(); var treeWidget = TreeView.init();
return Ui{ return Ui{
.window = window, .window = window,
@ -45,44 +46,120 @@ const Ui = struct {
sdl.quit(); sdl.quit();
} }
pub fn update(self: Ui) !void { pub fn update(self: *Ui) !void {
while (sdl.Event.poll()) |event| { while (sdl.Event.poll()) |event| {
var type_ = event.type_(); var type_ = event.type_();
// std.debug.warn("event: {}\n", .{@tagName(type_)}); // std.debug.warn("event: {}\n", .{@tagName(type_)});
switch (type_) { switch (type_) {
.Quit => return error.Exiting, .Quit => return error.Exiting,
.MouseMotion => {
var motion = event.mouseMotion().?;
self.treeWidget.mouseMotion(motion);
},
else => {}, 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.setDrawColor(.{ .r = 30, .g = 30, .b = 30 });
try self.renderer.clear(); try self.renderer.clear();
try self.treeWidget.render(self); try self.treeWidget.render(self.*);
self.renderer.present(); self.renderer.present();
} }
}; };
const TreeWidget = struct { const TreeView = struct {
pub fn init() TreeWidget { const Entry = struct {
return .{}; 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 deinit(self: TreeWidget) void {} pub fn render(self: *Entry, ui: Ui) !void {
if (self.texture == null) {
try self.prerender(ui);
}
pub fn render(self: TreeWidget, ui: Ui) !void { if (self.highlighted) {
var surface = try ui.uiFont.renderBlended("Hello world", .{ .r = 255, .g = 255, .b = 255 }); try ui.renderer.setDrawColor(.{ .r = 42, .g = 45, .b = 46 });
defer surface.deinit(); try ui.renderer.fillRect(sdl.Rect{ .x = 0, .y = self.y, .w = 200, .h = 25 });
}
var texture = try ui.renderer.createTextureFromSurface(surface); var y = @divTrunc(25 - self.height, 2);
defer texture.deinit(); var dst = sdl.Rect{ .x = 10, .y = self.y + y, .w = self.width, .h = self.height };
try ui.renderer.copy(self.texture.?, null, dst);
}
var dst = sdl.Rect{ .w = surface.width(), .h = surface.height() }; pub fn mouseMotion(self: *Entry, event: sdl.MouseMotionEvent) void {
try ui.renderer.copy(texture, null, dst); 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: 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: *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 });
for (self.entries[0..self.count]) |*entry, i| {
try entry.render(ui);
}
}
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);
}
} }
}; };

View File

@ -84,6 +84,13 @@ pub const Renderer = struct {
return error.SdlError; 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 { 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 { pub const Event = struct {
event: c.SDL_Event, event: c.SDL_Event,
@ -252,4 +270,22 @@ pub const Event = struct {
pub fn type_(self: Event) EventType { pub fn type_(self: Event) EventType {
return @intToEnum(EventType, self.event.type); 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,
};
}
}; };

View File

@ -36,7 +36,7 @@ pub const Font = struct {
c.TTF_CloseFont(self.font); 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); var cText = @ptrCast([*c]const u8, text);
if (c.TTF_RenderUTF8_Blended(self.font, cText, @bitCast(c.SDL_Color, color))) |surface| { if (c.TTF_RenderUTF8_Blended(self.font, cText, @bitCast(c.SDL_Color, color))) |surface| {
return sdl.Surface{ .surface = @ptrCast(*sdl.c.SDL_Surface, surface) }; return sdl.Surface{ .surface = @ptrCast(*sdl.c.SDL_Surface, surface) };