Make main code less directly dependent on termbox2

Signed-off-by: AnErrupTion <anerruption@disroot.org>
This commit is contained in:
AnErrupTion 2025-03-16 11:17:38 +01:00
parent e0ed1b4eb1
commit 1672d4a9ec
No known key found for this signature in database
9 changed files with 108 additions and 107 deletions

View File

@ -1,7 +1,7 @@
const std = @import("std"); const std = @import("std");
const Animation = @import("../tui/Animation.zig"); const Animation = @import("../tui/Animation.zig");
const Cell = @import("../tui/Cell.zig");
const TerminalBuffer = @import("../tui/TerminalBuffer.zig"); const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
const utils = @import("../tui/utils.zig");
const ColorMix = @This(); const ColorMix = @This();
@ -19,7 +19,7 @@ terminal_buffer: *TerminalBuffer,
frames: u64, frames: u64,
pattern_cos_mod: f32, pattern_cos_mod: f32,
pattern_sin_mod: f32, pattern_sin_mod: f32,
palette: [palette_len]utils.Cell, palette: [palette_len]Cell,
pub fn init(terminal_buffer: *TerminalBuffer, col1: u32, col2: u32, col3: u32) ColorMix { pub fn init(terminal_buffer: *TerminalBuffer, col1: u32, col2: u32, col3: u32) ColorMix {
return .{ return .{
@ -27,19 +27,19 @@ pub fn init(terminal_buffer: *TerminalBuffer, col1: u32, col2: u32, col3: u32) C
.frames = 0, .frames = 0,
.pattern_cos_mod = terminal_buffer.random.float(f32) * math.pi * 2.0, .pattern_cos_mod = terminal_buffer.random.float(f32) * math.pi * 2.0,
.pattern_sin_mod = terminal_buffer.random.float(f32) * math.pi * 2.0, .pattern_sin_mod = terminal_buffer.random.float(f32) * math.pi * 2.0,
.palette = [palette_len]utils.Cell{ .palette = [palette_len]Cell{
utils.initCell(0x2588, col1, col2), Cell.init(0x2588, col1, col2),
utils.initCell(0x2593, col1, col2), Cell.init(0x2593, col1, col2),
utils.initCell(0x2592, col1, col2), Cell.init(0x2592, col1, col2),
utils.initCell(0x2591, col1, col2), Cell.init(0x2591, col1, col2),
utils.initCell(0x2588, col2, col3), Cell.init(0x2588, col2, col3),
utils.initCell(0x2593, col2, col3), Cell.init(0x2593, col2, col3),
utils.initCell(0x2592, col2, col3), Cell.init(0x2592, col2, col3),
utils.initCell(0x2591, col2, col3), Cell.init(0x2591, col2, col3),
utils.initCell(0x2588, col3, col1), Cell.init(0x2588, col3, col1),
utils.initCell(0x2593, col3, col1), Cell.init(0x2593, col3, col1),
utils.initCell(0x2592, col3, col1), Cell.init(0x2592, col3, col1),
utils.initCell(0x2591, col3, col1), Cell.init(0x2591, col3, col1),
}, },
}; };
} }
@ -80,7 +80,7 @@ fn draw(self: *ColorMix) void {
} }
const cell = self.palette[@as(usize, @intFromFloat(math.floor(length(uv) * 5.0))) % palette_len]; const cell = self.palette[@as(usize, @intFromFloat(math.floor(length(uv) * 5.0))) % palette_len];
utils.putCell(x, y, cell); cell.put(x, y);
} }
} }
} }

View File

