artificer/gui/font-face.zig
2024-12-29 06:18:36 +02:00

139 lines
4.4 KiB
Zig

const std = @import("std");
const rl = @import("raylib");
font: rl.Font,
spacing: ?f32 = null,
line_height: f32 = 1.4,
pub fn getSpacing(self: @This()) f32 {
if (self.spacing) |spacing| {
return spacing;
} else {
return self.getSize() / 10;
}
}
pub fn getSize(self: @This()) f32 {
return @floatFromInt(self.font.baseSize);
}
pub fn drawTextLines(self: @This(), lines: []const []const u8, position: rl.Vector2, tint: rl.Color) void {
var offset_y: f32 = 0;
const font_size = self.getSize();
for (lines) |line| {
self.drawText(line, position.add(.{ .x = 0, .y = offset_y }), tint);
const line_size = self.measureText(line);
offset_y += line_size.y + font_size * (self.line_height - 1);
}
}
pub fn measureTextLines(self: @This(), lines: []const []const u8) rl.Vector2 {
var text_size = rl.Vector2.zero();
const font_size = self.getSize();
for (lines) |line| {
const line_size = self.measureText(line);
text_size.x = @max(text_size.x, line_size.x);
text_size.y += line_size.y;
}
text_size.y += (self.line_height - 1) * font_size * @as(f32, @floatFromInt(@max(lines.len - 1, 0)));
return text_size;
}
pub fn drawTextEx(self: @This(), text: []const u8, position: rl.Vector2, tint: rl.Color, offset: *rl.Vector2) void {
if (self.font.texture.id == 0) return;
const font_size = self.getSize();
const spacing = self.getSpacing();
var iter = std.unicode.Utf8Iterator{ .bytes = text, .i = 0 };
while (iter.nextCodepoint()) |codepoint| {
if (codepoint == '\n') {
offset.x = 0;
offset.y += font_size * self.line_height;
} else {
if (!(codepoint <= 255 and std.ascii.isWhitespace(@intCast(codepoint)))) {
var codepoint_position = position.add(offset.*);
codepoint_position.x = @round(codepoint_position.x);
codepoint_position.y = @round(codepoint_position.y);
rl.drawTextCodepoint(self.font, codepoint, codepoint_position, font_size, tint);
}
const index: u32 = @intCast(rl.getGlyphIndex(self.font, codepoint));
if (self.font.glyphs[index].advanceX != 0) {
offset.x += @floatFromInt(self.font.glyphs[index].advanceX);
} else {
offset.x += self.font.recs[index].width;
offset.x += @floatFromInt(self.font.glyphs[index].offsetX);
}
offset.x += spacing;
}
}
}
pub fn drawText(self: @This(), text: []const u8, position: rl.Vector2, tint: rl.Color) void {
var offset = rl.Vector2.init(0, 0);
self.drawTextEx(text, position, tint, &offset);
}
pub fn drawTextAlloc(self: @This(), allocator: std.mem.Allocator, comptime fmt: []const u8, args: anytype, position: rl.Vector2, tint: rl.Color) !void {
const text = try std.fmt.allocPrint(allocator, fmt, args);
defer allocator.free(text);
self.drawText(text, position, tint);
}
pub fn measureText(self: @This(), text: []const u8) rl.Vector2 {
var text_size = rl.Vector2.zero();
if (self.font.texture.id == 0) return text_size; // Security check
if (text.len == 0) return text_size;
const font_size = self.getSize();
const spacing = self.getSpacing();
var line_width: f32 = 0;
text_size.y = font_size;
var iter = std.unicode.Utf8Iterator{ .bytes = text, .i = 0 };
while (iter.nextCodepoint()) |codepoint| {
if (codepoint == '\n') {
text_size.y += font_size * self.line_height;
line_width = 0;
} else {
if (line_width > 0) {
line_width += spacing;
}
const index: u32 = @intCast(rl.getGlyphIndex(self.font, codepoint));
if (self.font.glyphs[index].advanceX != 0) {
line_width += @floatFromInt(self.font.glyphs[index].advanceX);
} else {
line_width += self.font.recs[index].width;
line_width += @floatFromInt(self.font.glyphs[index].offsetX);
}
text_size.x = @max(text_size.x, line_width);
}
}
return text_size;
}
pub fn drawTextCenter(self: @This(), text: []const u8, position: rl.Vector2, tint: rl.Color) void {
const text_size = self.measureText(text);
const adjusted_position = rl.Vector2{
.x = position.x - text_size.x / 2,
.y = position.y - text_size.y / 2,
};
self.drawText(text, adjusted_position, tint);
}