Files
ly/src/tui/components/generic.zig
AnErrupTion 207b352888 Add central Widget struct + clean up code
In particular, move all termbox2 usage to TerminalBuffer.zig &
keyboard.zig

Signed-off-by: AnErrupTion <anerruption@disroot.org>
2026-02-10 00:22:27 +01:00

160 lines
5.2 KiB
Zig

const std = @import("std");
const Cell = @import("../Cell.zig");
const keyboard = @import("../keyboard.zig");
const TerminalBuffer = @import("../TerminalBuffer.zig");
const Position = @import("../Position.zig");
pub fn CyclableLabel(comptime ItemType: type, comptime ChangeItemType: type) type {
return struct {
const Allocator = std.mem.Allocator;
const ItemList = std.ArrayListUnmanaged(ItemType);
const DrawItemFn = *const fn (*Self, ItemType, usize, usize, usize) void;
const ChangeItemFn = *const fn (ItemType, ?ChangeItemType) void;
const Self = @This();
allocator: Allocator,
buffer: *TerminalBuffer,
list: ItemList,
current: usize,
width: usize,
component_pos: Position,
children_pos: Position,
text_in_center: bool,
fg: u32,
bg: u32,
cursor: usize,
draw_item_fn: DrawItemFn,
change_item_fn: ?ChangeItemFn,
change_item_arg: ?ChangeItemType,
pub fn init(
allocator: Allocator,
buffer: *TerminalBuffer,
draw_item_fn: DrawItemFn,
change_item_fn: ?ChangeItemFn,
change_item_arg: ?ChangeItemType,
width: usize,
text_in_center: bool,
fg: u32,
bg: u32,
) Self {
return .{
.allocator = allocator,
.buffer = buffer,
.list = .empty,
.current = 0,
.width = width,
.component_pos = TerminalBuffer.START_POSITION,
.children_pos = TerminalBuffer.START_POSITION,
.text_in_center = text_in_center,
.fg = fg,
.bg = bg,
.cursor = 0,
.draw_item_fn = draw_item_fn,
.change_item_fn = change_item_fn,
.change_item_arg = change_item_arg,
};
}
pub fn deinit(self: *Self) void {
self.list.deinit(self.allocator);
}
pub fn positionX(self: *Self, original_pos: Position) void {
self.component_pos = original_pos;
self.cursor = self.component_pos.x + 2;
self.children_pos = original_pos.addX(self.width);
}
pub fn positionY(self: *Self, original_pos: Position) void {
self.component_pos = original_pos;
self.cursor = self.component_pos.x + 2;
self.children_pos = original_pos.addY(1);
}
pub fn positionXY(self: *Self, original_pos: Position) void {
self.component_pos = original_pos;
self.cursor = self.component_pos.x + 2;
self.children_pos = Position.init(
self.width,
1,
).add(original_pos);
}
pub fn childrenPosition(self: Self) Position {
return self.children_pos;
}
pub fn addItem(self: *Self, item: ItemType) !void {
try self.list.append(self.allocator, item);
self.current = self.list.items.len - 1;
}
pub fn handle(self: *Self, maybe_key: ?keyboard.Key, insert_mode: bool) void {
if (maybe_key) |key| {
if (key.left or (key.ctrl and key.h) or (!insert_mode and key.h)) {
self.goLeft();
} else if (key.right or (key.ctrl and key.l) or (!insert_mode and key.l)) {
self.goRight();
}
}
TerminalBuffer.setCursor(
self.component_pos.x + self.cursor + 2,
self.component_pos.y,
);
}
pub fn draw(self: *Self) void {
if (self.list.items.len == 0) return;
if (self.width < 2) return;
var left_arrow = Cell.init('<', self.fg, self.bg);
var right_arrow = Cell.init('>', self.fg, self.bg);
left_arrow.put(self.component_pos.x, self.component_pos.y);
right_arrow.put(
self.component_pos.x + self.width - 1,
self.component_pos.y,
);
const current_item = self.list.items[self.current];
const x = self.component_pos.x + 2;
const y = self.component_pos.y;
const width = self.width - 2;
@call(
.auto,
self.draw_item_fn,
.{ self, current_item, x, y, width },
);
}
fn goLeft(self: *Self) void {
self.current = if (self.current == 0) self.list.items.len - 1 else self.current - 1;
if (self.change_item_fn) |change_item_fn| {
@call(
.auto,
change_item_fn,
.{ self.list.items[self.current], self.change_item_arg },
);
}
}
fn goRight(self: *Self) void {
self.current = if (self.current == self.list.items.len - 1) 0 else self.current + 1;
if (self.change_item_fn) |change_item_fn| {
@call(
.auto,
change_item_fn,
.{ self.list.items[self.current], self.change_item_arg },
);
}
}
};
}