mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 00:06:09 +03:00
font/sprite: cleanup branch drawing character impl, implement fade-out lines
This commit is contained in:
@ -79,13 +79,15 @@ const Quads = packed struct(u4) {
|
|||||||
br: bool = false,
|
br: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Specification of a git branch node, which can have any of
|
/// Specification of a branch drawing node, which consists of a
|
||||||
/// 4 lines connecting to it in vertical or horizontal alignment
|
/// circle which is either empty or filled, and lines connecting
|
||||||
const NodeAlign = packed struct(u4) {
|
/// optionally between the circle and each of the 4 edges.
|
||||||
|
const BranchNode = packed struct(u5) {
|
||||||
up: bool = false,
|
up: bool = false,
|
||||||
|
right: bool = false,
|
||||||
down: bool = false,
|
down: bool = false,
|
||||||
left: bool = false,
|
left: bool = false,
|
||||||
right: bool = false,
|
filled: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Alignment of a figure within a cell
|
/// Alignment of a figure within a cell
|
||||||
@ -483,14 +485,14 @@ fn draw(self: Box, alloc: Allocator, canvas: *font.sprite.Canvas, cp: u32) !void
|
|||||||
// '╬'
|
// '╬'
|
||||||
0x256c => self.draw_lines(canvas, .{ .up = .double, .down = .double, .left = .double, .right = .double }),
|
0x256c => self.draw_lines(canvas, .{ .up = .double, .down = .double, .left = .double, .right = .double }),
|
||||||
// '╭'
|
// '╭'
|
||||||
0x256d => try self.draw_light_arc(canvas, .br),
|
0x256d => try self.draw_arc(canvas, .br, .light),
|
||||||
// '╮'
|
// '╮'
|
||||||
0x256e => try self.draw_light_arc(canvas, .bl),
|
0x256e => try self.draw_arc(canvas, .bl, .light),
|
||||||
// '╯'
|
// '╯'
|
||||||
0x256f => try self.draw_light_arc(canvas, .tl),
|
0x256f => try self.draw_arc(canvas, .tl, .light),
|
||||||
|
|
||||||
// '╰'
|
// '╰'
|
||||||
0x2570 => try self.draw_light_arc(canvas, .tr),
|
0x2570 => try self.draw_arc(canvas, .tr, .light),
|
||||||
// '╱'
|
// '╱'
|
||||||
0x2571 => self.draw_light_diagonal_upper_right_to_lower_left(canvas),
|
0x2571 => self.draw_light_diagonal_upper_right_to_lower_left(canvas),
|
||||||
// '╲'
|
// '╲'
|
||||||
@ -1311,319 +1313,329 @@ fn draw(self: Box, alloc: Allocator, canvas: *font.sprite.Canvas, cp: u32) !void
|
|||||||
// ''
|
// ''
|
||||||
0x1fbef => self.draw_circle(canvas, Alignment.top_left, true),
|
0x1fbef => self.draw_circle(canvas, Alignment.top_left, true),
|
||||||
|
|
||||||
|
// (Below:)
|
||||||
|
// Branch drawing character set, used for drawing git-like
|
||||||
|
// graphs in the terminal. Originally implemented in Kitty.
|
||||||
|
// Ref:
|
||||||
|
// - https://github.com/kovidgoyal/kitty/pull/7681
|
||||||
|
// - https://github.com/kovidgoyal/kitty/pull/7805
|
||||||
|
// NOTE: Kitty is GPL licensed, and its code was not referenced
|
||||||
|
// for these characters, only the loose specification of
|
||||||
|
// the character set in the pull request descriptions.
|
||||||
|
//
|
||||||
|
// TODO(qwerasd): This should be in another file, but really the
|
||||||
|
// general organization of the sprite font code
|
||||||
|
// needs to be reworked eventually.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5d0 => self.hline_middle(canvas, Thickness.light),
|
0x0f5d0 => self.hline_middle(canvas, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5d1 => self.vline_middle(canvas, Thickness.light),
|
0x0f5d1 => self.vline_middle(canvas, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
// 0x0f5d2 => self.draw_dash_fading(canvas, 4, Direction.LEFT, Thickness.light.height(self.thickness)),
|
0x0f5d2 => self.draw_fading_line(canvas, .right, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
// 0x0f5d3 => self.draw_dash_fading(canvas, 4, Direction.RIGHT, Thickness.light.height(self.thickness)),
|
0x0f5d3 => self.draw_fading_line(canvas, .left, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
// 0x0f5d4 => self.draw_dash_fading(canvas, 5, Direction.UP, Thickness.light.height(self.thickness)),
|
0x0f5d4 => self.draw_fading_line(canvas, .bottom, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
// 0x0f5d5 => self.draw_dash_fading(canvas, 5, Direction.DOWN, Thickness.light.height(self.thickness)),
|
0x0f5d5 => self.draw_fading_line(canvas, .top, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5d6 => try self.draw_light_arc(canvas, .br),
|
0x0f5d6 => try self.draw_arc(canvas, .br, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5d7 => try self.draw_light_arc(canvas, .bl),
|
0x0f5d7 => try self.draw_arc(canvas, .bl, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5d8 => try self.draw_light_arc(canvas, .tr),
|
0x0f5d8 => try self.draw_arc(canvas, .tr, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5d9 => try self.draw_light_arc(canvas, .tl),
|
0x0f5d9 => try self.draw_arc(canvas, .tl, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5da => {
|
0x0f5da => {
|
||||||
self.vline_middle(canvas, Thickness.light);
|
self.vline_middle(canvas, .light);
|
||||||
try self.draw_light_arc(canvas, .tr);
|
try self.draw_arc(canvas, .tr, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5db => {
|
0x0f5db => {
|
||||||
self.vline_middle(canvas, Thickness.light);
|
self.vline_middle(canvas, .light);
|
||||||
try self.draw_light_arc(canvas, .br);
|
try self.draw_arc(canvas, .br, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5dc => {
|
0x0f5dc => {
|
||||||
try self.draw_light_arc(canvas, .tr);
|
try self.draw_arc(canvas, .tr, .light);
|
||||||
try self.draw_light_arc(canvas, .br);
|
try self.draw_arc(canvas, .br, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5dd => {
|
0x0f5dd => {
|
||||||
self.vline_middle(canvas, Thickness.light);
|
self.vline_middle(canvas, .light);
|
||||||
try self.draw_light_arc(canvas, .tl);
|
try self.draw_arc(canvas, .tl, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5de => {
|
0x0f5de => {
|
||||||
self.vline_middle(canvas, Thickness.light);
|
self.vline_middle(canvas, .light);
|
||||||
try self.draw_light_arc(canvas, .bl);
|
try self.draw_arc(canvas, .bl, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5df => {
|
0x0f5df => {
|
||||||
try self.draw_light_arc(canvas, .tl);
|
try self.draw_arc(canvas, .tl, .light);
|
||||||
try self.draw_light_arc(canvas, .bl);
|
try self.draw_arc(canvas, .bl, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5e0 => {
|
0x0f5e0 => {
|
||||||
try self.draw_light_arc(canvas, .bl);
|
try self.draw_arc(canvas, .bl, .light);
|
||||||
self.hline_middle(canvas, Thickness.light);
|
self.hline_middle(canvas, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5e1 => {
|
0x0f5e1 => {
|
||||||
try self.draw_light_arc(canvas, .br);
|
try self.draw_arc(canvas, .br, .light);
|
||||||
self.hline_middle(canvas, Thickness.light);
|
self.hline_middle(canvas, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5e2 => {
|
0x0f5e2 => {
|
||||||
try self.draw_light_arc(canvas, .br);
|
try self.draw_arc(canvas, .br, .light);
|
||||||
try self.draw_light_arc(canvas, .bl);
|
try self.draw_arc(canvas, .bl, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5e3 => {
|
0x0f5e3 => {
|
||||||
try self.draw_light_arc(canvas, .tl);
|
try self.draw_arc(canvas, .tl, .light);
|
||||||
self.hline_middle(canvas, Thickness.light);
|
self.hline_middle(canvas, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5e4 => {
|
0x0f5e4 => {
|
||||||
try self.draw_light_arc(canvas, .tr);
|
try self.draw_arc(canvas, .tr, .light);
|
||||||
self.hline_middle(canvas, Thickness.light);
|
self.hline_middle(canvas, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5e5 => {
|
0x0f5e5 => {
|
||||||
try self.draw_light_arc(canvas, .tr);
|
try self.draw_arc(canvas, .tr, .light);
|
||||||
try self.draw_light_arc(canvas, .tl);
|
try self.draw_arc(canvas, .tl, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5e6 => {
|
0x0f5e6 => {
|
||||||
self.vline_middle(canvas, Thickness.light);
|
self.vline_middle(canvas, .light);
|
||||||
try self.draw_light_arc(canvas, .tl);
|
try self.draw_arc(canvas, .tl, .light);
|
||||||
try self.draw_light_arc(canvas, .tr);
|
try self.draw_arc(canvas, .tr, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5e7 => {
|
0x0f5e7 => {
|
||||||
self.vline_middle(canvas, Thickness.light);
|
self.vline_middle(canvas, .light);
|
||||||
try self.draw_light_arc(canvas, .bl);
|
try self.draw_arc(canvas, .bl, .light);
|
||||||
try self.draw_light_arc(canvas, .br);
|
try self.draw_arc(canvas, .br, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5e8 => {
|
0x0f5e8 => {
|
||||||
self.hline_middle(canvas, Thickness.light);
|
self.hline_middle(canvas, .light);
|
||||||
try self.draw_light_arc(canvas, .bl);
|
try self.draw_arc(canvas, .bl, .light);
|
||||||
try self.draw_light_arc(canvas, .tl);
|
try self.draw_arc(canvas, .tl, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5e9 => {
|
0x0f5e9 => {
|
||||||
self.hline_middle(canvas, Thickness.light);
|
self.hline_middle(canvas, .light);
|
||||||
try self.draw_light_arc(canvas, .tr);
|
try self.draw_arc(canvas, .tr, .light);
|
||||||
try self.draw_light_arc(canvas, .br);
|
try self.draw_arc(canvas, .br, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5ea => {
|
0x0f5ea => {
|
||||||
self.vline_middle(canvas, Thickness.light);
|
self.vline_middle(canvas, .light);
|
||||||
try self.draw_light_arc(canvas, .tl);
|
try self.draw_arc(canvas, .tl, .light);
|
||||||
try self.draw_light_arc(canvas, .br);
|
try self.draw_arc(canvas, .br, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5eb => {
|
0x0f5eb => {
|
||||||
self.vline_middle(canvas, Thickness.light);
|
self.vline_middle(canvas, .light);
|
||||||
try self.draw_light_arc(canvas, .tr);
|
try self.draw_arc(canvas, .tr, .light);
|
||||||
try self.draw_light_arc(canvas, .bl);
|
try self.draw_arc(canvas, .bl, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5ec => {
|
0x0f5ec => {
|
||||||
self.hline_middle(canvas, Thickness.light);
|
self.hline_middle(canvas, .light);
|
||||||
try self.draw_light_arc(canvas, .tl);
|
try self.draw_arc(canvas, .tl, .light);
|
||||||
try self.draw_light_arc(canvas, .br);
|
try self.draw_arc(canvas, .br, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5ed => {
|
0x0f5ed => {
|
||||||
self.hline_middle(canvas, Thickness.light);
|
self.hline_middle(canvas, .light);
|
||||||
try self.draw_light_arc(canvas, .tr);
|
try self.draw_arc(canvas, .tr, .light);
|
||||||
try self.draw_light_arc(canvas, .bl);
|
try self.draw_arc(canvas, .bl, .light);
|
||||||
},
|
},
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5ee => self.draw_git_node(canvas, .{}, Thickness.light, true),
|
0x0f5ee => self.draw_branch_node(canvas, .{ .filled = true }, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5ef => self.draw_git_node(canvas, .{}, Thickness.light, false),
|
0x0f5ef => self.draw_branch_node(canvas, .{}, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5f0 => {
|
0x0f5f0 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .right = true }, Thickness.light, true);
|
.right = true,
|
||||||
},
|
.filled = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f5f1 => {
|
0x0f5f1 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .right = true }, Thickness.light, false);
|
.right = true,
|
||||||
},
|
}, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5f2 => {
|
0x0f5f2 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .left = true }, Thickness.light, true);
|
.left = true,
|
||||||
},
|
.filled = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f5f3 => {
|
0x0f5f3 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .left = true }, Thickness.light, false);
|
.left = true,
|
||||||
},
|
}, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5f4 => {
|
0x0f5f4 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .left = true, .right = true }, Thickness.light, true);
|
.left = true,
|
||||||
},
|
.right = true,
|
||||||
|
.filled = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f5f5 => {
|
0x0f5f5 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .left = true, .right = true }, Thickness.light, false);
|
.left = true,
|
||||||
},
|
.right = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f5f6 => {
|
0x0f5f6 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .down = true }, Thickness.light, true);
|
.down = true,
|
||||||
},
|
.filled = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f5f7 => {
|
0x0f5f7 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .down = true }, Thickness.light, false);
|
.down = true,
|
||||||
},
|
}, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5f8 => {
|
0x0f5f8 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true }, Thickness.light, true);
|
.up = true,
|
||||||
},
|
.filled = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f5f9 => {
|
0x0f5f9 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true }, Thickness.light, false);
|
.up = true,
|
||||||
},
|
}, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f5fa => {
|
0x0f5fa => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true, .down = true }, Thickness.light, true);
|
.up = true,
|
||||||
},
|
.down = true,
|
||||||
|
.filled = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f5fb => {
|
0x0f5fb => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true, .down = true }, Thickness.light, false);
|
.up = true,
|
||||||
},
|
.down = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f5fc => {
|
0x0f5fc => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .right = true, .down = true }, Thickness.light, true);
|
.right = true,
|
||||||
},
|
.down = true,
|
||||||
|
.filled = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f5fd => {
|
0x0f5fd => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .right = true, .down = true }, Thickness.light, false);
|
.right = true,
|
||||||
},
|
.down = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f5fe => {
|
0x0f5fe => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .left = true, .down = true }, Thickness.light, true);
|
.left = true,
|
||||||
},
|
.down = true,
|
||||||
|
.filled = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f5ff => {
|
0x0f5ff => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .left = true, .down = true }, Thickness.light, false);
|
.left = true,
|
||||||
},
|
.down = true,
|
||||||
|
}, .light),
|
||||||
|
|
||||||
// ''
|
// ''
|
||||||
0x0f600 => {
|
0x0f600 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true, .right = true }, Thickness.light, true);
|
.up = true,
|
||||||
},
|
.right = true,
|
||||||
|
.filled = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f601 => {
|
0x0f601 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true, .right = true }, Thickness.light, false);
|
.up = true,
|
||||||
},
|
.right = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f602 => {
|
0x0f602 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true, .left = true }, Thickness.light, true);
|
.up = true,
|
||||||
},
|
.left = true,
|
||||||
|
.filled = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f603 => {
|
0x0f603 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true, .left = true }, Thickness.light, false);
|
.up = true,
|
||||||
},
|
.left = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f604 => {
|
0x0f604 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true, .down = true, .right = true }, Thickness.light, true);
|
.up = true,
|
||||||
},
|
.down = true,
|
||||||
|
.right = true,
|
||||||
|
.filled = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f605 => {
|
0x0f605 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true, .down = true, .right = true }, Thickness.light, false);
|
.up = true,
|
||||||
},
|
.down = true,
|
||||||
|
.right = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f606 => {
|
0x0f606 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true, .down = true, .left = true }, Thickness.light, true);
|
.up = true,
|
||||||
},
|
.down = true,
|
||||||
|
.left = true,
|
||||||
|
.filled = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f607 => {
|
0x0f607 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true, .down = true, .left = true }, Thickness.light, false);
|
.up = true,
|
||||||
},
|
.down = true,
|
||||||
|
.left = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f608 => {
|
0x0f608 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .down = true, .left = true, .right = true }, Thickness.light, true);
|
.down = true,
|
||||||
},
|
.left = true,
|
||||||
|
.right = true,
|
||||||
|
.filled = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f609 => {
|
0x0f609 => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .down = true, .left = true, .right = true }, Thickness.light, false);
|
.down = true,
|
||||||
},
|
.left = true,
|
||||||
|
.right = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f60a => {
|
0x0f60a => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true, .left = true, .right = true }, Thickness.light, true);
|
.up = true,
|
||||||
},
|
.left = true,
|
||||||
|
.right = true,
|
||||||
|
.filled = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f60b => {
|
0x0f60b => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true, .left = true, .right = true }, Thickness.light, false);
|
.up = true,
|
||||||
},
|
.left = true,
|
||||||
|
.right = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f60c => {
|
0x0f60c => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true, .down = true, .left = true, .right = true }, Thickness.light, true);
|
.up = true,
|
||||||
},
|
.down = true,
|
||||||
|
.left = true,
|
||||||
|
.right = true,
|
||||||
|
.filled = true,
|
||||||
|
}, .light),
|
||||||
// ''
|
// ''
|
||||||
0x0f60d => {
|
0x0f60d => self.draw_branch_node(canvas, .{
|
||||||
self.draw_git_node(canvas, .{ .up = true, .down = true, .left = true, .right = true }, Thickness.light, false);
|
.up = true,
|
||||||
},
|
.down = true,
|
||||||
|
.left = true,
|
||||||
|
.right = true,
|
||||||
|
}, .light),
|
||||||
|
|
||||||
// Not official box characters but special characters we hide
|
// Not official box characters but special characters we hide
|
||||||
// in the high bits of a unicode codepoint.
|
// in the high bits of a unicode codepoint.
|
||||||
@ -2116,21 +2128,98 @@ fn draw_cell_diagonal(
|
|||||||
) catch {};
|
) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_git_node(
|
fn draw_fading_line(
|
||||||
self: Box,
|
self: Box,
|
||||||
canvas: *font.sprite.Canvas,
|
canvas: *font.sprite.Canvas,
|
||||||
comptime nodes: NodeAlign,
|
comptime to: Edge,
|
||||||
comptime thickness: Thickness,
|
comptime thickness: Thickness,
|
||||||
comptime filled: bool,
|
|
||||||
) void {
|
) void {
|
||||||
|
const thick_px = thickness.height(self.thickness);
|
||||||
const float_width: f64 = @floatFromInt(self.width);
|
const float_width: f64 = @floatFromInt(self.width);
|
||||||
const float_height: f64 = @floatFromInt(self.height);
|
const float_height: f64 = @floatFromInt(self.height);
|
||||||
|
|
||||||
const x: f64 = float_width / 2;
|
// Top of horizontal strokes
|
||||||
const y: f64 = float_height / 2;
|
const h_top = (self.height -| thick_px) / 2;
|
||||||
|
// Bottom of horizontal strokes
|
||||||
|
const h_bottom = h_top +| thick_px;
|
||||||
|
// Left of vertical strokes
|
||||||
|
const v_left = (self.width -| thick_px) / 2;
|
||||||
|
// Right of vertical strokes
|
||||||
|
const v_right = v_left +| thick_px;
|
||||||
|
|
||||||
// we need at least 1px leeway to see node + right/left line
|
// If we're fading to the top or left, we start with 0.0
|
||||||
const r: f64 = 0.47 * @min(float_width, float_height);
|
// and increment up as we progress, otherwise we start
|
||||||
|
// at 255.0 and increment down (negative).
|
||||||
|
var color: f64 = switch (to) {
|
||||||
|
.top, .left => 0.0,
|
||||||
|
.bottom, .right => 255.0,
|
||||||
|
};
|
||||||
|
const inc: f64 = 255.0 / switch (to) {
|
||||||
|
.top => float_height,
|
||||||
|
.bottom => -float_height,
|
||||||
|
.left => float_width,
|
||||||
|
.right => -float_width,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (to) {
|
||||||
|
.top, .bottom => {
|
||||||
|
for (0..self.height) |y| {
|
||||||
|
for (v_left..v_right) |x| {
|
||||||
|
canvas.pixel(
|
||||||
|
@intCast(x),
|
||||||
|
@intCast(y),
|
||||||
|
@enumFromInt(@as(u8, @intFromFloat(@round(color)))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
color += inc;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.left, .right => {
|
||||||
|
for (0..self.width) |x| {
|
||||||
|
for (h_top..h_bottom) |y| {
|
||||||
|
canvas.pixel(
|
||||||
|
@intCast(x),
|
||||||
|
@intCast(y),
|
||||||
|
@enumFromInt(@as(u8, @intFromFloat(@round(color)))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
color += inc;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_branch_node(
|
||||||
|
self: Box,
|
||||||
|
canvas: *font.sprite.Canvas,
|
||||||
|
node: BranchNode,
|
||||||
|
comptime thickness: Thickness,
|
||||||
|
) void {
|
||||||
|
const thick_px = thickness.height(self.thickness);
|
||||||
|
const float_width: f64 = @floatFromInt(self.width);
|
||||||
|
const float_height: f64 = @floatFromInt(self.height);
|
||||||
|
const float_thick: f64 = @floatFromInt(thick_px);
|
||||||
|
|
||||||
|
// Top of horizontal strokes
|
||||||
|
const h_top = (self.height -| thick_px) / 2;
|
||||||
|
// Bottom of horizontal strokes
|
||||||
|
const h_bottom = h_top +| thick_px;
|
||||||
|
// Left of vertical strokes
|
||||||
|
const v_left = (self.width -| thick_px) / 2;
|
||||||
|
// Right of vertical strokes
|
||||||
|
const v_right = v_left +| thick_px;
|
||||||
|
|
||||||
|
// We calculate the center of the circle this way
|
||||||
|
// to ensure it aligns with box drawing characters
|
||||||
|
// since the lines are sometimes off center to
|
||||||
|
// make sure they aren't split between pixels.
|
||||||
|
const cx: f64 = @as(f64, @floatFromInt(v_left)) + float_thick / 2;
|
||||||
|
const cy: f64 = @as(f64, @floatFromInt(h_top)) + float_thick / 2;
|
||||||
|
// The radius needs to be the smallest distance from the center to an edge.
|
||||||
|
const r: f64 = @min(
|
||||||
|
@min(cx, cy),
|
||||||
|
@min(float_width - cx, float_height - cy),
|
||||||
|
);
|
||||||
|
|
||||||
var ctx: z2d.Context = .{
|
var ctx: z2d.Context = .{
|
||||||
.surface = canvas.sfc,
|
.surface = canvas.sfc,
|
||||||
@ -2139,29 +2228,30 @@ fn draw_git_node(
|
|||||||
.pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } },
|
.pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.line_width = @floatFromInt(thickness.height(self.thickness)),
|
.line_width = float_thick,
|
||||||
};
|
};
|
||||||
|
|
||||||
var path = z2d.Path.init(canvas.alloc);
|
var path = z2d.Path.init(canvas.alloc);
|
||||||
defer path.deinit();
|
defer path.deinit();
|
||||||
|
|
||||||
const int_radius: u32 = @intFromFloat(r);
|
// These @intFromFloat casts shouldn't ever fail since r can never
|
||||||
|
// be greater than cx or cy, so when subtracting it from them the
|
||||||
|
// result can never be negative.
|
||||||
|
if (node.up)
|
||||||
|
self.rect(canvas, v_left, 0, v_right, @intFromFloat(@ceil(cy - r)));
|
||||||
|
if (node.right)
|
||||||
|
self.rect(canvas, @intFromFloat(@floor(cx + r)), h_top, self.width, h_bottom);
|
||||||
|
if (node.down)
|
||||||
|
self.rect(canvas, v_left, @intFromFloat(@floor(cy + r)), v_right, self.height);
|
||||||
|
if (node.left)
|
||||||
|
self.rect(canvas, 0, h_top, @intFromFloat(@ceil(cx - r)), h_bottom);
|
||||||
|
|
||||||
if (nodes.up)
|
if (node.filled) {
|
||||||
self.vline_middle_xy(canvas, 0, (self.height / 2) - int_radius, self.width, thickness);
|
path.arc(cx, cy, r, 0, std.math.pi * 2, false, null) catch return;
|
||||||
if (nodes.down)
|
|
||||||
self.vline_middle_xy(canvas, (self.height / 2) + int_radius, self.height, self.width, thickness);
|
|
||||||
if (nodes.left)
|
|
||||||
self.hline_middle_xy(canvas, 0, (self.width / 2) - int_radius, self.height, thickness);
|
|
||||||
if (nodes.right)
|
|
||||||
self.hline_middle_xy(canvas, (self.width / 2) + int_radius, self.width, self.height, thickness);
|
|
||||||
|
|
||||||
if (filled) {
|
|
||||||
path.arc(x, y, r, 0, std.math.pi * 2, false, null) catch return;
|
|
||||||
path.close() catch return;
|
path.close() catch return;
|
||||||
ctx.fill(canvas.alloc, path) catch return;
|
ctx.fill(canvas.alloc, path) catch return;
|
||||||
} else {
|
} else {
|
||||||
path.arc(x, y, r - ctx.line_width / 2, 0, std.math.pi * 2, false, null) catch return;
|
path.arc(cx, cy, r - float_thick / 2, 0, std.math.pi * 2, false, null) catch return;
|
||||||
path.close() catch return;
|
path.close() catch return;
|
||||||
ctx.stroke(canvas.alloc, path) catch return;
|
ctx.stroke(canvas.alloc, path) catch return;
|
||||||
}
|
}
|
||||||
@ -2492,12 +2582,13 @@ fn draw_edge_triangle(
|
|||||||
try ctx.fill(canvas.alloc, path);
|
try ctx.fill(canvas.alloc, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_light_arc(
|
fn draw_arc(
|
||||||
self: Box,
|
self: Box,
|
||||||
canvas: *font.sprite.Canvas,
|
canvas: *font.sprite.Canvas,
|
||||||
comptime corner: Corner,
|
comptime corner: Corner,
|
||||||
|
comptime thickness: Thickness,
|
||||||
) !void {
|
) !void {
|
||||||
const thick_px = Thickness.light.height(self.thickness);
|
const thick_px = thickness.height(self.thickness);
|
||||||
const float_width: f64 = @floatFromInt(self.width);
|
const float_width: f64 = @floatFromInt(self.width);
|
||||||
const float_height: f64 = @floatFromInt(self.height);
|
const float_height: f64 = @floatFromInt(self.height);
|
||||||
const float_thick: f64 = @floatFromInt(thick_px);
|
const float_thick: f64 = @floatFromInt(thick_px);
|
||||||
@ -2751,16 +2842,6 @@ fn draw_cursor_bar(self: Box, canvas: *font.sprite.Canvas) void {
|
|||||||
self.vline(canvas, 0, self.height, 0, thick_px);
|
self.vline(canvas, 0, self.height, 0, thick_px);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vline_middle_xy(self: Box, canvas: *font.sprite.Canvas, y: u32, y2: u32, x: u32, thickness: Thickness) void {
|
|
||||||
const thick_px = thickness.height(self.thickness);
|
|
||||||
self.vline(canvas, y, y2, (x -| thick_px) / 2, thick_px);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hline_middle_xy(self: Box, canvas: *font.sprite.Canvas, x: u32, x2: u32, y: u32, thickness: Thickness) void {
|
|
||||||
const thick_px = thickness.height(self.thickness);
|
|
||||||
self.hline(canvas, x, x2, (y -| thick_px) / 2, thick_px);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vline_middle(self: Box, canvas: *font.sprite.Canvas, thickness: Thickness) void {
|
fn vline_middle(self: Box, canvas: *font.sprite.Canvas, thickness: Thickness) void {
|
||||||
const thick_px = thickness.height(self.thickness);
|
const thick_px = thickness.height(self.thickness);
|
||||||
self.vline(canvas, 0, self.height, (self.width -| thick_px) / 2, thick_px);
|
self.vline(canvas, 0, self.height, (self.width -| thick_px) / 2, thick_px);
|
||||||
@ -2864,20 +2945,6 @@ fn testRenderAll(self: Box, alloc: Allocator, atlas: *font.Atlas) !void {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Git Branch characters
|
|
||||||
cp = 0xf5d0;
|
|
||||||
while (cp <= 0xf60d) : (cp += 1) {
|
|
||||||
switch (cp) {
|
|
||||||
0xf5d0...0xf60d,
|
|
||||||
=> _ = try self.renderGlyph(
|
|
||||||
alloc,
|
|
||||||
atlas,
|
|
||||||
cp,
|
|
||||||
),
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Symbols for Legacy Computing.
|
// Symbols for Legacy Computing.
|
||||||
cp = 0x1fb00;
|
cp = 0x1fb00;
|
||||||
while (cp <= 0x1fbef) : (cp += 1) {
|
while (cp <= 0x1fbef) : (cp += 1) {
|
||||||
@ -2932,6 +2999,32 @@ fn testRenderAll(self: Box, alloc: Allocator, atlas: *font.Atlas) !void {
|
|||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Branch drawing character set, used for drawing git-like
|
||||||
|
// graphs in the terminal. Originally implemented in Kitty.
|
||||||
|
// Ref:
|
||||||
|
// - https://github.com/kovidgoyal/kitty/pull/7681
|
||||||
|
// - https://github.com/kovidgoyal/kitty/pull/7805
|
||||||
|
// NOTE: Kitty is GPL licensed, and its code was not referenced
|
||||||
|
// for these characters, only the loose specification of
|
||||||
|
// the character set in the pull request descriptions.
|
||||||
|
//
|
||||||
|
// TODO(qwerasd): This should be in another file, but really the
|
||||||
|
// general organization of the sprite font code
|
||||||
|
// needs to be reworked eventually.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
cp = 0xf5d0;
|
||||||
|
while (cp <= 0xf60d) : (cp += 1) {
|
||||||
|
_ = try self.renderGlyph(
|
||||||
|
alloc,
|
||||||
|
atlas,
|
||||||
|
cp,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "render all sprites" {
|
test "render all sprites" {
|
||||||
|
@ -263,6 +263,21 @@ const Kind = enum {
|
|||||||
0x1FBCE...0x1FBEF,
|
0x1FBCE...0x1FBEF,
|
||||||
=> .box,
|
=> .box,
|
||||||
|
|
||||||
|
// Branch drawing character set, used for drawing git-like
|
||||||
|
// graphs in the terminal. Originally implemented in Kitty.
|
||||||
|
// Ref:
|
||||||
|
// - https://github.com/kovidgoyal/kitty/pull/7681
|
||||||
|
// - https://github.com/kovidgoyal/kitty/pull/7805
|
||||||
|
// NOTE: Kitty is GPL licensed, and its code was not referenced
|
||||||
|
// for these characters, only the loose specification of
|
||||||
|
// the character set in the pull request descriptions.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
0xF5D0...0xF60D => .box,
|
||||||
|
|
||||||
// Powerline fonts
|
// Powerline fonts
|
||||||
0xE0B0,
|
0xE0B0,
|
||||||
0xE0B4,
|
0xE0B4,
|
||||||
@ -276,13 +291,6 @@ const Kind = enum {
|
|||||||
0xE0D4,
|
0xE0D4,
|
||||||
=> .powerline,
|
=> .powerline,
|
||||||
|
|
||||||
// (Git Branch)
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
0xF5D0...0xF60D => .box,
|
|
||||||
|
|
||||||
else => null,
|
else => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
BIN
src/font/sprite/testdata/Box.ppm
vendored
BIN
src/font/sprite/testdata/Box.ppm
vendored
Binary file not shown.
Reference in New Issue
Block a user