styles
This commit is contained in:
+15
-1
@@ -1,17 +1,31 @@
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const view = @import("root.zig");
|
||||
const style = view.style;
|
||||
|
||||
const Writer = std.Io.Writer;
|
||||
const Style = style.Style;
|
||||
|
||||
// Cell is a single cell in the [DoubleBuffer].
|
||||
pub const Cell = struct {
|
||||
char: [8]u8,
|
||||
width: usize,
|
||||
style: ?Style,
|
||||
|
||||
/// eql returns
|
||||
pub fn eql(self: *const Cell, b: *const Cell) bool {
|
||||
return mem.eql(u8, &self.char, &b.char) and self.width == b.width;
|
||||
}
|
||||
|
||||
pub fn render(self: *const @This(), w: *std.Io.Writer) !void {
|
||||
pub fn render(self: *const @This(), w: *Writer) !void {
|
||||
if (self.style) |*s| {
|
||||
try s.render(w);
|
||||
}
|
||||
|
||||
_ = try w.write(self.char[0..self.width]);
|
||||
|
||||
if (self.style) |_| {
|
||||
try style.Reset.render(w);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -23,10 +23,18 @@ pub const DoubleBuffer = struct {
|
||||
back: Matrix(Cell),
|
||||
|
||||
pub fn init(gpa: Allocator, size: Rect) !DoubleBuffer {
|
||||
const a = try Matrix(Cell).init(gpa, .{ .char = [_]u8{' '} ** 8, .width = 1 }, size);
|
||||
const a = try Matrix(Cell).init(gpa, .{
|
||||
.char = [_]u8{' '} ** 8,
|
||||
.width = 1,
|
||||
.style = null,
|
||||
}, size);
|
||||
errdefer a.deinit(gpa);
|
||||
|
||||
const b = try Matrix(Cell).init(gpa, .{ .char = [_]u8{' '} ** 8, .width = 1 }, size);
|
||||
const b = try Matrix(Cell).init(gpa, .{
|
||||
.char = [_]u8{' '} ** 8,
|
||||
.width = 1,
|
||||
.style = null,
|
||||
}, size);
|
||||
|
||||
return .{
|
||||
.front = a,
|
||||
@@ -60,18 +68,19 @@ pub const DoubleBuffer = struct {
|
||||
for (back_row) |cell| {
|
||||
_ = try cell.render(w);
|
||||
}
|
||||
_ = try w.write("\n");
|
||||
_ = try w.write("\x1b[1E");
|
||||
}
|
||||
|
||||
_ = try w.write("\x1b[H");
|
||||
|
||||
self.swap();
|
||||
}
|
||||
|
||||
pub fn refresh(self: *@This(), w: *std.Io.Writer) !void {
|
||||
_ = try w.write("\x1b[H");
|
||||
|
||||
var back_iter = self.back.row_iterator();
|
||||
var front_iter = self.front.row_iterator();
|
||||
var skip_lines: usize = 0;
|
||||
var rendered: bool = false;
|
||||
|
||||
while (true) {
|
||||
var back_row = back_iter.next() orelse break;
|
||||
@@ -88,15 +97,18 @@ pub const DoubleBuffer = struct {
|
||||
for (back_row[x..]) |*cell| {
|
||||
try cell.render(w);
|
||||
}
|
||||
_ = try w.write("\n");
|
||||
_ = try w.write("\x1b[1E");
|
||||
skip_lines = 0;
|
||||
rendered = true;
|
||||
break;
|
||||
}
|
||||
|
||||
skip_lines += 1;
|
||||
}
|
||||
|
||||
_ = try w.write("\x1b[?25l");
|
||||
if (rendered) {
|
||||
_ = try w.write("\x1b[H");
|
||||
}
|
||||
self.swap();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
const widget = @import("widget.zig");
|
||||
|
||||
pub const style = @import("style.zig");
|
||||
|
||||
pub const DoubleBuffer = @import("double_buffer.zig").DoubleBuffer;
|
||||
pub const Cell = @import("cell.zig").Cell;
|
||||
pub const Widget = widget.Widget;
|
||||
pub const WidgetError = widget.WidgetError;
|
||||
pub const Viewport = @import("viewport.zig").Viewport;
|
||||
|
||||
test {
|
||||
@import("std").testing.refAllDecls(@This());
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
const std = @import("std");
|
||||
|
||||
const Writer = std.Io.Writer;
|
||||
|
||||
/// Style is a specific style which will write out to the writer.
|
||||
pub const Style = struct {
|
||||
escape: []const u8,
|
||||
|
||||
pub fn render(self: @This(), w: *Writer) !void {
|
||||
_ = try w.write(self.escape);
|
||||
}
|
||||
};
|
||||
|
||||
/// Reset is a special case that will reset all styles
|
||||
pub const Reset = Style{ .escape = "\x1b[0m" };
|
||||
pub const Red = Style{ .escape = "\x1b[31m" };
|
||||
+49
-1
@@ -1,8 +1,56 @@
|
||||
const std = @import("std");
|
||||
const grome = @import("../root.zig");
|
||||
const view = @import("root.zig");
|
||||
|
||||
const DoubleBuffer = grome.draw.DoubleBuffer;
|
||||
const ArrayList = std.ArrayList;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Writer = std.Io.Writer;
|
||||
|
||||
const DoubleBuffer = view.DoubleBuffer;
|
||||
const Widget = view.Widget;
|
||||
const Rect = grome.container.Rect;
|
||||
|
||||
pub const Viewport = struct {
|
||||
/// buffer holds the double buffer which will actually write things to
|
||||
/// the screen.
|
||||
buffer: DoubleBuffer,
|
||||
|
||||
/// widgets define the widgets which will be rendered to the double
|
||||
/// buffer
|
||||
widgets: ArrayList(*Widget),
|
||||
|
||||
pub fn init(gpa: Allocator, size: Rect) !@This() {
|
||||
return .{
|
||||
.buffer = try DoubleBuffer.init(gpa, size),
|
||||
.widgets = .empty,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn hard_refresh(self: *@This(), w: *Writer) !void {
|
||||
try self.render();
|
||||
try self.buffer.hard_refresh(w);
|
||||
}
|
||||
|
||||
pub fn deinit(self: *@This(), gpa: Allocator) void {
|
||||
self.buffer.deinit(gpa);
|
||||
self.widgets.deinit(gpa);
|
||||
}
|
||||
|
||||
pub fn render(self: *@This()) !void {
|
||||
// loop through all the widgets and render them
|
||||
for (self.widgets.items) |widget| {
|
||||
const b = widget.geometry();
|
||||
var frame = self.buffer.frame(b);
|
||||
try widget.render(&frame);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn refresh(self: *@This(), w: *Writer) !void {
|
||||
try self.render();
|
||||
try self.buffer.refresh(w);
|
||||
}
|
||||
|
||||
pub fn add_widget(self: *@This(), gpa: Allocator, widget: *Widget) !void {
|
||||
return self.widgets.append(gpa, widget);
|
||||
}
|
||||
};
|
||||
|
||||
+32
-1
@@ -2,7 +2,38 @@ const std = @import("std");
|
||||
const mem = std.mem;
|
||||
|
||||
const grome = @import("../root.zig");
|
||||
const view = @import("root.zig");
|
||||
|
||||
const Block = grome.container.Block;
|
||||
const SubMatrix = grome.container.SubMatrix;
|
||||
const Cell = view.Cell;
|
||||
|
||||
/// WidgetError is an error returned when doing things
|
||||
/// and stuff
|
||||
pub const WidgetError = error{
|
||||
UnknownError,
|
||||
};
|
||||
|
||||
/// A widget is an intrusive interface that allows the implementor to draw
|
||||
/// a specific item to a frame.
|
||||
pub const Widget = struct {};
|
||||
pub const Widget = struct {
|
||||
/// geometryFn returns a Block, which specifies the location and size of the
|
||||
/// submatrix which will be passed into the render function
|
||||
geometryFn: *const fn (*const @This()) Block,
|
||||
|
||||
/// renderFn passes in the SubMatrix which can be written to...
|
||||
/// neat
|
||||
renderFn: *const fn (*@This(), frame: *SubMatrix(Cell)) WidgetError!void,
|
||||
|
||||
/// geometry is the driver for geometryFn for the Widget interface.
|
||||
/// you must create the geometryFn.
|
||||
pub fn geometry(self: *const @This()) Block {
|
||||
return self.geometryFn(self);
|
||||
}
|
||||
|
||||
/// render is the driver for renderFn for the Widget interface.
|
||||
/// you must create the renderFn.
|
||||
pub fn render(self: *@This(), frame: *SubMatrix(Cell)) WidgetError!void {
|
||||
return self.renderFn(self, frame);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user