diff --git a/src/main.zig b/src/main.zig index f10727e..a3a4926 100644 --- a/src/main.zig +++ b/src/main.zig @@ -8,6 +8,8 @@ const menu = @import("menu.zig"); const btn = @import("button.zig"); const log = @import("log.zig"); const line = @import("line.zig"); +const tabs = @import("tabs.zig"); +const stack = @import("stack.zig"); var term_io: term.TermIO = undefined; var side_menu: menu.Menu = undefined; @@ -91,13 +93,16 @@ pub fn main() !void { m.pane.background = child.background; m.pane.foreground = child.foreground; - var l = line.HorizontalLine.create(&child, .{ .anchor = .Center, .x = .{ .value = 100, .type = .Relative }, .y = .{ .value = 1 } }, borders.BasicBorder); + // var l = line.HorizontalLine.create(&child, .{ .anchor = .Center, .x = .{ .value = 100, .type = .Relative }, .y = .{ .value = 1 } }, borders.BasicBorder); + var _tabs = [_]tabs.Tab{ .{ .name = "Tab 1", .pane = &side_menu.pane }, .{ .name = "Tab 2", .pane = &child }, .{ .name = "Tab 3", .pane = &child }, .{ .name = "Tab 4", .pane = &child }, .{ .name = "Tab 5", .pane = &child } }; + var tabbar = tabs.TabBar.create(&child, .{ .highlight_color = color.RGB(0, 0, 255) }, &_tabs, .{ .type = .Relative, .value = 100 }); + tabbar.pane.dimensions.anchor = .Center; // var l = line.HorizontalLine.create(@ptrFromInt(0x7fffabc0), .{ .anchor = .Center, .x = .{ .value = 100, .type = .Relative }, .y = .{ .value = 1 } }, borders.BasicBorder); try top.children.?.append(&side_menu.pane); try top.children.?.append(&child); try child.children.?.append(&m.pane); - try child.children.?.append(&l.pane); + try child.children.?.append(&tabbar.pane); try child.children.?.append(&button.pane); defer top.children.?.deinit(); diff --git a/src/tabs.zig b/src/tabs.zig new file mode 100644 index 0000000..a5a7410 --- /dev/null +++ b/src/tabs.zig @@ -0,0 +1,121 @@ +const dims = @import("dimensions.zig"); +const colors = @import("colors.zig"); +const log = @import("log.zig"); +const menu = @import("menu.zig"); +const pane = @import("pane.zig"); +const term = @import("term.zig"); +const std = @import("std"); + +const TermIO = term.TermIO; + +pub const Tab = struct { + name: []const u8, + pane: *pane.Pane, +}; + +pub const TabBar = struct { + pane: pane.Pane, + config: Config, + tabs: []Tab, + index: usize = 0, + + const Config = struct { + align_text: menu.TextAlignment = .Center, + highlight_color: colors.Color, + expand_highlight: bool = true, + underline: bool = true, + }; + + pub fn create(parent: *pane.Pane, config: Config, tabs: []Tab, width: dims.Dimension) TabBar { + return TabBar{ + .pane = pane.Pane{ + .parent = parent, + .children = null, + .focusable = true, + .vtable = .{ + .draw = draw, + .update = update, + }, + .dimensions = .{ + .x = width, + .y = .{ .value = 1, .type = .Absolute }, + }, + }, + .config = config, + .tabs = tabs, + }; + } + + fn draw(pane_ptr: *pane.Pane, term_io: *TermIO) !void { + var self: *TabBar = @fieldParentPtr("pane", pane_ptr); + + const tab_width = self.pane.calcDims.internal_size.width / self.tabs.len; + const extra = self.pane.calcDims.internal_size.width - (tab_width * self.tabs.len); + var writer = pane_ptr.writer(term_io); + self.pane.cursor = .{ .x = 0, .y = 0 }; + self.pane.moveCursor(term_io); + + const normal_background = self.pane.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; + } else { + self.pane.background = normal_background; + } + + const width = if (i < extra) tab_width + 1 else tab_width; + if (tab.name.len >= width) { + try writer.writeAll(tab.name[0..width]); + continue; + } + const left = (width - tab.name.len) / 2; + try writer.writeByteNTimes(' ', left); + try writer.writeAll(tab.name); + try writer.writeByteNTimes(' ', width - (tab.name.len + left)); + } + self.pane.background = normal_background; + term_io.disableFormats(.{ .underline = self.config.underline }); + } + + fn update(pane_ptr: *pane.Pane, term_io: *TermIO, key: term.Key) !bool { + var self: *TabBar = @fieldParentPtr("pane", pane_ptr); + + if (key.type == .SEQUENCE) { + const seq: term.SequenceKey = @enumFromInt(key.value); + switch (seq) { + .LEFT => { + if (self.index > 0) { + self.index -= 1; + try draw(pane_ptr, term_io); + return true; + } + }, + .RIGHT => { + self.index = @min(self.index + 1, self.tabs.len - 1); + try draw(pane_ptr, term_io); + return true; + }, + else => {}, + } + } + + switch (key.value) { + 'h' => { + if (self.index > 0) { + self.index -= 1; + try draw(pane_ptr, term_io); + return true; + } + }, + 'l' => { + self.index = @min(self.index + 1, self.tabs.len - 1); + try draw(pane_ptr, term_io); + return true; + }, + else => {}, + } + + return false; + } +};