mirror of
https://github.com/fairyglade/ly.git
synced 2026-03-25 09:46:06 +00:00
Add Label component & make colors custom
This commit also makes Ly more resilient to (impossible) screen resolutions. Signed-off-by: AnErrupTion <anerruption@disroot.org>
This commit is contained in:
409
src/main.zig
409
src/main.zig
@@ -30,8 +30,10 @@ const DisplayServer = enums.DisplayServer;
|
|||||||
const Environment = @import("Environment.zig");
|
const Environment = @import("Environment.zig");
|
||||||
const Entry = Environment.Entry;
|
const Entry = Environment.Entry;
|
||||||
const Animation = @import("tui/Animation.zig");
|
const Animation = @import("tui/Animation.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 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");
|
||||||
@@ -68,6 +70,20 @@ const UiState = struct {
|
|||||||
animation_timed_out: bool,
|
animation_timed_out: bool,
|
||||||
animation: *?Animation,
|
animation: *?Animation,
|
||||||
can_draw_battery: bool,
|
can_draw_battery: bool,
|
||||||
|
shutdown_label: *Label,
|
||||||
|
restart_label: *Label,
|
||||||
|
sleep_label: *Label,
|
||||||
|
hibernate_label: *Label,
|
||||||
|
brightness_down_label: *Label,
|
||||||
|
brightness_up_label: *Label,
|
||||||
|
numlock_label: *Label,
|
||||||
|
capslock_label: *Label,
|
||||||
|
battery_label: *Label,
|
||||||
|
clock_label: *Label,
|
||||||
|
session_specifier_label: *Label,
|
||||||
|
login_label: *Label,
|
||||||
|
password_label: *Label,
|
||||||
|
version_label: *Label,
|
||||||
box: *CenteredBox,
|
box: *CenteredBox,
|
||||||
info_line: *InfoLine,
|
info_line: *InfoLine,
|
||||||
animate: bool,
|
animate: bool,
|
||||||
@@ -85,6 +101,9 @@ const UiState = struct {
|
|||||||
brightness_down_len: u8,
|
brightness_down_len: u8,
|
||||||
brightness_up_len: u8,
|
brightness_up_len: u8,
|
||||||
can_get_lock_state: bool,
|
can_get_lock_state: bool,
|
||||||
|
edge_margin: Position,
|
||||||
|
hide_key_hints: bool,
|
||||||
|
uses_clock: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
@@ -320,6 +339,127 @@ 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(
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
|
);
|
||||||
|
defer shutdown_label.deinit(allocator);
|
||||||
|
|
||||||
|
var restart_label = Label.init(
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
|
);
|
||||||
|
defer restart_label.deinit(allocator);
|
||||||
|
|
||||||
|
var sleep_label = Label.init(
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
|
);
|
||||||
|
defer sleep_label.deinit(allocator);
|
||||||
|
|
||||||
|
var hibernate_label = Label.init(
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
|
);
|
||||||
|
defer hibernate_label.deinit(allocator);
|
||||||
|
|
||||||
|
var brightness_down_label = Label.init(
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
|
);
|
||||||
|
defer brightness_down_label.deinit(allocator);
|
||||||
|
|
||||||
|
var brightness_up_label = Label.init(
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
|
);
|
||||||
|
defer brightness_up_label.deinit(allocator);
|
||||||
|
|
||||||
|
if (!config.hide_key_hints) {
|
||||||
|
try shutdown_label.setTextAlloc(
|
||||||
|
allocator,
|
||||||
|
"{s} {s}",
|
||||||
|
.{ config.shutdown_key, lang.shutdown },
|
||||||
|
);
|
||||||
|
try restart_label.setTextAlloc(
|
||||||
|
allocator,
|
||||||
|
"{s} {s}",
|
||||||
|
.{ config.restart_key, lang.restart },
|
||||||
|
);
|
||||||
|
if (config.sleep_cmd != null) {
|
||||||
|
try sleep_label.setTextAlloc(
|
||||||
|
allocator,
|
||||||
|
"{s} {s}",
|
||||||
|
.{ config.sleep_key, lang.sleep },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (config.hibernate_cmd != null) {
|
||||||
|
try hibernate_label.setTextAlloc(
|
||||||
|
allocator,
|
||||||
|
"{s} {s}",
|
||||||
|
.{ config.hibernate_key, lang.hibernate },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (config.brightness_down_key) |key| {
|
||||||
|
try brightness_down_label.setTextAlloc(
|
||||||
|
allocator,
|
||||||
|
"{s} {s}",
|
||||||
|
.{ key, lang.brightness_down },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (config.brightness_up_key) |key| {
|
||||||
|
try brightness_up_label.setTextAlloc(
|
||||||
|
allocator,
|
||||||
|
"{s} {s}",
|
||||||
|
.{ key, lang.brightness_up },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var numlock_label = Label.init(
|
||||||
|
lang.numlock,
|
||||||
|
null,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
|
);
|
||||||
|
defer numlock_label.deinit(null);
|
||||||
|
|
||||||
|
var capslock_label = Label.init(
|
||||||
|
lang.capslock,
|
||||||
|
null,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
|
);
|
||||||
|
defer capslock_label.deinit(null);
|
||||||
|
|
||||||
|
var battery_label = Label.init(
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
|
);
|
||||||
|
defer battery_label.deinit(null);
|
||||||
|
|
||||||
|
var clock_label = Label.init(
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
|
);
|
||||||
|
defer clock_label.deinit(null);
|
||||||
|
|
||||||
var box = CenteredBox.init(
|
var box = CenteredBox.init(
|
||||||
&buffer,
|
&buffer,
|
||||||
config.margin_box_h,
|
config.margin_box_h,
|
||||||
@@ -330,12 +470,17 @@ pub fn main() !void {
|
|||||||
config.blank_box,
|
config.blank_box,
|
||||||
config.box_title,
|
config.box_title,
|
||||||
null,
|
null,
|
||||||
|
buffer.border_fg,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
);
|
);
|
||||||
|
|
||||||
var info_line = InfoLine.init(
|
var info_line = InfoLine.init(
|
||||||
allocator,
|
allocator,
|
||||||
&buffer,
|
&buffer,
|
||||||
box.width - 2 * box.horizontal_margin,
|
box.width - 2 * box.horizontal_margin,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
);
|
);
|
||||||
defer info_line.deinit();
|
defer info_line.deinit();
|
||||||
|
|
||||||
@@ -380,15 +525,33 @@ pub fn main() !void {
|
|||||||
|
|
||||||
var login: UserList = undefined;
|
var login: UserList = undefined;
|
||||||
|
|
||||||
|
var session_specifier_label = Label.init(
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
|
);
|
||||||
|
defer session_specifier_label.deinit(null);
|
||||||
|
|
||||||
var session = Session.init(
|
var session = Session.init(
|
||||||
allocator,
|
allocator,
|
||||||
&buffer,
|
&buffer,
|
||||||
&login,
|
&login,
|
||||||
box.width - 2 * box.horizontal_margin - labels_max_length - 1,
|
box.width - 2 * box.horizontal_margin - labels_max_length - 1,
|
||||||
config.text_in_center,
|
config.text_in_center,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
);
|
);
|
||||||
defer session.deinit();
|
defer session.deinit();
|
||||||
|
|
||||||
|
var login_label = Label.init(
|
||||||
|
lang.login,
|
||||||
|
null,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
|
);
|
||||||
|
defer login_label.deinit(null);
|
||||||
|
|
||||||
login = try UserList.init(
|
login = try UserList.init(
|
||||||
allocator,
|
allocator,
|
||||||
&buffer,
|
&buffer,
|
||||||
@@ -397,6 +560,8 @@ pub fn main() !void {
|
|||||||
&session,
|
&session,
|
||||||
box.width - 2 * box.horizontal_margin - labels_max_length - 1,
|
box.width - 2 * box.horizontal_margin - labels_max_length - 1,
|
||||||
config.text_in_center,
|
config.text_in_center,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
);
|
);
|
||||||
defer login.deinit();
|
defer login.deinit();
|
||||||
|
|
||||||
@@ -459,15 +624,33 @@ 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(
|
||||||
|
lang.password,
|
||||||
|
null,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
|
);
|
||||||
|
defer password_label.deinit(null);
|
||||||
|
|
||||||
var password = Text.init(
|
var password = Text.init(
|
||||||
allocator,
|
allocator,
|
||||||
&buffer,
|
&buffer,
|
||||||
true,
|
true,
|
||||||
config.asterisk,
|
config.asterisk,
|
||||||
box.width - 2 * box.horizontal_margin - labels_max_length - 1,
|
box.width - 2 * box.horizontal_margin - labels_max_length - 1,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
);
|
);
|
||||||
defer password.deinit();
|
defer password.deinit();
|
||||||
|
|
||||||
|
var version_label = Label.init(
|
||||||
|
ly_version_str,
|
||||||
|
null,
|
||||||
|
buffer.fg,
|
||||||
|
buffer.bg,
|
||||||
|
);
|
||||||
|
defer version_label.deinit(null);
|
||||||
|
|
||||||
var is_autologin = false;
|
var is_autologin = false;
|
||||||
|
|
||||||
check_autologin: {
|
check_autologin: {
|
||||||
@@ -506,6 +689,20 @@ pub fn main() !void {
|
|||||||
.animation_timed_out = false,
|
.animation_timed_out = false,
|
||||||
.animation = &animation,
|
.animation = &animation,
|
||||||
.can_draw_battery = true,
|
.can_draw_battery = true,
|
||||||
|
.shutdown_label = &shutdown_label,
|
||||||
|
.restart_label = &restart_label,
|
||||||
|
.sleep_label = &sleep_label,
|
||||||
|
.hibernate_label = &hibernate_label,
|
||||||
|
.brightness_down_label = &brightness_down_label,
|
||||||
|
.brightness_up_label = &brightness_up_label,
|
||||||
|
.numlock_label = &numlock_label,
|
||||||
|
.capslock_label = &capslock_label,
|
||||||
|
.battery_label = &battery_label,
|
||||||
|
.clock_label = &clock_label,
|
||||||
|
.session_specifier_label = &session_specifier_label,
|
||||||
|
.login_label = &login_label,
|
||||||
|
.password_label = &password_label,
|
||||||
|
.version_label = &version_label,
|
||||||
.box = &box,
|
.box = &box,
|
||||||
.info_line = &info_line,
|
.info_line = &info_line,
|
||||||
.animate = config.animation != .none,
|
.animate = config.animation != .none,
|
||||||
@@ -523,6 +720,12 @@ pub fn main() !void {
|
|||||||
.brightness_down_len = try TerminalBuffer.strWidth(lang.brightness_down),
|
.brightness_down_len = try TerminalBuffer.strWidth(lang.brightness_down),
|
||||||
.brightness_up_len = try TerminalBuffer.strWidth(lang.brightness_up),
|
.brightness_up_len = try TerminalBuffer.strWidth(lang.brightness_up),
|
||||||
.can_get_lock_state = true,
|
.can_get_lock_state = true,
|
||||||
|
.edge_margin = Position.init(
|
||||||
|
config.edge_margin,
|
||||||
|
config.edge_margin,
|
||||||
|
),
|
||||||
|
.hide_key_hints = config.hide_key_hints,
|
||||||
|
.uses_clock = config.clock != null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load last saved username and desktop selection, if any
|
// Load last saved username and desktop selection, if any
|
||||||
@@ -550,17 +753,13 @@ pub fn main() !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Position components
|
// Position components
|
||||||
state.box.position(TerminalBuffer.START_POSITION);
|
positionComponents(&state);
|
||||||
state.info_line.label.positionY(state.box.childrenPosition());
|
|
||||||
state.session.label.positionY(state.info_line.label.childrenPosition().addY(1).addX(state.labels_max_length + 1));
|
|
||||||
state.login.label.positionY(state.session.label.childrenPosition().addY(1));
|
|
||||||
state.password.positionY(state.login.label.childrenPosition().addY(1));
|
|
||||||
|
|
||||||
switch (state.active_input) {
|
switch (state.active_input) {
|
||||||
.info_line => info_line.label.handle(null, state.insert_mode),
|
.info_line => state.info_line.label.handle(null, state.insert_mode),
|
||||||
.session => session.label.handle(null, state.insert_mode),
|
.session => state.session.label.handle(null, state.insert_mode),
|
||||||
.login => login.label.handle(null, state.insert_mode),
|
.login => state.login.label.handle(null, state.insert_mode),
|
||||||
.password => password.handle(null, state.insert_mode) catch |err| {
|
.password => state.password.handle(null, state.insert_mode) catch |err| {
|
||||||
try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg);
|
try info_line.addMessage(lang.err_alloc, config.error_bg, 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)});
|
||||||
},
|
},
|
||||||
@@ -1006,13 +1205,9 @@ fn drawUi(config: Config, lang: Lang, log_file: *LogFile, state: *UiState) !bool
|
|||||||
|
|
||||||
try TerminalBuffer.clearScreenStatic(false);
|
try TerminalBuffer.clearScreenStatic(false);
|
||||||
|
|
||||||
var length: usize = config.edge_margin;
|
|
||||||
|
|
||||||
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) {
|
if (!config.hide_version_string) state.version_label.draw();
|
||||||
state.buffer.drawLabel(ly_version_str, config.edge_margin, state.buffer.height - 1 - config.edge_margin);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.battery_id) |id| draw_battery: {
|
if (config.battery_id) |id| draw_battery: {
|
||||||
if (!state.can_draw_battery) break :draw_battery;
|
if (!state.can_draw_battery) break :draw_battery;
|
||||||
@@ -1025,14 +1220,12 @@ fn drawUi(config: Config, lang: Lang, log_file: *LogFile, state: *UiState) !bool
|
|||||||
};
|
};
|
||||||
|
|
||||||
var battery_buf: [16:0]u8 = undefined;
|
var battery_buf: [16:0]u8 = undefined;
|
||||||
const battery_str = std.fmt.bufPrintZ(&battery_buf, "BAT: {d}%", .{battery_percentage}) catch break :draw_battery;
|
state.battery_label.setTextBuf(
|
||||||
|
&battery_buf,
|
||||||
var battery_y: usize = config.edge_margin;
|
"BAT: {d}%",
|
||||||
if (!config.hide_key_hints) {
|
.{battery_percentage},
|
||||||
battery_y += 1;
|
) catch break :draw_battery;
|
||||||
}
|
state.battery_label.draw();
|
||||||
state.buffer.drawLabel(battery_str, config.edge_margin, battery_y);
|
|
||||||
state.can_draw_battery = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.bigclock != .none and state.box.height + (bigclock.HEIGHT + 2) * 2 < state.buffer.height) {
|
if (config.bigclock != .none and state.box.height + (bigclock.HEIGHT + 2) * 2 < state.buffer.height) {
|
||||||
@@ -1060,12 +1253,7 @@ fn drawUi(config: Config, lang: Lang, log_file: *LogFile, state: *UiState) !bool
|
|||||||
state.box.draw();
|
state.box.draw();
|
||||||
|
|
||||||
if (state.resolution_changed) {
|
if (state.resolution_changed) {
|
||||||
state.box.position(TerminalBuffer.START_POSITION);
|
positionComponents(state);
|
||||||
state.info_line.label.positionY(state.box.childrenPosition());
|
|
||||||
state.session.label.positionY(state.info_line.label.childrenPosition().addY(1).addX(state.labels_max_length + 1));
|
|
||||||
state.login.label.positionY(state.session.label.childrenPosition().addY(1));
|
|
||||||
state.password.positionY(state.login.label.childrenPosition().addY(1));
|
|
||||||
|
|
||||||
state.resolution_changed = false;
|
state.resolution_changed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1092,78 +1280,25 @@ fn drawUi(config: Config, lang: Lang, log_file: *LogFile, state: *UiState) !bool
|
|||||||
break :draw_clock;
|
break :draw_clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.buffer.drawLabel(clock_str, state.buffer.width - @min(state.buffer.width, clock_str.len) - config.edge_margin, config.edge_margin);
|
state.clock_label.setText(clock_str);
|
||||||
|
state.clock_label.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
const env = state.session.label.list.items[state.session.label.current];
|
const env = state.session.label.list.items[state.session.label.current];
|
||||||
state.buffer.drawLabel(
|
state.session_specifier_label.setText(env.environment.specifier);
|
||||||
env.environment.specifier,
|
state.session_specifier_label.draw();
|
||||||
state.box.childrenPosition().x,
|
state.login_label.draw();
|
||||||
state.session.label.component_pos.y,
|
state.password_label.draw();
|
||||||
);
|
|
||||||
state.buffer.drawLabel(
|
|
||||||
lang.login,
|
|
||||||
state.box.childrenPosition().x,
|
|
||||||
state.login.label.component_pos.y,
|
|
||||||
);
|
|
||||||
state.buffer.drawLabel(
|
|
||||||
lang.password,
|
|
||||||
state.box.childrenPosition().x,
|
|
||||||
state.password.component_pos.y,
|
|
||||||
);
|
|
||||||
|
|
||||||
state.info_line.label.draw();
|
state.info_line.label.draw();
|
||||||
|
|
||||||
if (!config.hide_key_hints) {
|
if (!config.hide_key_hints) {
|
||||||
state.buffer.drawLabel(config.shutdown_key, length, config.edge_margin);
|
state.shutdown_label.draw();
|
||||||
length += config.shutdown_key.len + 1;
|
state.restart_label.draw();
|
||||||
state.buffer.drawLabel(" ", length - 1, config.edge_margin);
|
state.sleep_label.draw();
|
||||||
|
state.hibernate_label.draw();
|
||||||
state.buffer.drawLabel(lang.shutdown, length, config.edge_margin);
|
state.brightness_down_label.draw();
|
||||||
length += state.shutdown_len + 1;
|
state.brightness_up_label.draw();
|
||||||
|
|
||||||
state.buffer.drawLabel(config.restart_key, length, config.edge_margin);
|
|
||||||
length += config.restart_key.len + 1;
|
|
||||||
state.buffer.drawLabel(" ", length - 1, config.edge_margin);
|
|
||||||
|
|
||||||
state.buffer.drawLabel(lang.restart, length, config.edge_margin);
|
|
||||||
length += state.restart_len + 1;
|
|
||||||
|
|
||||||
if (config.sleep_cmd != null) {
|
|
||||||
state.buffer.drawLabel(config.sleep_key, length, config.edge_margin);
|
|
||||||
length += config.sleep_key.len + 1;
|
|
||||||
state.buffer.drawLabel(" ", length - 1, config.edge_margin);
|
|
||||||
|
|
||||||
state.buffer.drawLabel(lang.sleep, length, config.edge_margin);
|
|
||||||
length += state.sleep_len + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.hibernate_cmd != null) {
|
|
||||||
state.buffer.drawLabel(config.hibernate_key, length, config.edge_margin);
|
|
||||||
length += config.hibernate_key.len + 1;
|
|
||||||
state.buffer.drawLabel(" ", length - 1, config.edge_margin);
|
|
||||||
|
|
||||||
state.buffer.drawLabel(lang.hibernate, length, config.edge_margin);
|
|
||||||
length += state.hibernate_len + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.brightness_down_key) |key| {
|
|
||||||
state.buffer.drawLabel(key, length, config.edge_margin);
|
|
||||||
length += key.len + 1;
|
|
||||||
state.buffer.drawLabel(" ", length - 1, config.edge_margin);
|
|
||||||
|
|
||||||
state.buffer.drawLabel(lang.brightness_down, length, config.edge_margin);
|
|
||||||
length += state.brightness_down_len + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.brightness_up_key) |key| {
|
|
||||||
state.buffer.drawLabel(key, length, config.edge_margin);
|
|
||||||
length += key.len + 1;
|
|
||||||
state.buffer.drawLabel(" ", length - 1, config.edge_margin);
|
|
||||||
|
|
||||||
state.buffer.drawLabel(lang.brightness_up, length, config.edge_margin);
|
|
||||||
length += state.brightness_up_len + 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.vi_mode) {
|
if (config.vi_mode) {
|
||||||
@@ -1178,17 +1313,8 @@ fn drawUi(config: Config, lang: Lang, log_file: *LogFile, state: *UiState) !bool
|
|||||||
break :draw_lock_state;
|
break :draw_lock_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
var lock_state_x = state.buffer.width - @min(state.buffer.width, lang.numlock.len) - config.edge_margin;
|
if (lock_state.numlock) state.numlock_label.draw();
|
||||||
var lock_state_y: usize = config.edge_margin;
|
if (lock_state.capslock) state.capslock_label.draw();
|
||||||
|
|
||||||
if (config.clock != null) lock_state_y += 1;
|
|
||||||
|
|
||||||
if (lock_state.numlock) state.buffer.drawLabel(lang.numlock, lock_state_x, lock_state_y);
|
|
||||||
|
|
||||||
if (lock_state_x >= lang.capslock.len + 1) {
|
|
||||||
lock_state_x -= lang.capslock.len + 1;
|
|
||||||
if (lock_state.capslock) state.buffer.drawLabel(lang.capslock, lock_state_x, lock_state_y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.session.label.draw();
|
state.session.label.draw();
|
||||||
@@ -1199,6 +1325,81 @@ fn drawUi(config: Config, lang: Lang, log_file: *LogFile, state: *UiState) !bool
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn positionComponents(state: *UiState) void {
|
||||||
|
if (!state.hide_key_hints) {
|
||||||
|
state.shutdown_label.positionX(state.edge_margin
|
||||||
|
.add(TerminalBuffer.START_POSITION));
|
||||||
|
state.restart_label.positionX(state.shutdown_label
|
||||||
|
.childrenPosition()
|
||||||
|
.addX(1));
|
||||||
|
state.sleep_label.positionX(state.restart_label
|
||||||
|
.childrenPosition()
|
||||||
|
.addX(1));
|
||||||
|
state.hibernate_label.positionX(state.sleep_label
|
||||||
|
.childrenPosition()
|
||||||
|
.addX(1));
|
||||||
|
state.brightness_down_label.positionX(state.hibernate_label
|
||||||
|
.childrenPosition()
|
||||||
|
.addX(1));
|
||||||
|
state.brightness_up_label.positionX(state.brightness_down_label
|
||||||
|
.childrenPosition()
|
||||||
|
.addX(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
state.battery_label.positionXY(state.edge_margin
|
||||||
|
.add(TerminalBuffer.START_POSITION)
|
||||||
|
.addYFromIf(state.shutdown_label.childrenPosition(), !state.hide_key_hints)
|
||||||
|
.removeYFromIf(state.edge_margin, !state.hide_key_hints));
|
||||||
|
// TODO: Fix not showing on first try (with separate update function)
|
||||||
|
state.clock_label.positionXY(state.edge_margin
|
||||||
|
.add(TerminalBuffer.START_POSITION)
|
||||||
|
.invertX(state.buffer.width)
|
||||||
|
.removeXIf(state.clock_label.text.len, state.buffer.width > state.clock_label.text.len + state.edge_margin.x));
|
||||||
|
|
||||||
|
state.numlock_label.positionX(state.edge_margin
|
||||||
|
.add(TerminalBuffer.START_POSITION)
|
||||||
|
.addYFromIf(state.clock_label.childrenPosition(), state.uses_clock)
|
||||||
|
.removeYFromIf(state.edge_margin, state.uses_clock)
|
||||||
|
.invertX(state.buffer.width)
|
||||||
|
.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
|
||||||
|
.childrenPosition()
|
||||||
|
.removeX(state.numlock_label.text.len + state.capslock_label.text.len + 1));
|
||||||
|
|
||||||
|
state.box.positionXY(TerminalBuffer.START_POSITION);
|
||||||
|
|
||||||
|
state.info_line.label.positionY(state.box
|
||||||
|
.childrenPosition());
|
||||||
|
|
||||||
|
// TODO: Same as above
|
||||||
|
state.session_specifier_label.positionX(state.info_line.label
|
||||||
|
.childrenPosition()
|
||||||
|
.addY(1));
|
||||||
|
state.session.label.positionY(state.session_specifier_label
|
||||||
|
.childrenPosition()
|
||||||
|
.addX(state.labels_max_length - state.session_specifier_label.text.len + 1));
|
||||||
|
|
||||||
|
state.login_label.positionX(state.session.label
|
||||||
|
.childrenPosition()
|
||||||
|
.resetXFrom(state.info_line.label.childrenPosition())
|
||||||
|
.addY(1));
|
||||||
|
state.login.label.positionY(state.login_label
|
||||||
|
.childrenPosition()
|
||||||
|
.addX(state.labels_max_length - state.login_label.text.len + 1));
|
||||||
|
|
||||||
|
state.password_label.positionX(state.login.label
|
||||||
|
.childrenPosition()
|
||||||
|
.resetXFrom(state.info_line.label.childrenPosition())
|
||||||
|
.addY(1));
|
||||||
|
state.password.positionY(state.password_label
|
||||||
|
.childrenPosition()
|
||||||
|
.addX(state.labels_max_length - state.password_label.text.len + 1));
|
||||||
|
|
||||||
|
state.version_label.positionXY(state.edge_margin
|
||||||
|
.add(TerminalBuffer.START_POSITION)
|
||||||
|
.invertY(state.buffer.height - 1));
|
||||||
|
}
|
||||||
|
|
||||||
fn addOtherEnvironment(session: *Session, lang: Lang, display_server: DisplayServer, exec: ?[]const u8) !void {
|
fn addOtherEnvironment(session: *Session, lang: Lang, display_server: DisplayServer, exec: ?[]const u8) !void {
|
||||||
const name = switch (display_server) {
|
const name = switch (display_server) {
|
||||||
.shell => lang.shell,
|
.shell => lang.shell,
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ pub fn add(self: Position, other: Position) Position {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn addIf(self: Position, other: Position, condition: bool) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x + if (condition) other.x else 0,
|
||||||
|
.y = self.y + if (condition) other.y else 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn addX(self: Position, x: usize) Position {
|
pub fn addX(self: Position, x: usize) Position {
|
||||||
return .{
|
return .{
|
||||||
.x = self.x + x,
|
.x = self.x + x,
|
||||||
@@ -30,3 +37,185 @@ pub fn addY(self: Position, y: usize) Position {
|
|||||||
.y = self.y + y,
|
.y = self.y + y,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn addXIf(self: Position, x: usize, condition: bool) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x + if (condition) x else 0,
|
||||||
|
.y = self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addYIf(self: Position, y: usize, condition: bool) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x,
|
||||||
|
.y = self.y + if (condition) y else 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addXFrom(self: Position, other: Position) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x + other.x,
|
||||||
|
.y = self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addYFrom(self: Position, other: Position) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x,
|
||||||
|
.y = self.y + other.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addXFromIf(self: Position, other: Position, condition: bool) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x + if (condition) other.x else 0,
|
||||||
|
.y = self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addYFromIf(self: Position, other: Position, condition: bool) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x,
|
||||||
|
.y = self.y + if (condition) other.y else 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(self: Position, other: Position) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x - other.x,
|
||||||
|
.y = self.y - other.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removeIf(self: Position, other: Position, condition: bool) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x - if (condition) other.x else 0,
|
||||||
|
.y = self.y - if (condition) other.y else 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removeX(self: Position, x: usize) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x - x,
|
||||||
|
.y = self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removeY(self: Position, y: usize) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x,
|
||||||
|
.y = self.y - y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removeXIf(self: Position, x: usize, condition: bool) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x - if (condition) x else 0,
|
||||||
|
.y = self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removeYIf(self: Position, y: usize, condition: bool) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x,
|
||||||
|
.y = self.y - if (condition) y else 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removeXFrom(self: Position, other: Position) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x - other.x,
|
||||||
|
.y = self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removeYFrom(self: Position, other: Position) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x,
|
||||||
|
.y = self.y - other.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removeXFromIf(self: Position, other: Position, condition: bool) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x - if (condition) other.x else 0,
|
||||||
|
.y = self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removeYFromIf(self: Position, other: Position, condition: bool) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x,
|
||||||
|
.y = self.y - if (condition) other.y else 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invert(self: Position, other: Position) Position {
|
||||||
|
return .{
|
||||||
|
.x = other.x - self.x,
|
||||||
|
.y = other.y - self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invertIf(self: Position, other: Position, condition: bool) Position {
|
||||||
|
return .{
|
||||||
|
.x = if (condition) other.x - self.x else self.x,
|
||||||
|
.y = if (condition) other.y - self.y else self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invertX(self: Position, width: usize) Position {
|
||||||
|
return .{
|
||||||
|
.x = width - self.x,
|
||||||
|
.y = self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invertY(self: Position, height: usize) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x,
|
||||||
|
.y = height - self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invertXIf(self: Position, width: usize, condition: bool) Position {
|
||||||
|
return .{
|
||||||
|
.x = if (condition) width - self.x else self.x,
|
||||||
|
.y = self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invertYIf(self: Position, height: usize, condition: bool) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x,
|
||||||
|
.y = if (condition) height - self.y else self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resetXFrom(self: Position, other: Position) Position {
|
||||||
|
return .{
|
||||||
|
.x = other.x,
|
||||||
|
.y = self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resetYFrom(self: Position, other: Position) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x,
|
||||||
|
.y = other.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resetXFromIf(self: Position, other: Position, condition: bool) Position {
|
||||||
|
return .{
|
||||||
|
.x = if (condition) other.x else self.x,
|
||||||
|
.y = self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resetYFromIf(self: Position, other: Position, condition: bool) Position {
|
||||||
|
return .{
|
||||||
|
.x = self.x,
|
||||||
|
.y = if (condition) other.y else self.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -201,11 +201,13 @@ pub fn cascade(self: TerminalBuffer) bool {
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drawLabel(self: TerminalBuffer, text: []const u8, x: usize, y: usize) void {
|
pub fn drawText(
|
||||||
drawColorLabel(text, x, y, self.fg, self.bg);
|
text: []const u8,
|
||||||
}
|
x: usize,
|
||||||
|
y: usize,
|
||||||
pub fn drawColorLabel(text: []const u8, x: usize, y: usize, fg: u32, bg: u32) void {
|
fg: u32,
|
||||||
|
bg: u32,
|
||||||
|
) void {
|
||||||
const yc: c_int = @intCast(y);
|
const yc: c_int = @intCast(y);
|
||||||
const utf8view = std.unicode.Utf8View.init(text) catch return;
|
const utf8view = std.unicode.Utf8View.init(text) catch return;
|
||||||
var utf8 = utf8view.iterator();
|
var utf8 = utf8view.iterator();
|
||||||
@@ -216,7 +218,14 @@ pub fn drawColorLabel(text: []const u8, x: usize, y: usize, fg: u32, bg: u32) vo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drawConfinedLabel(self: TerminalBuffer, text: []const u8, x: usize, y: usize, max_length: usize) void {
|
pub fn drawConfinedText(
|
||||||
|
text: []const u8,
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
max_length: usize,
|
||||||
|
fg: u32,
|
||||||
|
bg: u32,
|
||||||
|
) void {
|
||||||
const yc: c_int = @intCast(y);
|
const yc: c_int = @intCast(y);
|
||||||
const utf8view = std.unicode.Utf8View.init(text) catch return;
|
const utf8view = std.unicode.Utf8View.init(text) catch return;
|
||||||
var utf8 = utf8view.iterator();
|
var utf8 = utf8view.iterator();
|
||||||
@@ -224,12 +233,19 @@ pub fn drawConfinedLabel(self: TerminalBuffer, text: []const u8, x: usize, y: us
|
|||||||
var i: c_int = @intCast(x);
|
var i: c_int = @intCast(x);
|
||||||
while (utf8.nextCodepoint()) |codepoint| : (i += termbox.tb_wcwidth(codepoint)) {
|
while (utf8.nextCodepoint()) |codepoint| : (i += termbox.tb_wcwidth(codepoint)) {
|
||||||
if (i - @as(c_int, @intCast(x)) >= max_length) break;
|
if (i - @as(c_int, @intCast(x)) >= max_length) break;
|
||||||
_ = termbox.tb_set_cell(i, yc, codepoint, self.fg, self.bg);
|
_ = termbox.tb_set_cell(i, yc, codepoint, fg, bg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drawCharMultiple(self: TerminalBuffer, char: u32, x: usize, y: usize, length: usize) void {
|
pub fn drawCharMultiple(
|
||||||
const cell = Cell.init(char, self.fg, self.bg);
|
char: u32,
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
length: usize,
|
||||||
|
fg: u32,
|
||||||
|
bg: u32,
|
||||||
|
) void {
|
||||||
|
const cell = Cell.init(char, fg, bg);
|
||||||
for (0..length) |xx| cell.put(x + xx, y);
|
for (0..length) |xx| cell.put(x + xx, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
|
|
||||||
const Cell = @import("../Cell.zig");
|
const Cell = @import("../Cell.zig");
|
||||||
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
|
||||||
const Position = @import("../Position.zig");
|
const Position = @import("../Position.zig");
|
||||||
|
const TerminalBuffer = @import("../TerminalBuffer.zig");
|
||||||
const termbox = TerminalBuffer.termbox;
|
const termbox = TerminalBuffer.termbox;
|
||||||
|
|
||||||
const CenteredBox = @This();
|
const CenteredBox = @This();
|
||||||
@@ -17,6 +16,9 @@ show_borders: bool,
|
|||||||
blank_box: bool,
|
blank_box: bool,
|
||||||
top_title: ?[]const u8,
|
top_title: ?[]const u8,
|
||||||
bottom_title: ?[]const u8,
|
bottom_title: ?[]const u8,
|
||||||
|
border_fg: u32,
|
||||||
|
title_fg: u32,
|
||||||
|
bg: u32,
|
||||||
left_pos: Position,
|
left_pos: Position,
|
||||||
right_pos: Position,
|
right_pos: Position,
|
||||||
children_pos: Position,
|
children_pos: Position,
|
||||||
@@ -31,6 +33,9 @@ pub fn init(
|
|||||||
blank_box: bool,
|
blank_box: bool,
|
||||||
top_title: ?[]const u8,
|
top_title: ?[]const u8,
|
||||||
bottom_title: ?[]const u8,
|
bottom_title: ?[]const u8,
|
||||||
|
border_fg: u32,
|
||||||
|
title_fg: u32,
|
||||||
|
bg: u32,
|
||||||
) CenteredBox {
|
) CenteredBox {
|
||||||
return .{
|
return .{
|
||||||
.buffer = buffer,
|
.buffer = buffer,
|
||||||
@@ -42,13 +47,16 @@ pub fn init(
|
|||||||
.blank_box = blank_box,
|
.blank_box = blank_box,
|
||||||
.top_title = top_title,
|
.top_title = top_title,
|
||||||
.bottom_title = bottom_title,
|
.bottom_title = bottom_title,
|
||||||
|
.border_fg = border_fg,
|
||||||
|
.title_fg = title_fg,
|
||||||
|
.bg = bg,
|
||||||
.left_pos = TerminalBuffer.START_POSITION,
|
.left_pos = TerminalBuffer.START_POSITION,
|
||||||
.right_pos = TerminalBuffer.START_POSITION,
|
.right_pos = TerminalBuffer.START_POSITION,
|
||||||
.children_pos = TerminalBuffer.START_POSITION,
|
.children_pos = TerminalBuffer.START_POSITION,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn position(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;
|
||||||
|
|
||||||
self.left_pos = Position.init(
|
self.left_pos = Position.init(
|
||||||
@@ -77,33 +85,33 @@ pub fn draw(self: CenteredBox) void {
|
|||||||
@intCast(self.left_pos.x - 1),
|
@intCast(self.left_pos.x - 1),
|
||||||
@intCast(self.left_pos.y - 1),
|
@intCast(self.left_pos.y - 1),
|
||||||
self.buffer.box_chars.left_up,
|
self.buffer.box_chars.left_up,
|
||||||
self.buffer.border_fg,
|
self.border_fg,
|
||||||
self.buffer.bg,
|
self.bg,
|
||||||
);
|
);
|
||||||
_ = termbox.tb_set_cell(
|
_ = termbox.tb_set_cell(
|
||||||
@intCast(self.right_pos.x),
|
@intCast(self.right_pos.x),
|
||||||
@intCast(self.left_pos.y - 1),
|
@intCast(self.left_pos.y - 1),
|
||||||
self.buffer.box_chars.right_up,
|
self.buffer.box_chars.right_up,
|
||||||
self.buffer.border_fg,
|
self.border_fg,
|
||||||
self.buffer.bg,
|
self.bg,
|
||||||
);
|
);
|
||||||
_ = termbox.tb_set_cell(
|
_ = termbox.tb_set_cell(
|
||||||
@intCast(self.left_pos.x - 1),
|
@intCast(self.left_pos.x - 1),
|
||||||
@intCast(self.right_pos.y),
|
@intCast(self.right_pos.y),
|
||||||
self.buffer.box_chars.left_down,
|
self.buffer.box_chars.left_down,
|
||||||
self.buffer.border_fg,
|
self.border_fg,
|
||||||
self.buffer.bg,
|
self.bg,
|
||||||
);
|
);
|
||||||
_ = termbox.tb_set_cell(
|
_ = termbox.tb_set_cell(
|
||||||
@intCast(self.right_pos.x),
|
@intCast(self.right_pos.x),
|
||||||
@intCast(self.right_pos.y),
|
@intCast(self.right_pos.y),
|
||||||
self.buffer.box_chars.right_down,
|
self.buffer.box_chars.right_down,
|
||||||
self.buffer.border_fg,
|
self.border_fg,
|
||||||
self.buffer.bg,
|
self.bg,
|
||||||
);
|
);
|
||||||
|
|
||||||
var c1 = Cell.init(self.buffer.box_chars.top, self.buffer.border_fg, self.buffer.bg);
|
var c1 = Cell.init(self.buffer.box_chars.top, self.border_fg, self.bg);
|
||||||
var c2 = Cell.init(self.buffer.box_chars.bottom, self.buffer.border_fg, self.buffer.bg);
|
var c2 = Cell.init(self.buffer.box_chars.bottom, self.border_fg, self.bg);
|
||||||
|
|
||||||
for (0..self.width) |i| {
|
for (0..self.width) |i| {
|
||||||
c1.put(self.left_pos.x + i, self.left_pos.y - 1);
|
c1.put(self.left_pos.x + i, self.left_pos.y - 1);
|
||||||
@@ -128,20 +136,24 @@ pub fn draw(self: CenteredBox) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (self.top_title) |title| {
|
if (self.top_title) |title| {
|
||||||
self.buffer.drawConfinedLabel(
|
TerminalBuffer.drawConfinedText(
|
||||||
title,
|
title,
|
||||||
self.left_pos.x,
|
self.left_pos.x,
|
||||||
self.left_pos.y - 1,
|
self.left_pos.y - 1,
|
||||||
self.width,
|
self.width,
|
||||||
|
self.title_fg,
|
||||||
|
self.bg,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.bottom_title) |title| {
|
if (self.bottom_title) |title| {
|
||||||
self.buffer.drawConfinedLabel(
|
TerminalBuffer.drawConfinedText(
|
||||||
title,
|
title,
|
||||||
self.left_pos.x,
|
self.left_pos.x,
|
||||||
self.left_pos.y + self.height,
|
self.left_pos.y + self.height,
|
||||||
self.width,
|
self.width,
|
||||||
|
self.title_fg,
|
||||||
|
self.bg,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ pub fn init(
|
|||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
buffer: *TerminalBuffer,
|
buffer: *TerminalBuffer,
|
||||||
width: usize,
|
width: usize,
|
||||||
|
arrow_fg: u32,
|
||||||
|
arrow_bg: u32,
|
||||||
) InfoLine {
|
) InfoLine {
|
||||||
return .{
|
return .{
|
||||||
.label = MessageLabel.init(
|
.label = MessageLabel.init(
|
||||||
@@ -31,6 +33,8 @@ pub fn init(
|
|||||||
null,
|
null,
|
||||||
width,
|
width,
|
||||||
true,
|
true,
|
||||||
|
arrow_fg,
|
||||||
|
arrow_bg,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -57,23 +61,26 @@ pub fn clearRendered(self: InfoLine, allocator: Allocator) !void {
|
|||||||
|
|
||||||
@memset(spaces, ' ');
|
@memset(spaces, ' ');
|
||||||
|
|
||||||
self.label.buffer.drawLabel(
|
TerminalBuffer.drawText(
|
||||||
spaces,
|
spaces,
|
||||||
self.label.component_pos.x + 2,
|
self.label.component_pos.x + 2,
|
||||||
self.label.component_pos.y,
|
self.label.component_pos.y,
|
||||||
|
TerminalBuffer.Color.DEFAULT,
|
||||||
|
TerminalBuffer.Color.DEFAULT,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drawItem(label: *MessageLabel, message: Message, x: usize, y: usize, width: usize) void {
|
fn drawItem(label: *MessageLabel, message: Message, x: usize, y: usize, width: usize) void {
|
||||||
if (message.width == 0 or width <= message.width) return;
|
if (message.width == 0) return;
|
||||||
|
|
||||||
const x_offset = if (label.text_in_center) (width - message.width - 1) / 2 else 0;
|
const x_offset = if (label.text_in_center and width >= message.width) (width - message.width) / 2 else 0;
|
||||||
|
|
||||||
label.item_width = message.width + x_offset;
|
label.cursor = message.width + x_offset;
|
||||||
TerminalBuffer.drawColorLabel(
|
TerminalBuffer.drawConfinedText(
|
||||||
message.text,
|
message.text,
|
||||||
x + x_offset,
|
x + x_offset,
|
||||||
y,
|
y,
|
||||||
|
width,
|
||||||
message.fg,
|
message.fg,
|
||||||
message.bg,
|
message.bg,
|
||||||
);
|
);
|
||||||
|
|||||||
109
src/tui/components/Label.zig
Normal file
109
src/tui/components/Label.zig
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -25,6 +25,8 @@ pub fn init(
|
|||||||
user_list: *UserList,
|
user_list: *UserList,
|
||||||
width: usize,
|
width: usize,
|
||||||
text_in_center: bool,
|
text_in_center: bool,
|
||||||
|
fg: u32,
|
||||||
|
bg: u32,
|
||||||
) Session {
|
) Session {
|
||||||
return .{
|
return .{
|
||||||
.label = EnvironmentLabel.init(
|
.label = EnvironmentLabel.init(
|
||||||
@@ -35,6 +37,8 @@ pub fn init(
|
|||||||
user_list,
|
user_list,
|
||||||
width,
|
width,
|
||||||
text_in_center,
|
text_in_center,
|
||||||
|
fg,
|
||||||
|
bg,
|
||||||
),
|
),
|
||||||
.user_list = user_list,
|
.user_list = user_list,
|
||||||
};
|
};
|
||||||
@@ -70,11 +74,20 @@ fn sessionChanged(env: Env, maybe_user_list: ?*UserList) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn drawItem(label: *EnvironmentLabel, env: Env, x: usize, y: usize, width: usize) void {
|
fn drawItem(label: *EnvironmentLabel, env: Env, x: usize, y: usize, width: usize) void {
|
||||||
|
if (width < 3) return;
|
||||||
|
|
||||||
const length = @min(env.environment.name.len, width - 3);
|
const length = @min(env.environment.name.len, width - 3);
|
||||||
if (length == 0) return;
|
if (length == 0) return;
|
||||||
|
|
||||||
const x_offset = if (label.text_in_center) (width - length - 1) / 2 else 0;
|
const x_offset = if (label.text_in_center and width >= length) (width - length) / 2 else 0;
|
||||||
|
|
||||||
label.item_width = length + x_offset;
|
label.cursor = length + x_offset;
|
||||||
label.buffer.drawLabel(env.environment.name, x + x_offset, y);
|
TerminalBuffer.drawConfinedText(
|
||||||
|
env.environment.name,
|
||||||
|
x + x_offset,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
label.fg,
|
||||||
|
label.bg,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ component_pos: Position,
|
|||||||
children_pos: Position,
|
children_pos: Position,
|
||||||
masked: bool,
|
masked: bool,
|
||||||
maybe_mask: ?u32,
|
maybe_mask: ?u32,
|
||||||
|
fg: u32,
|
||||||
|
bg: u32,
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
@@ -27,6 +29,8 @@ pub fn init(
|
|||||||
masked: bool,
|
masked: bool,
|
||||||
maybe_mask: ?u32,
|
maybe_mask: ?u32,
|
||||||
width: usize,
|
width: usize,
|
||||||
|
fg: u32,
|
||||||
|
bg: u32,
|
||||||
) Text {
|
) Text {
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
@@ -40,6 +44,8 @@ pub fn init(
|
|||||||
.children_pos = TerminalBuffer.START_POSITION,
|
.children_pos = TerminalBuffer.START_POSITION,
|
||||||
.masked = masked,
|
.masked = masked,
|
||||||
.maybe_mask = maybe_mask,
|
.maybe_mask = maybe_mask,
|
||||||
|
.fg = fg,
|
||||||
|
.bg = bg,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,14 +121,18 @@ pub fn handle(self: *Text, maybe_event: ?*termbox.tb_event, insert_mode: bool) !
|
|||||||
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;
|
||||||
|
|
||||||
const length = @min(self.text.items.len, self.width - 1);
|
const length = @min(self.text.items.len, self.width - 1);
|
||||||
if (length == 0) return;
|
if (length == 0) return;
|
||||||
|
|
||||||
self.buffer.drawCharMultiple(
|
TerminalBuffer.drawCharMultiple(
|
||||||
mask,
|
mask,
|
||||||
self.component_pos.x,
|
self.component_pos.x,
|
||||||
self.component_pos.y,
|
self.component_pos.y,
|
||||||
length,
|
length,
|
||||||
|
self.fg,
|
||||||
|
self.bg,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -139,7 +149,13 @@ pub fn draw(self: Text) void {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.buffer.drawLabel(visible_slice, self.component_pos.x, self.component_pos.y);
|
TerminalBuffer.drawText(
|
||||||
|
visible_slice,
|
||||||
|
self.component_pos.x,
|
||||||
|
self.component_pos.y,
|
||||||
|
self.fg,
|
||||||
|
self.bg,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(self: *Text) void {
|
pub fn clear(self: *Text) void {
|
||||||
|
|||||||
@@ -27,8 +27,10 @@ pub fn init(
|
|||||||
session: *Session,
|
session: *Session,
|
||||||
width: usize,
|
width: usize,
|
||||||
text_in_center: bool,
|
text_in_center: bool,
|
||||||
|
fg: u32,
|
||||||
|
bg: u32,
|
||||||
) !UserList {
|
) !UserList {
|
||||||
var userList = UserList{
|
var user_list = UserList{
|
||||||
.label = UserLabel.init(
|
.label = UserLabel.init(
|
||||||
allocator,
|
allocator,
|
||||||
buffer,
|
buffer,
|
||||||
@@ -37,6 +39,8 @@ pub fn init(
|
|||||||
session,
|
session,
|
||||||
width,
|
width,
|
||||||
text_in_center,
|
text_in_center,
|
||||||
|
fg,
|
||||||
|
bg,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -60,7 +64,7 @@ pub fn init(
|
|||||||
allocated_index = true;
|
allocated_index = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
try userList.label.addItem(.{
|
try user_list.label.addItem(.{
|
||||||
.name = username,
|
.name = username,
|
||||||
.session_index = maybe_session_index.?,
|
.session_index = maybe_session_index.?,
|
||||||
.allocated_index = allocated_index,
|
.allocated_index = allocated_index,
|
||||||
@@ -68,7 +72,7 @@ pub fn init(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return userList;
|
return user_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *UserList) void {
|
pub fn deinit(self: *UserList) void {
|
||||||
@@ -92,11 +96,20 @@ fn usernameChanged(user: User, maybe_session: ?*Session) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn drawItem(label: *UserLabel, user: User, x: usize, y: usize, width: usize) void {
|
fn drawItem(label: *UserLabel, user: User, x: usize, y: usize, width: usize) void {
|
||||||
|
if (width < 3) return;
|
||||||
|
|
||||||
const length = @min(user.name.len, width - 3);
|
const length = @min(user.name.len, width - 3);
|
||||||
if (length == 0) return;
|
if (length == 0) return;
|
||||||
|
|
||||||
const x_offset = if (label.text_in_center) (width - length - 1) / 2 else 0;
|
const x_offset = if (label.text_in_center and width >= length) (width - length) / 2 else 0;
|
||||||
|
|
||||||
label.item_width = length + x_offset;
|
label.cursor = length + x_offset;
|
||||||
label.buffer.drawLabel(user.name, x + x_offset, y);
|
TerminalBuffer.drawConfinedText(
|
||||||
|
user.name,
|
||||||
|
x + x_offset,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
label.fg,
|
||||||
|
label.bg,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ pub fn CyclableLabel(comptime ItemType: type, comptime ChangeItemType: type) typ
|
|||||||
component_pos: Position,
|
component_pos: Position,
|
||||||
children_pos: Position,
|
children_pos: Position,
|
||||||
text_in_center: bool,
|
text_in_center: bool,
|
||||||
item_width: usize,
|
fg: u32,
|
||||||
|
bg: u32,
|
||||||
|
cursor: usize,
|
||||||
draw_item_fn: DrawItemFn,
|
draw_item_fn: DrawItemFn,
|
||||||
change_item_fn: ?ChangeItemFn,
|
change_item_fn: ?ChangeItemFn,
|
||||||
change_item_arg: ?ChangeItemType,
|
change_item_arg: ?ChangeItemType,
|
||||||
@@ -35,6 +37,8 @@ pub fn CyclableLabel(comptime ItemType: type, comptime ChangeItemType: type) typ
|
|||||||
change_item_arg: ?ChangeItemType,
|
change_item_arg: ?ChangeItemType,
|
||||||
width: usize,
|
width: usize,
|
||||||
text_in_center: bool,
|
text_in_center: bool,
|
||||||
|
fg: u32,
|
||||||
|
bg: u32,
|
||||||
) Self {
|
) Self {
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
@@ -45,7 +49,9 @@ pub fn CyclableLabel(comptime ItemType: type, comptime ChangeItemType: type) typ
|
|||||||
.component_pos = TerminalBuffer.START_POSITION,
|
.component_pos = TerminalBuffer.START_POSITION,
|
||||||
.children_pos = TerminalBuffer.START_POSITION,
|
.children_pos = TerminalBuffer.START_POSITION,
|
||||||
.text_in_center = text_in_center,
|
.text_in_center = text_in_center,
|
||||||
.item_width = 0,
|
.fg = fg,
|
||||||
|
.bg = bg,
|
||||||
|
.cursor = 0,
|
||||||
.draw_item_fn = draw_item_fn,
|
.draw_item_fn = draw_item_fn,
|
||||||
.change_item_fn = change_item_fn,
|
.change_item_fn = change_item_fn,
|
||||||
.change_item_arg = change_item_arg,
|
.change_item_arg = change_item_arg,
|
||||||
@@ -58,19 +64,19 @@ pub fn CyclableLabel(comptime ItemType: type, comptime ChangeItemType: type) typ
|
|||||||
|
|
||||||
pub fn positionX(self: *Self, original_pos: Position) void {
|
pub fn positionX(self: *Self, original_pos: Position) void {
|
||||||
self.component_pos = original_pos;
|
self.component_pos = original_pos;
|
||||||
self.item_width = self.component_pos.x + 2;
|
self.cursor = self.component_pos.x + 2;
|
||||||
self.children_pos = original_pos.addX(self.width);
|
self.children_pos = original_pos.addX(self.width);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn positionY(self: *Self, original_pos: Position) void {
|
pub fn positionY(self: *Self, original_pos: Position) void {
|
||||||
self.component_pos = original_pos;
|
self.component_pos = original_pos;
|
||||||
self.item_width = self.component_pos.x + 2;
|
self.cursor = self.component_pos.x + 2;
|
||||||
self.children_pos = original_pos.addY(1);
|
self.children_pos = original_pos.addY(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn positionXY(self: *Self, original_pos: Position) void {
|
pub fn positionXY(self: *Self, original_pos: Position) void {
|
||||||
self.component_pos = original_pos;
|
self.component_pos = original_pos;
|
||||||
self.item_width = self.component_pos.x + 2;
|
self.cursor = self.component_pos.x + 2;
|
||||||
self.children_pos = Position.init(
|
self.children_pos = Position.init(
|
||||||
self.width,
|
self.width,
|
||||||
1,
|
1,
|
||||||
@@ -106,27 +112,28 @@ pub fn CyclableLabel(comptime ItemType: type, comptime ChangeItemType: type) typ
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ = termbox.tb_set_cursor(
|
_ = termbox.tb_set_cursor(
|
||||||
@intCast(self.component_pos.x + self.item_width + 2),
|
@intCast(self.component_pos.x + self.cursor + 2),
|
||||||
@intCast(self.component_pos.y),
|
@intCast(self.component_pos.y),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(self: *Self) void {
|
pub fn draw(self: *Self) void {
|
||||||
if (self.list.items.len == 0) return;
|
if (self.list.items.len == 0) return;
|
||||||
|
if (self.width < 2) return;
|
||||||
|
|
||||||
_ = termbox.tb_set_cell(
|
_ = termbox.tb_set_cell(
|
||||||
@intCast(self.component_pos.x),
|
@intCast(self.component_pos.x),
|
||||||
@intCast(self.component_pos.y),
|
@intCast(self.component_pos.y),
|
||||||
'<',
|
'<',
|
||||||
self.buffer.fg,
|
self.fg,
|
||||||
self.buffer.bg,
|
self.bg,
|
||||||
);
|
);
|
||||||
_ = termbox.tb_set_cell(
|
_ = termbox.tb_set_cell(
|
||||||
@intCast(self.component_pos.x + self.width - 1),
|
@intCast(self.component_pos.x + self.width - 1),
|
||||||
@intCast(self.component_pos.y),
|
@intCast(self.component_pos.y),
|
||||||
'>',
|
'>',
|
||||||
self.buffer.fg,
|
self.fg,
|
||||||
self.buffer.bg,
|
self.bg,
|
||||||
);
|
);
|
||||||
|
|
||||||
const current_item = self.list.items[self.current];
|
const current_item = self.list.items[self.current];
|
||||||
|
|||||||
Reference in New Issue
Block a user