@ -1,8 +1,8 @@
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const Animation = @import("../tui/Animation.zig"); const Animation = @import("../tui/Animation.zig");
const Cell = @import("../tui/Cell.zig");
const TerminalBuffer = @import("../tui/TerminalBuffer.zig"); const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
const utils = @import("../tui/utils.zig");
const Doom = @This(); const Doom = @This();
@ -11,7 +11,7 @@ pub const STEPS = 12;
allocator: Allocator, allocator: Allocator,
terminal_buffer: *TerminalBuffer, terminal_buffer: *TerminalBuffer,
buffer: []u8, buffer: []u8,
fire: [STEPS + 1]utils.Cell, fire: [STEPS + 1]Cell,
pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, top_color: u32, middle_color: u32, bottom_color: u32) !Doom { pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, top_color: u32, middle_color: u32, bottom_color: u32) !Doom {
const buffer = try allocator.alloc(u8, terminal_buffer.width * terminal_buffer.height); const buffer = try allocator.alloc(u8, terminal_buffer.width * terminal_buffer.height);
@ -21,20 +21,20 @@ pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, top_color: u
.allocator = allocator, .allocator = allocator,
.terminal_buffer = terminal_buffer, .terminal_buffer = terminal_buffer,
.buffer = buffer, .buffer = buffer,
.fire = [_]utils.Cell{ .fire = [_]Cell{
utils.initCell(' ', 0x00000000, 0), Cell.init(' ', 0x00000000, 0),
utils.initCell(0x2591, top_color, 0), Cell.init(0x2591, top_color, 0),
utils.initCell(0x2592, top_color, 0), Cell.init(0x2592, top_color, 0),
utils.initCell(0x2593, top_color, 0), Cell.init(0x2593, top_color, 0),
utils.initCell(0x2588, top_color, 0), Cell.init(0x2588, top_color, 0),
utils.initCell(0x2591, middle_color, 2), Cell.init(0x2591, middle_color, 2),
utils.initCell(0x2592, middle_color, 2), Cell.init(0x2592, middle_color, 2),
utils.initCell(0x2593, middle_color, 2), Cell.init(0x2593, middle_color, 2),
utils.initCell(0x2588, middle_color, 2), Cell.init(0x2588, middle_color, 2),
utils.initCell(0x2591, bottom_color, 4), Cell.init(0x2591, bottom_color, 4),
utils.initCell(0x2592, bottom_color, 4), Cell.init(0x2592, bottom_color, 4),
utils.initCell(0x2593, bottom_color, 4), Cell.init(0x2593, bottom_color, 4),
utils.initCell(0x2588, bottom_color, 4), Cell.init(0x2588, bottom_color, 4),
}, },
}; };
} }
@ -73,11 +73,13 @@ fn draw(self: *Doom) void {
const dest_y = dest / self.terminal_buffer.width; const dest_y = dest / self.terminal_buffer.width;
const dest_x = dest % self.terminal_buffer.width; const dest_x = dest % self.terminal_buffer.width;
utils.putCell(dest_x, dest_y, self.fire[buffer_dest]); const dest_cell = self.fire[buffer_dest];
dest_cell.put(dest_x, dest_y);
const source_y = source / self.terminal_buffer.width; const source_y = source / self.terminal_buffer.width;
const source_x = source % self.terminal_buffer.width; const source_x = source % self.terminal_buffer.width;
utils.putCell(source_x, source_y, self.fire[buffer_source]); const source_cell = self.fire[buffer_source];
source_cell.put(source_x, source_y);
} }
} }
} }

View File

@ -1,11 +1,11 @@
const std = @import("std"); const std = @import("std");
const interop = @import("../interop.zig");
const Animation = @import("../tui/Animation.zig");
const Cell = @import("../tui/Cell.zig");
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const Random = std.Random; const Random = std.Random;
const Animation = @import("../tui/Animation.zig");
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
const utils = @import("../tui/utils.zig");
const interop = @import("../interop.zig");
const termbox = interop.termbox; const termbox = interop.termbox;
pub const FRAME_DELAY: usize = 8; pub const FRAME_DELAY: usize = 8;
@ -13,6 +13,8 @@ pub const FRAME_DELAY: usize = 8;
// Characters change mid-scroll // Characters change mid-scroll
pub const MID_SCROLL_CHANGE = true; pub const MID_SCROLL_CHANGE = true;
const DOT_HEAD_COLOR: u32 = @intCast(0x00FFFFFF | termbox.TB_BOLD); // White and bold
const Matrix = @This(); const Matrix = @This();
pub const Dot = struct { pub const Dot = struct {
@ -35,6 +37,7 @@ count: usize,
fg_ini: u32, fg_ini: u32,
min_codepoint: u16, min_codepoint: u16,
max_codepoint: u16, max_codepoint: u16,
default_cell: Cell,
pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, fg_ini: u32, min_codepoint: u16, max_codepoint: u16) !Matrix { pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, fg_ini: u32, min_codepoint: u16, max_codepoint: u16) !Matrix {
const dots = try allocator.alloc(Dot, terminal_buffer.width * (terminal_buffer.height + 1)); const dots = try allocator.alloc(Dot, terminal_buffer.width * (terminal_buffer.height + 1));
@ -52,6 +55,7 @@ pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, fg_ini: u32,
.fg_ini = fg_ini, .fg_ini = fg_ini,
.min_codepoint = min_codepoint, .min_codepoint = min_codepoint,
.max_codepoint = max_codepoint - min_codepoint, .max_codepoint = max_codepoint - min_codepoint,
.default_cell = .{ .ch = ' ', .fg = fg_ini, .bg = termbox.TB_DEFAULT },
}; };
} }
@ -153,16 +157,13 @@ fn draw(self: *Matrix) void {
var y: usize = 1; var y: usize = 1;
while (y <= self.terminal_buffer.height) : (y += 1) { while (y <= self.terminal_buffer.height) : (y += 1) {
const dot = self.dots[buf_width * y + x]; const dot = self.dots[buf_width * y + x];
const cell = if (dot.value == null or dot.value == ' ') self.default_cell else Cell{
.ch = @intCast(dot.value.?),
.fg = if (dot.is_head) DOT_HEAD_COLOR else self.fg_ini,
.bg = termbox.TB_DEFAULT,
};
var fg = self.fg_ini; cell.put(x, y - 1);
if (dot.value == null or dot.value == ' ') {
utils.putCell(x, y - 1, .{ .ch = ' ', .fg = fg, .bg = termbox.TB_DEFAULT });
continue;
}
if (dot.is_head) fg = @intCast(0x00FFFFFF | termbox.TB_BOLD); // White and bold
utils.putCell(x, y - 1, .{ .ch = @intCast(dot.value.?), .fg = fg, .bg = termbox.TB_DEFAULT });
} }
} }
} }

