160 lines
4.7 KiB
Zig
160 lines
4.7 KiB
Zig
const rl = @import("raylib");
|
|
const std = @import("std");
|
|
|
|
const UI = @This();
|
|
|
|
font: rl.Font,
|
|
|
|
pub fn init() UI {
|
|
return UI{
|
|
.font = rl.getFontDefault()
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: UI) void {
|
|
rl.unloadFont(self.font);
|
|
}
|
|
|
|
// Reimplementation of `GetGlyphIndex` from raylib in src/rtext.c
|
|
fn GetGlyphIndex(font: rl.Font, codepoint: i32) usize {
|
|
var index: usize = 0;
|
|
|
|
var fallbackIndex: usize = 0; // Get index of fallback glyph '?'
|
|
|
|
for (0..@intCast(font.glyphCount), font.glyphs) |i, glyph| {
|
|
if (glyph.value == '?') fallbackIndex = i;
|
|
|
|
if (glyph.value == codepoint)
|
|
{
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((index == 0) and (font.glyphs[0].value != codepoint)) index = fallbackIndex;
|
|
|
|
return index;
|
|
}
|
|
|
|
fn GetCodePointNext(text: []const u8, next: *usize) i32 {
|
|
var letter: i32 = '?';
|
|
|
|
if (std.unicode.utf8ByteSequenceLength(text[0])) |codepointSize| {
|
|
next.* = codepointSize;
|
|
if (std.unicode.utf8Decode(text[0..codepointSize])) |codepoint| {
|
|
letter = @intCast(codepoint);
|
|
} else |_| {}
|
|
} else |_| {}
|
|
|
|
return letter;
|
|
}
|
|
|
|
// NOTE: Line spacing is a global variable, use SetTextLineSpacing() to setup
|
|
const textLineSpacing = 2; // TODO: Assume that line spacing is not changed.
|
|
|
|
// Reimplementation of `rl.drawTextEx`, so a null terminated would not be required
|
|
pub fn drawTextEx(font: rl.Font, text: []const u8, position: rl.Vector2, font_size: f32, spacing: f32, tint: rl.Color) void {
|
|
var used_font = font;
|
|
if (font.texture.id == 0) {
|
|
used_font = rl.getFontDefault();
|
|
}
|
|
|
|
var text_offset_y: f32 = 0;
|
|
var text_offset_x: f32 = 0;
|
|
|
|
const scale_factor = font_size / @as(f32, @floatFromInt(used_font.baseSize));
|
|
|
|
var i: usize = 0;
|
|
while (i < text.len) {
|
|
var next: usize = 0;
|
|
|
|
const letter = GetCodePointNext(text[i..], &next);
|
|
const index = GetGlyphIndex(font, letter);
|
|
|
|
i += next;
|
|
|
|
if (letter == '\n') {
|
|
text_offset_x = 0;
|
|
text_offset_y += (font_size + textLineSpacing);
|
|
} else {
|
|
if (letter != ' ' and letter != '\t') {
|
|
rl.drawTextCodepoint(font, letter, .{
|
|
.x = position.x + text_offset_x,
|
|
.y = position.y + text_offset_y,
|
|
}, font_size, tint);
|
|
}
|
|
|
|
if (font.glyphs[index].advanceX == 0) {
|
|
text_offset_x += font.recs[index].width*scale_factor + spacing;
|
|
} else {
|
|
text_offset_x += @as(f32, @floatFromInt(font.glyphs[index].advanceX))*scale_factor + spacing;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reimplementation of `rl.measureTextEx`, so a null terminated would not be required
|
|
pub fn measureTextEx(font: rl.Font, text: []const u8, fontSize: f32, spacing: f32) rl.Vector2 {
|
|
var textSize = rl.Vector2.init(0, 0);
|
|
|
|
if (font.texture.id == 0) return textSize; // Security check
|
|
|
|
var tempByteCounter: i32 = 0; // Used to count longer text line num chars
|
|
var byteCounter: i32 = 0;
|
|
|
|
var textWidth: f32 = 0;
|
|
var tempTextWidth: f32 = 0; // Used to count longer text line width
|
|
|
|
var textHeight: f32 = fontSize;
|
|
const scaleFactor: f32 = fontSize/@as(f32, @floatFromInt(font.baseSize));
|
|
|
|
var i: usize = 0;
|
|
while (i < text.len)
|
|
{
|
|
byteCounter += 1;
|
|
|
|
var next: usize = 0;
|
|
|
|
const letter = GetCodePointNext(text[i..], &next);
|
|
const index = GetGlyphIndex(font, letter);
|
|
|
|
i += next;
|
|
|
|
if (letter != '\n')
|
|
{
|
|
if (font.glyphs[index].advanceX != 0) {
|
|
textWidth += @floatFromInt(font.glyphs[index].advanceX);
|
|
} else {
|
|
textWidth += font.recs[index].width;
|
|
textWidth += @floatFromInt(font.glyphs[index].offsetX);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (tempTextWidth < textWidth) tempTextWidth = textWidth;
|
|
byteCounter = 0;
|
|
textWidth = 0;
|
|
|
|
textHeight += (fontSize + textLineSpacing);
|
|
}
|
|
|
|
if (tempByteCounter < byteCounter) tempByteCounter = byteCounter;
|
|
}
|
|
|
|
if (tempTextWidth < textWidth) tempTextWidth = textWidth;
|
|
|
|
textSize.x = tempTextWidth*scaleFactor + @as(f32, @floatFromInt(tempByteCounter - 1)) * spacing;
|
|
textSize.y = textHeight;
|
|
|
|
return textSize;
|
|
}
|
|
|
|
pub fn drawTextCentered(font: rl.Font, text: []const u8, position: rl.Vector2, font_size: f32, spacing: f32, color: rl.Color) void {
|
|
const text_size = measureTextEx(font, text, font_size, spacing);
|
|
const adjusted_position = rl.Vector2{
|
|
.x = position.x - text_size.x/2,
|
|
.y = position.y - text_size.y/2,
|
|
};
|
|
drawTextEx(font, text, adjusted_position, font_size, spacing, color);
|
|
}
|