Add a Label component.

This commit is contained in:
IntegratedQuantum 2023-02-28 13:05:10 +01:00
parent 7ce9dc8716
commit 82ad5f2b98
5 changed files with 71 additions and 28 deletions

View File

@ -4,8 +4,9 @@ const main = @import("root");
const vec = main.vec;
const Vec2f = vec.Vec2f;
const Button = @import("components/Button.zig");
const VerticalList = @import("components/VerticalList.zig");
pub const Button = @import("components/Button.zig");
pub const Label = @import("components/Label.zig");
pub const VerticalList = @import("components/VerticalList.zig");
const GuiComponent = @This();
@ -15,6 +16,7 @@ impl: Impl,
const Impl = union(enum) {
button: Button,
label: Label,
verticalList: VerticalList,
};
@ -37,7 +39,7 @@ pub fn update(self: *GuiComponent) void {
// Only call the function if it exists:
inline for(@typeInfo(@TypeOf(impl.*)).Struct.decls) |decl| {
if(comptime std.mem.eql(u8, decl.name, "update")) {
impl.update(self);
impl.update(self.pos, self.size);
}
}
}
@ -50,7 +52,7 @@ pub fn render(self: *GuiComponent, mousePosition: Vec2f) !void {
// Only call the function if it exists:
inline for(@typeInfo(@TypeOf(impl.*)).Struct.decls) |decl| {
if(comptime std.mem.eql(u8, decl.name, "render")) {
try impl.render(self, mousePosition);
try impl.render(self.pos, self.size, mousePosition);
}
}
}
@ -63,7 +65,7 @@ pub fn mainButtonPressed(self: *GuiComponent, mousePosition: Vec2f) void {
// Only call the function if it exists:
inline for(@typeInfo(@TypeOf(impl.*)).Struct.decls) |decl| {
if(comptime std.mem.eql(u8, decl.name, "mainButtonPressed")) {
impl.mainButtonPressed(self, mousePosition);
impl.mainButtonPressed(self.pos, self.size, mousePosition);
}
}
}
@ -76,13 +78,13 @@ pub fn mainButtonReleased(self: *GuiComponent, mousePosition: Vec2f) void {
// Only call the function if it exists:
inline for(@typeInfo(@TypeOf(impl.*)).Struct.decls) |decl| {
if(comptime std.mem.eql(u8, decl.name, "mainButtonReleased")) {
impl.mainButtonReleased(self, mousePosition);
impl.mainButtonReleased(self.pos, self.size, mousePosition);
}
}
}
}
}
pub fn contains(self: GuiComponent, pos: Vec2f) bool {
return @reduce(.And, pos >= self.pos) and @reduce(.And, pos < self.pos + self.size);
pub fn contains(pos: Vec2f, size: Vec2f, point: Vec2f) bool {
return @reduce(.And, point >= pos) and @reduce(.And, point < pos + size);
}

View File

@ -120,7 +120,7 @@ pub fn mainButtonPressed(self: *const GuiWindow) void {
} else {
var selectedComponent: ?*GuiComponent = null;
for(self.components) |*component| {
if(component.contains(mousePosition)) {
if(GuiComponent.contains(component.pos, component.size, mousePosition)) {
selectedComponent = component;
}
}

View File

@ -14,6 +14,7 @@ const Vec2f = vec.Vec2f;
const gui = @import("../gui.zig");
const GuiComponent = gui.GuiComponent;
const Label = GuiComponent.Label;
const Button = @This();
@ -36,8 +37,8 @@ var buttonUniforms: struct {
pressed: bool = false,
onAction: *const fn() void,
text: TextBuffer,
textSize: Vec2f = undefined,
textSize: Vec2f,
label: Label,
randomOffset: Vec2f = undefined,
pub fn __init() !void {
@ -57,40 +58,41 @@ pub fn __deinit() void {
}
pub fn init(pos: Vec2f, width: f32, allocator: Allocator, text: []const u8, onAction: *const fn() void) Allocator.Error!GuiComponent {
const labelComponent = try Label.init(allocator, undefined, width - 3*border, text);
var self = Button {
.onAction = onAction,
.text = try TextBuffer.init(allocator, text, .{}, false),
.label = labelComponent.impl.label,
.textSize = labelComponent.size,
.randomOffset = Vec2f{
random.nextFloat(&main.seed),
random.nextFloat(&main.seed),
},
};
self.textSize = try self.text.calculateLineBreaks(fontSize, width - 3*border);
return GuiComponent {
.pos = pos,
.size = .{@max(width, self.textSize[0] + 3*border), self.textSize[1] + 3*border},
.size = Vec2f{@max(width, self.textSize[0] + 3*border), self.textSize[1] + 3*border},
.impl = .{.button = self}
};
}
pub fn deinit(self: Button) void {
self.text.deinit();
self.label.deinit();
}
pub fn mainButtonPressed(self: *Button, _: *const GuiComponent, _: Vec2f) void {
pub fn mainButtonPressed(self: *Button, _: Vec2f, _: Vec2f, _: Vec2f) void {
self.pressed = true;
}
pub fn mainButtonReleased(self: *Button, component: *const GuiComponent, mousePosition: Vec2f) void {
pub fn mainButtonReleased(self: *Button, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) void {
if(self.pressed) {
self.pressed = false;
if(component.contains(mousePosition)) {
if(GuiComponent.contains(pos, size, mousePosition)) {
self.onAction();
}
}
}
pub fn render(self: *Button, component: *const GuiComponent, mousePosition: Vec2f) !void {
pub fn render(self: *Button, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) !void {
graphics.c.glActiveTexture(graphics.c.GL_TEXTURE0);
texture.bind();
shader.bind();
@ -99,12 +101,12 @@ pub fn render(self: *Button, component: *const GuiComponent, mousePosition: Vec2
if(self.pressed) {
draw.setColor(0xff000000);
graphics.c.glUniform1i(buttonUniforms.pressed, 1);
} else if(component.contains(mousePosition)) {
} else if(GuiComponent.contains(pos, size, mousePosition)) {
draw.setColor(0xff000040);
} else {
draw.setColor(0xff000000);
}
draw.customShadedRect(buttonUniforms, component.pos, component.size);
const textPos = component.pos + component.size/@splat(2, @as(f32, 2.0)) - self.textSize/@splat(2, @as(f32, 2.0));
try self.text.render(textPos[0], textPos[1], fontSize);
draw.customShadedRect(buttonUniforms, pos, size);
const textPos = pos + size/@splat(2, @as(f32, 2.0)) - self.textSize/@splat(2, @as(f32, 2.0));
try self.label.render(textPos, self.textSize, mousePosition - textPos);
}

View File

@ -0,0 +1,39 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const main = @import("root");
const graphics = main.graphics;
const draw = graphics.draw;
const TextBuffer = graphics.TextBuffer;
const vec = main.vec;
const Vec2f = vec.Vec2f;
const gui = @import("../gui.zig");
const GuiComponent = gui.GuiComponent;
const Label = @This();
const fontSize: f32 = 16;
text: TextBuffer,
textSize: Vec2f = undefined,
pub fn init(allocator: Allocator, pos: Vec2f, maxWidth: f32, text: []const u8) Allocator.Error!GuiComponent {
var self = Label {
.text = try TextBuffer.init(allocator, text, .{}, false),
};
self.textSize = try self.text.calculateLineBreaks(fontSize, maxWidth);
return GuiComponent {
.pos = pos,
.size = self.textSize,
.impl = .{.label = self}
};
}
pub fn deinit(self: Label) void {
self.text.deinit();
}
pub fn render(self: *Label, pos: Vec2f, _: Vec2f, _: Vec2f) !void {
try self.text.render(pos[0], pos[1], fontSize);
}

View File

@ -50,22 +50,22 @@ pub fn add(self: *VerticalList, other: GuiComponent) Allocator.Error!void {
self.maxWidth = @max(self.maxWidth, added.pos[0] + added.size[0]);
}
pub fn update(self: *VerticalList, _: *const GuiComponent) void {
pub fn update(self: *VerticalList, _: Vec2f, _: Vec2f) void {
for(self.children.items) |*child| {
child.update();
}
}
pub fn render(self: *VerticalList, _: *const GuiComponent, mousePosition: Vec2f) anyerror!void { // TODO: Remove anyerror once error union inference works in recursive loops.
pub fn render(self: *VerticalList, _: Vec2f, _: Vec2f, mousePosition: Vec2f) anyerror!void { // TODO: Remove anyerror once error union inference works in recursive loops.
for(self.children.items) |*child| {
try child.render(mousePosition);
}
}
pub fn mainButtonPressed(self: *VerticalList, _: *const GuiComponent, mousePosition: Vec2f) void {
pub fn mainButtonPressed(self: *VerticalList, _: Vec2f, _: Vec2f, mousePosition: Vec2f) void {
var selectedChild: ?*GuiComponent = null;
for(self.children.items) |*child| {
if(child.contains(mousePosition)) {
if(GuiComponent.contains(child.pos, child.size, mousePosition)) {
selectedChild = child;
}
}
@ -74,7 +74,7 @@ pub fn mainButtonPressed(self: *VerticalList, _: *const GuiComponent, mousePosit
}
}
pub fn mainButtonReleased(self: *VerticalList, _: *const GuiComponent, mousePosition: Vec2f) void {
pub fn mainButtonReleased(self: *VerticalList, _: Vec2f, _: Vec2f, mousePosition: Vec2f) void {
for(self.children.items) |*child| {
child.mainButtonReleased(mousePosition);
}