diff --git a/src/gui/GuiComponent.zig b/src/gui/GuiComponent.zig deleted file mode 100644 index f3b1a081..00000000 --- a/src/gui/GuiComponent.zig +++ /dev/null @@ -1,111 +0,0 @@ -const std = @import("std"); - -const main = @import("root"); -const vec = main.vec; -const Vec2f = vec.Vec2f; - -pub const Button = @import("components/Button.zig"); -pub const CheckBox = @import("components/CheckBox.zig"); -pub const Label = @import("components/Label.zig"); -pub const Slider = @import("components/Slider.zig"); -pub const ScrollBar = @import("components/ScrollBar.zig"); -pub const TextInput = @import("components/TextInput.zig"); -pub const VerticalList = @import("components/VerticalList.zig"); - -const GuiComponent = @This(); - -pos: Vec2f, -size: Vec2f, -impl: Impl, - -const Impl = union(enum) { - button: Button, - checkBox: CheckBox, - label: Label, - scrollBar: ScrollBar, - slider: Slider, - textInput: TextInput, - verticalList: VerticalList, -}; - -pub fn deinit(self: *GuiComponent) void { - switch(self.impl) { - inline else => |*impl| { - // Only call the function if it exists: - inline for(@typeInfo(@TypeOf(impl.*)).Struct.decls) |decl| { - if(comptime std.mem.eql(u8, decl.name, "deinit")) { - impl.deinit(); - } - } - } - } -} - -pub fn updateSelected(self: *GuiComponent) void { - switch(self.impl) { - inline else => |*impl| { - // Only call the function if it exists: - inline for(@typeInfo(@TypeOf(impl.*)).Struct.decls) |decl| { - if(comptime std.mem.eql(u8, decl.name, "updateSelected")) { - impl.updateSelected(self.pos, self.size); - } - } - } - } -} - -pub fn updateHovered(self: *GuiComponent, mousePosition: Vec2f) void { - switch(self.impl) { - inline else => |*impl| { - // Only call the function if it exists: - inline for(@typeInfo(@TypeOf(impl.*)).Struct.decls) |decl| { - if(comptime std.mem.eql(u8, decl.name, "updateHovered")) { - impl.updateHovered(self.pos, self.size, mousePosition); - } - } - } - } -} - -pub fn render(self: *GuiComponent, mousePosition: Vec2f) !void { - switch(self.impl) { - inline else => |*impl| { - // 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.pos, self.size, mousePosition); - } - } - } - } -} - -pub fn mainButtonPressed(self: *GuiComponent, mousePosition: Vec2f) void { - switch(self.impl) { - inline else => |*impl| { - // 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.pos, self.size, mousePosition); - } - } - } - } -} - -pub fn mainButtonReleased(self: *GuiComponent, mousePosition: Vec2f) void { - switch(self.impl) { - inline else => |*impl| { - // 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.pos, self.size, mousePosition); - } - } - } - } -} - -pub fn contains(pos: Vec2f, size: Vec2f, point: Vec2f) bool { - return @reduce(.And, point >= pos) and @reduce(.And, point < pos + size); -} \ No newline at end of file diff --git a/src/gui/GuiWindow.zig b/src/gui/GuiWindow.zig index b1499bd8..99a5c120 100644 --- a/src/gui/GuiWindow.zig +++ b/src/gui/GuiWindow.zig @@ -119,7 +119,7 @@ pub fn mainButtonPressed(self: *const GuiWindow, mousePosition: Vec2f) void { } else { var selectedComponent: ?*GuiComponent = null; for(self.components) |*component| { - if(GuiComponent.contains(component.pos, component.size, scaledMousePos)) { + if(GuiComponent.contains(component.pos(), component.size(), scaledMousePos)) { selectedComponent = component; } } @@ -326,7 +326,7 @@ pub fn updateHovered(self: *GuiWindow, mousePosition: Vec2f) !void { while(i != 0) { i -= 1; const component = &self.components[i]; - if(GuiComponent.contains(component.pos, component.size, (mousePosition - self.pos)/@splat(2, self.scale))) { + if(GuiComponent.contains(component.pos(), component.size(), (mousePosition - self.pos)/@splat(2, self.scale))) { component.updateHovered((mousePosition - self.pos)/@splat(2, self.scale)); break; } diff --git a/src/gui/components/Button.zig b/src/gui/components/Button.zig index 15247e4f..841c2f58 100644 --- a/src/gui/components/Button.zig +++ b/src/gui/components/Button.zig @@ -32,11 +32,12 @@ pub var buttonUniforms: struct { pressed: c_int, } = undefined; +pos: Vec2f, +size: Vec2f, pressed: bool = false, hovered: bool = false, onAction: *const fn() void, -textSize: Vec2f, -label: Label, +label: *Label, pub fn __init() !void { shader = try Shader.initAndGetUniforms("assets/cubyz/shaders/ui/button.vs", "assets/cubyz/shaders/ui/button.fs", &buttonUniforms); @@ -52,42 +53,47 @@ pub fn __deinit() void { fn defaultOnAction() void {} -pub fn init(pos: Vec2f, width: f32, text: []const u8, onAction: ?*const fn() void) Allocator.Error!GuiComponent { - const labelComponent = try Label.init(undefined, width - 3*border, text, .center); - var self = Button { - .onAction = if(onAction) |a| a else &defaultOnAction, - .label = labelComponent.impl.label, - .textSize = labelComponent.size, - }; - return GuiComponent { +pub fn init(pos: Vec2f, width: f32, text: []const u8, onAction: ?*const fn() void) Allocator.Error!*Button { + const label = try Label.init(undefined, width - 3*border, text, .center); + const self = try gui.allocator.create(Button); + self.* = Button { .pos = pos, - .size = Vec2f{width, self.textSize[1] + 3*border}, - .impl = .{.button = self} + .size = Vec2f{width, label.size[1] + 3*border}, + .onAction = if(onAction) |a| a else &defaultOnAction, + .label = label, + }; + return self; +} + +pub fn deinit(self: *const Button) void { + self.label.deinit(); + gui.allocator.destroy(self); +} + +pub fn toComponent(self: *Button) GuiComponent { + return GuiComponent { + .button = self }; } -pub fn deinit(self: Button) void { - self.label.deinit(); -} - -pub fn updateHovered(self: *Button, _: Vec2f, _: Vec2f, _: Vec2f) void { +pub fn updateHovered(self: *Button, _: Vec2f) void { self.hovered = true; } -pub fn mainButtonPressed(self: *Button, _: Vec2f, _: Vec2f, _: Vec2f) void { +pub fn mainButtonPressed(self: *Button, _: Vec2f) void { self.pressed = true; } -pub fn mainButtonReleased(self: *Button, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) void { +pub fn mainButtonReleased(self: *Button, mousePosition: Vec2f) void { if(self.pressed) { self.pressed = false; - if(GuiComponent.contains(pos, size, mousePosition)) { + if(GuiComponent.contains(self.pos, self.size, mousePosition)) { self.onAction(); } } } -pub fn render(self: *Button, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) !void { +pub fn render(self: *Button, mousePosition: Vec2f) !void { graphics.c.glActiveTexture(graphics.c.GL_TEXTURE0); texture.bind(); shader.bind(); @@ -95,14 +101,15 @@ pub fn render(self: *Button, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) !voi if(self.pressed) { draw.setColor(0xff000000); graphics.c.glUniform1i(buttonUniforms.pressed, 1); - } else if(GuiComponent.contains(pos, size, mousePosition) and self.hovered) { + } else if(GuiComponent.contains(self.pos, self.size, mousePosition) and self.hovered) { draw.setColor(0xff000040); } else { draw.setColor(0xff000000); } self.hovered = false; - draw.customShadedRect(buttonUniforms, pos, size); + draw.customShadedRect(buttonUniforms, self.pos, self.size); graphics.c.glUniform1i(buttonUniforms.pressed, 0); - 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); + const textPos = self.pos + self.size/@splat(2, @as(f32, 2.0)) - self.label.size/@splat(2, @as(f32, 2.0)); + self.label.pos = textPos; + try self.label.render(mousePosition - self.pos); } \ No newline at end of file diff --git a/src/gui/components/CheckBox.zig b/src/gui/components/CheckBox.zig index 5fd6fd6b..af8c9647 100644 --- a/src/gui/components/CheckBox.zig +++ b/src/gui/components/CheckBox.zig @@ -25,12 +25,13 @@ const boxSize: f32 = 16; var textureChecked: Texture = undefined; var textureEmpty: Texture = undefined; +pos: Vec2f, +size: Vec2f, state: bool = false, pressed: bool = false, hovered: bool = false, onAction: *const fn(bool) void, -textSize: Vec2f, -label: Label, +label: *Label, pub fn __init() !void { textureChecked = try Texture.initFromFile("assets/cubyz/ui/checked_box.png"); @@ -42,44 +43,49 @@ pub fn __deinit() void { textureEmpty.deinit(); } -pub fn init(pos: Vec2f, width: f32, text: []const u8, initialValue: bool, onAction: *const fn(bool) void) Allocator.Error!GuiComponent { - const labelComponent = try Label.init(undefined, width - 3*border - boxSize, text, .left); - var self = CheckBox { +pub fn init(pos: Vec2f, width: f32, text: []const u8, initialValue: bool, onAction: *const fn(bool) void) Allocator.Error!*CheckBox { + const label = (try Label.init(undefined, width - 3*border - boxSize, text, .left)); + const self = try gui.allocator.create(CheckBox); + self.* = CheckBox { + .pos = pos, + .size = Vec2f{@max(width, label.size[0] + 3*border + boxSize), label.size[1] + 3*border}, .state = initialValue, .onAction = onAction, - .label = labelComponent.impl.label, - .textSize = labelComponent.size, - }; - return GuiComponent { - .pos = pos, - .size = Vec2f{@max(width, self.textSize[0] + 3*border + boxSize), self.textSize[1] + 3*border}, - .impl = .{.checkBox = self} + .label = label, }; + return self; } -pub fn deinit(self: CheckBox) void { +pub fn deinit(self: *const CheckBox) void { self.label.deinit(); + gui.allocator.destroy(self); } -pub fn updateHovered(self: *CheckBox, _: Vec2f, _: Vec2f, _: Vec2f) void { +pub fn toComponent(self: *CheckBox) GuiComponent { + return GuiComponent { + .checkBox = self + }; +} + +pub fn updateHovered(self: *CheckBox, _: Vec2f) void { self.hovered = true; } -pub fn mainButtonPressed(self: *CheckBox, _: Vec2f, _: Vec2f, _: Vec2f) void { +pub fn mainButtonPressed(self: *CheckBox, _: Vec2f) void { self.pressed = true; } -pub fn mainButtonReleased(self: *CheckBox, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) void { +pub fn mainButtonReleased(self: *CheckBox, mousePosition: Vec2f) void { if(self.pressed) { self.pressed = false; - if(GuiComponent.contains(pos, size, mousePosition)) { + if(GuiComponent.contains(self.pos, self.size, mousePosition)) { self.state = !self.state; self.onAction(self.state); } } } -pub fn render(self: *CheckBox, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) !void { +pub fn render(self: *CheckBox, mousePosition: Vec2f) !void { graphics.c.glActiveTexture(graphics.c.GL_TEXTURE0); if(self.state) { textureChecked.bind(); @@ -91,14 +97,15 @@ pub fn render(self: *CheckBox, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) !v if(self.pressed) { draw.setColor(0xff000000); graphics.c.glUniform1i(Button.buttonUniforms.pressed, 1); - } else if(GuiComponent.contains(pos, size, mousePosition) and self.hovered) { + } else if(GuiComponent.contains(self.pos, self.size, mousePosition) and self.hovered) { draw.setColor(0xff000040); } else { draw.setColor(0xff000000); } self.hovered = false; - draw.customShadedRect(Button.buttonUniforms, pos + Vec2f{0, size[1]/2 - boxSize/2}, @splat(2, boxSize)); + draw.customShadedRect(Button.buttonUniforms, self.pos + Vec2f{0, self.size[1]/2 - boxSize/2}, @splat(2, boxSize)); graphics.c.glUniform1i(Button.buttonUniforms.pressed, 0); - const textPos = pos + Vec2f{boxSize/2, 0} + size/@splat(2, @as(f32, 2.0)) - self.textSize/@splat(2, @as(f32, 2.0)); - try self.label.render(textPos, self.textSize, mousePosition - textPos); + const textPos = self.pos + Vec2f{boxSize/2, 0} + self.size/@splat(2, @as(f32, 2.0)) - self.label.size/@splat(2, @as(f32, 2.0)); + self.label.pos = textPos; + try self.label.render(mousePosition - textPos); } \ No newline at end of file diff --git a/src/gui/components/Label.zig b/src/gui/components/Label.zig index bd312cce..9284503a 100644 --- a/src/gui/components/Label.zig +++ b/src/gui/components/Label.zig @@ -15,25 +15,39 @@ const Label = @This(); const fontSize: f32 = 16; +pos: Vec2f, +size: Vec2f, text: TextBuffer, -textSize: Vec2f = undefined, -pub fn init(pos: Vec2f, maxWidth: f32, text: []const u8, alignment: TextBuffer.Alignment) Allocator.Error!GuiComponent { - var self = Label { +pub fn init(pos: Vec2f, maxWidth: f32, text: []const u8, alignment: TextBuffer.Alignment) Allocator.Error!*Label { + const self = try gui.allocator.create(Label); + self.* = Label { .text = try TextBuffer.init(gui.allocator, text, .{}, false, alignment), - }; - self.textSize = try self.text.calculateLineBreaks(fontSize, maxWidth); - return GuiComponent { .pos = pos, - .size = self.textSize, - .impl = .{.label = self} + .size = undefined, + }; + self.size = try self.text.calculateLineBreaks(fontSize, maxWidth); + return self; +} + +pub fn deinit(self: *const Label) void { + self.text.deinit(); + gui.allocator.destroy(self); +} + +pub fn toComponent(self: *Label) GuiComponent { + return GuiComponent{ + .label = self }; } -pub fn deinit(self: Label) void { +pub fn updateText(self: *Label, newText: []const u8) !void { + const alignment = self.text.alignment; self.text.deinit(); + self.text = try TextBuffer.init(gui.allocator, newText, .{}, false, alignment); + self.size = try self.text.calculateLineBreaks(fontSize, self.size[0]); } -pub fn render(self: *Label, pos: Vec2f, _: Vec2f, _: Vec2f) !void { - try self.text.render(pos[0], pos[1], fontSize); +pub fn render(self: *Label, _: Vec2f) !void { + try self.text.render(self.pos[0], self.pos[1], fontSize); } \ No newline at end of file diff --git a/src/gui/components/ScrollBar.zig b/src/gui/components/ScrollBar.zig index 391a8365..55fc5818 100644 --- a/src/gui/components/ScrollBar.zig +++ b/src/gui/components/ScrollBar.zig @@ -22,10 +22,10 @@ const fontSize: f32 = 16; var texture: Texture = undefined; +pos: Vec2f, +size: Vec2f, currentState: f32, -button: Button, -buttonSize: Vec2f, -buttonPos: Vec2f = .{0, 0}, +button: *Button, mouseAnchor: f32 = undefined, pub fn __init() !void { @@ -36,34 +36,39 @@ pub fn __deinit() void { texture.deinit(); } -pub fn init(pos: Vec2f, width: f32, height: f32, initialState: f32) Allocator.Error!GuiComponent { - const buttonComponent = try Button.init(undefined, undefined, "", null); - var self = ScrollBar { - .currentState = initialState, - .button = buttonComponent.impl.button, - .buttonSize = .{width, 16}, - }; - const size = Vec2f{width, height}; - self.setButtonPosFromValue(size); - return GuiComponent { +pub fn init(pos: Vec2f, width: f32, height: f32, initialState: f32) Allocator.Error!*ScrollBar { + const button = try Button.init(.{0, 0}, undefined, "", null); + const self = try gui.allocator.create(ScrollBar); + self.* = ScrollBar { .pos = pos, - .size = size, - .impl = .{.scrollBar = self} + .size = Vec2f{width, height}, + .currentState = initialState, + .button = button, + }; + self.button.size = .{width, 16}; + self.setButtonPosFromValue(); + return self; +} + +pub fn deinit(self: *const ScrollBar) void { + self.button.deinit(); + gui.allocator.destroy(self); +} + +pub fn toComponent(self: *ScrollBar) GuiComponent { + return GuiComponent{ + .scrollBar = self }; } -pub fn deinit(self: ScrollBar) void { - self.button.deinit(); +fn setButtonPosFromValue(self: *ScrollBar) void { + const range: f32 = self.size[1] - self.button.size[1]; + self.button.pos[1] = range*self.currentState; } -fn setButtonPosFromValue(self: *ScrollBar, size: Vec2f) void { - const range: f32 = size[1] - self.buttonSize[1]; - self.buttonPos[1] = range*self.currentState; -} - -fn updateValueFromButtonPos(self: *ScrollBar, size: Vec2f) void { - const range: f32 = size[1] - self.buttonSize[1]; - const value = self.buttonPos[1]/range; +fn updateValueFromButtonPos(self: *ScrollBar) void { + const range: f32 = self.size[1] - self.button.size[1]; + const value = self.button.pos[1]/range; if(value != self.currentState) { self.currentState = value; } @@ -74,36 +79,38 @@ pub fn scroll(self: *ScrollBar, offset: f32) void { self.currentState = @min(1, @max(0, self.currentState)); } -pub fn updateHovered(self: *ScrollBar, pos: Vec2f, _: Vec2f, mousePosition: Vec2f) void { - if(GuiComponent.contains(self.buttonPos + pos, self.buttonSize, mousePosition)) { - self.button.updateHovered(self.buttonPos, self.buttonSize, mousePosition - pos); +pub fn updateHovered(self: *ScrollBar, mousePosition: Vec2f) void { + if(GuiComponent.contains(self.button.pos, self.button.size, mousePosition - self.pos)) { + self.button.updateHovered(mousePosition - self.pos); } } -pub fn mainButtonPressed(self: *ScrollBar, pos: Vec2f, _: Vec2f, mousePosition: Vec2f) void { - if(GuiComponent.contains(self.buttonPos, self.buttonSize, mousePosition - pos)) { - self.button.mainButtonPressed(self.buttonPos, self.buttonSize, mousePosition - pos); - self.mouseAnchor = mousePosition[1] - self.buttonPos[1]; +pub fn mainButtonPressed(self: *ScrollBar, mousePosition: Vec2f) void { + if(GuiComponent.contains(self.button.pos, self.button.size, mousePosition - self.pos)) { + self.button.mainButtonPressed(mousePosition - self.pos); + self.mouseAnchor = mousePosition[1] - self.button.pos[1]; } } -pub fn mainButtonReleased(self: *ScrollBar, _: Vec2f, _: Vec2f, _: Vec2f) void { - self.button.mainButtonReleased(undefined, undefined, undefined); +pub fn mainButtonReleased(self: *ScrollBar, mousePosition: Vec2f) void { + self.button.mainButtonReleased(mousePosition - self.pos); } -pub fn render(self: *ScrollBar, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) !void { +pub fn render(self: *ScrollBar, mousePosition: Vec2f) !void { graphics.c.glActiveTexture(graphics.c.GL_TEXTURE0); texture.bind(); Button.shader.bind(); draw.setColor(0xff000000); - draw.customShadedRect(Button.buttonUniforms, pos, size); + draw.customShadedRect(Button.buttonUniforms, self.pos, self.size); - const range: f32 = size[1] - self.buttonSize[1]; - self.setButtonPosFromValue(size); + const range: f32 = self.size[1] - self.button.size[1]; + self.setButtonPosFromValue(); if(self.button.pressed) { - self.buttonPos[1] = mousePosition[1] - self.mouseAnchor; - self.buttonPos[1] = @min(@max(self.buttonPos[1], 0), range - 0.001); - self.updateValueFromButtonPos(size); + self.button.pos[1] = mousePosition[1] - self.mouseAnchor; + self.button.pos[1] = @min(@max(self.button.pos[1], 0), range - 0.001); + self.updateValueFromButtonPos(); } - try self.button.render(pos + self.buttonPos, self.buttonSize, mousePosition); + const oldTranslation = draw.setTranslation(self.pos); + defer draw.restoreTranslation(oldTranslation); + try self.button.render(mousePosition - self.pos); } \ No newline at end of file diff --git a/src/gui/components/Slider.zig b/src/gui/components/Slider.zig index a406517f..5884bf34 100644 --- a/src/gui/components/Slider.zig +++ b/src/gui/components/Slider.zig @@ -23,16 +23,15 @@ const fontSize: f32 = 16; var texture: Texture = undefined; +pos: Vec2f, +size: Vec2f, callback: *const fn(u16) void, currentSelection: u16, text: []const u8, currentText: []u8, values: [][]const u8, -label: Label, -labelSize: Vec2f, -button: Button, -buttonSize: Vec2f, -buttonPos: Vec2f = .{0, 0}, +label: *Label, +button: *Button, mouseAnchor: f32 = undefined, pub fn __init() !void { @@ -43,7 +42,7 @@ pub fn __deinit() void { texture.deinit(); } -pub fn init(pos: Vec2f, width: f32, text: []const u8, comptime fmt: []const u8, valueList: anytype, initialValue: u16, callback: *const fn(u16) void) Allocator.Error!GuiComponent { +pub fn init(pos: Vec2f, width: f32, text: []const u8, comptime fmt: []const u8, valueList: anytype, initialValue: u16, callback: *const fn(u16) void) Allocator.Error!*Slider { var values = try gui.allocator.alloc([]const u8, valueList.len); var maxLen: usize = 0; for(valueList, 0..) |value, i| { @@ -54,30 +53,28 @@ pub fn init(pos: Vec2f, width: f32, text: []const u8, comptime fmt: []const u8, const initialText = try gui.allocator.alloc(u8, text.len + maxLen); std.mem.copy(u8, initialText, text); std.mem.set(u8, initialText[text.len..], ' '); - const labelComponent = try Label.init(undefined, width - 3*border, initialText, .center); - const buttonComponent = try Button.init(undefined, undefined, "", null); - var self = Slider { + const label = try Label.init(undefined, width - 3*border, initialText, .center); + const button = try Button.init(.{0, 0}, undefined, "", null); + const self = try gui.allocator.create(Slider); + self.* = Slider { + .pos = pos, + .size = undefined, .callback = callback, .currentSelection = initialValue, .text = text, .currentText = initialText, - .label = labelComponent.impl.label, - .button = buttonComponent.impl.button, - .labelSize = labelComponent.size, - .buttonSize = .{16, 16}, + .label = label, + .button = button, .values = values, }; - self.buttonPos[1] = self.labelSize[1] + 3.5*border; - const size = Vec2f{@max(width, self.labelSize[0] + 3*border), self.labelSize[1] + self.buttonSize[1] + 5*border}; - try self.setButtonPosFromValue(size); - return GuiComponent { - .pos = pos, - .size = size, - .impl = .{.slider = self} - }; + self.button.size = .{16, 16}; + self.button.pos[1] = self.label.size[1] + 3.5*border; + self.size = Vec2f{@max(width, self.label.size[0] + 3*border), self.label.size[1] + self.button.size[1] + 5*border}; + try self.setButtonPosFromValue(); + return self; } -pub fn deinit(self: Slider) void { +pub fn deinit(self: *const Slider) void { self.label.deinit(); self.button.deinit(); for(self.values) |value| { @@ -85,12 +82,19 @@ pub fn deinit(self: Slider) void { } gui.allocator.free(self.values); gui.allocator.free(self.currentText); + gui.allocator.destroy(self); } -fn setButtonPosFromValue(self: *Slider, size: Vec2f) !void { - const range: f32 = size[0] - 3*border - self.buttonSize[0]; - self.buttonPos[0] = 1.5*border + range*(0.5 + @intToFloat(f32, self.currentSelection))/@intToFloat(f32, self.values.len); - try self.updateLabel(self.values[self.currentSelection], size[0]); +pub fn toComponent(self: *Slider) GuiComponent { + return GuiComponent { + .slider = self + }; +} + +fn setButtonPosFromValue(self: *Slider) !void { + const range: f32 = self.size[0] - 3*border - self.button.size[0]; + self.button.pos[0] = 1.5*border + range*(0.5 + @intToFloat(f32, self.currentSelection))/@intToFloat(f32, self.values.len); + try self.updateLabel(self.values[self.currentSelection], self.size[0]); } fn updateLabel(self: *Slider, newValue: []const u8, width: f32) !void { @@ -98,56 +102,58 @@ fn updateLabel(self: *Slider, newValue: []const u8, width: f32) !void { self.currentText = try gui.allocator.alloc(u8, newValue.len + self.text.len); std.mem.copy(u8, self.currentText, self.text); std.mem.copy(u8, self.currentText[self.text.len..], newValue); - const labelComponent = try Label.init(undefined, width - 3*border, self.currentText, .center); + const label = try Label.init(undefined, width - 3*border, self.currentText, .center); self.label.deinit(); - self.label = labelComponent.impl.label; + self.label = label; } -fn updateValueFromButtonPos(self: *Slider, size: Vec2f) !void { - const range: f32 = size[0] - 3*border - self.buttonSize[0]; - const selection = @floatToInt(u16, (self.buttonPos[0] - 1.5*border)/range*@intToFloat(f32, self.values.len)); +fn updateValueFromButtonPos(self: *Slider) !void { + const range: f32 = self.size[0] - 3*border - self.button.size[0]; + const selection = @floatToInt(u16, (self.button.pos[0] - 1.5*border)/range*@intToFloat(f32, self.values.len)); if(selection != self.currentSelection) { self.currentSelection = selection; - try self.updateLabel(self.values[selection], size[0]); + try self.updateLabel(self.values[selection], self.size[0]); self.callback(selection); } } -pub fn updateHovered(self: *Slider, pos: Vec2f, _: Vec2f, mousePosition: Vec2f) void { - if(GuiComponent.contains(self.buttonPos + pos, self.buttonSize, mousePosition)) { - self.button.updateHovered(self.buttonPos, self.buttonSize, mousePosition - pos); +pub fn updateHovered(self: *Slider, mousePosition: Vec2f) void { + if(GuiComponent.contains(self.button.pos, self.button.size, mousePosition - self.pos)) { + self.button.updateHovered(mousePosition - self.pos); } } -pub fn mainButtonPressed(self: *Slider, pos: Vec2f, _: Vec2f, mousePosition: Vec2f) void { - if(GuiComponent.contains(self.buttonPos, self.buttonSize, mousePosition - pos)) { - self.button.mainButtonPressed(self.buttonPos, self.buttonSize, mousePosition - pos); - self.mouseAnchor = mousePosition[0] - self.buttonPos[0]; +pub fn mainButtonPressed(self: *Slider, mousePosition: Vec2f) void { + if(GuiComponent.contains(self.button.pos, self.button.size, mousePosition - self.pos)) { + self.button.mainButtonPressed(mousePosition - self.pos); + self.mouseAnchor = mousePosition[0] - self.button.pos[0]; } } -pub fn mainButtonReleased(self: *Slider, _: Vec2f, _: Vec2f, _: Vec2f) void { - self.button.mainButtonReleased(undefined, undefined, undefined); +pub fn mainButtonReleased(self: *Slider, _: Vec2f) void { + self.button.mainButtonReleased(undefined); } -pub fn render(self: *Slider, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) !void { +pub fn render(self: *Slider, mousePosition: Vec2f) !void { graphics.c.glActiveTexture(graphics.c.GL_TEXTURE0); texture.bind(); Button.shader.bind(); draw.setColor(0xff000000); - draw.customShadedRect(Button.buttonUniforms, pos, size); + draw.customShadedRect(Button.buttonUniforms, self.pos, self.size); - const range: f32 = size[0] - 3*border - self.buttonSize[0]; + const range: f32 = self.size[0] - 3*border - self.button.size[0]; draw.setColor(0x80000000); - draw.rect(pos + Vec2f{1.5*border + self.buttonSize[0]/2, self.buttonPos[1] + self.buttonSize[1]/2 - border}, .{range, 2*border}); + draw.rect(self.pos + Vec2f{1.5*border + self.button.size[0]/2, self.button.pos[1] + self.button.size[1]/2 - border}, .{range, 2*border}); - const labelPos = pos + @splat(2, 1.5*border); - try self.label.render(labelPos, self.labelSize, mousePosition); + self.label.pos = self.pos + @splat(2, 1.5*border); + try self.label.render(mousePosition); if(self.button.pressed) { - self.buttonPos[0] = mousePosition[0] - self.mouseAnchor; - self.buttonPos[0] = @min(@max(self.buttonPos[0], 1.5*border), 1.5*border + range - 0.001); - try self.updateValueFromButtonPos(size); + self.button.pos[0] = mousePosition[0] - self.mouseAnchor; + self.button.pos[0] = @min(@max(self.button.pos[0], 1.5*border), 1.5*border + range - 0.001); + try self.updateValueFromButtonPos(); } - try self.button.render(pos + self.buttonPos, self.buttonSize, mousePosition); + const oldTranslation = draw.setTranslation(self.pos); + defer draw.restoreTranslation(oldTranslation); + try self.button.render(mousePosition - self.pos); } \ No newline at end of file diff --git a/src/gui/components/TextInput.zig b/src/gui/components/TextInput.zig index c0dc2acf..ad9b83ec 100644 --- a/src/gui/components/TextInput.zig +++ b/src/gui/components/TextInput.zig @@ -22,6 +22,8 @@ const fontSize: f32 = 16; var texture: Texture = undefined; +pos: Vec2f, +size: Vec2f, pressed: bool = false, cursor: ?u32 = null, selectionStart: ?u32 = null, @@ -30,8 +32,7 @@ textBuffer: TextBuffer, maxWidth: f32, maxHeight: f32, textSize: Vec2f = undefined, -scrollBar: ScrollBar, -scrollBarSize: Vec2f, +scrollBar: *ScrollBar, pub fn __init() !void { texture = try Texture.initFromFile("assets/cubyz/ui/text_input.png"); @@ -41,49 +42,54 @@ pub fn __deinit() void { texture.deinit(); } -pub fn init(pos: Vec2f, maxWidth: f32, maxHeight: f32, text: []const u8) Allocator.Error!GuiComponent { - const scrollBarComponent = try ScrollBar.init(undefined, scrollBarWidth, maxHeight - 2*border, 0); - var self = TextInput { +pub fn init(pos: Vec2f, maxWidth: f32, maxHeight: f32, text: []const u8) Allocator.Error!*TextInput { + const scrollBar = try ScrollBar.init(undefined, scrollBarWidth, maxHeight - 2*border, 0); + const self = try gui.allocator.create(TextInput); + self.* = TextInput { + .pos = pos, + .size = .{maxWidth, maxHeight}, .currentString = std.ArrayList(u8).init(gui.allocator), .textBuffer = try TextBuffer.init(gui.allocator, text, .{}, true, .left), .maxWidth = maxWidth, .maxHeight = maxHeight, - .scrollBar = scrollBarComponent.impl.scrollBar, - .scrollBarSize = scrollBarComponent.size, + .scrollBar = scrollBar, }; try self.currentString.appendSlice(text); self.textSize = try self.textBuffer.calculateLineBreaks(fontSize, maxWidth - 2*border - scrollBarWidth); - return GuiComponent { - .pos = pos, - .size = .{maxWidth, maxHeight}, - .impl = .{.textInput = self} - }; + return self; } -pub fn deinit(self: TextInput) void { +pub fn deinit(self: *const TextInput) void { self.textBuffer.deinit(); self.currentString.deinit(); self.scrollBar.deinit(); + gui.allocator.destroy(self); } -pub fn updateHovered(self: *TextInput, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) void { +pub fn toComponent(self: *TextInput) GuiComponent { + return GuiComponent { + .textInput = self + }; +} + +pub fn updateHovered(self: *TextInput, mousePosition: Vec2f) void { if(self.textSize[1] > self.maxHeight - 2*border) { const diff = self.textSize[1] - (self.maxHeight - 2*border); self.scrollBar.scroll(-main.Window.scrollOffset*32/diff); } if(self.textSize[1] > self.maxHeight - 2*border) { - const scrollBarPos = Vec2f{size[0] - border - scrollBarWidth, border}; - if(GuiComponent.contains(scrollBarPos, self.scrollBarSize, mousePosition - pos)) { - self.scrollBar.updateHovered(scrollBarPos, self.scrollBarSize, mousePosition - pos); + self.scrollBar.pos = Vec2f{self.size[0] - border - scrollBarWidth, border}; + if(GuiComponent.contains(self.scrollBar.pos, self.scrollBar.size, mousePosition - self.pos)) { + self.scrollBar.updateHovered(mousePosition - self.pos); } } } -pub fn mainButtonPressed(self: *TextInput, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) void { +pub fn mainButtonPressed(self: *TextInput, mousePosition: Vec2f) void { if(self.textSize[1] > self.maxHeight - 2*border) { - const scrollBarPos = Vec2f{size[0] - border - scrollBarWidth, border}; - if(GuiComponent.contains(scrollBarPos, self.scrollBarSize, mousePosition - pos)) { - self.scrollBar.mainButtonPressed(scrollBarPos, self.scrollBarSize, mousePosition - pos); + self.scrollBar.pos = Vec2f{self.size[0] - border - scrollBarWidth, border}; + if(GuiComponent.contains(self.scrollBar.pos, self.scrollBar.size, mousePosition - self.pos)) { + self.scrollBar.mainButtonPressed(mousePosition - self.pos); return; } } @@ -93,25 +99,26 @@ pub fn mainButtonPressed(self: *TextInput, pos: Vec2f, size: Vec2f, mousePositio const diff = self.textSize[1] - (self.maxHeight - 2*border); textPos[1] -= diff*self.scrollBar.currentState; } - self.selectionStart = self.textBuffer.mousePosToIndex(mousePosition - textPos - pos, self.currentString.items.len); + self.selectionStart = self.textBuffer.mousePosToIndex(mousePosition - textPos - self.pos, self.currentString.items.len); self.pressed = true; } -pub fn mainButtonReleased(self: *TextInput, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) void { +pub fn mainButtonReleased(self: *TextInput, mousePosition: Vec2f) void { if(self.pressed) { var textPos = Vec2f{border, border}; if(self.textSize[1] > self.maxHeight - 2*border) { const diff = self.textSize[1] - (self.maxHeight - 2*border); textPos[1] -= diff*self.scrollBar.currentState; } - self.cursor = self.textBuffer.mousePosToIndex(mousePosition - textPos - pos, self.currentString.items.len); + self.cursor = self.textBuffer.mousePosToIndex(mousePosition - textPos - self.pos, self.currentString.items.len); if(self.cursor == self.selectionStart) { self.selectionStart = null; } self.pressed = false; gui.setSelectedTextInput(self); } else if(self.textSize[1] > self.maxHeight - 2*border) { - self.scrollBar.mainButtonReleased(.{size[0] - border - scrollBarWidth, border}, self.scrollBarSize, mousePosition - pos); + self.scrollBar.pos = .{self.size[0] - border - scrollBarWidth, border}; + self.scrollBar.mainButtonReleased(mousePosition - self.pos); gui.setSelectedTextInput(self); } } @@ -435,26 +442,27 @@ fn ensureCursorVisibility(self: *TextInput) void { } } -pub fn render(self: *TextInput, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) !void { +pub fn render(self: *TextInput, mousePosition: Vec2f) !void { graphics.c.glActiveTexture(graphics.c.GL_TEXTURE0); texture.bind(); Button.shader.bind(); draw.setColor(0xff000000); - draw.customShadedRect(Button.buttonUniforms, pos, size); - const oldTranslation = draw.setTranslation(pos); + draw.customShadedRect(Button.buttonUniforms, self.pos, self.size); + const oldTranslation = draw.setTranslation(self.pos); defer draw.restoreTranslation(oldTranslation); - const oldClip = draw.setClip(size); + const oldClip = draw.setClip(self.size); defer draw.restoreClip(oldClip); var textPos = Vec2f{border, border}; if(self.textSize[1] > self.maxHeight - 2*border) { const diff = self.textSize[1] - (self.maxHeight - 2*border); textPos[1] -= diff*self.scrollBar.currentState; - try self.scrollBar.render(.{size[0] - self.scrollBarSize[0] - border, border}, self.scrollBarSize, mousePosition - pos); + self.scrollBar.pos = .{self.size[0] - self.scrollBar.size[0] - border, border}; + try self.scrollBar.render(mousePosition - self.pos); } try self.textBuffer.render(textPos[0], textPos[1], fontSize); if(self.pressed) { - self.cursor = self.textBuffer.mousePosToIndex(mousePosition - textPos - pos, self.currentString.items.len); + self.cursor = self.textBuffer.mousePosToIndex(mousePosition - textPos - self.pos, self.currentString.items.len); } if(self.cursor) |cursor| { var cursorPos = textPos + self.textBuffer.indexToCursorPos(cursor); diff --git a/src/gui/components/VerticalList.zig b/src/gui/components/VerticalList.zig index f77ae53f..325466cf 100644 --- a/src/gui/components/VerticalList.zig +++ b/src/gui/components/VerticalList.zig @@ -13,80 +13,89 @@ const GuiComponent = gui.GuiComponent; const VerticalList = @This(); +pos: Vec2f, +size: Vec2f, children: std.ArrayList(GuiComponent), -currentOffset: f32 = 0, -maxWidth: f32 = 0, -pub fn init() Allocator.Error!VerticalList { - const self = VerticalList { +pub fn init() Allocator.Error!*VerticalList { + const self = try gui.allocator.create(VerticalList); + self.* = VerticalList { .children = std.ArrayList(GuiComponent).init(gui.allocator), + .pos = undefined, + .size = .{0, 0}, }; return self; } -pub fn deinit(self: VerticalList) void { +pub fn deinit(self: *const VerticalList) void { for(self.children.items) |*child| { child.deinit(); } self.children.deinit(); + gui.allocator.destroy(self); } pub fn toComponent(self: *VerticalList, pos: Vec2f) GuiComponent { + self.pos = pos; return GuiComponent { - .pos = pos, - .size = .{self.maxWidth, self.currentOffset}, - .impl = .{.verticalList = self.*} + .verticalList = self }; } -pub fn add(self: *VerticalList, other: GuiComponent) Allocator.Error!void { +pub fn add(self: *VerticalList, _other: anytype) Allocator.Error!void { + var other: GuiComponent = undefined; + if(@TypeOf(_other) == GuiComponent) { + other = _other; + } else { + other = _other.toComponent(); + } const added = try self.children.addOne(); added.* = other; - added.pos[1] += self.currentOffset; - self.currentOffset = added.pos[1] + added.size[1]; - self.maxWidth = @max(self.maxWidth, added.pos[0] + added.size[0]); + added.mutPos().*[1] += self.size[1]; + self.size[1] = added.pos()[1] + added.size()[1]; + self.size[0] = @max(self.size[0], added.pos()[0] + added.size()[0]); } -pub fn updateSelected(self: *VerticalList, _: Vec2f, _: Vec2f) void { +pub fn updateSelected(self: *VerticalList) void { for(self.children.items) |*child| { child.updateSelected(); } } -pub fn updateHovered(self: *VerticalList, pos: Vec2f, _: Vec2f, mousePosition: Vec2f) void { +pub fn updateHovered(self: *VerticalList, mousePosition: Vec2f) void { var i: usize = self.children.items.len; while(i != 0) { i -= 1; const child = &self.children.items[i]; - if(GuiComponent.contains(child.pos + pos, child.size, mousePosition)) { - child.updateHovered(mousePosition - pos); + if(GuiComponent.contains(child.pos() + self.pos, child.size(), mousePosition)) { + child.updateHovered(mousePosition - self.pos); break; } } } -pub fn render(self: *VerticalList, pos: Vec2f, _: Vec2f, mousePosition: Vec2f) anyerror!void { // TODO: Remove anyerror once error union inference works in recursive loops. - const oldTranslation = draw.setTranslation(pos); +pub fn render(self: *VerticalList, mousePosition: Vec2f) anyerror!void { // TODO: Remove anyerror once error union inference works in recursive loops. + const oldTranslation = draw.setTranslation(self.pos); for(self.children.items) |*child| { - try child.render(mousePosition - pos); + try child.render(mousePosition - self.pos); } draw.restoreTranslation(oldTranslation); } -pub fn mainButtonPressed(self: *VerticalList, pos: Vec2f, _: Vec2f, mousePosition: Vec2f) void { +pub fn mainButtonPressed(self: *VerticalList, mousePosition: Vec2f) void { var selectedChild: ?*GuiComponent = null; for(self.children.items) |*child| { - if(GuiComponent.contains(child.pos + pos, child.size, mousePosition)) { + if(GuiComponent.contains(child.pos() + self.pos, child.size(), mousePosition)) { selectedChild = child; } } if(selectedChild) |child| { - child.mainButtonPressed(mousePosition - pos); + child.mainButtonPressed(mousePosition - self.pos); } } -pub fn mainButtonReleased(self: *VerticalList, pos: Vec2f, _: Vec2f, mousePosition: Vec2f) void { +pub fn mainButtonReleased(self: *VerticalList, mousePosition: Vec2f) void { for(self.children.items) |*child| { - child.mainButtonReleased(mousePosition - pos); + child.mainButtonReleased(mousePosition - self.pos); } } \ No newline at end of file diff --git a/src/gui/gui.zig b/src/gui/gui.zig index 9c55f3b9..5cf47fe9 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -14,7 +14,7 @@ const CheckBox = @import("components/CheckBox.zig"); const ScrollBar = @import("components/ScrollBar.zig"); const Slider = @import("components/Slider.zig"); const TextInput = @import("components/TextInput.zig"); -pub const GuiComponent = @import("GuiComponent.zig"); +pub const GuiComponent = @import("gui_component.zig").GuiComponent; pub const GuiWindow = @import("GuiWindow.zig"); const windowlist = @import("windows/_windowlist.zig"); diff --git a/src/gui/gui_component.zig b/src/gui/gui_component.zig new file mode 100644 index 00000000..0f077d58 --- /dev/null +++ b/src/gui/gui_component.zig @@ -0,0 +1,139 @@ +const std = @import("std"); + +const main = @import("root"); +const vec = main.vec; +const Vec2f = vec.Vec2f; + +pub const GuiComponent = union(enum) { + + pub const Button = @import("components/Button.zig"); + pub const CheckBox = @import("components/CheckBox.zig"); + pub const Label = @import("components/Label.zig"); + pub const Slider = @import("components/Slider.zig"); + pub const ScrollBar = @import("components/ScrollBar.zig"); + pub const TextInput = @import("components/TextInput.zig"); + pub const VerticalList = @import("components/VerticalList.zig"); + + + button: *Button, + checkBox: *CheckBox, + label: *Label, + scrollBar: *ScrollBar, + slider: *Slider, + textInput: *TextInput, + verticalList: *VerticalList, + + pub fn deinit(self: *GuiComponent) void { + switch(self.*) { + inline else => |impl| { + // Only call the function if it exists: + inline for(@typeInfo(@TypeOf(impl.*)).Struct.decls) |decl| { + if(comptime std.mem.eql(u8, decl.name, "deinit")) { + impl.deinit(); + } + } + } + } + } + + pub fn mutPos(self: *GuiComponent) *Vec2f { + switch(self.*) { + inline else => |impl| { + return &impl.pos; + } + } + } + + pub fn mutSize(self: *GuiComponent) *Vec2f { + switch(self.*) { + inline else => |impl| { + return &impl.size; + } + } + } + + pub fn pos(self: *GuiComponent) Vec2f { + switch(self.*) { + inline else => |impl| { + return impl.pos; + } + } + } + + pub fn size(self: *GuiComponent) Vec2f { + switch(self.*) { + inline else => |impl| { + return impl.size; + } + } + } + + pub fn updateSelected(self: *GuiComponent) void { + switch(self.*) { + inline else => |impl| { + // Only call the function if it exists: + inline for(@typeInfo(@TypeOf(impl.*)).Struct.decls) |decl| { + if(comptime std.mem.eql(u8, decl.name, "updateSelected")) { + impl.updateSelected(); + } + } + } + } + } + + pub fn updateHovered(self: *GuiComponent, mousePosition: Vec2f) void { + switch(self.*) { + inline else => |impl| { + // Only call the function if it exists: + inline for(@typeInfo(@TypeOf(impl.*)).Struct.decls) |decl| { + if(comptime std.mem.eql(u8, decl.name, "updateHovered")) { + impl.updateHovered(mousePosition); + } + } + } + } + } + + pub fn render(self: *GuiComponent, mousePosition: Vec2f) !void { + switch(self.*) { + inline else => |impl| { + // 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(mousePosition); + } + } + } + } + } + + pub fn mainButtonPressed(self: *GuiComponent, mousePosition: Vec2f) void { + switch(self.*) { + inline else => |impl| { + // 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(mousePosition); + } + } + } + } + } + + pub fn mainButtonReleased(self: *GuiComponent, mousePosition: Vec2f) void { + switch(self.*) { + inline else => |impl| { + // 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(mousePosition); + } + } + } + } + } + + pub fn contains(_pos: Vec2f, _size: Vec2f, point: Vec2f) bool { + return @reduce(.And, point >= _pos) and @reduce(.And, point < _pos + _size); + } +}; \ No newline at end of file diff --git a/src/gui/windows/change_name.zig b/src/gui/windows/change_name.zig index eb05a432..11a5a23c 100644 --- a/src/gui/windows/change_name.zig +++ b/src/gui/windows/change_name.zig @@ -22,12 +22,12 @@ pub var window = GuiWindow { .onCloseFn = &onClose, .components = &components, }; +var textComponent: *TextInput = undefined; const padding: f32 = 8; fn apply() void { const oldName = settings.playerName; - const textComponent: *TextInput = &components[0].impl.verticalList.children.items[5].impl.textInput; main.globalAllocator.free(settings.playerName); settings.playerName = main.globalAllocator.dupe(u8, textComponent.currentString.items) catch { std.log.err("Encountered out of memory in change_name.apply.", .{}); @@ -55,10 +55,11 @@ pub fn onOpen() Allocator.Error!void { try list.add(try Label.init(.{0, 16}, width, "\\**italic*\\* \\*\\***bold**\\*\\* \\__underlined_\\_ \\_\\___strike-through__\\_\\_", .center)); try list.add(try Label.init(.{0, 16}, width, "Even colors are possible, using the hexadecimal color code:", .center)); try list.add(try Label.init(.{0, 16}, width, "\\##ff0000ff#00000000#00000000#ff0000red#000000 \\##ff0000ff#00770077#00000000#ff7700orange#000000 \\##00000000#00ff00ff#00000000#00ff00green#000000 \\##00000000#00000000#0000ffff#0000ffblue", .center)); - try list.add(try TextInput.init(.{0, 16}, width, 32, "quanturmdoelvloper")); + textComponent = try TextInput.init(.{0, 16}, width, 32, "quanturmdoelvloper"); + try list.add(textComponent); try list.add(try Button.init(.{0, 16}, 100, "Apply", &apply)); components[0] = list.toComponent(.{padding, padding}); - window.contentSize = components[0].size + @splat(2, @as(f32, 2*padding)); + window.contentSize = components[0].size() + @splat(2, @as(f32, 2*padding)); gui.updateWindowPositions(); } diff --git a/src/gui/windows/controls.zig b/src/gui/windows/controls.zig index d1a93ee2..11411d98 100644 --- a/src/gui/windows/controls.zig +++ b/src/gui/windows/controls.zig @@ -46,7 +46,7 @@ fn keypressListener(key: c_int, mouseButton: c_int, scancode: c_int) void { pub fn onOpen() Allocator.Error!void { var list = try VerticalList.init(); - list.currentOffset = 8; + list.size[1] = 8; inline for(comptime std.meta.fieldNames(@TypeOf(main.keyboard))) |field| { var label = try Label.init(.{0, 8}, 128, field, .left); var button = if(&@field(main.keyboard, field) == selectedKey) ( @@ -67,7 +67,7 @@ pub fn onOpen() Allocator.Error!void { } } components[0] = list.toComponent(.{padding, padding}); - window.contentSize = components[0].size + @splat(2, @as(f32, 2*padding)); + window.contentSize = components[0].size() + @splat(2, @as(f32, 2*padding)); gui.updateWindowPositions(); } diff --git a/src/gui/windows/graphics.zig b/src/gui/windows/graphics.zig index 4be3ab17..3f4bd230 100644 --- a/src/gui/windows/graphics.zig +++ b/src/gui/windows/graphics.zig @@ -52,7 +52,7 @@ pub fn onOpen() Allocator.Error!void { try list.add(try CheckBox.init(.{0, 16}, 128, "Bloom", settings.bloom, &bloomCallback)); try list.add(try CheckBox.init(.{0, 16}, 128, "Vertical Synchronization", settings.vsync, &vsyncCallback)); components[0] = list.toComponent(.{padding, padding}); - window.contentSize = components[0].size + @splat(2, @as(f32, 2*padding)); + window.contentSize = components[0].size() + @splat(2, @as(f32, 2*padding)); gui.updateWindowPositions(); } diff --git a/src/gui/windows/hotbar.zig b/src/gui/windows/hotbar.zig index f0d8cf2e..cd69a273 100644 --- a/src/gui/windows/hotbar.zig +++ b/src/gui/windows/hotbar.zig @@ -13,7 +13,6 @@ pub var window = GuiWindow { .title = "Hotbar", .id = "cubyz:hotbar", .renderFn = &render, - .components = &[_]GuiComponent{}, .isHud = true, }; diff --git a/src/gui/windows/main.zig b/src/gui/windows/main.zig index 5d1dc9b9..4ec4b70f 100644 --- a/src/gui/windows/main.zig +++ b/src/gui/windows/main.zig @@ -32,7 +32,7 @@ pub fn onOpen() Allocator.Error!void { try list.add(try Button.init(.{0, 16}, 128, "Settings", gui.openWindowFunction("cubyz:settings"))); try list.add(try Button.init(.{0, 16}, 128, "Exit TODO", &buttonCallbackTest)); components[0] = list.toComponent(.{padding, padding}); - window.contentSize = components[0].size + @splat(2, @as(f32, 2*padding)); + window.contentSize = components[0].size() + @splat(2, @as(f32, 2*padding)); gui.updateWindowPositions(); } diff --git a/src/gui/windows/multiplayer.zig b/src/gui/windows/multiplayer.zig index 023647ed..756ed026 100644 --- a/src/gui/windows/multiplayer.zig +++ b/src/gui/windows/multiplayer.zig @@ -24,6 +24,8 @@ pub var window = GuiWindow { .components = &components, }; +var ipAddressLabel: *Label = undefined; + const padding: f32 = 8; var connection: ?*ConnectionManager = null; @@ -34,9 +36,7 @@ const width: f32 = 420; fn flawedDiscoverIpAddress() !void { connection = try ConnectionManager.init(12347, true); // TODO: default port ipAddress = try std.fmt.allocPrint(main.globalAllocator, "{}", .{connection.?.externalAddress}); - components[0].impl.verticalList.children.items[1].impl.label.deinit(); - const labelComponent = try Label.init(undefined, width, ipAddress, .center); - components[0].impl.verticalList.children.items[1].impl.label = labelComponent.impl.label; + try ipAddressLabel.updateText(ipAddress); } fn discoverIpAddress() void { @@ -86,13 +86,14 @@ fn copyIp() void { pub fn onOpen() Allocator.Error!void { var list = try VerticalList.init(); try list.add(try Label.init(.{0, 16}, width, "Please send your IP to the host of the game and enter the host's IP below.", .center)); - // 255.255.255.255:?65536 (longest possible ip address) - try list.add(try Label.init(.{0, 16}, width, " ", .center)); + // 255.255.255.255:?65536 (longest possible ip address) + ipAddressLabel = try Label.init(.{0, 16}, width, " ", .center); + try list.add(ipAddressLabel); try list.add(try Button.init(.{0, 16}, 100, "Copy IP", ©Ip)); try list.add(try TextInput.init(.{0, 16}, width, 32, settings.lastUsedIPAddress)); try list.add(try Button.init(.{0, 16}, 100, "Join", &join)); components[0] = list.toComponent(.{padding, padding}); - window.contentSize = components[0].size + @splat(2, @as(f32, 2*padding)); + window.contentSize = components[0].size() + @splat(2, @as(f32, 2*padding)); gui.updateWindowPositions(); thread = std.Thread.spawn(.{}, discoverIpAddressFromNewThread, .{}) catch |err| blk: { diff --git a/src/gui/windows/settings.zig b/src/gui/windows/settings.zig index fb40a579..830790d6 100644 --- a/src/gui/windows/settings.zig +++ b/src/gui/windows/settings.zig @@ -29,7 +29,7 @@ pub fn onOpen() Allocator.Error!void { try list.add(try Button.init(.{0, 16}, 128, "Controls", gui.openWindowFunction("cubyz:controls"))); try list.add(try Button.init(.{0, 16}, 128, "Change Name", gui.openWindowFunction("cubyz:change_name"))); components[0] = list.toComponent(.{padding, padding}); - window.contentSize = components[0].size + @splat(2, @as(f32, 2*padding)); + window.contentSize = components[0].size() + @splat(2, @as(f32, 2*padding)); gui.updateWindowPositions(); } diff --git a/src/gui/windows/sound.zig b/src/gui/windows/sound.zig index 2f0504e7..8c7f81ad 100644 --- a/src/gui/windows/sound.zig +++ b/src/gui/windows/sound.zig @@ -26,7 +26,7 @@ pub fn onOpen() Allocator.Error!void { var list = try VerticalList.init(); // TODO components[0] = list.toComponent(.{padding, padding}); - window.contentSize = components[0].size + @splat(2, @as(f32, 2*padding)); + window.contentSize = components[0].size() + @splat(2, @as(f32, 2*padding)); gui.updateWindowPositions(); }