mirror of
https://github.com/fairyglade/ly.git
synced 2026-03-21 22:43:38 +00:00
Add update function for Label
Signed-off-by: AnErrupTion <anerruption@disroot.org>
This commit is contained in:
278
src/main.zig
278
src/main.zig
@@ -33,7 +33,7 @@ const Animation = @import("tui/Animation.zig");
|
|||||||
const Position = @import("tui/Position.zig");
|
const Position = @import("tui/Position.zig");
|
||||||
const CenteredBox = @import("tui/components/CenteredBox.zig");
|
const CenteredBox = @import("tui/components/CenteredBox.zig");
|
||||||
const InfoLine = @import("tui/components/InfoLine.zig");
|
const InfoLine = @import("tui/components/InfoLine.zig");
|
||||||
const Label = @import("tui/components/Label.zig");
|
const label = @import("tui/components/label.zig");
|
||||||
const Session = @import("tui/components/Session.zig");
|
const Session = @import("tui/components/Session.zig");
|
||||||
const Text = @import("tui/components/Text.zig");
|
const Text = @import("tui/components/Text.zig");
|
||||||
const UserList = @import("tui/components/UserList.zig");
|
const UserList = @import("tui/components/UserList.zig");
|
||||||
@@ -41,6 +41,8 @@ const TerminalBuffer = @import("tui/TerminalBuffer.zig");
|
|||||||
const termbox = TerminalBuffer.termbox;
|
const termbox = TerminalBuffer.termbox;
|
||||||
|
|
||||||
const StringList = std.ArrayListUnmanaged([]const u8);
|
const StringList = std.ArrayListUnmanaged([]const u8);
|
||||||
|
|
||||||
|
const Label = label.Label;
|
||||||
const ly_version_str = "Ly version " ++ build_options.version;
|
const ly_version_str = "Ly version " ++ build_options.version;
|
||||||
|
|
||||||
var session_pid: std.posix.pid_t = -1;
|
var session_pid: std.posix.pid_t = -1;
|
||||||
@@ -62,6 +64,7 @@ fn ttyControlTransferSignalHandler(_: c_int) callconv(.c) void {
|
|||||||
TerminalBuffer.shutdownStatic();
|
TerminalBuffer.shutdownStatic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NoType = struct {};
|
||||||
const UiState = struct {
|
const UiState = struct {
|
||||||
auth_fails: u64,
|
auth_fails: u64,
|
||||||
update: bool,
|
update: bool,
|
||||||
@@ -69,21 +72,20 @@ const UiState = struct {
|
|||||||
labels_max_length: usize,
|
labels_max_length: usize,
|
||||||
animation_timed_out: bool,
|
animation_timed_out: bool,
|
||||||
animation: *?Animation,
|
animation: *?Animation,
|
||||||
can_draw_battery: bool,
|
shutdown_label: *Label(NoType),
|
||||||
shutdown_label: *Label,
|
restart_label: *Label(NoType),
|
||||||
restart_label: *Label,
|
sleep_label: *Label(NoType),
|
||||||
sleep_label: *Label,
|
hibernate_label: *Label(NoType),
|
||||||
hibernate_label: *Label,
|
brightness_down_label: *Label(NoType),
|
||||||
brightness_down_label: *Label,
|
brightness_up_label: *Label(NoType),
|
||||||
brightness_up_label: *Label,
|
numlock_label: *Label(*UiState),
|
||||||
numlock_label: *Label,
|
capslock_label: *Label(*UiState),
|
||||||
capslock_label: *Label,
|
battery_label: *Label(*UiState),
|
||||||
battery_label: *Label,
|
clock_label: *Label(*UiState),
|
||||||
clock_label: *Label,
|
session_specifier_label: *Label(*UiState),
|
||||||
session_specifier_label: *Label,
|
login_label: *Label(NoType),
|
||||||
login_label: *Label,
|
password_label: *Label(NoType),
|
||||||
password_label: *Label,
|
version_label: *Label(NoType),
|
||||||
version_label: *Label,
|
|
||||||
box: *CenteredBox,
|
box: *CenteredBox,
|
||||||
info_line: *InfoLine,
|
info_line: *InfoLine,
|
||||||
animate: bool,
|
animate: bool,
|
||||||
@@ -93,17 +95,12 @@ const UiState = struct {
|
|||||||
password: *Text,
|
password: *Text,
|
||||||
active_input: enums.Input,
|
active_input: enums.Input,
|
||||||
insert_mode: bool,
|
insert_mode: bool,
|
||||||
can_draw_clock: bool,
|
|
||||||
shutdown_len: u8,
|
|
||||||
restart_len: u8,
|
|
||||||
sleep_len: u8,
|
|
||||||
hibernate_len: u8,
|
|
||||||
brightness_down_len: u8,
|
|
||||||
brightness_up_len: u8,
|
|
||||||
can_get_lock_state: bool,
|
|
||||||
edge_margin: Position,
|
edge_margin: Position,
|
||||||
hide_key_hints: bool,
|
config: Config,
|
||||||
uses_clock: bool,
|
lang: Lang,
|
||||||
|
log_file: *LogFile,
|
||||||
|
battery_buf: [16:0]u8,
|
||||||
|
clock_buf: [64:0]u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
@@ -339,51 +336,57 @@ pub fn main() !void {
|
|||||||
std.posix.sigaction(std.posix.SIG.TERM, &act, null);
|
std.posix.sigaction(std.posix.SIG.TERM, &act, null);
|
||||||
|
|
||||||
// Initialize components
|
// Initialize components
|
||||||
var shutdown_label = Label.init(
|
var shutdown_label = Label(NoType).init(
|
||||||
"",
|
"",
|
||||||
null,
|
null,
|
||||||
buffer.fg,
|
buffer.fg,
|
||||||
buffer.bg,
|
buffer.bg,
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
defer shutdown_label.deinit(allocator);
|
defer shutdown_label.deinit(allocator);
|
||||||
|
|
||||||
var restart_label = Label.init(
|
var restart_label = Label(NoType).init(
|
||||||
"",
|
"",
|
||||||
null,
|
null,
|
||||||
buffer.fg,
|
buffer.fg,
|
||||||
buffer.bg,
|
buffer.bg,
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
defer restart_label.deinit(allocator);
|
defer restart_label.deinit(allocator);
|
||||||
|
|
||||||
var sleep_label = Label.init(
|
var sleep_label = Label(NoType).init(
|
||||||
"",
|
"",
|
||||||
null,
|
null,
|
||||||
buffer.fg,
|
buffer.fg,
|
||||||
buffer.bg,
|
buffer.bg,
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
defer sleep_label.deinit(allocator);
|
defer sleep_label.deinit(allocator);
|
||||||
|
|
||||||
var hibernate_label = Label.init(
|
var hibernate_label = Label(NoType).init(
|
||||||
"",
|
"",
|
||||||
null,
|
null,
|
||||||
buffer.fg,
|
buffer.fg,
|
||||||
buffer.bg,
|
buffer.bg,
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
defer hibernate_label.deinit(allocator);
|
defer hibernate_label.deinit(allocator);
|
||||||
|
|
||||||
var brightness_down_label = Label.init(
|
var brightness_down_label = Label(NoType).init(
|
||||||
"",
|
"",
|
||||||
null,
|
null,
|
||||||
buffer.fg,
|
buffer.fg,
|
||||||
buffer.bg,
|
buffer.bg,
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
defer brightness_down_label.deinit(allocator);
|
defer brightness_down_label.deinit(allocator);
|
||||||
|
|
||||||
var brightness_up_label = Label.init(
|
var brightness_up_label = Label(NoType).init(
|
||||||
"",
|
"",
|
||||||
null,
|
null,
|
||||||
buffer.fg,
|
buffer.fg,
|
||||||
buffer.bg,
|
buffer.bg,
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
defer brightness_up_label.deinit(allocator);
|
defer brightness_up_label.deinit(allocator);
|
||||||
|
|
||||||
@@ -428,35 +431,39 @@ pub fn main() !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var numlock_label = Label.init(
|
var numlock_label = Label(*UiState).init(
|
||||||
lang.numlock,
|
"",
|
||||||
null,
|
null,
|
||||||
buffer.fg,
|
buffer.fg,
|
||||||
buffer.bg,
|
buffer.bg,
|
||||||
|
&updateNumlock,
|
||||||
);
|
);
|
||||||
defer numlock_label.deinit(null);
|
defer numlock_label.deinit(null);
|
||||||
|
|
||||||
var capslock_label = Label.init(
|
var capslock_label = Label(*UiState).init(
|
||||||
lang.capslock,
|
"",
|
||||||
null,
|
null,
|
||||||
buffer.fg,
|
buffer.fg,
|
||||||
buffer.bg,
|
buffer.bg,
|
||||||
|
&updateCapslock,
|
||||||
);
|
);
|
||||||
defer capslock_label.deinit(null);
|
defer capslock_label.deinit(null);
|
||||||
|
|
||||||
var battery_label = Label.init(
|
var battery_label = Label(*UiState).init(
|
||||||
"",
|
"",
|
||||||
null,
|
null,
|
||||||
buffer.fg,
|
buffer.fg,
|
||||||
buffer.bg,
|
buffer.bg,
|
||||||
|
&updateBattery,
|
||||||
);
|
);
|
||||||
defer battery_label.deinit(null);
|
defer battery_label.deinit(null);
|
||||||
|
|
||||||
var clock_label = Label.init(
|
var clock_label = Label(*UiState).init(
|
||||||
"",
|
"",
|
||||||
null,
|
null,
|
||||||
buffer.fg,
|
buffer.fg,
|
||||||
buffer.bg,
|
buffer.bg,
|
||||||
|
&updateClock,
|
||||||
);
|
);
|
||||||
defer clock_label.deinit(null);
|
defer clock_label.deinit(null);
|
||||||
|
|
||||||
@@ -525,11 +532,12 @@ pub fn main() !void {
|
|||||||
|
|
||||||
var login: UserList = undefined;
|
var login: UserList = undefined;
|
||||||
|
|
||||||
var session_specifier_label = Label.init(
|
var session_specifier_label = Label(*UiState).init(
|
||||||
"",
|
"",
|
||||||
null,
|
null,
|
||||||
buffer.fg,
|
buffer.fg,
|
||||||
buffer.bg,
|
buffer.bg,
|
||||||
|
&updateSessionSpecifier,
|
||||||
);
|
);
|
||||||
defer session_specifier_label.deinit(null);
|
defer session_specifier_label.deinit(null);
|
||||||
|
|
||||||
@@ -544,11 +552,12 @@ pub fn main() !void {
|
|||||||
);
|
);
|
||||||
defer session.deinit();
|
defer session.deinit();
|
||||||
|
|
||||||
var login_label = Label.init(
|
var login_label = Label(NoType).init(
|
||||||
lang.login,
|
lang.login,
|
||||||
null,
|
null,
|
||||||
buffer.fg,
|
buffer.fg,
|
||||||
buffer.bg,
|
buffer.bg,
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
defer login_label.deinit(null);
|
defer login_label.deinit(null);
|
||||||
|
|
||||||
@@ -624,11 +633,12 @@ pub fn main() !void {
|
|||||||
try log_file.err("sys", "no users found", .{});
|
try log_file.err("sys", "no users found", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
var password_label = Label.init(
|
var password_label = Label(NoType).init(
|
||||||
lang.password,
|
lang.password,
|
||||||
null,
|
null,
|
||||||
buffer.fg,
|
buffer.fg,
|
||||||
buffer.bg,
|
buffer.bg,
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
defer password_label.deinit(null);
|
defer password_label.deinit(null);
|
||||||
|
|
||||||
@@ -643,11 +653,12 @@ pub fn main() !void {
|
|||||||
);
|
);
|
||||||
defer password.deinit();
|
defer password.deinit();
|
||||||
|
|
||||||
var version_label = Label.init(
|
var version_label = Label(NoType).init(
|
||||||
ly_version_str,
|
ly_version_str,
|
||||||
null,
|
null,
|
||||||
buffer.fg,
|
buffer.fg,
|
||||||
buffer.bg,
|
buffer.bg,
|
||||||
|
null,
|
||||||
);
|
);
|
||||||
defer version_label.deinit(null);
|
defer version_label.deinit(null);
|
||||||
|
|
||||||
@@ -688,7 +699,6 @@ pub fn main() !void {
|
|||||||
.labels_max_length = labels_max_length,
|
.labels_max_length = labels_max_length,
|
||||||
.animation_timed_out = false,
|
.animation_timed_out = false,
|
||||||
.animation = &animation,
|
.animation = &animation,
|
||||||
.can_draw_battery = true,
|
|
||||||
.shutdown_label = &shutdown_label,
|
.shutdown_label = &shutdown_label,
|
||||||
.restart_label = &restart_label,
|
.restart_label = &restart_label,
|
||||||
.sleep_label = &sleep_label,
|
.sleep_label = &sleep_label,
|
||||||
@@ -712,20 +722,15 @@ pub fn main() !void {
|
|||||||
.password = &password,
|
.password = &password,
|
||||||
.active_input = config.default_input,
|
.active_input = config.default_input,
|
||||||
.insert_mode = !config.vi_mode or config.vi_default_mode == .insert,
|
.insert_mode = !config.vi_mode or config.vi_default_mode == .insert,
|
||||||
.can_draw_clock = true,
|
|
||||||
.shutdown_len = try TerminalBuffer.strWidth(lang.shutdown),
|
|
||||||
.restart_len = try TerminalBuffer.strWidth(lang.restart),
|
|
||||||
.sleep_len = try TerminalBuffer.strWidth(lang.sleep),
|
|
||||||
.hibernate_len = try TerminalBuffer.strWidth(lang.hibernate),
|
|
||||||
.brightness_down_len = try TerminalBuffer.strWidth(lang.brightness_down),
|
|
||||||
.brightness_up_len = try TerminalBuffer.strWidth(lang.brightness_up),
|
|
||||||
.can_get_lock_state = true,
|
|
||||||
.edge_margin = Position.init(
|
.edge_margin = Position.init(
|
||||||
config.edge_margin,
|
config.edge_margin,
|
||||||
config.edge_margin,
|
config.edge_margin,
|
||||||
),
|
),
|
||||||
.hide_key_hints = config.hide_key_hints,
|
.config = config,
|
||||||
.uses_clock = config.clock != null,
|
.lang = lang,
|
||||||
|
.log_file = &log_file,
|
||||||
|
.battery_buf = undefined,
|
||||||
|
.clock_buf = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load last saved username and desktop selection, if any
|
// Load last saved username and desktop selection, if any
|
||||||
@@ -753,6 +758,7 @@ pub fn main() !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Position components
|
// Position components
|
||||||
|
try updateComponents(&state);
|
||||||
positionComponents(&state);
|
positionComponents(&state);
|
||||||
|
|
||||||
switch (state.active_input) {
|
switch (state.active_input) {
|
||||||
@@ -857,7 +863,8 @@ pub fn main() !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state.update) {
|
if (state.update) {
|
||||||
if (!try drawUi(config, lang, &log_file, &state)) continue;
|
try updateComponents(&state);
|
||||||
|
if (!try drawUi(&log_file, &state)) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var timeout: i32 = -1;
|
var timeout: i32 = -1;
|
||||||
@@ -1188,9 +1195,26 @@ pub fn main() !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drawUi(config: Config, lang: Lang, log_file: *LogFile, state: *UiState) !bool {
|
fn updateComponents(state: *UiState) !void {
|
||||||
|
if (state.config.battery_id != null) {
|
||||||
|
try state.battery_label.update(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.config.clock != null) {
|
||||||
|
try state.clock_label.update(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
try state.session_specifier_label.update(state);
|
||||||
|
|
||||||
|
if (!state.config.hide_keyboard_locks) {
|
||||||
|
try state.numlock_label.update(state);
|
||||||
|
try state.capslock_label.update(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drawUi(log_file: *LogFile, state: *UiState) !bool {
|
||||||
// If the user entered a wrong password 10 times in a row, play a cascade animation, else update normally
|
// If the user entered a wrong password 10 times in a row, play a cascade animation, else update normally
|
||||||
if (config.auth_fails > 0 and state.auth_fails >= config.auth_fails) {
|
if (state.config.auth_fails > 0 and state.auth_fails >= state.config.auth_fails) {
|
||||||
std.Thread.sleep(std.time.ns_per_ms * 10);
|
std.Thread.sleep(std.time.ns_per_ms * 10);
|
||||||
state.update = state.buffer.cascade();
|
state.update = state.buffer.cascade();
|
||||||
|
|
||||||
@@ -1207,36 +1231,19 @@ fn drawUi(config: Config, lang: Lang, log_file: *LogFile, state: *UiState) !bool
|
|||||||
|
|
||||||
if (!state.animation_timed_out) if (state.animation.*) |*a| a.draw();
|
if (!state.animation_timed_out) if (state.animation.*) |*a| a.draw();
|
||||||
|
|
||||||
if (!config.hide_version_string) state.version_label.draw();
|
if (!state.config.hide_version_string) state.version_label.draw();
|
||||||
|
|
||||||
if (config.battery_id) |id| draw_battery: {
|
if (state.config.battery_id != null) state.battery_label.draw();
|
||||||
if (!state.can_draw_battery) break :draw_battery;
|
|
||||||
|
|
||||||
const battery_percentage = getBatteryPercentage(id) catch |err| {
|
if (state.config.bigclock != .none and state.box.height + (bigclock.HEIGHT + 2) * 2 < state.buffer.height) {
|
||||||
try log_file.err("sys", "failed to get battery percentage: {s}", .{@errorName(err)});
|
|
||||||
try state.info_line.addMessage(lang.err_battery, config.error_bg, config.error_fg);
|
|
||||||
state.can_draw_battery = false;
|
|
||||||
break :draw_battery;
|
|
||||||
};
|
|
||||||
|
|
||||||
var battery_buf: [16:0]u8 = undefined;
|
|
||||||
state.battery_label.setTextBuf(
|
|
||||||
&battery_buf,
|
|
||||||
"BAT: {d}%",
|
|
||||||
.{battery_percentage},
|
|
||||||
) catch break :draw_battery;
|
|
||||||
state.battery_label.draw();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.bigclock != .none and state.box.height + (bigclock.HEIGHT + 2) * 2 < state.buffer.height) {
|
|
||||||
var format_buf: [16:0]u8 = undefined;
|
var format_buf: [16:0]u8 = undefined;
|
||||||
var clock_buf: [32:0]u8 = undefined;
|
var clock_buf: [32:0]u8 = undefined;
|
||||||
// We need the slice/c-string returned by `bufPrintZ`.
|
// We need the slice/c-string returned by `bufPrintZ`.
|
||||||
const format = try std.fmt.bufPrintZ(&format_buf, "{s}{s}{s}{s}", .{
|
const format = try std.fmt.bufPrintZ(&format_buf, "{s}{s}{s}{s}", .{
|
||||||
if (config.bigclock_12hr) "%I" else "%H",
|
if (state.config.bigclock_12hr) "%I" else "%H",
|
||||||
":%M",
|
":%M",
|
||||||
if (config.bigclock_seconds) ":%S" else "",
|
if (state.config.bigclock_seconds) ":%S" else "",
|
||||||
if (config.bigclock_12hr) "%P" else "",
|
if (state.config.bigclock_12hr) "%P" else "",
|
||||||
});
|
});
|
||||||
const xo = state.buffer.width / 2 - @min(state.buffer.width, (format.len * (bigclock.WIDTH + 1))) / 2;
|
const xo = state.buffer.width / 2 - @min(state.buffer.width, (format.len * (bigclock.WIDTH + 1))) / 2;
|
||||||
const yo = (state.buffer.height - state.box.height) / 2 - bigclock.HEIGHT - 2;
|
const yo = (state.buffer.height - state.box.height) / 2 - bigclock.HEIGHT - 2;
|
||||||
@@ -1245,7 +1252,7 @@ fn drawUi(config: Config, lang: Lang, log_file: *LogFile, state: *UiState) !bool
|
|||||||
|
|
||||||
for (clock_str, 0..) |c, i| {
|
for (clock_str, 0..) |c, i| {
|
||||||
// TODO: Show error
|
// TODO: Show error
|
||||||
const clock_cell = try bigclock.clockCell(state.animate, c, state.buffer.fg, state.buffer.bg, config.bigclock);
|
const clock_cell = try bigclock.clockCell(state.animate, c, state.buffer.fg, state.buffer.bg, state.config.bigclock);
|
||||||
bigclock.alphaBlit(xo + i * (bigclock.WIDTH + 1), yo, state.buffer.width, state.buffer.height, clock_cell);
|
bigclock.alphaBlit(xo + i * (bigclock.WIDTH + 1), yo, state.buffer.width, state.buffer.height, clock_cell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1262,37 +1269,20 @@ fn drawUi(config: Config, lang: Lang, log_file: *LogFile, state: *UiState) !bool
|
|||||||
.session => state.session.label.handle(null, state.insert_mode),
|
.session => state.session.label.handle(null, state.insert_mode),
|
||||||
.login => state.login.label.handle(null, state.insert_mode),
|
.login => state.login.label.handle(null, state.insert_mode),
|
||||||
.password => state.password.handle(null, state.insert_mode) catch |err| {
|
.password => state.password.handle(null, state.insert_mode) catch |err| {
|
||||||
try state.info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg);
|
try state.info_line.addMessage(state.lang.err_alloc, state.config.error_bg, state.config.error_fg);
|
||||||
try log_file.err("tui", "failed to handle password input: {s}", .{@errorName(err)});
|
try log_file.err("tui", "failed to handle password input: {s}", .{@errorName(err)});
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.clock) |clock| draw_clock: {
|
if (state.config.clock != null) state.clock_label.draw();
|
||||||
if (!state.can_draw_clock) break :draw_clock;
|
|
||||||
|
|
||||||
var clock_buf: [64:0]u8 = undefined;
|
|
||||||
const clock_str = interop.timeAsString(&clock_buf, clock);
|
|
||||||
|
|
||||||
if (clock_str.len == 0) {
|
|
||||||
try state.info_line.addMessage(lang.err_clock_too_long, config.error_bg, config.error_fg);
|
|
||||||
state.can_draw_clock = false;
|
|
||||||
try log_file.err("tui", "clock string too long", .{});
|
|
||||||
break :draw_clock;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.clock_label.setText(clock_str);
|
|
||||||
state.clock_label.draw();
|
|
||||||
}
|
|
||||||
|
|
||||||
const env = state.session.label.list.items[state.session.label.current];
|
|
||||||
state.session_specifier_label.setText(env.environment.specifier);
|
|
||||||
state.session_specifier_label.draw();
|
state.session_specifier_label.draw();
|
||||||
state.login_label.draw();
|
state.login_label.draw();
|
||||||
state.password_label.draw();
|
state.password_label.draw();
|
||||||
|
|
||||||
state.info_line.label.draw();
|
state.info_line.label.draw();
|
||||||
|
|
||||||
if (!config.hide_key_hints) {
|
if (!state.config.hide_key_hints) {
|
||||||
state.shutdown_label.draw();
|
state.shutdown_label.draw();
|
||||||
state.restart_label.draw();
|
state.restart_label.draw();
|
||||||
state.sleep_label.draw();
|
state.sleep_label.draw();
|
||||||
@@ -1301,20 +1291,13 @@ fn drawUi(config: Config, lang: Lang, log_file: *LogFile, state: *UiState) !bool
|
|||||||
state.brightness_up_label.draw();
|
state.brightness_up_label.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.vi_mode) {
|
if (state.config.vi_mode) {
|
||||||
state.box.bottom_title = if (state.insert_mode) lang.insert else lang.normal;
|
state.box.bottom_title = if (state.insert_mode) state.lang.insert else state.lang.normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.hide_keyboard_locks and state.can_get_lock_state) draw_lock_state: {
|
if (!state.config.hide_keyboard_locks) {
|
||||||
const lock_state = interop.getLockState() catch |err| {
|
state.numlock_label.draw();
|
||||||
try state.info_line.addMessage(lang.err_lock_state, config.error_bg, config.error_fg);
|
state.capslock_label.draw();
|
||||||
state.can_get_lock_state = false;
|
|
||||||
try log_file.err("sys", "failed to get lock state: {s}", .{@errorName(err)});
|
|
||||||
break :draw_lock_state;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (lock_state.numlock) state.numlock_label.draw();
|
|
||||||
if (lock_state.capslock) state.capslock_label.draw();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.session.label.draw();
|
state.session.label.draw();
|
||||||
@@ -1325,8 +1308,67 @@ fn drawUi(config: Config, lang: Lang, log_file: *LogFile, state: *UiState) !bool
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn updateNumlock(self: *Label(*UiState), state: *UiState) !void {
|
||||||
|
const lock_state = interop.getLockState() catch |err| {
|
||||||
|
self.update_fn = null;
|
||||||
|
try state.info_line.addMessage(state.lang.err_lock_state, state.config.error_bg, state.config.error_fg);
|
||||||
|
try state.log_file.err("sys", "failed to get lock state: {s}", .{@errorName(err)});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.setText(if (lock_state.numlock) state.lang.numlock else "");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn updateCapslock(self: *Label(*UiState), state: *UiState) !void {
|
||||||
|
const lock_state = interop.getLockState() catch |err| {
|
||||||
|
self.update_fn = null;
|
||||||
|
try state.info_line.addMessage(state.lang.err_lock_state, state.config.error_bg, state.config.error_fg);
|
||||||
|
try state.log_file.err("sys", "failed to get lock state: {s}", .{@errorName(err)});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.setText(if (lock_state.capslock) state.lang.capslock else "");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn updateBattery(self: *Label(*UiState), state: *UiState) !void {
|
||||||
|
if (state.config.battery_id) |id| {
|
||||||
|
const battery_percentage = getBatteryPercentage(id) catch |err| {
|
||||||
|
self.update_fn = null;
|
||||||
|
try state.log_file.err("sys", "failed to get battery percentage: {s}", .{@errorName(err)});
|
||||||
|
try state.info_line.addMessage(state.lang.err_battery, state.config.error_bg, state.config.error_fg);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
try self.setTextBuf(
|
||||||
|
&state.battery_buf,
|
||||||
|
"BAT: {d}%",
|
||||||
|
.{battery_percentage},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn updateClock(self: *Label(*UiState), state: *UiState) !void {
|
||||||
|
if (state.config.clock) |clock| draw_clock: {
|
||||||
|
const clock_str = interop.timeAsString(&state.clock_buf, clock);
|
||||||
|
|
||||||
|
if (clock_str.len == 0) {
|
||||||
|
self.update_fn = null;
|
||||||
|
try state.info_line.addMessage(state.lang.err_clock_too_long, state.config.error_bg, state.config.error_fg);
|
||||||
|
try state.log_file.err("tui", "clock string too long", .{});
|
||||||
|
break :draw_clock;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setText(clock_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn updateSessionSpecifier(self: *Label(*UiState), state: *UiState) !void {
|
||||||
|
const env = state.session.label.list.items[state.session.label.current];
|
||||||
|
self.setText(env.environment.specifier);
|
||||||
|
}
|
||||||
|
|
||||||
fn positionComponents(state: *UiState) void {
|
fn positionComponents(state: *UiState) void {
|
||||||
if (!state.hide_key_hints) {
|
if (!state.config.hide_key_hints) {
|
||||||
state.shutdown_label.positionX(state.edge_margin
|
state.shutdown_label.positionX(state.edge_margin
|
||||||
.add(TerminalBuffer.START_POSITION));
|
.add(TerminalBuffer.START_POSITION));
|
||||||
state.restart_label.positionX(state.shutdown_label
|
state.restart_label.positionX(state.shutdown_label
|
||||||
@@ -1348,9 +1390,8 @@ fn positionComponents(state: *UiState) void {
|
|||||||
|
|
||||||
state.battery_label.positionXY(state.edge_margin
|
state.battery_label.positionXY(state.edge_margin
|
||||||
.add(TerminalBuffer.START_POSITION)
|
.add(TerminalBuffer.START_POSITION)
|
||||||
.addYFromIf(state.shutdown_label.childrenPosition(), !state.hide_key_hints)
|
.addYFromIf(state.shutdown_label.childrenPosition(), !state.config.hide_key_hints)
|
||||||
.removeYFromIf(state.edge_margin, !state.hide_key_hints));
|
.removeYFromIf(state.edge_margin, !state.config.hide_key_hints));
|
||||||
// TODO: Fix not showing on first try (with separate update function)
|
|
||||||
state.clock_label.positionXY(state.edge_margin
|
state.clock_label.positionXY(state.edge_margin
|
||||||
.add(TerminalBuffer.START_POSITION)
|
.add(TerminalBuffer.START_POSITION)
|
||||||
.invertX(state.buffer.width)
|
.invertX(state.buffer.width)
|
||||||
@@ -1358,8 +1399,8 @@ fn positionComponents(state: *UiState) void {
|
|||||||
|
|
||||||
state.numlock_label.positionX(state.edge_margin
|
state.numlock_label.positionX(state.edge_margin
|
||||||
.add(TerminalBuffer.START_POSITION)
|
.add(TerminalBuffer.START_POSITION)
|
||||||
.addYFromIf(state.clock_label.childrenPosition(), state.uses_clock)
|
.addYFromIf(state.clock_label.childrenPosition(), state.config.clock != null)
|
||||||
.removeYFromIf(state.edge_margin, state.uses_clock)
|
.removeYFromIf(state.edge_margin, state.config.clock != null)
|
||||||
.invertX(state.buffer.width)
|
.invertX(state.buffer.width)
|
||||||
.removeXIf(state.numlock_label.text.len, state.buffer.width > state.numlock_label.text.len + state.edge_margin.x));
|
.removeXIf(state.numlock_label.text.len, state.buffer.width > state.numlock_label.text.len + state.edge_margin.x));
|
||||||
state.capslock_label.positionX(state.numlock_label
|
state.capslock_label.positionX(state.numlock_label
|
||||||
@@ -1371,7 +1412,6 @@ fn positionComponents(state: *UiState) void {
|
|||||||
state.info_line.label.positionY(state.box
|
state.info_line.label.positionY(state.box
|
||||||
.childrenPosition());
|
.childrenPosition());
|
||||||
|
|
||||||
// TODO: Same as above
|
|
||||||
state.session_specifier_label.positionX(state.info_line.label
|
state.session_specifier_label.positionX(state.info_line.label
|
||||||
.childrenPosition()
|
.childrenPosition()
|
||||||
.addY(1));
|
.addY(1));
|
||||||
|
|||||||
@@ -1,109 +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;
|
|
||||||
|
|
||||||
const Label = @This();
|
|
||||||
|
|
||||||
text: []const u8,
|
|
||||||
max_width: ?usize,
|
|
||||||
fg: u32,
|
|
||||||
bg: u32,
|
|
||||||
is_text_allocated: bool,
|
|
||||||
component_pos: Position,
|
|
||||||
children_pos: Position,
|
|
||||||
|
|
||||||
pub fn init(
|
|
||||||
text: []const u8,
|
|
||||||
max_width: ?usize,
|
|
||||||
fg: u32,
|
|
||||||
bg: u32,
|
|
||||||
) Label {
|
|
||||||
return .{
|
|
||||||
.text = text,
|
|
||||||
.max_width = max_width,
|
|
||||||
.fg = fg,
|
|
||||||
.bg = bg,
|
|
||||||
.is_text_allocated = false,
|
|
||||||
.component_pos = TerminalBuffer.START_POSITION,
|
|
||||||
.children_pos = TerminalBuffer.START_POSITION,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setTextAlloc(
|
|
||||||
self: *Label,
|
|
||||||
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: *Label,
|
|
||||||
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: *Label, text: []const u8) void {
|
|
||||||
self.text = text;
|
|
||||||
self.is_text_allocated = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: Label, allocator: ?Allocator) void {
|
|
||||||
if (self.is_text_allocated) {
|
|
||||||
if (allocator) |alloc| alloc.free(self.text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn positionX(self: *Label, original_pos: Position) void {
|
|
||||||
self.component_pos = original_pos;
|
|
||||||
self.children_pos = original_pos.addX(self.text.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
|
||||||
self.text.len,
|
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
126
src/tui/components/label.zig
Normal file
126
src/tui/components/label.zig
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
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(self.text.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
||||||
|
self.text.len,
|
||||||
|
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 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user