View File

@ -1,36 +1,35 @@
const std = @import("std"); const std = @import("std");
const interop = @import("interop.zig"); const interop = @import("interop.zig");
const utils = @import("tui/utils.zig");
const enums = @import("enums.zig"); const enums = @import("enums.zig");
const Lang = @import("bigclock/Lang.zig"); const Lang = @import("bigclock/Lang.zig");
const en = @import("bigclock/en.zig"); const en = @import("bigclock/en.zig");
const fa = @import("bigclock/fa.zig"); const fa = @import("bigclock/fa.zig");
const Cell = @import("tui/Cell.zig");
const termbox = interop.termbox;
const Bigclock = enums.Bigclock; const Bigclock = enums.Bigclock;
pub const WIDTH = Lang.WIDTH; pub const WIDTH = Lang.WIDTH;
pub const HEIGHT = Lang.HEIGHT; pub const HEIGHT = Lang.HEIGHT;
pub const SIZE = Lang.SIZE; pub const SIZE = Lang.SIZE;
pub fn clockCell(animate: bool, char: u8, fg: u32, bg: u32, bigclock: Bigclock) [SIZE]utils.Cell { pub fn clockCell(animate: bool, char: u8, fg: u32, bg: u32, bigclock: Bigclock) [SIZE]Cell {
var cells: [SIZE]utils.Cell = undefined; var cells: [SIZE]Cell = undefined;
var tv: interop.system_time.timeval = undefined; var tv: interop.system_time.timeval = undefined;
_ = interop.system_time.gettimeofday(&tv, null); _ = interop.system_time.gettimeofday(&tv, null);
const clock_chars = toBigNumber(if (animate and char == ':' and @divTrunc(tv.tv_usec, 500000) != 0) ' ' else char, bigclock); const clock_chars = toBigNumber(if (animate and char == ':' and @divTrunc(tv.tv_usec, 500000) != 0) ' ' else char, bigclock);
for (0..cells.len) |i| cells[i] = utils.initCell(clock_chars[i], fg, bg); for (0..cells.len) |i| cells[i] = Cell.init(clock_chars[i], fg, bg);
return cells; return cells;
} }
pub fn alphaBlit(x: usize, y: usize, tb_width: usize, tb_height: usize, cells: [SIZE]utils.Cell) void { pub fn alphaBlit(x: usize, y: usize, tb_width: usize, tb_height: usize, cells: [SIZE]Cell) void {
if (x + WIDTH >= tb_width or y + HEIGHT >= tb_height) return; if (x + WIDTH >= tb_width or y + HEIGHT >= tb_height) return;
for (0..HEIGHT) |yy| { for (0..HEIGHT) |yy| {
for (0..WIDTH) |xx| { for (0..WIDTH) |xx| {
const cell = cells[yy * WIDTH + xx]; const cell = cells[yy * WIDTH + xx];
if (cell.ch != 0) utils.putCell(x + xx, y + yy, cell); cell.put(x + xx, y + yy);
} }
} }
} }

View File

