mirror of
https://github.com/fairyglade/ly.git
synced 2026-03-25 01:36:05 +00:00
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>
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
|
|
||||||
const Animation = @import("../tui/Animation.zig");
|
|
||||||
const Cell = @import("../tui/Cell.zig");
|
const Cell = @import("../tui/Cell.zig");
|
||||||
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
|
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
|
||||||
|
const Widget = @import("../tui/Widget.zig");
|
||||||
|
|
||||||
const ColorMix = @This();
|
const ColorMix = @This();
|
||||||
|
|
||||||
@@ -45,14 +45,17 @@ pub fn init(terminal_buffer: *TerminalBuffer, col1: u32, col2: u32, col3: u32) C
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn animation(self: *ColorMix) Animation {
|
pub fn widget(self: *ColorMix) Widget {
|
||||||
return Animation.init(self, deinit, realloc, draw);
|
return Widget.init(
|
||||||
|
self,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
draw,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinit(_: *ColorMix) void {}
|
|
||||||
|
|
||||||
fn realloc(_: *ColorMix) anyerror!void {}
|
|
||||||
|
|
||||||
fn draw(self: *ColorMix) void {
|
fn draw(self: *ColorMix) void {
|
||||||
self.frames +%= 1;
|
self.frames +%= 1;
|
||||||
const time: f32 = @as(f32, @floatFromInt(self.frames)) * time_scale;
|
const time: f32 = @as(f32, @floatFromInt(self.frames)) * time_scale;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
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 Cell = @import("../tui/Cell.zig");
|
const Cell = @import("../tui/Cell.zig");
|
||||||
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
|
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
|
||||||
|
const Widget = @import("../tui/Widget.zig");
|
||||||
|
|
||||||
const Doom = @This();
|
const Doom = @This();
|
||||||
|
|
||||||
@@ -49,15 +49,22 @@ pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, top_color: u
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn animation(self: *Doom) Animation {
|
pub fn widget(self: *Doom) Widget {
|
||||||
return Animation.init(self, deinit, realloc, draw);
|
return Widget.init(
|
||||||
|
self,
|
||||||
|
deinit,
|
||||||
|
realloc,
|
||||||
|
draw,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinit(self: *Doom) void {
|
fn deinit(self: *Doom) void {
|
||||||
self.allocator.free(self.buffer);
|
self.allocator.free(self.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn realloc(self: *Doom) anyerror!void {
|
fn realloc(self: *Doom) !void {
|
||||||
const buffer = try self.allocator.realloc(self.buffer, self.terminal_buffer.width * self.terminal_buffer.height);
|
const buffer = try self.allocator.realloc(self.buffer, self.terminal_buffer.width * self.terminal_buffer.height);
|
||||||
initBuffer(buffer, self.terminal_buffer.width);
|
initBuffer(buffer, self.terminal_buffer.width);
|
||||||
self.buffer = buffer;
|
self.buffer = buffer;
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ const LogFile = ly_core.LogFile;
|
|||||||
|
|
||||||
const enums = @import("../enums.zig");
|
const enums = @import("../enums.zig");
|
||||||
const DurOffsetAlignment = enums.DurOffsetAlignment;
|
const DurOffsetAlignment = enums.DurOffsetAlignment;
|
||||||
const Animation = @import("../tui/Animation.zig");
|
|
||||||
const Cell = @import("../tui/Cell.zig");
|
const Cell = @import("../tui/Cell.zig");
|
||||||
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
|
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
|
||||||
const Color = TerminalBuffer.Color;
|
const Color = TerminalBuffer.Color;
|
||||||
const Styling = TerminalBuffer.Styling;
|
const Styling = TerminalBuffer.Styling;
|
||||||
|
const Widget = @import("../tui/Widget.zig");
|
||||||
|
|
||||||
fn read_decompress_file(allocator: Allocator, file_path: []const u8) ![]u8 {
|
fn read_decompress_file(allocator: Allocator, file_path: []const u8) ![]u8 {
|
||||||
const file_buffer = std.fs.cwd().openFile(file_path, .{}) catch {
|
const file_buffer = std.fs.cwd().openFile(file_path, .{}) catch {
|
||||||
@@ -403,15 +403,22 @@ pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, log_file: *L
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn animation(self: *DurFile) Animation {
|
pub fn widget(self: *DurFile) Widget {
|
||||||
return Animation.init(self, deinit, realloc, draw);
|
return Widget.init(
|
||||||
|
self,
|
||||||
|
deinit,
|
||||||
|
realloc,
|
||||||
|
draw,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinit(self: *DurFile) void {
|
fn deinit(self: *DurFile) void {
|
||||||
self.dur_movie.deinit();
|
self.dur_movie.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn realloc(self: *DurFile) anyerror!void {
|
fn realloc(self: *DurFile) !void {
|
||||||
// when terminal size changes, we need to recalculate the start_pos and frame_size based on the new size
|
// when terminal size changes, we need to recalculate the start_pos and frame_size based on the new size
|
||||||
self.start_pos = calc_start_position(self.terminal_buffer, &self.dur_movie, self.offset_alignment, self.offset);
|
self.start_pos = calc_start_position(self.terminal_buffer, &self.dur_movie, self.offset_alignment, self.offset);
|
||||||
self.frame_size = calc_frame_size(self.terminal_buffer, &self.dur_movie);
|
self.frame_size = calc_frame_size(self.terminal_buffer, &self.dur_movie);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
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 Cell = @import("../tui/Cell.zig");
|
const Cell = @import("../tui/Cell.zig");
|
||||||
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
|
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
|
||||||
|
const Widget = @import("../tui/Widget.zig");
|
||||||
|
|
||||||
const GameOfLife = @This();
|
const GameOfLife = @This();
|
||||||
|
|
||||||
@@ -60,8 +60,15 @@ pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, fg_color: u3
|
|||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn animation(self: *GameOfLife) Animation {
|
pub fn widget(self: *GameOfLife) Widget {
|
||||||
return Animation.init(self, deinit, realloc, draw);
|
return Widget.init(
|
||||||
|
self,
|
||||||
|
deinit,
|
||||||
|
realloc,
|
||||||
|
draw,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinit(self: *GameOfLife) void {
|
fn deinit(self: *GameOfLife) void {
|
||||||
@@ -69,7 +76,7 @@ fn deinit(self: *GameOfLife) void {
|
|||||||
self.allocator.free(self.next_grid);
|
self.allocator.free(self.next_grid);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn realloc(self: *GameOfLife) anyerror!void {
|
fn realloc(self: *GameOfLife) !void {
|
||||||
const new_width = self.terminal_buffer.width;
|
const new_width = self.terminal_buffer.width;
|
||||||
const new_height = self.terminal_buffer.height;
|
const new_height = self.terminal_buffer.height;
|
||||||
const new_size = new_width * new_height;
|
const new_size = new_width * new_height;
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ const std = @import("std");
|
|||||||
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 Cell = @import("../tui/Cell.zig");
|
const Cell = @import("../tui/Cell.zig");
|
||||||
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
|
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
|
||||||
|
const Widget = @import("../tui/Widget.zig");
|
||||||
|
|
||||||
pub const FRAME_DELAY: usize = 8;
|
pub const FRAME_DELAY: usize = 8;
|
||||||
|
|
||||||
@@ -57,8 +57,15 @@ pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, fg: u32, hea
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn animation(self: *Matrix) Animation {
|
pub fn widget(self: *Matrix) Widget {
|
||||||
return Animation.init(self, deinit, realloc, draw);
|
return Widget.init(
|
||||||
|
self,
|
||||||
|
deinit,
|
||||||
|
realloc,
|
||||||
|
draw,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinit(self: *Matrix) void {
|
fn deinit(self: *Matrix) void {
|
||||||
@@ -66,7 +73,7 @@ fn deinit(self: *Matrix) void {
|
|||||||
self.allocator.free(self.lines);
|
self.allocator.free(self.lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn realloc(self: *Matrix) anyerror!void {
|
fn realloc(self: *Matrix) !void {
|
||||||
const dots = try self.allocator.realloc(self.dots, self.terminal_buffer.width * (self.terminal_buffer.height + 1));
|
const dots = try self.allocator.realloc(self.dots, self.terminal_buffer.width * (self.terminal_buffer.height + 1));
|
||||||
const lines = try self.allocator.realloc(self.lines, self.terminal_buffer.width);
|
const lines = try self.allocator.realloc(self.lines, self.terminal_buffer.width);
|
||||||
|
|
||||||
|
|||||||
1194
src/main.zig
1194
src/main.zig
File diff suppressed because it is too large
Load Diff
@@ -1,61 +0,0 @@
|
|||||||
const Animation = @This();
|
|
||||||
|
|
||||||
const VTable = struct {
|
|
||||||
deinit_fn: *const fn (ptr: *anyopaque) void,
|
|
||||||
realloc_fn: *const fn (ptr: *anyopaque) anyerror!void,
|
|
||||||
draw_fn: *const fn (ptr: *anyopaque) void,
|
|
||||||
};
|
|
||||||
|
|
||||||
pointer: *anyopaque,
|
|
||||||
vtable: VTable,
|
|
||||||
|
|
||||||
pub fn init(
|
|
||||||
pointer: anytype,
|
|
||||||
comptime deinit_fn: fn (ptr: @TypeOf(pointer)) void,
|
|
||||||
comptime realloc_fn: fn (ptr: @TypeOf(pointer)) anyerror!void,
|
|
||||||
comptime draw_fn: fn (ptr: @TypeOf(pointer)) void,
|
|
||||||
) Animation {
|
|
||||||
const Pointer = @TypeOf(pointer);
|
|
||||||
const Impl = struct {
|
|
||||||
pub fn deinitImpl(ptr: *anyopaque) void {
|
|
||||||
const impl: Pointer = @ptrCast(@alignCast(ptr));
|
|
||||||
return @call(.always_inline, deinit_fn, .{impl});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reallocImpl(ptr: *anyopaque) anyerror!void {
|
|
||||||
const impl: Pointer = @ptrCast(@alignCast(ptr));
|
|
||||||
return @call(.always_inline, realloc_fn, .{impl});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn drawImpl(ptr: *anyopaque) void {
|
|
||||||
const impl: Pointer = @ptrCast(@alignCast(ptr));
|
|
||||||
return @call(.always_inline, draw_fn, .{impl});
|
|
||||||
}
|
|
||||||
|
|
||||||
const vtable = VTable{
|
|
||||||
.deinit_fn = deinitImpl,
|
|
||||||
.realloc_fn = reallocImpl,
|
|
||||||
.draw_fn = drawImpl,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
return .{
|
|
||||||
.pointer = pointer,
|
|
||||||
.vtable = Impl.vtable,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *Animation) void {
|
|
||||||
const impl: @TypeOf(self.pointer) = @ptrCast(@alignCast(self.pointer));
|
|
||||||
return @call(.auto, self.vtable.deinit_fn, .{impl});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn realloc(self: *Animation) anyerror!void {
|
|
||||||
const impl: @TypeOf(self.pointer) = @ptrCast(@alignCast(self.pointer));
|
|
||||||
return @call(.auto, self.vtable.realloc_fn, .{impl});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw(self: *Animation) void {
|
|
||||||
const impl: @TypeOf(self.pointer) = @ptrCast(@alignCast(self.pointer));
|
|
||||||
return @call(.auto, self.vtable.draw_fn, .{impl});
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
const TerminalBuffer = @import("TerminalBuffer.zig");
|
const TerminalBuffer = @import("TerminalBuffer.zig");
|
||||||
const termbox = TerminalBuffer.termbox;
|
|
||||||
|
|
||||||
const Cell = @This();
|
const Cell = @This();
|
||||||
|
|
||||||
@@ -18,5 +17,5 @@ pub fn init(ch: u32, fg: u32, bg: u32) Cell {
|
|||||||
pub fn put(self: Cell, x: usize, y: usize) void {
|
pub fn put(self: Cell, x: usize, y: usize) void {
|
||||||
if (self.ch == 0) return;
|
if (self.ch == 0) return;
|
||||||
|
|
||||||
_ = termbox.tb_set_cell(@intCast(x), @intCast(y), self.ch, self.fg, self.bg);
|
TerminalBuffer.setCell(x, y, self.ch, self.fg, self.bg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,34 +144,50 @@ pub fn init(allocator: Allocator, options: InitOptions, log_file: *LogFile, rand
|
|||||||
|
|
||||||
pub fn deinit(self: *TerminalBuffer) void {
|
pub fn deinit(self: *TerminalBuffer) void {
|
||||||
self.keybinds.deinit();
|
self.keybinds.deinit();
|
||||||
TerminalBuffer.shutdownStatic();
|
TerminalBuffer.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getWidthStatic() usize {
|
pub fn getWidth() usize {
|
||||||
return @intCast(termbox.tb_width());
|
return @intCast(termbox.tb_width());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getHeightStatic() usize {
|
pub fn getHeight() usize {
|
||||||
return @intCast(termbox.tb_height());
|
return @intCast(termbox.tb_height());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setCursorStatic(x: usize, y: usize) void {
|
pub fn setCursor(x: usize, y: usize) void {
|
||||||
_ = termbox.tb_set_cursor(@intCast(x), @intCast(y));
|
_ = termbox.tb_set_cursor(@intCast(x), @intCast(y));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clearScreenStatic(clear_back_buffer: bool) !void {
|
pub fn clearScreen(clear_back_buffer: bool) !void {
|
||||||
_ = termbox.tb_clear();
|
_ = termbox.tb_clear();
|
||||||
if (clear_back_buffer) try clearBackBuffer();
|
if (clear_back_buffer) try clearBackBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shutdownStatic() void {
|
pub fn shutdown() void {
|
||||||
_ = termbox.tb_shutdown();
|
_ = termbox.tb_shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn presentBufferStatic() void {
|
pub fn presentBuffer() void {
|
||||||
_ = termbox.tb_present();
|
_ = termbox.tb_present();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn setCell(
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
ch: u32,
|
||||||
|
fg: u32,
|
||||||
|
bg: u32,
|
||||||
|
) void {
|
||||||
|
_ = termbox.tb_set_cell(
|
||||||
|
@intCast(x),
|
||||||
|
@intCast(y),
|
||||||
|
ch,
|
||||||
|
fg,
|
||||||
|
bg,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn reclaim(self: TerminalBuffer) !void {
|
pub fn reclaim(self: TerminalBuffer) !void {
|
||||||
if (self.termios) |termios| {
|
if (self.termios) |termios| {
|
||||||
// Take back control of the TTY
|
// Take back control of the TTY
|
||||||
@@ -257,17 +273,22 @@ pub fn handleKeybind(
|
|||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
tb_event: termbox.tb_event,
|
tb_event: termbox.tb_event,
|
||||||
context: *anyopaque,
|
context: *anyopaque,
|
||||||
) !bool {
|
) !?std.ArrayList(keyboard.Key) {
|
||||||
var keys = try keyboard.getKeyList(allocator, tb_event);
|
var keys = try keyboard.getKeyList(allocator, tb_event);
|
||||||
defer keys.deinit(allocator);
|
|
||||||
|
|
||||||
for (keys.items) |key| {
|
for (keys.items) |key| {
|
||||||
if (self.keybinds.get(key)) |callback| {
|
if (self.keybinds.get(key)) |callback| {
|
||||||
return @call(.auto, callback, .{context});
|
const passthrough_event = try @call(.auto, callback, .{context});
|
||||||
|
if (!passthrough_event) {
|
||||||
|
keys.deinit(allocator);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drawText(
|
pub fn drawText(
|
||||||
|
|||||||
150
src/tui/Widget.zig
Normal file
150
src/tui/Widget.zig
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
const Widget = @This();
|
||||||
|
|
||||||
|
const keyboard = @import("keyboard.zig");
|
||||||
|
const TerminalBuffer = @import("TerminalBuffer.zig");
|
||||||
|
|
||||||
|
const VTable = struct {
|
||||||
|
deinit_fn: *const fn (ptr: *anyopaque) void,
|
||||||
|
realloc_fn: *const fn (ptr: *anyopaque) anyerror!void,
|
||||||
|
draw_fn: *const fn (ptr: *anyopaque) void,
|
||||||
|
update_fn: *const fn (ptr: *anyopaque, ctx: *anyopaque) anyerror!void,
|
||||||
|
handle_fn: *const fn (ptr: *anyopaque, maybe_key: ?keyboard.Key, insert_mode: bool) anyerror!void,
|
||||||
|
};
|
||||||
|
|
||||||
|
pointer: *anyopaque,
|
||||||
|
vtable: VTable,
|
||||||
|
|
||||||
|
pub fn init(
|
||||||
|
pointer: anytype,
|
||||||
|
comptime deinit_fn: ?fn (ptr: @TypeOf(pointer)) void,
|
||||||
|
comptime realloc_fn: ?fn (ptr: @TypeOf(pointer)) anyerror!void,
|
||||||
|
comptime draw_fn: ?fn (ptr: @TypeOf(pointer)) void,
|
||||||
|
comptime update_fn: ?fn (ptr: @TypeOf(pointer), ctx: *anyopaque) anyerror!void,
|
||||||
|
comptime handle_fn: ?fn (ptr: @TypeOf(pointer), maybe_key: ?keyboard.Key, insert_mode: bool) anyerror!void,
|
||||||
|
) Widget {
|
||||||
|
const Pointer = @TypeOf(pointer);
|
||||||
|
const Impl = struct {
|
||||||
|
pub fn deinitImpl(ptr: *anyopaque) void {
|
||||||
|
const impl: Pointer = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
if (deinit_fn) |func| {
|
||||||
|
return @call(
|
||||||
|
.always_inline,
|
||||||
|
func,
|
||||||
|
.{impl},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reallocImpl(ptr: *anyopaque) !void {
|
||||||
|
const impl: Pointer = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
if (realloc_fn) |func| {
|
||||||
|
return @call(
|
||||||
|
.always_inline,
|
||||||
|
func,
|
||||||
|
.{impl},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawImpl(ptr: *anyopaque) void {
|
||||||
|
const impl: Pointer = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
if (draw_fn) |func| {
|
||||||
|
return @call(
|
||||||
|
.always_inline,
|
||||||
|
func,
|
||||||
|
.{impl},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn updateImpl(ptr: *anyopaque, ctx: *anyopaque) !void {
|
||||||
|
const impl: Pointer = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
if (update_fn) |func| {
|
||||||
|
return @call(
|
||||||
|
.always_inline,
|
||||||
|
func,
|
||||||
|
.{ impl, ctx },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handleImpl(ptr: *anyopaque, maybe_key: ?keyboard.Key, insert_mode: bool) !void {
|
||||||
|
const impl: Pointer = @ptrCast(@alignCast(ptr));
|
||||||
|
|
||||||
|
if (handle_fn) |func| {
|
||||||
|
return @call(
|
||||||
|
.always_inline,
|
||||||
|
func,
|
||||||
|
.{ impl, maybe_key, insert_mode },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const vtable = VTable{
|
||||||
|
.deinit_fn = deinitImpl,
|
||||||
|
.realloc_fn = reallocImpl,
|
||||||
|
.draw_fn = drawImpl,
|
||||||
|
.update_fn = updateImpl,
|
||||||
|
.handle_fn = handleImpl,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.pointer = pointer,
|
||||||
|
.vtable = Impl.vtable,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Widget) void {
|
||||||
|
const impl: @TypeOf(self.pointer) = @ptrCast(@alignCast(self.pointer));
|
||||||
|
|
||||||
|
return @call(
|
||||||
|
.auto,
|
||||||
|
self.vtable.deinit_fn,
|
||||||
|
.{impl},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn realloc(self: *Widget) !void {
|
||||||
|
const impl: @TypeOf(self.pointer) = @ptrCast(@alignCast(self.pointer));
|
||||||
|
|
||||||
|
return @call(
|
||||||
|
.auto,
|
||||||
|
self.vtable.realloc_fn,
|
||||||
|
.{impl},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(self: *Widget) void {
|
||||||
|
const impl: @TypeOf(self.pointer) = @ptrCast(@alignCast(self.pointer));
|
||||||
|
|
||||||
|
return @call(
|
||||||
|
.auto,
|
||||||
|
self.vtable.draw_fn,
|
||||||
|
.{impl},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(self: *Widget, ctx: *anyopaque) !void {
|
||||||
|
const impl: @TypeOf(self.pointer) = @ptrCast(@alignCast(self.pointer));
|
||||||
|
|
||||||
|
return @call(
|
||||||
|
.auto,
|
||||||
|
self.vtable.update_fn,
|
||||||
|
.{ impl, ctx },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle(self: *Widget, maybe_key: ?keyboard.Key, insert_mode: bool) !void {
|
||||||
|
const impl: @TypeOf(self.pointer) = @ptrCast(@alignCast(self.pointer));
|
||||||
|
|
||||||
|
return @call(
|
||||||
|
.auto,
|
||||||
|
self.vtable.handle_fn,
|
||||||
|
.{ impl, maybe_key, insert_mode },
|
||||||
|
);
|
||||||
|
}
|
||||||
215
src/tui/components/BigLabel.zig
Normal file
215
src/tui/components/BigLabel.zig
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
const BigLabel = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const ly_core = @import("ly-core");
|
||||||
|
const interop = ly_core.interop;
|
||||||
|
|
||||||
|
const en = @import("bigLabelLocales/en.zig");
|
||||||
|
const fa = @import("bigLabelLocales/fa.zig");
|
||||||
|
const Cell = @import("../Cell.zig");
|
||||||
|
const Position = @import("../Position.zig");
|
||||||
|
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
||||||
|
const Widget = @import("../Widget.zig");
|
||||||
|
|
||||||
|
pub const CHAR_WIDTH = 5;
|
||||||
|
pub const CHAR_HEIGHT = 5;
|
||||||
|
pub const CHAR_SIZE = CHAR_WIDTH * CHAR_HEIGHT;
|
||||||
|
pub const X: u32 = if (ly_core.interop.supportsUnicode()) 0x2593 else '#';
|
||||||
|
pub const O: u32 = 0;
|
||||||
|
|
||||||
|
// zig fmt: off
|
||||||
|
pub const LocaleChars = struct {
|
||||||
|
ZERO: [CHAR_SIZE]u21,
|
||||||
|
ONE: [CHAR_SIZE]u21,
|
||||||
|
TWO: [CHAR_SIZE]u21,
|
||||||
|
THREE: [CHAR_SIZE]u21,
|
||||||
|
FOUR: [CHAR_SIZE]u21,
|
||||||
|
FIVE: [CHAR_SIZE]u21,
|
||||||
|
SIX: [CHAR_SIZE]u21,
|
||||||
|
SEVEN: [CHAR_SIZE]u21,
|
||||||
|
EIGHT: [CHAR_SIZE]u21,
|
||||||
|
NINE: [CHAR_SIZE]u21,
|
||||||
|
S: [CHAR_SIZE]u21,
|
||||||
|
E: [CHAR_SIZE]u21,
|
||||||
|
P: [CHAR_SIZE]u21,
|
||||||
|
A: [CHAR_SIZE]u21,
|
||||||
|
M: [CHAR_SIZE]u21,
|
||||||
|
};
|
||||||
|
// zig fmt: on
|
||||||
|
|
||||||
|
pub const BigLabelLocale = enum {
|
||||||
|
en,
|
||||||
|
fa,
|
||||||
|
};
|
||||||
|
|
||||||
|
allocator: ?Allocator = null,
|
||||||
|
buffer: *TerminalBuffer,
|
||||||
|
text: []const u8,
|
||||||
|
max_width: ?usize,
|
||||||
|
fg: u32,
|
||||||
|
bg: u32,
|
||||||
|
locale: BigLabelLocale,
|
||||||
|
update_fn: ?*const fn (*BigLabel, *anyopaque) anyerror!void,
|
||||||
|
component_pos: Position,
|
||||||
|
children_pos: Position,
|
||||||
|
|
||||||
|
pub fn init(
|
||||||
|
buffer: *TerminalBuffer,
|
||||||
|
text: []const u8,
|
||||||
|
max_width: ?usize,
|
||||||
|
fg: u32,
|
||||||
|
bg: u32,
|
||||||
|
locale: BigLabelLocale,
|
||||||
|
update_fn: ?*const fn (*BigLabel, *anyopaque) anyerror!void,
|
||||||
|
) BigLabel {
|
||||||
|
return .{
|
||||||
|
.allocator = null,
|
||||||
|
.buffer = buffer,
|
||||||
|
.text = text,
|
||||||
|
.max_width = max_width,
|
||||||
|
.fg = fg,
|
||||||
|
.bg = bg,
|
||||||
|
.locale = locale,
|
||||||
|
.update_fn = update_fn,
|
||||||
|
.component_pos = TerminalBuffer.START_POSITION,
|
||||||
|
.children_pos = TerminalBuffer.START_POSITION,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *BigLabel) void {
|
||||||
|
if (self.allocator) |allocator| allocator.free(self.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn widget(self: *BigLabel) Widget {
|
||||||
|
return Widget.init(
|
||||||
|
self,
|
||||||
|
deinit,
|
||||||
|
null,
|
||||||
|
draw,
|
||||||
|
update,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setTextAlloc(
|
||||||
|
self: *BigLabel,
|
||||||
|
allocator: Allocator,
|
||||||
|
comptime fmt: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) !void {
|
||||||
|
self.text = try std.fmt.allocPrint(allocator, fmt, args);
|
||||||
|
self.allocator = allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setTextBuf(
|
||||||
|
self: *BigLabel,
|
||||||
|
buffer: []u8,
|
||||||
|
comptime fmt: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) !void {
|
||||||
|
self.text = try std.fmt.bufPrint(buffer, fmt, args);
|
||||||
|
self.allocator = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setText(self: *BigLabel, text: []const u8) void {
|
||||||
|
self.text = text;
|
||||||
|
self.allocator = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn positionX(self: *BigLabel, original_pos: Position) void {
|
||||||
|
self.component_pos = original_pos;
|
||||||
|
self.children_pos = original_pos.addX(TerminalBuffer.strWidth(self.text) * CHAR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn positionY(self: *BigLabel, original_pos: Position) void {
|
||||||
|
self.component_pos = original_pos;
|
||||||
|
self.children_pos = original_pos.addY(CHAR_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn positionXY(self: *BigLabel, original_pos: Position) void {
|
||||||
|
self.component_pos = original_pos;
|
||||||
|
self.children_pos = Position.init(
|
||||||
|
TerminalBuffer.strWidth(self.text) * CHAR_WIDTH,
|
||||||
|
CHAR_HEIGHT,
|
||||||
|
).add(original_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn childrenPosition(self: BigLabel) Position {
|
||||||
|
return self.children_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(self: *BigLabel) void {
|
||||||
|
for (self.text, 0..) |c, i| {
|
||||||
|
const clock_cell = clockCell(
|
||||||
|
c,
|
||||||
|
self.fg,
|
||||||
|
self.bg,
|
||||||
|
self.locale,
|
||||||
|
);
|
||||||
|
|
||||||
|
alphaBlit(
|
||||||
|
self.component_pos.x + i * (CHAR_WIDTH + 1),
|
||||||
|
self.component_pos.y,
|
||||||
|
self.buffer.width,
|
||||||
|
self.buffer.height,
|
||||||
|
clock_cell,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(self: *BigLabel, context: *anyopaque) !void {
|
||||||
|
if (self.update_fn) |update_fn| {
|
||||||
|
return @call(
|
||||||
|
.auto,
|
||||||
|
update_fn,
|
||||||
|
.{ self, context },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clockCell(char: u8, fg: u32, bg: u32, locale: BigLabelLocale) [CHAR_SIZE]Cell {
|
||||||
|
var cells: [CHAR_SIZE]Cell = undefined;
|
||||||
|
|
||||||
|
//@divTrunc(time.microseconds, 500000) != 0)
|
||||||
|
const clock_chars = toBigNumber(char, locale);
|
||||||
|
for (0..cells.len) |i| cells[i] = Cell.init(clock_chars[i], fg, bg);
|
||||||
|
|
||||||
|
return cells;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alphaBlit(x: usize, y: usize, tb_width: usize, tb_height: usize, cells: [CHAR_SIZE]Cell) void {
|
||||||
|
if (x + CHAR_WIDTH >= tb_width or y + CHAR_HEIGHT >= tb_height) return;
|
||||||
|
|
||||||
|
for (0..CHAR_HEIGHT) |yy| {
|
||||||
|
for (0..CHAR_WIDTH) |xx| {
|
||||||
|
const cell = cells[yy * CHAR_WIDTH + xx];
|
||||||
|
cell.put(x + xx, y + yy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toBigNumber(char: u8, locale: BigLabelLocale) [CHAR_SIZE]u21 {
|
||||||
|
const locale_chars = switch (locale) {
|
||||||
|
.fa => fa.locale_chars,
|
||||||
|
.en => en.locale_chars,
|
||||||
|
};
|
||||||
|
return switch (char) {
|
||||||
|
'0' => locale_chars.ZERO,
|
||||||
|
'1' => locale_chars.ONE,
|
||||||
|
'2' => locale_chars.TWO,
|
||||||
|
'3' => locale_chars.THREE,
|
||||||
|
'4' => locale_chars.FOUR,
|
||||||
|
'5' => locale_chars.FIVE,
|
||||||
|
'6' => locale_chars.SIX,
|
||||||
|
'7' => locale_chars.SEVEN,
|
||||||
|
'8' => locale_chars.EIGHT,
|
||||||
|
'9' => locale_chars.NINE,
|
||||||
|
'p', 'P' => locale_chars.P,
|
||||||
|
'a', 'A' => locale_chars.A,
|
||||||
|
'm', 'M' => locale_chars.M,
|
||||||
|
':' => locale_chars.S,
|
||||||
|
else => locale_chars.E,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ const std = @import("std");
|
|||||||
const Cell = @import("../Cell.zig");
|
const Cell = @import("../Cell.zig");
|
||||||
const Position = @import("../Position.zig");
|
const Position = @import("../Position.zig");
|
||||||
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
||||||
const termbox = TerminalBuffer.termbox;
|
const Widget = @import("../Widget.zig");
|
||||||
|
|
||||||
const CenteredBox = @This();
|
const CenteredBox = @This();
|
||||||
|
|
||||||
@@ -56,6 +56,17 @@ pub fn init(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn widget(self: *CenteredBox) Widget {
|
||||||
|
return Widget.init(
|
||||||
|
self,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
draw,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn positionXY(self: *CenteredBox, original_pos: Position) void {
|
pub fn positionXY(self: *CenteredBox, original_pos: Position) void {
|
||||||
if (self.buffer.width < 2 or self.buffer.height < 2) return;
|
if (self.buffer.width < 2 or self.buffer.height < 2) return;
|
||||||
|
|
||||||
@@ -79,51 +90,55 @@ pub fn childrenPosition(self: CenteredBox) Position {
|
|||||||
return self.children_pos;
|
return self.children_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(self: CenteredBox) void {
|
pub fn draw(self: *CenteredBox) void {
|
||||||
if (self.show_borders) {
|
if (self.show_borders) {
|
||||||
_ = termbox.tb_set_cell(
|
var left_up = Cell.init(
|
||||||
@intCast(self.left_pos.x - 1),
|
|
||||||
@intCast(self.left_pos.y - 1),
|
|
||||||
self.buffer.box_chars.left_up,
|
self.buffer.box_chars.left_up,
|
||||||
self.border_fg,
|
self.border_fg,
|
||||||
self.bg,
|
self.bg,
|
||||||
);
|
);
|
||||||
_ = termbox.tb_set_cell(
|
var right_up = Cell.init(
|
||||||
@intCast(self.right_pos.x),
|
|
||||||
@intCast(self.left_pos.y - 1),
|
|
||||||
self.buffer.box_chars.right_up,
|
self.buffer.box_chars.right_up,
|
||||||
self.border_fg,
|
self.border_fg,
|
||||||
self.bg,
|
self.bg,
|
||||||
);
|
);
|
||||||
_ = termbox.tb_set_cell(
|
var left_down = Cell.init(
|
||||||
@intCast(self.left_pos.x - 1),
|
|
||||||
@intCast(self.right_pos.y),
|
|
||||||
self.buffer.box_chars.left_down,
|
self.buffer.box_chars.left_down,
|
||||||
self.border_fg,
|
self.border_fg,
|
||||||
self.bg,
|
self.bg,
|
||||||
);
|
);
|
||||||
_ = termbox.tb_set_cell(
|
var right_down = Cell.init(
|
||||||
@intCast(self.right_pos.x),
|
|
||||||
@intCast(self.right_pos.y),
|
|
||||||
self.buffer.box_chars.right_down,
|
self.buffer.box_chars.right_down,
|
||||||
self.border_fg,
|
self.border_fg,
|
||||||
self.bg,
|
self.bg,
|
||||||
);
|
);
|
||||||
|
var top = Cell.init(
|
||||||
|
self.buffer.box_chars.top,
|
||||||
|
self.border_fg,
|
||||||
|
self.bg,
|
||||||
|
);
|
||||||
|
var bottom = Cell.init(
|
||||||
|
self.buffer.box_chars.bottom,
|
||||||
|
self.border_fg,
|
||||||
|
self.bg,
|
||||||
|
);
|
||||||
|
|
||||||
var c1 = Cell.init(self.buffer.box_chars.top, self.border_fg, self.bg);
|
left_up.put(self.left_pos.x - 1, self.left_pos.y - 1);
|
||||||
var c2 = Cell.init(self.buffer.box_chars.bottom, self.border_fg, self.bg);
|
right_up.put(self.right_pos.x, self.left_pos.y - 1);
|
||||||
|
left_down.put(self.left_pos.x - 1, self.right_pos.y);
|
||||||
|
right_down.put(self.right_pos.x, self.right_pos.y);
|
||||||
|
|
||||||
for (0..self.width) |i| {
|
for (0..self.width) |i| {
|
||||||
c1.put(self.left_pos.x + i, self.left_pos.y - 1);
|
top.put(self.left_pos.x + i, self.left_pos.y - 1);
|
||||||
c2.put(self.left_pos.x + i, self.right_pos.y);
|
bottom.put(self.left_pos.x + i, self.right_pos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
c1.ch = self.buffer.box_chars.left;
|
top.ch = self.buffer.box_chars.left;
|
||||||
c2.ch = self.buffer.box_chars.right;
|
bottom.ch = self.buffer.box_chars.right;
|
||||||
|
|
||||||
for (0..self.height) |i| {
|
for (0..self.height) |i| {
|
||||||
c1.put(self.left_pos.x - 1, self.left_pos.y + i);
|
top.put(self.left_pos.x - 1, self.left_pos.y + i);
|
||||||
c2.put(self.right_pos.x, self.left_pos.y + i);
|
bottom.put(self.right_pos.x, self.left_pos.y + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const keyboard = @import("../keyboard.zig");
|
||||||
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
||||||
|
const Widget = @import("../Widget.zig");
|
||||||
const generic = @import("generic.zig");
|
const generic = @import("generic.zig");
|
||||||
|
|
||||||
const MessageLabel = generic.CyclableLabel(Message, Message);
|
const MessageLabel = generic.CyclableLabel(Message, Message);
|
||||||
@@ -43,6 +45,25 @@ pub fn deinit(self: *InfoLine) void {
|
|||||||
self.label.deinit();
|
self.label.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn widget(self: *InfoLine) Widget {
|
||||||
|
return Widget.init(
|
||||||
|
self,
|
||||||
|
deinit,
|
||||||
|
null,
|
||||||
|
draw,
|
||||||
|
null,
|
||||||
|
handle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(self: *InfoLine) void {
|
||||||
|
self.label.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle(self: *InfoLine, maybe_key: ?keyboard.Key, insert_mode: bool) !void {
|
||||||
|
self.label.handle(maybe_key, insert_mode);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn addMessage(self: *InfoLine, text: []const u8, bg: u32, fg: u32) !void {
|
pub fn addMessage(self: *InfoLine, text: []const u8, bg: u32, fg: u32) !void {
|
||||||
if (text.len == 0) return;
|
if (text.len == 0) return;
|
||||||
|
|
||||||
|
|||||||
131
src/tui/components/Label.zig
Normal file
131
src/tui/components/Label.zig
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
const Label = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const Cell = @import("../Cell.zig");
|
||||||
|
const Position = @import("../Position.zig");
|
||||||
|
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
||||||
|
const Widget = @import("../Widget.zig");
|
||||||
|
|
||||||
|
allocator: ?Allocator,
|
||||||
|
text: []const u8,
|
||||||
|
max_width: ?usize,
|
||||||
|
fg: u32,
|
||||||
|
bg: u32,
|
||||||
|
update_fn: ?*const fn (*Label, *anyopaque) anyerror!void,
|
||||||
|
component_pos: Position,
|
||||||
|
children_pos: Position,
|
||||||
|
|
||||||
|
pub fn init(
|
||||||
|
text: []const u8,
|
||||||
|
max_width: ?usize,
|
||||||
|
fg: u32,
|
||||||
|
bg: u32,
|
||||||
|
update_fn: ?*const fn (*Label, *anyopaque) anyerror!void,
|
||||||
|
) Label {
|
||||||
|
return .{
|
||||||
|
.allocator = null,
|
||||||
|
.text = text,
|
||||||
|
.max_width = max_width,
|
||||||
|
.fg = fg,
|
||||||
|
.bg = bg,
|
||||||
|
.update_fn = update_fn,
|
||||||
|
.component_pos = TerminalBuffer.START_POSITION,
|
||||||
|
.children_pos = TerminalBuffer.START_POSITION,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Label) void {
|
||||||
|
if (self.allocator) |allocator| allocator.free(self.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn widget(self: *Label) Widget {
|
||||||
|
return Widget.init(
|
||||||
|
self,
|
||||||
|
deinit,
|
||||||
|
null,
|
||||||
|
draw,
|
||||||
|
update,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setTextAlloc(
|
||||||
|
self: *Label,
|
||||||
|
allocator: Allocator,
|
||||||
|
comptime fmt: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) !void {
|
||||||
|
self.text = try std.fmt.allocPrint(allocator, fmt, args);
|
||||||
|
self.allocator = allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setTextBuf(
|
||||||
|
self: *Label,
|
||||||
|
buffer: []u8,
|
||||||
|
comptime fmt: []const u8,
|
||||||
|
args: anytype,
|
||||||
|
) !void {
|
||||||
|
self.text = try std.fmt.bufPrint(buffer, fmt, args);
|
||||||
|
self.allocator = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setText(self: *Label, text: []const u8) void {
|
||||||
|
self.text = text;
|
||||||
|
self.allocator = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn positionX(self: *Label, original_pos: Position) void {
|
||||||
|
self.component_pos = original_pos;
|
||||||
|
self.children_pos = original_pos.addX(TerminalBuffer.strWidth(self.text));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn positionY(self: *Label, original_pos: Position) void {
|
||||||
|
self.component_pos = original_pos;
|
||||||
|
self.children_pos = original_pos.addY(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn positionXY(self: *Label, original_pos: Position) void {
|
||||||
|
self.component_pos = original_pos;
|
||||||
|
self.children_pos = Position.init(
|
||||||
|
TerminalBuffer.strWidth(self.text),
|
||||||
|
1,
|
||||||
|
).add(original_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn childrenPosition(self: Label) Position {
|
||||||
|
return self.children_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(self: *Label) void {
|
||||||
|
if (self.max_width) |width| {
|
||||||
|
TerminalBuffer.drawConfinedText(
|
||||||
|
self.text,
|
||||||
|
self.component_pos.x,
|
||||||
|
self.component_pos.y,
|
||||||
|
width,
|
||||||
|
self.fg,
|
||||||
|
self.bg,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TerminalBuffer.drawText(
|
||||||
|
self.text,
|
||||||
|
self.component_pos.x,
|
||||||
|
self.component_pos.y,
|
||||||
|
self.fg,
|
||||||
|
self.bg,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(self: *Label, ctx: *anyopaque) !void {
|
||||||
|
if (self.update_fn) |update_fn| {
|
||||||
|
return @call(
|
||||||
|
.auto,
|
||||||
|
update_fn,
|
||||||
|
.{ self, ctx },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,9 @@ const Allocator = std.mem.Allocator;
|
|||||||
const enums = @import("../../enums.zig");
|
const enums = @import("../../enums.zig");
|
||||||
const DisplayServer = enums.DisplayServer;
|
const DisplayServer = enums.DisplayServer;
|
||||||
const Environment = @import("../../Environment.zig");
|
const Environment = @import("../../Environment.zig");
|
||||||
|
const keyboard = @import("../keyboard.zig");
|
||||||
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
||||||
|
const Widget = @import("../Widget.zig");
|
||||||
const generic = @import("generic.zig");
|
const generic = @import("generic.zig");
|
||||||
const UserList = @import("UserList.zig");
|
const UserList = @import("UserList.zig");
|
||||||
|
|
||||||
@@ -53,6 +55,25 @@ pub fn deinit(self: *Session) void {
|
|||||||
self.label.deinit();
|
self.label.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn widget(self: *Session) Widget {
|
||||||
|
return Widget.init(
|
||||||
|
self,
|
||||||
|
deinit,
|
||||||
|
null,
|
||||||
|
draw,
|
||||||
|
null,
|
||||||
|
handle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(self: *Session) void {
|
||||||
|
self.label.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle(self: *Session, maybe_key: ?keyboard.Key, insert_mode: bool) !void {
|
||||||
|
self.label.handle(maybe_key, insert_mode);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn addEnvironment(self: *Session, environment: Environment) !void {
|
pub fn addEnvironment(self: *Session, environment: Environment) !void {
|
||||||
const env = Env{ .environment = environment, .index = self.label.list.items.len };
|
const env = Env{ .environment = environment, .index = self.label.list.items.len };
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const keyboard = @import("../keyboard.zig");
|
||||||
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
||||||
const Position = @import("../Position.zig");
|
const Position = @import("../Position.zig");
|
||||||
const termbox = TerminalBuffer.termbox;
|
const Widget = @import("../Widget.zig");
|
||||||
|
|
||||||
const DynamicString = std.ArrayListUnmanaged(u8);
|
const DynamicString = std.ArrayListUnmanaged(u8);
|
||||||
|
|
||||||
@@ -53,6 +54,17 @@ pub fn deinit(self: *Text) void {
|
|||||||
self.text.deinit(self.allocator);
|
self.text.deinit(self.allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn widget(self: *Text) Widget {
|
||||||
|
return Widget.init(
|
||||||
|
self,
|
||||||
|
deinit,
|
||||||
|
null,
|
||||||
|
draw,
|
||||||
|
null,
|
||||||
|
handle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn positionX(self: *Text, original_pos: Position) void {
|
pub fn positionX(self: *Text, original_pos: Position) void {
|
||||||
self.component_pos = original_pos;
|
self.component_pos = original_pos;
|
||||||
self.children_pos = original_pos.addX(self.width);
|
self.children_pos = original_pos.addX(self.width);
|
||||||
@@ -75,50 +87,37 @@ pub fn childrenPosition(self: Text) Position {
|
|||||||
return self.children_pos;
|
return self.children_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle(self: *Text, maybe_event: ?*termbox.tb_event, insert_mode: bool) !void {
|
pub fn handle(self: *Text, maybe_key: ?keyboard.Key, insert_mode: bool) !void {
|
||||||
if (maybe_event) |event| blk: {
|
if (maybe_key) |key| {
|
||||||
if (event.type != termbox.TB_EVENT_KEY) break :blk;
|
if (key.left or (!insert_mode and (key.h or key.backspace))) {
|
||||||
|
self.goLeft();
|
||||||
switch (event.key) {
|
} else if (key.right or (!insert_mode and key.l)) {
|
||||||
termbox.TB_KEY_ARROW_LEFT => self.goLeft(),
|
self.goRight();
|
||||||
termbox.TB_KEY_ARROW_RIGHT => self.goRight(),
|
} else if (key.delete) {
|
||||||
termbox.TB_KEY_DELETE => self.delete(),
|
self.delete();
|
||||||
termbox.TB_KEY_BACKSPACE, termbox.TB_KEY_BACKSPACE2 => {
|
} else if (key.backspace) {
|
||||||
if (insert_mode) {
|
self.backspace();
|
||||||
self.backspace();
|
} else if (insert_mode) {
|
||||||
} else {
|
const maybe_character = key.getEnabledPrintableAscii();
|
||||||
self.goLeft();
|
if (maybe_character) |character| try self.write(character);
|
||||||
}
|
|
||||||
},
|
|
||||||
termbox.TB_KEY_SPACE => try self.write(' '),
|
|
||||||
else => {
|
|
||||||
if (event.ch > 31 and event.ch < 127) {
|
|
||||||
if (insert_mode) {
|
|
||||||
try self.write(@intCast(event.ch));
|
|
||||||
} else {
|
|
||||||
switch (event.ch) {
|
|
||||||
'h' => self.goLeft(),
|
|
||||||
'l' => self.goRight(),
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.masked and self.maybe_mask == null) {
|
if (self.masked and self.maybe_mask == null) {
|
||||||
_ = termbox.tb_set_cursor(@intCast(self.component_pos.x), @intCast(self.component_pos.y));
|
TerminalBuffer.setCursor(
|
||||||
|
self.component_pos.x,
|
||||||
|
self.component_pos.y,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = termbox.tb_set_cursor(
|
TerminalBuffer.setCursor(
|
||||||
@intCast(self.component_pos.x + (self.cursor - self.visible_start)),
|
self.component_pos.x + (self.cursor - self.visible_start),
|
||||||
@intCast(self.component_pos.y),
|
self.component_pos.y,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(self: Text) void {
|
pub fn draw(self: *Text) void {
|
||||||
if (self.masked) {
|
if (self.masked) {
|
||||||
if (self.maybe_mask) |mask| {
|
if (self.maybe_mask) |mask| {
|
||||||
if (self.width < 1) return;
|
if (self.width < 1) return;
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ const std = @import("std");
|
|||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
const SavedUsers = @import("../../config/SavedUsers.zig");
|
const SavedUsers = @import("../../config/SavedUsers.zig");
|
||||||
|
const keyboard = @import("../keyboard.zig");
|
||||||
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
||||||
|
const Widget = @import("../Widget.zig");
|
||||||
const generic = @import("generic.zig");
|
const generic = @import("generic.zig");
|
||||||
const Session = @import("Session.zig");
|
const Session = @import("Session.zig");
|
||||||
|
|
||||||
@@ -85,10 +87,29 @@ pub fn deinit(self: *UserList) void {
|
|||||||
self.label.deinit();
|
self.label.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn widget(self: *UserList) Widget {
|
||||||
|
return Widget.init(
|
||||||
|
self,
|
||||||
|
deinit,
|
||||||
|
null,
|
||||||
|
draw,
|
||||||
|
null,
|
||||||
|
handle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn getCurrentUsername(self: UserList) []const u8 {
|
pub fn getCurrentUsername(self: UserList) []const u8 {
|
||||||
return self.label.list.items[self.label.current].name;
|
return self.label.list.items[self.label.current].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw(self: *UserList) void {
|
||||||
|
self.label.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle(self: *UserList, maybe_key: ?keyboard.Key, insert_mode: bool) !void {
|
||||||
|
self.label.handle(maybe_key, insert_mode);
|
||||||
|
}
|
||||||
|
|
||||||
fn usernameChanged(user: User, maybe_session: ?*Session) void {
|
fn usernameChanged(user: User, maybe_session: ?*Session) void {
|
||||||
if (maybe_session) |session| {
|
if (maybe_session) |session| {
|
||||||
session.label.current = @min(user.session_index.*, session.label.list.items.len - 1);
|
session.label.current = @min(user.session_index.*, session.label.list.items.len - 1);
|
||||||
|
|||||||
@@ -1,210 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
|
|
||||||
const ly_core = @import("ly-core");
|
|
||||||
const interop = ly_core.interop;
|
|
||||||
|
|
||||||
const en = @import("bigLabelLocales/en.zig");
|
|
||||||
const fa = @import("bigLabelLocales/fa.zig");
|
|
||||||
const Cell = @import("../Cell.zig");
|
|
||||||
const Position = @import("../Position.zig");
|
|
||||||
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
|
||||||
const termbox = TerminalBuffer.termbox;
|
|
||||||
|
|
||||||
pub const CHAR_WIDTH = 5;
|
|
||||||
pub const CHAR_HEIGHT = 5;
|
|
||||||
pub const CHAR_SIZE = CHAR_WIDTH * CHAR_HEIGHT;
|
|
||||||
pub const X: u32 = if (ly_core.interop.supportsUnicode()) 0x2593 else '#';
|
|
||||||
pub const O: u32 = 0;
|
|
||||||
|
|
||||||
// zig fmt: off
|
|
||||||
pub const LocaleChars = struct {
|
|
||||||
ZERO: [CHAR_SIZE]u21,
|
|
||||||
ONE: [CHAR_SIZE]u21,
|
|
||||||
TWO: [CHAR_SIZE]u21,
|
|
||||||
THREE: [CHAR_SIZE]u21,
|
|
||||||
FOUR: [CHAR_SIZE]u21,
|
|
||||||
FIVE: [CHAR_SIZE]u21,
|
|
||||||
SIX: [CHAR_SIZE]u21,
|
|
||||||
SEVEN: [CHAR_SIZE]u21,
|
|
||||||
EIGHT: [CHAR_SIZE]u21,
|
|
||||||
NINE: [CHAR_SIZE]u21,
|
|
||||||
S: [CHAR_SIZE]u21,
|
|
||||||
E: [CHAR_SIZE]u21,
|
|
||||||
P: [CHAR_SIZE]u21,
|
|
||||||
A: [CHAR_SIZE]u21,
|
|
||||||
M: [CHAR_SIZE]u21,
|
|
||||||
};
|
|
||||||
// zig fmt: on
|
|
||||||
|
|
||||||
pub const BigLabelLocale = enum {
|
|
||||||
en,
|
|
||||||
fa,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn BigLabel(comptime ContextType: type) type {
|
|
||||||
return struct {
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
buffer: *TerminalBuffer,
|
|
||||||
text: []const u8,
|
|
||||||
max_width: ?usize,
|
|
||||||
fg: u32,
|
|
||||||
bg: u32,
|
|
||||||
locale: BigLabelLocale,
|
|
||||||
update_fn: ?*const fn (*Self, ContextType) anyerror!void,
|
|
||||||
is_text_allocated: bool,
|
|
||||||
component_pos: Position,
|
|
||||||
children_pos: Position,
|
|
||||||
|
|
||||||
pub fn init(
|
|
||||||
buffer: *TerminalBuffer,
|
|
||||||
text: []const u8,
|
|
||||||
max_width: ?usize,
|
|
||||||
fg: u32,
|
|
||||||
bg: u32,
|
|
||||||
locale: BigLabelLocale,
|
|
||||||
update_fn: ?*const fn (*Self, ContextType) anyerror!void,
|
|
||||||
) Self {
|
|
||||||
return .{
|
|
||||||
.buffer = buffer,
|
|
||||||
.text = text,
|
|
||||||
.max_width = max_width,
|
|
||||||
.fg = fg,
|
|
||||||
.bg = bg,
|
|
||||||
.locale = locale,
|
|
||||||
.update_fn = update_fn,
|
|
||||||
.is_text_allocated = false,
|
|
||||||
.component_pos = TerminalBuffer.START_POSITION,
|
|
||||||
.children_pos = TerminalBuffer.START_POSITION,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setTextAlloc(
|
|
||||||
self: *Self,
|
|
||||||
allocator: Allocator,
|
|
||||||
comptime fmt: []const u8,
|
|
||||||
args: anytype,
|
|
||||||
) !void {
|
|
||||||
self.text = try std.fmt.allocPrint(allocator, fmt, args);
|
|
||||||
self.is_text_allocated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setTextBuf(
|
|
||||||
self: *Self,
|
|
||||||
buffer: []u8,
|
|
||||||
comptime fmt: []const u8,
|
|
||||||
args: anytype,
|
|
||||||
) !void {
|
|
||||||
self.text = try std.fmt.bufPrint(buffer, fmt, args);
|
|
||||||
self.is_text_allocated = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setText(self: *Self, text: []const u8) void {
|
|
||||||
self.text = text;
|
|
||||||
self.is_text_allocated = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: Self, allocator: ?Allocator) void {
|
|
||||||
if (self.is_text_allocated) {
|
|
||||||
if (allocator) |alloc| alloc.free(self.text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn positionX(self: *Self, original_pos: Position) void {
|
|
||||||
self.component_pos = original_pos;
|
|
||||||
self.children_pos = original_pos.addX(TerminalBuffer.strWidth(self.text) * CHAR_WIDTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn positionY(self: *Self, original_pos: Position) void {
|
|
||||||
self.component_pos = original_pos;
|
|
||||||
self.children_pos = original_pos.addY(CHAR_HEIGHT);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn positionXY(self: *Self, original_pos: Position) void {
|
|
||||||
self.component_pos = original_pos;
|
|
||||||
self.children_pos = Position.init(
|
|
||||||
TerminalBuffer.strWidth(self.text) * CHAR_WIDTH,
|
|
||||||
CHAR_HEIGHT,
|
|
||||||
).add(original_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn childrenPosition(self: Self) Position {
|
|
||||||
return self.children_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw(self: Self) void {
|
|
||||||
for (self.text, 0..) |c, i| {
|
|
||||||
const clock_cell = clockCell(
|
|
||||||
c,
|
|
||||||
self.fg,
|
|
||||||
self.bg,
|
|
||||||
self.locale,
|
|
||||||
);
|
|
||||||
|
|
||||||
alphaBlit(
|
|
||||||
self.component_pos.x + i * (CHAR_WIDTH + 1),
|
|
||||||
self.component_pos.y,
|
|
||||||
self.buffer.width,
|
|
||||||
self.buffer.height,
|
|
||||||
clock_cell,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update(self: *Self, context: ContextType) !void {
|
|
||||||
if (self.update_fn) |update_fn| {
|
|
||||||
return @call(
|
|
||||||
.auto,
|
|
||||||
update_fn,
|
|
||||||
.{ self, context },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clockCell(char: u8, fg: u32, bg: u32, locale: BigLabelLocale) [CHAR_SIZE]Cell {
|
|
||||||
var cells: [CHAR_SIZE]Cell = undefined;
|
|
||||||
|
|
||||||
//@divTrunc(time.microseconds, 500000) != 0)
|
|
||||||
const clock_chars = toBigNumber(char, locale);
|
|
||||||
for (0..cells.len) |i| cells[i] = Cell.init(clock_chars[i], fg, bg);
|
|
||||||
|
|
||||||
return cells;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn alphaBlit(x: usize, y: usize, tb_width: usize, tb_height: usize, cells: [CHAR_SIZE]Cell) void {
|
|
||||||
if (x + CHAR_WIDTH >= tb_width or y + CHAR_HEIGHT >= tb_height) return;
|
|
||||||
|
|
||||||
for (0..CHAR_HEIGHT) |yy| {
|
|
||||||
for (0..CHAR_WIDTH) |xx| {
|
|
||||||
const cell = cells[yy * CHAR_WIDTH + xx];
|
|
||||||
cell.put(x + xx, y + yy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn toBigNumber(char: u8, locale: BigLabelLocale) [CHAR_SIZE]u21 {
|
|
||||||
const locale_chars = switch (locale) {
|
|
||||||
.fa => fa.locale_chars,
|
|
||||||
.en => en.locale_chars,
|
|
||||||
};
|
|
||||||
return switch (char) {
|
|
||||||
'0' => locale_chars.ZERO,
|
|
||||||
'1' => locale_chars.ONE,
|
|
||||||
'2' => locale_chars.TWO,
|
|
||||||
'3' => locale_chars.THREE,
|
|
||||||
'4' => locale_chars.FOUR,
|
|
||||||
'5' => locale_chars.FIVE,
|
|
||||||
'6' => locale_chars.SIX,
|
|
||||||
'7' => locale_chars.SEVEN,
|
|
||||||
'8' => locale_chars.EIGHT,
|
|
||||||
'9' => locale_chars.NINE,
|
|
||||||
'p', 'P' => locale_chars.P,
|
|
||||||
'a', 'A' => locale_chars.A,
|
|
||||||
'm', 'M' => locale_chars.M,
|
|
||||||
':' => locale_chars.S,
|
|
||||||
else => locale_chars.E,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
const bigLabel = @import("../bigLabel.zig");
|
const BigLabel = @import("../BigLabel.zig");
|
||||||
const LocaleChars = bigLabel.LocaleChars;
|
const LocaleChars = BigLabel.LocaleChars;
|
||||||
const X = bigLabel.X;
|
const X = BigLabel.X;
|
||||||
const O = bigLabel.O;
|
const O = BigLabel.O;
|
||||||
|
|
||||||
// zig fmt: off
|
// zig fmt: off
|
||||||
pub const locale_chars = LocaleChars{
|
pub const locale_chars = LocaleChars{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
const bigLabel = @import("../bigLabel.zig");
|
const BigLabel = @import("../BigLabel.zig");
|
||||||
const LocaleChars = bigLabel.LocaleChars;
|
const LocaleChars = BigLabel.LocaleChars;
|
||||||
const X = bigLabel.X;
|
const X = BigLabel.X;
|
||||||
const O = bigLabel.O;
|
const O = BigLabel.O;
|
||||||
|
|
||||||
// zig fmt: off
|
// zig fmt: off
|
||||||
pub const locale_chars = LocaleChars{
|
pub const locale_chars = LocaleChars{
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Cell = @import("../Cell.zig");
|
||||||
|
const keyboard = @import("../keyboard.zig");
|
||||||
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
||||||
const Position = @import("../Position.zig");
|
const Position = @import("../Position.zig");
|
||||||
|
|
||||||
@@ -10,8 +12,6 @@ pub fn CyclableLabel(comptime ItemType: type, comptime ChangeItemType: type) typ
|
|||||||
const DrawItemFn = *const fn (*Self, ItemType, usize, usize, usize) void;
|
const DrawItemFn = *const fn (*Self, ItemType, usize, usize, usize) void;
|
||||||
const ChangeItemFn = *const fn (ItemType, ?ChangeItemType) void;
|
const ChangeItemFn = *const fn (ItemType, ?ChangeItemType) void;
|
||||||
|
|
||||||
const termbox = TerminalBuffer.termbox;
|
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
@@ -92,28 +92,18 @@ pub fn CyclableLabel(comptime ItemType: type, comptime ChangeItemType: type) typ
|
|||||||
self.current = self.list.items.len - 1;
|
self.current = self.list.items.len - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle(self: *Self, maybe_event: ?*termbox.tb_event, insert_mode: bool) void {
|
pub fn handle(self: *Self, maybe_key: ?keyboard.Key, insert_mode: bool) void {
|
||||||
if (maybe_event) |event| blk: {
|
if (maybe_key) |key| {
|
||||||
if (event.type != termbox.TB_EVENT_KEY) break :blk;
|
if (key.left or (key.ctrl and key.h) or (!insert_mode and key.h)) {
|
||||||
|
self.goLeft();
|
||||||
switch (event.key) {
|
} else if (key.right or (key.ctrl and key.l) or (!insert_mode and key.l)) {
|
||||||
termbox.TB_KEY_ARROW_LEFT, termbox.TB_KEY_CTRL_H => self.goLeft(),
|
self.goRight();
|
||||||
termbox.TB_KEY_ARROW_RIGHT, termbox.TB_KEY_CTRL_L => self.goRight(),
|
|
||||||
else => {
|
|
||||||
if (!insert_mode) {
|
|
||||||
switch (event.ch) {
|
|
||||||
'h' => self.goLeft(),
|
|
||||||
'l' => self.goRight(),
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = termbox.tb_set_cursor(
|
TerminalBuffer.setCursor(
|
||||||
@intCast(self.component_pos.x + self.cursor + 2),
|
self.component_pos.x + self.cursor + 2,
|
||||||
@intCast(self.component_pos.y),
|
self.component_pos.y,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,19 +111,13 @@ pub fn CyclableLabel(comptime ItemType: type, comptime ChangeItemType: type) typ
|
|||||||
if (self.list.items.len == 0) return;
|
if (self.list.items.len == 0) return;
|
||||||
if (self.width < 2) return;
|
if (self.width < 2) return;
|
||||||
|
|
||||||
_ = termbox.tb_set_cell(
|
var left_arrow = Cell.init('<', self.fg, self.bg);
|
||||||
@intCast(self.component_pos.x),
|
var right_arrow = Cell.init('>', self.fg, self.bg);
|
||||||
@intCast(self.component_pos.y),
|
|
||||||
'<',
|
left_arrow.put(self.component_pos.x, self.component_pos.y);
|
||||||
self.fg,
|
right_arrow.put(
|
||||||
self.bg,
|
self.component_pos.x + self.width - 1,
|
||||||
);
|
self.component_pos.y,
|
||||||
_ = termbox.tb_set_cell(
|
|
||||||
@intCast(self.component_pos.x + self.width - 1),
|
|
||||||
@intCast(self.component_pos.y),
|
|
||||||
'>',
|
|
||||||
self.fg,
|
|
||||||
self.bg,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const current_item = self.list.items[self.current];
|
const current_item = self.list.items[self.current];
|
||||||
|
|||||||
@@ -1,126 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
|
|
||||||
const Cell = @import("../Cell.zig");
|
|
||||||
const Position = @import("../Position.zig");
|
|
||||||
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
|
||||||
const termbox = TerminalBuffer.termbox;
|
|
||||||
|
|
||||||
pub fn Label(comptime ContextType: type) type {
|
|
||||||
return struct {
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
text: []const u8,
|
|
||||||
max_width: ?usize,
|
|
||||||
fg: u32,
|
|
||||||
bg: u32,
|
|
||||||
update_fn: ?*const fn (*Self, ContextType) anyerror!void,
|
|
||||||
is_text_allocated: bool,
|
|
||||||
component_pos: Position,
|
|
||||||
children_pos: Position,
|
|
||||||
|
|
||||||
pub fn init(
|
|
||||||
text: []const u8,
|
|
||||||
max_width: ?usize,
|
|
||||||
fg: u32,
|
|
||||||
bg: u32,
|
|
||||||
update_fn: ?*const fn (*Self, ContextType) anyerror!void,
|
|
||||||
) Self {
|
|
||||||
return .{
|
|
||||||
.text = text,
|
|
||||||
.max_width = max_width,
|
|
||||||
.fg = fg,
|
|
||||||
.bg = bg,
|
|
||||||
.update_fn = update_fn,
|
|
||||||
.is_text_allocated = false,
|
|
||||||
.component_pos = TerminalBuffer.START_POSITION,
|
|
||||||
.children_pos = TerminalBuffer.START_POSITION,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setTextAlloc(
|
|
||||||
self: *Self,
|
|
||||||
allocator: Allocator,
|
|
||||||
comptime fmt: []const u8,
|
|
||||||
args: anytype,
|
|
||||||
) !void {
|
|
||||||
self.text = try std.fmt.allocPrint(allocator, fmt, args);
|
|
||||||
self.is_text_allocated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setTextBuf(
|
|
||||||
self: *Self,
|
|
||||||
buffer: []u8,
|
|
||||||
comptime fmt: []const u8,
|
|
||||||
args: anytype,
|
|
||||||
) !void {
|
|
||||||
self.text = try std.fmt.bufPrint(buffer, fmt, args);
|
|
||||||
self.is_text_allocated = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setText(self: *Self, text: []const u8) void {
|
|
||||||
self.text = text;
|
|
||||||
self.is_text_allocated = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: Self, allocator: ?Allocator) void {
|
|
||||||
if (self.is_text_allocated) {
|
|
||||||
if (allocator) |alloc| alloc.free(self.text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn positionX(self: *Self, original_pos: Position) void {
|
|
||||||
self.component_pos = original_pos;
|
|
||||||
self.children_pos = original_pos.addX(TerminalBuffer.strWidth(self.text));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn positionY(self: *Self, original_pos: Position) void {
|
|
||||||
self.component_pos = original_pos;
|
|
||||||
self.children_pos = original_pos.addY(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn positionXY(self: *Self, original_pos: Position) void {
|
|
||||||
self.component_pos = original_pos;
|
|
||||||
self.children_pos = Position.init(
|
|
||||||
TerminalBuffer.strWidth(self.text),
|
|
||||||
1,
|
|
||||||
).add(original_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn childrenPosition(self: Self) Position {
|
|
||||||
return self.children_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw(self: Self) void {
|
|
||||||
if (self.max_width) |width| {
|
|
||||||
TerminalBuffer.drawConfinedText(
|
|
||||||
self.text,
|
|
||||||
self.component_pos.x,
|
|
||||||
self.component_pos.y,
|
|
||||||
width,
|
|
||||||
self.fg,
|
|
||||||
self.bg,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TerminalBuffer.drawText(
|
|
||||||
self.text,
|
|
||||||
self.component_pos.x,
|
|
||||||
self.component_pos.y,
|
|
||||||
self.fg,
|
|
||||||
self.bg,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update(self: *Self, context: ContextType) !void {
|
|
||||||
if (self.update_fn) |update_fn| {
|
|
||||||
return @call(
|
|
||||||
.auto,
|
|
||||||
update_fn,
|
|
||||||
.{ self, context },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -36,8 +36,8 @@ pub const Key = packed struct {
|
|||||||
tab: bool,
|
tab: bool,
|
||||||
backspace: bool,
|
backspace: bool,
|
||||||
enter: bool,
|
enter: bool,
|
||||||
space: bool,
|
|
||||||
|
|
||||||
|
@" ": bool,
|
||||||
@"!": bool,
|
@"!": bool,
|
||||||
@"`": bool,
|
@"`": bool,
|
||||||
esc: bool,
|
esc: bool,
|
||||||
@@ -109,6 +109,18 @@ pub const Key = packed struct {
|
|||||||
x: bool,
|
x: bool,
|
||||||
y: bool,
|
y: bool,
|
||||||
z: bool,
|
z: bool,
|
||||||
|
|
||||||
|
pub fn getEnabledPrintableAscii(self: Key) ?u8 {
|
||||||
|
if (self.ctrl or self.shift or self.alt) return null;
|
||||||
|
|
||||||
|
inline for (std.meta.fields(Key)) |field| {
|
||||||
|
if (field.name.len == 1 and std.ascii.isPrint(field.name[0]) and @field(self, field.name)) {
|
||||||
|
return field.name[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn getKeyList(allocator: Allocator, tb_event: termbox.tb_event) !KeyList {
|
pub fn getKeyList(allocator: Allocator, tb_event: termbox.tb_event) !KeyList {
|
||||||
@@ -326,7 +338,7 @@ pub fn getKeyList(allocator: Allocator, tb_event: termbox.tb_event) !KeyList {
|
|||||||
key._ = true;
|
key._ = true;
|
||||||
},
|
},
|
||||||
32 => {
|
32 => {
|
||||||
key.space = true;
|
key.@" " = true;
|
||||||
},
|
},
|
||||||
33 => {
|
33 => {
|
||||||
key.shift = true;
|
key.shift = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user