Better styling

This commit is contained in:
Cameron Reed 2024-10-14 17:35:47 -06:00
parent a4ee6e5961
commit c1eea0352e
7 changed files with 124 additions and 108 deletions

View File

@ -2,24 +2,28 @@ const std = @import("std");
const dim = @import("dimensions.zig");
const pane = @import("pane.zig");
const term = @import("term.zig");
const Pane = pane.Pane;
const TermIO = term.TermIO;
pub const ButtonConfig = struct {
text: []const u8,
callback: *const fn () void,
};
const Pane = pane.Pane;
const Style = pane.Style;
const TermIO = term.TermIO;
pub const Button = struct {
pane: Pane,
text: []const u8,
callback: *const fn () void,
pub fn create(mem: *Button, config: ButtonConfig) *Pane {
pub const Config = struct {
text: []const u8,
callback: *const fn () void,
style: Style = .{},
};
pub fn create(mem: *Button, config: Config) *Pane {
mem.text = config.text;
mem.callback = config.callback;
mem.pane = Pane{
.focusable = true,
.style = config.style,
.vtable = .{
.draw = draw,
.update = update,

View File

@ -34,4 +34,27 @@ pub const HorizontalLine = struct {
pub const VerticalLine = struct {
pane: Pane,
border: borders.Border,
pub fn create(mem: *VerticalLine, border: borders.Border) *Pane {
mem.border = border;
mem.pane = Pane{
.vtable = .{
.draw = draw,
},
};
return &mem.pane;
}
fn draw(pane_ptr: *Pane, term_io: *TermIO) !void {
const self: *VerticalLine = @fieldParentPtr("pane", pane_ptr);
const x = pane_ptr.dimensions.size.width / 2;
for (0..pane_ptr.dimensions.size.height) |h| {
pane_ptr.cursor = .{ .x = x, .y = h };
pane_ptr.moveCursor(term_io);
term_io.print("{u}", .{self.border.left});
}
}
};

View File

@ -50,28 +50,36 @@ pub fn main() !void {
var child: stack.Stack = undefined;
var button: btn.Button = undefined;
var tabbar: tabs.TabBar = undefined;
var lineV: line.VerticalLine = undefined;
var lineH: line.HorizontalLine = undefined;
var items = [_]menu.MenuItem{ .{ .name = "Item 1" }, .{ .name = "Item ab" } };
var items2 = [_]menu.MenuItem{ .{ .name = "Item 1" }, .{ .name = "Item ab" } };
var tabs_ = [_]tabs.Tab{ .{ .name = "Tab 1", .pane = &side_menu.pane }, .{ .name = "Tab 2", .pane = &child.pane }, .{ .name = "Tab 3", .pane = &child.pane }, .{ .name = "Tab 4", .pane = &child.pane }, .{ .name = "Tab 5", .pane = &child.pane } };
_ = stack.Stack.create(&top, .Horizontal, &[_]stack.StackedPane{
const green = color.RGB(0, 255, 0);
const purple = color.RGB(125, 0, 125);
const orange = color.RGB(255, 125, 10);
_ = stack.Stack.create(&top, .{ .direction = .Horizontal, .style = .{ .border = borders.BoldBorder, .background = color.RGB(30, 30, 30), .foreground = green } }, &[_]stack.StackedPane{
.{
.pane = menu.Menu.create(&side_menu, .{ .title = "Menu", .align_text = .Center, .expand_highlight = true, .on_select = on_side_select }, &items2),
.pane = menu.Menu.create(&side_menu, .{ .title = "Menu", .style = .{ .background = color.RGB(80, 80, 80), .foreground = green }, .align_text = .Center, .expand_highlight = true, .on_select = on_side_select }, &items2),
.dimensions = .{ .width = .{ .type = .Fill, .value = 1 }, .height = .{ .type = .Fill, .value = 100 } },
},
.{ .pane = line.VerticalLine.create(&lineV, borders.BoldBorder), .dimensions = .{ .width = .{ .type = .Absolute, .value = 1 }, .height = .{ .type = .Fill, .value = 100 } } },
.{
.pane = stack.Stack.create(&child, .Vertical, &[_]stack.StackedPane{
.pane = stack.Stack.create(&child, .{ .direction = .Vertical, .style = .{ .border = borders.BoldBorder, .background = purple, .foreground = orange } }, &[_]stack.StackedPane{
.{
.pane = tabs.TabBar.create(&tabbar, .{ .highlight_color = color.RGB(0, 0, 255) }, &tabs_),
.dimensions = .{ .width = .{ .type = .Fill, .value = 100 }, .height = .{ .type = .Absolute, .value = 1 } },
},
.{
.pane = menu.Menu.create(&m, .{ .title = "Test", .align_text = .Left, .expand_highlight = true, .on_select = on_select }, &items),
.pane = menu.Menu.create(&m, .{ .title = "Test", .style = .{ .background = purple, .foreground = orange }, .align_text = .Left, .expand_highlight = true, .on_select = on_select }, &items),
.dimensions = .{ .width = .{ .type = .Fill, .value = 100 }, .height = .{ .type = .Fill, .value = 1 } },
},
.{ .pane = line.HorizontalLine.create(&lineH, borders.BoldBorder), .dimensions = .{ .width = .{ .type = .Fill, .value = 100 }, .height = .{ .type = .Absolute, .value = 1 } } },
.{
.pane = btn.Button.create(&button, .{ .text = "<Button>", .callback = on_click }),
.pane = btn.Button.create(&button, .{ .text = "<Button>", .style = .{ .background = purple, .foreground = orange }, .callback = on_click }),
.dimensions = .{ .width = .{ .type = .Absolute, .value = 8 }, .height = .{ .type = .Absolute, .value = 1 } },
},
}),
@ -79,23 +87,6 @@ pub fn main() !void {
},
});
top.pane.border = borders.BoldBorder;
top.pane.background = color.RGB(30, 30, 30);
top.pane.foreground = color.RGB(0, 255, 0);
side_menu.pane.background = color.RGB(80, 80, 80);
side_menu.pane.foreground = top.pane.foreground;
child.pane.border = borders.BoldBorder;
child.pane.background = color.RGB(125, 0, 125);
child.pane.foreground = color.RGB(255, 125, 10);
button.pane.background = child.pane.background;
button.pane.foreground = child.pane.foreground;
m.pane.background = child.pane.background;
m.pane.foreground = child.pane.foreground;
pane.set_layout(&top.pane, &m.pane);
try pane.init(&term_io);
defer pane.cleanup(&term_io);

View File

@ -3,7 +3,9 @@ const log = @import("log.zig");
const dim = @import("dimensions.zig");
const pane = @import("pane.zig");
const term = @import("term.zig");
const Pane = pane.Pane;
const Style = pane.Style;
const TermIO = term.TermIO;
pub const TextAlignment = enum {
@ -17,26 +19,28 @@ pub const MenuItem = struct {
disabled: bool = false,
};
pub const MenuConfig = struct {
title: []const u8 = "",
align_text: TextAlignment = .Left,
expand_highlight: bool = false,
on_select: *const fn (usize) void,
};
pub const Menu = struct {
pane: Pane,
config: MenuConfig,
config: Config,
items: []MenuItem,
on_select: *const fn (usize) void,
index: usize = 0,
pub fn create(mem: *Menu, config: MenuConfig, items: []MenuItem) *Pane {
pub const Config = struct {
title: []const u8 = "",
style: pane.Style = .{},
align_text: TextAlignment = .Left,
expand_highlight: bool = false,
on_select: *const fn (usize) void,
};
pub fn create(mem: *Menu, config: Config, items: []MenuItem) *Pane {
mem.config = config;
mem.on_select = config.on_select;
mem.items = items;
mem.pane = .{
mem.pane = Pane{
.focusable = true,
.style = config.style,
.vtable = .{
.draw = draw,
.focus = focus,

View File

@ -8,34 +8,6 @@ const Border = @import("borders.zig").Border;
const TermIO = term.TermIO;
const Window = struct {
pane: Pane,
child: ?*Pane,
fn resize(self: *Window, term_io: *TermIO) void {
const size = term.getTermSize(term_io);
window.pane.dimensions = dim.CalculatedDimensions{
.pos = .{ .x = 1, .y = 1 },
.internal_pos = .{ .x = 1, .y = 1 },
.size = size,
.internal_size = size,
};
if (self.child) |child| {
child.dimensions.size = self.pane.dimensions.size;
child.dimensions.pos = self.pane.dimensions.pos;
child.resize();
}
}
fn draw(self: *Window, term_io: *TermIO) !void {
if (self.child) |child| {
try child.draw(term_io);
term_io.flush();
}
}
};
var window = Window{ .pane = Pane{}, .child = null };
pub var focused_pane: *Pane = undefined;
pub var focused_index: usize = 1;
@ -43,6 +15,12 @@ pub var should_exit: std.atomic.Value(bool) = std.atomic.Value(bool).init(false)
var needs_redraw: std.atomic.Value(bool) = std.atomic.Value(bool).init(false);
var redraw_count: usize = 0;
pub const Style = struct {
border: ?Border = null,
background: color.Color = color.Default,
foreground: color.Color = color.Default,
};
fn resize_signal(_: i32) callconv(.C) void {
needs_redraw.store(true, .release);
}
@ -157,12 +135,10 @@ pub const Cursor = struct {
pub const Pane = struct {
parent: *Pane = undefined,
border: ?Border = null,
cursor: Cursor = .{ .x = 0, .y = 0 },
overflow: Overflow = .{ .x = .Hidden, .y = .Hidden },
dimensions: dim.CalculatedDimensions = undefined,
background: color.Color = color.Default,
foreground: color.Color = color.Default,
style: Style = .{},
should_draw: bool = true,
focusable: bool = false,
focused: bool = false,
@ -272,7 +248,7 @@ pub const Pane = struct {
// }
pub fn resize(self: *Pane) void {
if (self.border) |_| {
if (self.style.border) |_| {
self.dimensions.internal_pos = .{ .x = self.dimensions.pos.x + 1, .y = self.dimensions.pos.y + 1 };
self.dimensions.internal_size = .{ .height = self.dimensions.size.height - 2, .width = self.dimensions.size.width - 2 };
} else {
@ -284,11 +260,11 @@ pub const Pane = struct {
}
pub fn draw(self: *Pane, term_io: *TermIO) !void {
if (self.border) |border| {
term_io.setColor(self.background, self.foreground);
try term_io.drawBox(self.dimensions, border, !self.background.equal(self.parent.background));
} else if (!self.background.equal(self.parent.background)) {
term_io.setColor(self.background, self.foreground);
if (self.style.border) |border| {
term_io.setColor(self.style.background, self.style.foreground);
try term_io.drawBox(self.dimensions, border, !self.style.background.equal(self.parent.style.background));
} else if (!self.style.background.equal(self.parent.style.background)) {
term_io.setColor(self.style.background, self.style.foreground);
term_io.fillBox(self.dimensions);
}
try self.vtable.draw(self, term_io);
@ -304,7 +280,7 @@ pub const Pane = struct {
self.cursor = .{ .x = 0, .y = 0 };
self.moveCursor(term_io);
term_io.setColor(self.background, self.foreground);
term_io.setColor(self.style.background, self.style.foreground);
self.vtable.focus(self, term_io) catch {};
}
@ -317,12 +293,12 @@ pub const Pane = struct {
}
pub fn moveCursor(self: *Pane, term_io: *const TermIO) void {
const borderWidth: u1 = if (self.border != null) 1 else 0;
const borderWidth: u1 = if (self.style.border != null) 1 else 0;
term_io.moveCursor(self.dimensions.pos.x + self.cursor.x + borderWidth, self.dimensions.pos.y + self.cursor.y + borderWidth);
}
pub fn print(self: *Pane, term_io: *const TermIO, string: []const u8) !void {
const borderWidth: u2 = if (self.border != null) 1 else 0;
const borderWidth: u2 = if (self.style.border != null) 1 else 0;
var space = self.dimensions.size.width - self.cursor.x - (2 * borderWidth);
var i: usize = 0;
@ -346,8 +322,8 @@ pub const Pane = struct {
}
pub fn write(self: WriterContext, bytes: []const u8) !usize {
self.term_io.setColor(self.pane.background, self.pane.foreground);
const borderWidth: u2 = if (self.pane.border != null) 1 else 0;
self.term_io.setColor(self.pane.style.background, self.pane.style.foreground);
const borderWidth: u2 = if (self.pane.style.border != null) 1 else 0;
for (bytes) |byte| {
switch (byte) {
'\x1b' => continue,
@ -367,3 +343,31 @@ pub const Pane = struct {
return bytes.len;
}
};
const Window = struct {
pane: Pane,
child: ?*Pane,
fn resize(self: *Window, term_io: *TermIO) void {
const size = term.getTermSize(term_io);
window.pane.dimensions = dim.CalculatedDimensions{
.pos = .{ .x = 1, .y = 1 },
.internal_pos = .{ .x = 1, .y = 1 },
.size = size,
.internal_size = size,
};
if (self.child) |child| {
child.dimensions.size = self.pane.dimensions.size;
child.dimensions.pos = self.pane.dimensions.pos;
child.resize();
}
}
fn draw(self: *Window, term_io: *TermIO) !void {
if (self.child) |child| {
try child.draw(term_io);
term_io.flush();
}
}
};

View File

@ -1,8 +1,10 @@
const dim = @import("dimensions.zig");
const term = @import("term.zig");
const pane = @import("pane.zig");
const std = @import("std");
const Pane = @import("pane.zig").Pane;
const Pane = pane.Pane;
const Style = pane.Style;
const TermIO = term.TermIO;
pub const StackDirection = enum {
@ -32,24 +34,17 @@ pub const Stack = struct {
direction: StackDirection,
children: []const StackedPane,
pub fn create(mem: *Stack, direction: StackDirection, children: []const StackedPane) *Pane {
// if (@typeInfo(@TypeOf(children)) != .Struct) {
// @compileError("Invalid type" ++ @typeName(@TypeOf(children)));
// }
//
// const fields = std.meta.fields(@TypeOf(children));
// var children_array: [fields.len]StackedPane = undefined;
// inline for (fields, 0..) |field, i| {
// if (field.type != StackedPane) {
// @compileError("Invalid child type");
// }
// children_array[i] = @field(children, field.name);
// }
const Config = struct {
direction: StackDirection,
style: Style = .{},
};
mem.direction = direction;
pub fn create(mem: *Stack, config: Config, children: []const StackedPane) *Pane {
mem.direction = config.direction;
mem.children = children;
mem.pane = Pane{
.focusable = false,
.style = config.style,
.vtable = .{
.resize = resize,
.draw = draw,
@ -246,14 +241,6 @@ pub const Stack = struct {
fn draw(pane_ptr: *Pane, term_io: *TermIO) !void {
const self: *Stack = @fieldParentPtr("pane", pane_ptr);
if (self.pane.border) |border| {
term_io.setColor(self.pane.background, self.pane.foreground);
try term_io.drawBox(self.pane.dimensions, border, !self.pane.background.equal(self.pane.parent.background));
} else if (!self.pane.background.equal(self.pane.parent.background)) {
term_io.setColor(self.pane.background, self.pane.foreground);
term_io.fillBox(self.pane.dimensions);
}
for (self.children) |child| {
if (child.pane.should_draw and self.pane.dimensions.size.width > 0 and self.pane.dimensions.size.height > 0) {
try child.pane.draw(term_io);

View File

@ -7,6 +7,7 @@ const term = @import("term.zig");
const std = @import("std");
const Pane = pane.Pane;
const Style = pane.Style;
const TermIO = term.TermIO;
pub const Tab = struct {
@ -22,6 +23,7 @@ pub const TabBar = struct {
const Config = struct {
align_text: menu.TextAlignment = .Center,
style: Style = .{},
highlight_color: colors.Color,
expand_highlight: bool = true,
underline: bool = true,
@ -33,6 +35,7 @@ pub const TabBar = struct {
mem.index = 0;
mem.pane = Pane{
.focusable = true,
.style = config.style,
.vtable = .{
.draw = draw,
.update = update,
@ -51,13 +54,13 @@ pub const TabBar = struct {
self.pane.cursor = .{ .x = 0, .y = 0 };
self.pane.moveCursor(term_io);
const normal_background = self.pane.background;
const normal_background = self.pane.style.background;
term_io.enableFormats(.{ .underline = self.config.underline });
for (self.tabs, 0..) |tab, i| {
if (i == self.index) {
self.pane.background = self.config.highlight_color;
self.pane.style.background = self.config.highlight_color;
} else {
self.pane.background = normal_background;
self.pane.style.background = normal_background;
}
const width = if (i < extra) tab_width + 1 else tab_width;
@ -70,7 +73,7 @@ pub const TabBar = struct {
try writer.writeAll(tab.name);
try writer.writeByteNTimes(' ', width - (tab.name.len + left));
}
self.pane.background = normal_background;
self.pane.style.background = normal_background;
term_io.disableFormats(.{ .underline = self.config.underline });
}