@ -21,7 +21,6 @@ const Lang = @import("config/Lang.zig");
const Save = @import("config/Save.zig"); const Save = @import("config/Save.zig");
const migrator = @import("config/migrator.zig"); const migrator = @import("config/migrator.zig");
const SharedError = @import("SharedError.zig"); const SharedError = @import("SharedError.zig");
const utils = @import("tui/utils.zig");
const Ini = ini.Ini; const Ini = ini.Ini;
const DisplayServer = enums.DisplayServer; const DisplayServer = enums.DisplayServer;
@ -358,15 +357,15 @@ pub fn main() !void {
const animate = config.animation != .none; const animate = config.animation != .none;
const shutdown_key = try std.fmt.parseInt(u8, config.shutdown_key[1..], 10); const shutdown_key = try std.fmt.parseInt(u8, config.shutdown_key[1..], 10);
const shutdown_len = try utils.strWidth(lang.shutdown); const shutdown_len = try TerminalBuffer.strWidth(lang.shutdown);
const restart_key = try std.fmt.parseInt(u8, config.restart_key[1..], 10); const restart_key = try std.fmt.parseInt(u8, config.restart_key[1..], 10);
const restart_len = try utils.strWidth(lang.restart); const restart_len = try TerminalBuffer.strWidth(lang.restart);
const sleep_key = try std.fmt.parseInt(u8, config.sleep_key[1..], 10); const sleep_key = try std.fmt.parseInt(u8, config.sleep_key[1..], 10);
const sleep_len = try utils.strWidth(lang.sleep); const sleep_len = try TerminalBuffer.strWidth(lang.sleep);
const brightness_down_key = if (config.brightness_down_key) |key| try std.fmt.parseInt(u8, key[1..], 10) else null; const brightness_down_key = if (config.brightness_down_key) |key| try std.fmt.parseInt(u8, key[1..], 10) else null;
const brightness_down_len = try utils.strWidth(lang.brightness_down); const brightness_down_len = try TerminalBuffer.strWidth(lang.brightness_down);
const brightness_up_key = if (config.brightness_down_key) |key| try std.fmt.parseInt(u8, key[1..], 10) else null; const brightness_up_key = if (config.brightness_down_key) |key| try std.fmt.parseInt(u8, key[1..], 10) else null;
const brightness_up_len = try utils.strWidth(lang.brightness_up); const brightness_up_len = try TerminalBuffer.strWidth(lang.brightness_up);
var event: termbox.tb_event = undefined; var event: termbox.tb_event = undefined;
var run = true; var run = true;

23
src/tui/Cell.zig Normal file
View File

@ -0,0 +1,23 @@
const interop = @import("../interop.zig");
const termbox = interop.termbox;
const Cell = @This();
ch: u32,
fg: u32,
bg: u32,
pub fn init(ch: u32, fg: u32, bg: u32) Cell {
return .{
.ch = ch,
.fg = fg,
.bg = bg,
};
}
pub fn put(self: Cell, x: usize, y: usize) void {
if (self.ch == 0) return;
_ = termbox.tb_set_cell(@intCast(x), @intCast(y), self.ch, self.fg, self.bg);
}

View File

@ -1,7 +1,7 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const interop = @import("../interop.zig"); const interop = @import("../interop.zig");
const utils = @import("utils.zig"); const Cell = @import("Cell.zig");
const Random = std.Random; const Random = std.Random;
@ -41,6 +41,7 @@ box_width: usize,
box_height: usize, box_height: usize,
margin_box_v: u8, margin_box_v: u8,
margin_box_h: u8, margin_box_h: u8,
blank_cell: Cell,
pub fn init(options: InitOptions, labels_max_length: usize, random: Random) TerminalBuffer { pub fn init(options: InitOptions, labels_max_length: usize, random: Random) TerminalBuffer {
return .{ return .{
@ -76,6 +77,7 @@ pub fn init(options: InitOptions, labels_max_length: usize, random: Random) Term
.box_height = 7 + (2 * options.margin_box_v), .box_height = 7 + (2 * options.margin_box_v),
.margin_box_v = options.margin_box_v, .margin_box_v = options.margin_box_v,
.margin_box_h = options.margin_box_h, .margin_box_h = options.margin_box_h,
.blank_cell = Cell.init(' ', options.fg, options.bg),
}; };
} }
@ -125,29 +127,27 @@ pub fn drawBoxCenter(self: *TerminalBuffer, show_borders: bool, blank_box: bool)
_ = termbox.tb_set_cell(@intCast(x1 - 1), @intCast(y2), self.box_chars.left_down, self.border_fg, self.bg); _ = termbox.tb_set_cell(@intCast(x1 - 1), @intCast(y2), self.box_chars.left_down, self.border_fg, self.bg);
_ = termbox.tb_set_cell(@intCast(x2), @intCast(y2), self.box_chars.right_down, self.border_fg, self.bg); _ = termbox.tb_set_cell(@intCast(x2), @intCast(y2), self.box_chars.right_down, self.border_fg, self.bg);
var c1 = utils.initCell(self.box_chars.top, self.border_fg, self.bg); var c1 = Cell.init(self.box_chars.top, self.border_fg, self.bg);
var c2 = utils.initCell(self.box_chars.bottom, self.border_fg, self.bg); var c2 = Cell.init(self.box_chars.bottom, self.border_fg, self.bg);
for (0..self.box_width) |i| { for (0..self.box_width) |i| {
utils.putCell(x1 + i, y1 - 1, c1); c1.put(x1 + i, y1 - 1);
utils.putCell(x1 + i, y2, c2); c2.put(x1 + i, y2);
} }
c1.ch = self.box_chars.left; c1.ch = self.box_chars.left;
c2.ch = self.box_chars.right; c2.ch = self.box_chars.right;
for (0..self.box_height) |i| { for (0..self.box_height) |i| {
utils.putCell(x1 - 1, y1 + i, c1); c1.put(x1 - 1, y1 + i);
utils.putCell(x2, y1 + i, c2); c2.put(x2, y1 + i);
} }
} }
if (blank_box) { if (blank_box) {
const blank = utils.initCell(' ', self.fg, self.bg);
for (0..self.box_height) |y| { for (0..self.box_height) |y| {
for (0..self.box_width) |x| { for (0..self.box_width) |x| {
utils.putCell(x1 + x, y1 + y, blank); self.blank_cell.put(x1 + x, y1 + y);
} }
} }
} }
@ -203,6 +203,16 @@ pub fn drawConfinedLabel(self: TerminalBuffer, text: []const u8, x: usize, y: us
} }
pub fn drawCharMultiple(self: TerminalBuffer, char: u32, x: usize, y: usize, length: usize) void { pub fn drawCharMultiple(self: TerminalBuffer, char: u32, x: usize, y: usize, length: usize) void {
const cell = utils.initCell(char, self.fg, self.bg); const cell = Cell.init(char, self.fg, self.bg);
for (0..length) |xx| utils.putCell(x + xx, y, cell); for (0..length) |xx| cell.put(x + xx, y);
}
// Every codepoint is assumed to have a width of 1.
// Since Ly is normally running in a TTY, this should be fine.
pub fn strWidth(str: []const u8) !u8 {
const utf8view = try std.unicode.Utf8View.init(str);
var utf8 = utf8view.iterator();
var i: u8 = 0;
while (utf8.nextCodepoint()) |_| i += 1;
return i;
} }

