Implement TreeView (aka TreeWidget)
This commit is contained in:
parent
0569bb5de7
commit
cfde59e2f4
3 changed files with 130 additions and 17 deletions
109
src/main.zig
109
src/main.zig
|
@ -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 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 {
|
pub fn render(self: *TreeView, ui: Ui) !void {
|
||||||
var surface = try ui.uiFont.renderBlended("Hello world", .{ .r = 255, .g = 255, .b = 255 });
|
try ui.renderer.setDrawColor(.{ .r = 38, .g = 38, .b = 38 });
|
||||||
defer surface.deinit();
|
try ui.renderer.fillRect(sdl.Rect{ .x = 0, .y = 0, .w = 200, .h = 720 });
|
||||||
|
|
||||||
var texture = try ui.renderer.createTextureFromSurface(surface);
|
for (self.entries[0..self.count]) |*entry, i| {
|
||||||
defer texture.deinit();
|
try entry.render(ui);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var dst = sdl.Rect{ .w = surface.width(), .h = surface.height() };
|
pub fn refresh(self: *TreeView) !void {
|
||||||
try ui.renderer.copy(texture, null, dst);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
36
src/sdl.zig
36
src/sdl.zig
|
@ -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,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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) };
|
||||||
|
|
Loading…
Reference in a new issue