View File

@ -1,7 +1,6 @@
const std = @import("std"); const std = @import("std");
const TerminalBuffer = @import("../TerminalBuffer.zig"); const TerminalBuffer = @import("../TerminalBuffer.zig");
const generic = @import("generic.zig"); const generic = @import("generic.zig");
const utils = @import("../utils.zig");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
@ -32,7 +31,7 @@ pub fn addMessage(self: *InfoLine, text: []const u8, bg: u32, fg: u32) !void {
if (text.len == 0) return; if (text.len == 0) return;
try self.label.addItem(.{ try self.label.addItem(.{
.width = try utils.strWidth(text), .width = try TerminalBuffer.strWidth(text),
.text = text, .text = text,
.bg = bg, .bg = bg,
.fg = fg, .fg = fg,

View File

@ -1,32 +0,0 @@
const std = @import("std");
const interop = @import("../interop.zig");
const termbox = interop.termbox;
pub const Cell = struct {
ch: u32,
fg: u32,
bg: u32,
};
pub fn initCell(ch: u32, fg: u32, bg: u32) Cell {
return .{
.ch = ch,
.fg = fg,
.bg = bg,
};
}
pub fn putCell(x: usize, y: usize, cell: Cell) void {
_ = termbox.tb_set_cell(@intCast(x), @intCast(y), cell.ch, cell.fg, cell.bg);
}
// Every codepoint is assumed to have a width of 1.
// Since ly should be running in a tty, this should be fine.
pub fn strWidth(str: []const u8) !u8 {
const utf8view = try std.unicode.Utf8View.init(str);
var utf8 = utf8view.iterator();
var i: u8 = 0;
while (utf8.nextCodepoint()) |_| i += 1;
return i;
}