mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 19:28:49 -04:00
Add the chat gui and set the default text color to white.
This commit is contained in:
parent
d5389aefb7
commit
77610c0064
Binary file not shown.
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
@ -30,13 +30,13 @@ fn fileToString(allocator: Allocator, path: []const u8) ![]u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const draw = struct {
|
pub const draw = struct {
|
||||||
var color: i32 = 0;
|
var color: u32 = 0;
|
||||||
var clip: ?Vec4i = null;
|
var clip: ?Vec4i = null;
|
||||||
var translation: Vec2f = Vec2f{0, 0};
|
var translation: Vec2f = Vec2f{0, 0};
|
||||||
var scale: f32 = 1;
|
var scale: f32 = 1;
|
||||||
|
|
||||||
pub fn setColor(newColor: u32) void {
|
pub fn setColor(newColor: u32) void {
|
||||||
color = @bitCast(i32, newColor);
|
color = newColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the previous translation.
|
/// Returns the previous translation.
|
||||||
@ -52,6 +52,7 @@ pub const draw = struct {
|
|||||||
|
|
||||||
/// Returns the previous translation.
|
/// Returns the previous translation.
|
||||||
pub fn setScale(newScale: f32) f32 {
|
pub fn setScale(newScale: f32) f32 {
|
||||||
|
std.debug.assert(newScale >= 0);
|
||||||
const oldScale = scale;
|
const oldScale = scale;
|
||||||
scale *= newScale;
|
scale *= newScale;
|
||||||
return oldScale;
|
return oldScale;
|
||||||
@ -63,11 +64,12 @@ pub const draw = struct {
|
|||||||
|
|
||||||
/// Returns the previous clip.
|
/// Returns the previous clip.
|
||||||
pub fn setClip(clipRect: Vec2f) ?Vec4i {
|
pub fn setClip(clipRect: Vec2f) ?Vec4i {
|
||||||
|
std.debug.assert(@reduce(.And, clipRect >= Vec2f{0, 0}));
|
||||||
var newClip = Vec4i {
|
var newClip = Vec4i {
|
||||||
@floatToInt(i32, translation[0]),
|
std.math.lossyCast(i32, translation[0]),
|
||||||
main.Window.height - @floatToInt(i32, translation[1] + clipRect[1]*scale),
|
main.Window.height - std.math.lossyCast(i32, translation[1] + clipRect[1]*scale),
|
||||||
@floatToInt(i32, clipRect[0]*scale),
|
std.math.lossyCast(i32, clipRect[0]*scale),
|
||||||
@floatToInt(i32, clipRect[1]*scale),
|
std.math.lossyCast(i32, clipRect[1]*scale),
|
||||||
};
|
};
|
||||||
if(clip) |oldClip| {
|
if(clip) |oldClip| {
|
||||||
if (newClip[0] < oldClip[0]) {
|
if (newClip[0] < oldClip[0]) {
|
||||||
@ -84,6 +86,8 @@ pub const draw = struct {
|
|||||||
if (newClip[1] + newClip[3] > oldClip[1] + oldClip[3]) {
|
if (newClip[1] + newClip[3] > oldClip[1] + oldClip[3]) {
|
||||||
newClip[3] -= (newClip[1] + newClip[3]) - (oldClip[1] + oldClip[3]);
|
newClip[3] -= (newClip[1] + newClip[3]) - (oldClip[1] + oldClip[3]);
|
||||||
}
|
}
|
||||||
|
newClip[2] = @max(newClip[2], 0);
|
||||||
|
newClip[3] = @max(newClip[3], 0);
|
||||||
} else {
|
} else {
|
||||||
c.glEnable(c.GL_SCISSOR_TEST);
|
c.glEnable(c.GL_SCISSOR_TEST);
|
||||||
}
|
}
|
||||||
@ -151,7 +155,7 @@ pub const draw = struct {
|
|||||||
c.glUniform2f(rectUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
|
c.glUniform2f(rectUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
|
||||||
c.glUniform2f(rectUniforms.start, pos[0], pos[1]);
|
c.glUniform2f(rectUniforms.start, pos[0], pos[1]);
|
||||||
c.glUniform2f(rectUniforms.size, dim[0], dim[1]);
|
c.glUniform2f(rectUniforms.size, dim[0], dim[1]);
|
||||||
c.glUniform1i(rectUniforms.rectColor, color);
|
c.glUniform1i(rectUniforms.rectColor, @bitCast(i32, color));
|
||||||
|
|
||||||
c.glBindVertexArray(rectVAO);
|
c.glBindVertexArray(rectVAO);
|
||||||
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
||||||
@ -204,7 +208,7 @@ pub const draw = struct {
|
|||||||
c.glUniform2f(lineUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
|
c.glUniform2f(lineUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
|
||||||
c.glUniform2f(lineUniforms.start, pos1[0], pos1[1]);
|
c.glUniform2f(lineUniforms.start, pos1[0], pos1[1]);
|
||||||
c.glUniform2f(lineUniforms.direction, pos2[0] - pos1[0], pos2[1] - pos1[1]);
|
c.glUniform2f(lineUniforms.direction, pos2[0] - pos1[0], pos2[1] - pos1[1]);
|
||||||
c.glUniform1i(lineUniforms.lineColor, color);
|
c.glUniform1i(lineUniforms.lineColor, @bitCast(i32, color));
|
||||||
|
|
||||||
c.glBindVertexArray(lineVAO);
|
c.glBindVertexArray(lineVAO);
|
||||||
c.glDrawArrays(c.GL_LINE_STRIP, 0, 2);
|
c.glDrawArrays(c.GL_LINE_STRIP, 0, 2);
|
||||||
@ -250,7 +254,7 @@ pub const draw = struct {
|
|||||||
c.glUniform2f(lineUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
|
c.glUniform2f(lineUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
|
||||||
c.glUniform2f(lineUniforms.start, pos[0], pos[1]); // Move the coordinates, so they are in the center of a pixel.
|
c.glUniform2f(lineUniforms.start, pos[0], pos[1]); // Move the coordinates, so they are in the center of a pixel.
|
||||||
c.glUniform2f(lineUniforms.direction, dim[0] - 1, dim[1] - 1); // The height is a lot smaller because the inner edge of the rect is drawn.
|
c.glUniform2f(lineUniforms.direction, dim[0] - 1, dim[1] - 1); // The height is a lot smaller because the inner edge of the rect is drawn.
|
||||||
c.glUniform1i(lineUniforms.lineColor, color);
|
c.glUniform1i(lineUniforms.lineColor, @bitCast(i32, color));
|
||||||
|
|
||||||
c.glBindVertexArray(lineVAO);
|
c.glBindVertexArray(lineVAO);
|
||||||
c.glDrawArrays(c.GL_LINE_LOOP, 0, 5);
|
c.glDrawArrays(c.GL_LINE_LOOP, 0, 5);
|
||||||
@ -303,7 +307,7 @@ pub const draw = struct {
|
|||||||
c.glUniform2f(circleUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
|
c.glUniform2f(circleUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
|
||||||
c.glUniform2f(circleUniforms.center, center[0], center[1]); // Move the coordinates, so they are in the center of a pixel.
|
c.glUniform2f(circleUniforms.center, center[0], center[1]); // Move the coordinates, so they are in the center of a pixel.
|
||||||
c.glUniform1f(circleUniforms.radius, radius); // The height is a lot smaller because the inner edge of the rect is drawn.
|
c.glUniform1f(circleUniforms.radius, radius); // The height is a lot smaller because the inner edge of the rect is drawn.
|
||||||
c.glUniform1i(circleUniforms.circleColor, color);
|
c.glUniform1i(circleUniforms.circleColor, @bitCast(i32, color));
|
||||||
|
|
||||||
c.glBindVertexArray(circleVAO);
|
c.glBindVertexArray(circleVAO);
|
||||||
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
||||||
@ -341,7 +345,7 @@ pub const draw = struct {
|
|||||||
c.glUniform2f(imageUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
|
c.glUniform2f(imageUniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
|
||||||
c.glUniform2f(imageUniforms.start, pos[0], pos[1]);
|
c.glUniform2f(imageUniforms.start, pos[0], pos[1]);
|
||||||
c.glUniform2f(imageUniforms.size, dim[0], dim[1]);
|
c.glUniform2f(imageUniforms.size, dim[0], dim[1]);
|
||||||
c.glUniform1i(imageUniforms.color, color);
|
c.glUniform1i(imageUniforms.color, @bitCast(i32, color));
|
||||||
|
|
||||||
c.glBindVertexArray(rectVAO);
|
c.glBindVertexArray(rectVAO);
|
||||||
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
|
||||||
@ -359,7 +363,7 @@ pub const draw = struct {
|
|||||||
c.glUniform2f(uniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
|
c.glUniform2f(uniforms.screen, @intToFloat(f32, Window.width), @intToFloat(f32, Window.height));
|
||||||
c.glUniform2f(uniforms.start, pos[0], pos[1]);
|
c.glUniform2f(uniforms.start, pos[0], pos[1]);
|
||||||
c.glUniform2f(uniforms.size, dim[0], dim[1]);
|
c.glUniform2f(uniforms.size, dim[0], dim[1]);
|
||||||
c.glUniform1i(uniforms.color, color);
|
c.glUniform1i(uniforms.color, @bitCast(i32, color));
|
||||||
c.glUniform1f(uniforms.scale, scale);
|
c.glUniform1f(uniforms.scale, scale);
|
||||||
|
|
||||||
c.glBindVertexArray(rectVAO);
|
c.glBindVertexArray(rectVAO);
|
||||||
@ -382,7 +386,7 @@ pub const TextBuffer = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const FontEffect = packed struct(u28) {
|
pub const FontEffect = packed struct(u28) {
|
||||||
color: u24 = 0,
|
color: u24 = 0xffffff,
|
||||||
bold: bool = false,
|
bold: bool = false,
|
||||||
italic: bool = false,
|
italic: bool = false,
|
||||||
underline: bool = false,
|
underline: bool = false,
|
||||||
@ -741,6 +745,7 @@ pub const TextBuffer = struct {
|
|||||||
TextRendering.shader.bind();
|
TextRendering.shader.bind();
|
||||||
c.glUniform2f(TextRendering.uniforms.scene, @intToFloat(f32, main.Window.width), @intToFloat(f32, main.Window.height));
|
c.glUniform2f(TextRendering.uniforms.scene, @intToFloat(f32, main.Window.width), @intToFloat(f32, main.Window.height));
|
||||||
c.glUniform1f(TextRendering.uniforms.ratio, draw.scale);
|
c.glUniform1f(TextRendering.uniforms.ratio, draw.scale);
|
||||||
|
c.glUniform1f(TextRendering.uniforms.alpha, @intToFloat(f32, draw.color >> 24) / 255.0);
|
||||||
c.glActiveTexture(c.GL_TEXTURE0);
|
c.glActiveTexture(c.GL_TEXTURE0);
|
||||||
c.glBindTexture(c.GL_TEXTURE_2D, TextRendering.glyphTexture[0]);
|
c.glBindTexture(c.GL_TEXTURE_2D, TextRendering.glyphTexture[0]);
|
||||||
c.glBindVertexArray(draw.rectVAO);
|
c.glBindVertexArray(draw.rectVAO);
|
||||||
@ -767,7 +772,7 @@ pub const TextBuffer = struct {
|
|||||||
y = 0;
|
y = 0;
|
||||||
if(line.isUnderline) y += 15
|
if(line.isUnderline) y += 15
|
||||||
else y += 8;
|
else y += 8;
|
||||||
draw.setColor(line.color | @as(u32, 0xff000000));
|
draw.setColor(line.color | (@as(u32, 0xff000000) & draw.color));
|
||||||
for(lineWraps, 0..) |lineWrap, j| {
|
for(lineWraps, 0..) |lineWrap, j| {
|
||||||
const lineStart = @max(0, line.start);
|
const lineStart = @max(0, line.start);
|
||||||
const lineEnd = @min(lineWrap, line.end);
|
const lineEnd = @min(lineWrap, line.end);
|
||||||
@ -856,6 +861,7 @@ const TextRendering = struct {
|
|||||||
const swap = glyphTexture[1];
|
const swap = glyphTexture[1];
|
||||||
glyphTexture[1] = glyphTexture[0];
|
glyphTexture[1] = glyphTexture[0];
|
||||||
glyphTexture[0] = swap;
|
glyphTexture[0] = swap;
|
||||||
|
c.glActiveTexture(c.GL_TEXTURE0);
|
||||||
c.glBindTexture(c.GL_TEXTURE_2D, glyphTexture[0]);
|
c.glBindTexture(c.GL_TEXTURE_2D, glyphTexture[0]);
|
||||||
c.glTexImage2D(c.GL_TEXTURE_2D, 0, c.GL_R8, newWidth, textureHeight, 0, c.GL_RED, c.GL_UNSIGNED_BYTE, null);
|
c.glTexImage2D(c.GL_TEXTURE_2D, 0, c.GL_R8, newWidth, textureHeight, 0, c.GL_RED, c.GL_UNSIGNED_BYTE, null);
|
||||||
c.glCopyImageSubData(
|
c.glCopyImageSubData(
|
||||||
@ -1349,8 +1355,7 @@ pub const TextureArray = struct {
|
|||||||
c.glTexSubImage3D(c.GL_TEXTURE_2D_ARRAY, lod, 0, 0, @intCast(c_int, i), curWidth, curHeight, 1, c.GL_RGBA, c.GL_UNSIGNED_BYTE, lodBuffer[lod].ptr);
|
c.glTexSubImage3D(c.GL_TEXTURE_2D_ARRAY, lod, 0, 0, @intCast(c_int, i), curWidth, curHeight, 1, c.GL_RGBA, c.GL_UNSIGNED_BYTE, lodBuffer[lod].ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAX_LOD, maxLOD);
|
c.glTexParameteri(c.GL_TEXTURE_2D_ARRAY, c.GL_TEXTURE_MAX_LOD, maxLOD);
|
||||||
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_BASE_LEVEL, 5);
|
|
||||||
//glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
//glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
||||||
c.glTexParameteri(c.GL_TEXTURE_2D_ARRAY, c.GL_TEXTURE_MIN_FILTER, c.GL_NEAREST_MIPMAP_LINEAR);
|
c.glTexParameteri(c.GL_TEXTURE_2D_ARRAY, c.GL_TEXTURE_MIN_FILTER, c.GL_NEAREST_MIPMAP_LINEAR);
|
||||||
c.glTexParameteri(c.GL_TEXTURE_2D_ARRAY, c.GL_TEXTURE_MAG_FILTER, c.GL_NEAREST);
|
c.glTexParameteri(c.GL_TEXTURE_2D_ARRAY, c.GL_TEXTURE_MAG_FILTER, c.GL_NEAREST);
|
||||||
|
@ -63,6 +63,8 @@ isHud: bool = false,
|
|||||||
|
|
||||||
/// Called every frame.
|
/// Called every frame.
|
||||||
renderFn: *const fn()Allocator.Error!void = &defaultErrorFunction,
|
renderFn: *const fn()Allocator.Error!void = &defaultErrorFunction,
|
||||||
|
/// Called every frame before rendering.
|
||||||
|
updateFn: *const fn()Allocator.Error!void = &defaultErrorFunction,
|
||||||
/// Called every frame for the currently selected window.
|
/// Called every frame for the currently selected window.
|
||||||
updateSelectedFn: *const fn()Allocator.Error!void = &defaultErrorFunction,
|
updateSelectedFn: *const fn()Allocator.Error!void = &defaultErrorFunction,
|
||||||
/// Called every frame for the currently hovered window.
|
/// Called every frame for the currently hovered window.
|
||||||
@ -310,6 +312,10 @@ fn positionRelativeToConnectedWindow(self: *GuiWindow, other: *GuiWindow, i: usi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update(self: *GuiWindow) !void {
|
||||||
|
try self.updateFn();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn updateSelected(self: *GuiWindow, mousePosition: Vec2f) !void {
|
pub fn updateSelected(self: *GuiWindow, mousePosition: Vec2f) !void {
|
||||||
try self.updateSelectedFn();
|
try self.updateSelectedFn();
|
||||||
const windowSize = main.Window.getWindowSize()/@splat(2, gui.scale);
|
const windowSize = main.Window.getWindowSize()/@splat(2, gui.scale);
|
||||||
@ -478,7 +484,7 @@ pub fn render(self: *const GuiWindow, mousePosition: Vec2f) !void {
|
|||||||
draw.restoreTranslation(oldTranslation);
|
draw.restoreTranslation(oldTranslation);
|
||||||
draw.restoreScale(oldScale);
|
draw.restoreScale(oldScale);
|
||||||
if(self.showTitleBar) {
|
if(self.showTitleBar) {
|
||||||
var text = try graphics.TextBuffer.init(gui.allocator, self.title, .{}, false, .center);
|
var text = try graphics.TextBuffer.init(gui.allocator, self.title, .{.color=0}, false, .center);
|
||||||
defer text.deinit();
|
defer text.deinit();
|
||||||
const titleDimension = try text.calculateLineBreaks(16*self.scale, self.size[0]);
|
const titleDimension = try text.calculateLineBreaks(16*self.scale, self.size[0]);
|
||||||
try text.render(self.pos[0] + self.size[0]/2 - titleDimension[0]/2, self.pos[1], 16*self.scale);
|
try text.render(self.pos[0] + self.size[0]/2 - titleDimension[0]/2, self.pos[1], 16*self.scale);
|
||||||
|
@ -18,6 +18,7 @@ const fontSize: f32 = 16;
|
|||||||
pos: Vec2f,
|
pos: Vec2f,
|
||||||
size: Vec2f,
|
size: Vec2f,
|
||||||
text: TextBuffer,
|
text: TextBuffer,
|
||||||
|
alpha: f32 = 1,
|
||||||
|
|
||||||
pub fn init(pos: Vec2f, maxWidth: f32, text: []const u8, alignment: TextBuffer.Alignment) Allocator.Error!*Label {
|
pub fn init(pos: Vec2f, maxWidth: f32, text: []const u8, alignment: TextBuffer.Alignment) Allocator.Error!*Label {
|
||||||
const self = try gui.allocator.create(Label);
|
const self = try gui.allocator.create(Label);
|
||||||
@ -49,5 +50,6 @@ pub fn updateText(self: *Label, newText: []const u8) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(self: *Label, _: Vec2f) !void {
|
pub fn render(self: *Label, _: Vec2f) !void {
|
||||||
|
draw.setColor(@floatToInt(u32, self.alpha*255) << 24);
|
||||||
try self.text.render(self.pos[0], self.pos[1], fontSize);
|
try self.text.render(self.pos[0], self.pos[1], fontSize);
|
||||||
}
|
}
|
79
src/gui/components/MutexComponent.zig
Normal file
79
src/gui/components/MutexComponent.zig
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
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 ScrollBar = GuiComponent.ScrollBar;
|
||||||
|
|
||||||
|
const MutexComponent = @This();
|
||||||
|
|
||||||
|
const scrollBarWidth = 5;
|
||||||
|
const border: f32 = 3;
|
||||||
|
|
||||||
|
pos: Vec2f = undefined,
|
||||||
|
size: Vec2f = undefined,
|
||||||
|
child: GuiComponent = undefined,
|
||||||
|
mutex: std.Thread.Mutex = .{},
|
||||||
|
|
||||||
|
pub fn updateInner(self: *MutexComponent, _other: anytype) Allocator.Error!void {
|
||||||
|
std.debug.assert(!self.mutex.tryLock()); // self.mutex must be locked before calling!
|
||||||
|
var other: GuiComponent = undefined;
|
||||||
|
if(@TypeOf(_other) == GuiComponent) {
|
||||||
|
other = _other;
|
||||||
|
} else {
|
||||||
|
other = _other.toComponent();
|
||||||
|
}
|
||||||
|
self.child = other;
|
||||||
|
self.pos = other.pos();
|
||||||
|
self.size = other.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *MutexComponent) void {
|
||||||
|
std.debug.assert(!self.mutex.tryLock()); // self.mutex must be locked before calling!
|
||||||
|
self.child.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toComponent(self: *MutexComponent) GuiComponent {
|
||||||
|
return GuiComponent {
|
||||||
|
.mutexComponent = self
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn updateSelected(self: *MutexComponent) void {
|
||||||
|
self.mutex.lock();
|
||||||
|
defer self.mutex.unlock();
|
||||||
|
self.child.updateSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn updateHovered(self: *MutexComponent, mousePosition: Vec2f) void {
|
||||||
|
self.mutex.lock();
|
||||||
|
defer self.mutex.unlock();
|
||||||
|
self.child.updateHovered(mousePosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(self: *MutexComponent, mousePosition: Vec2f) anyerror!void { // TODO: Remove anyerror once error union inference works in recursive loops.
|
||||||
|
self.mutex.lock();
|
||||||
|
defer self.mutex.unlock();
|
||||||
|
try self.child.render(mousePosition);
|
||||||
|
self.pos = self.child.pos();
|
||||||
|
self.size = self.child.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mainButtonPressed(self: *MutexComponent, mousePosition: Vec2f) void {
|
||||||
|
self.mutex.lock();
|
||||||
|
defer self.mutex.unlock();
|
||||||
|
self.child.mainButtonPressed(mousePosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mainButtonReleased(self: *MutexComponent, mousePosition: Vec2f) void {
|
||||||
|
self.mutex.lock();
|
||||||
|
defer self.mutex.unlock();
|
||||||
|
self.child.mainButtonReleased(mousePosition);
|
||||||
|
}
|
@ -33,6 +33,7 @@ maxWidth: f32,
|
|||||||
maxHeight: f32,
|
maxHeight: f32,
|
||||||
textSize: Vec2f = undefined,
|
textSize: Vec2f = undefined,
|
||||||
scrollBar: *ScrollBar,
|
scrollBar: *ScrollBar,
|
||||||
|
onNewline: ?*const fn() void,
|
||||||
|
|
||||||
pub fn __init() !void {
|
pub fn __init() !void {
|
||||||
texture = try Texture.initFromFile("assets/cubyz/ui/text_input.png");
|
texture = try Texture.initFromFile("assets/cubyz/ui/text_input.png");
|
||||||
@ -42,7 +43,7 @@ pub fn __deinit() void {
|
|||||||
texture.deinit();
|
texture.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(pos: Vec2f, maxWidth: f32, maxHeight: f32, text: []const u8) Allocator.Error!*TextInput {
|
pub fn init(pos: Vec2f, maxWidth: f32, maxHeight: f32, text: []const u8, onNewline: ?*const fn() void) Allocator.Error!*TextInput {
|
||||||
const scrollBar = try ScrollBar.init(undefined, scrollBarWidth, maxHeight - 2*border, 0);
|
const scrollBar = try ScrollBar.init(undefined, scrollBarWidth, maxHeight - 2*border, 0);
|
||||||
const self = try gui.allocator.create(TextInput);
|
const self = try gui.allocator.create(TextInput);
|
||||||
self.* = TextInput {
|
self.* = TextInput {
|
||||||
@ -53,6 +54,7 @@ pub fn init(pos: Vec2f, maxWidth: f32, maxHeight: f32, text: []const u8) Allocat
|
|||||||
.maxWidth = maxWidth,
|
.maxWidth = maxWidth,
|
||||||
.maxHeight = maxHeight,
|
.maxHeight = maxHeight,
|
||||||
.scrollBar = scrollBar,
|
.scrollBar = scrollBar,
|
||||||
|
.onNewline = onNewline,
|
||||||
};
|
};
|
||||||
try self.currentString.appendSlice(text);
|
try self.currentString.appendSlice(text);
|
||||||
self.textSize = try self.textBuffer.calculateLineBreaks(fontSize, maxWidth - 2*border - scrollBarWidth);
|
self.textSize = try self.textBuffer.calculateLineBreaks(fontSize, maxWidth - 2*border - scrollBarWidth);
|
||||||
@ -66,6 +68,15 @@ pub fn deinit(self: *const TextInput) void {
|
|||||||
gui.allocator.destroy(self);
|
gui.allocator.destroy(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear(self: *TextInput) !void {
|
||||||
|
if(self.cursor != null) {
|
||||||
|
self.cursor = 0;
|
||||||
|
self.selectionStart = null;
|
||||||
|
}
|
||||||
|
self.currentString.clearRetainingCapacity();
|
||||||
|
try self.reloadText();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn toComponent(self: *TextInput) GuiComponent {
|
pub fn toComponent(self: *TextInput) GuiComponent {
|
||||||
return GuiComponent {
|
return GuiComponent {
|
||||||
.textInput = self
|
.textInput = self
|
||||||
@ -420,7 +431,11 @@ pub fn cut(self: *TextInput, mods: main.Key.Modifiers) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn newline(self: *TextInput, _: main.Key.Modifiers) void {
|
pub fn newline(self: *TextInput, mods: main.Key.Modifiers) void {
|
||||||
|
if(!mods.shift) if(self.onNewline) |onNewline| {
|
||||||
|
onNewline();
|
||||||
|
return;
|
||||||
|
};
|
||||||
self.inputCharacter('\n') catch |err| {
|
self.inputCharacter('\n') catch |err| {
|
||||||
std.log.err("Error while entering text: {s}", .{@errorName(err)});
|
std.log.err("Error while entering text: {s}", .{@errorName(err)});
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@ const TextInput = @import("components/TextInput.zig");
|
|||||||
pub const GuiComponent = @import("gui_component.zig").GuiComponent;
|
pub const GuiComponent = @import("gui_component.zig").GuiComponent;
|
||||||
pub const GuiWindow = @import("GuiWindow.zig");
|
pub const GuiWindow = @import("GuiWindow.zig");
|
||||||
|
|
||||||
const windowlist = @import("windows/_windowlist.zig");
|
pub const windowlist = @import("windows/_windowlist.zig");
|
||||||
|
|
||||||
var windowList: std.ArrayList(*GuiWindow) = undefined;
|
var windowList: std.ArrayList(*GuiWindow) = undefined;
|
||||||
var hudWindows: std.ArrayList(*GuiWindow) = undefined;
|
var hudWindows: std.ArrayList(*GuiWindow) = undefined;
|
||||||
@ -402,6 +402,9 @@ pub fn updateAndRenderGui() !void {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for(openWindows.items) |window| {
|
||||||
|
try window.update();
|
||||||
|
}
|
||||||
for(openWindows.items) |window| {
|
for(openWindows.items) |window| {
|
||||||
const oldScale = draw.setScale(scale);
|
const oldScale = draw.setScale(scale);
|
||||||
defer draw.restoreScale(oldScale);
|
defer draw.restoreScale(oldScale);
|
||||||
|
@ -10,6 +10,7 @@ pub const GuiComponent = union(enum) {
|
|||||||
pub const CheckBox = @import("components/CheckBox.zig");
|
pub const CheckBox = @import("components/CheckBox.zig");
|
||||||
pub const HorizontalList = @import("components/HorizontalList.zig");
|
pub const HorizontalList = @import("components/HorizontalList.zig");
|
||||||
pub const Label = @import("components/Label.zig");
|
pub const Label = @import("components/Label.zig");
|
||||||
|
pub const MutexComponent = @import("components/MutexComponent.zig");
|
||||||
pub const Slider = @import("components/Slider.zig");
|
pub const Slider = @import("components/Slider.zig");
|
||||||
pub const ScrollBar = @import("components/ScrollBar.zig");
|
pub const ScrollBar = @import("components/ScrollBar.zig");
|
||||||
pub const TextInput = @import("components/TextInput.zig");
|
pub const TextInput = @import("components/TextInput.zig");
|
||||||
@ -20,6 +21,7 @@ pub const GuiComponent = union(enum) {
|
|||||||
checkBox: *CheckBox,
|
checkBox: *CheckBox,
|
||||||
horizontalList: *HorizontalList,
|
horizontalList: *HorizontalList,
|
||||||
label: *Label,
|
label: *Label,
|
||||||
|
mutexComponent: *MutexComponent,
|
||||||
scrollBar: *ScrollBar,
|
scrollBar: *ScrollBar,
|
||||||
slider: *Slider,
|
slider: *Slider,
|
||||||
textInput: *TextInput,
|
textInput: *TextInput,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
pub const change_name = @import("change_name.zig");
|
pub const change_name = @import("change_name.zig");
|
||||||
|
pub const chat = @import("chat.zig");
|
||||||
pub const controls = @import("controls.zig");
|
pub const controls = @import("controls.zig");
|
||||||
pub const crosshair = @import("crosshair.zig");
|
pub const crosshair = @import("crosshair.zig");
|
||||||
pub const graphics = @import("graphics.zig");
|
pub const graphics = @import("graphics.zig");
|
||||||
|
@ -49,13 +49,13 @@ pub fn onOpen() Allocator.Error!void {
|
|||||||
if(settings.playerName.len == 0) {
|
if(settings.playerName.len == 0) {
|
||||||
try list.add(try Label.init(.{0, 0}, width, "Please enter your name!", .center));
|
try list.add(try Label.init(.{0, 0}, width, "Please enter your name!", .center));
|
||||||
} else {
|
} else {
|
||||||
try list.add(try Label.init(.{0, 0}, width, "#ff0000Warning: #000000You loose access to your inventory data when changing the name!", .center));
|
try list.add(try Label.init(.{0, 0}, width, "#ff0000Warning: #ffffffYou loose access to your inventory data when changing the name!", .center));
|
||||||
}
|
}
|
||||||
try list.add(try Label.init(.{0, 0}, width, "Cubyz supports formatting your username using a markdown-like syntax:", .center));
|
try list.add(try Label.init(.{0, 0}, width, "Cubyz supports formatting your username using a markdown-like syntax:", .center));
|
||||||
try list.add(try Label.init(.{0, 0}, width, "\\**italic*\\* \\*\\***bold**\\*\\* \\__underlined_\\_ \\_\\___strike-through__\\_\\_", .center));
|
try list.add(try Label.init(.{0, 0}, width, "\\**italic*\\* \\*\\***bold**\\*\\* \\__underlined_\\_ \\_\\___strike-through__\\_\\_", .center));
|
||||||
try list.add(try Label.init(.{0, 0}, width, "Even colors are possible, using the hexadecimal color code:", .center));
|
try list.add(try Label.init(.{0, 0}, width, "Even colors are possible, using the hexadecimal color code:", .center));
|
||||||
try list.add(try Label.init(.{0, 0}, 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 Label.init(.{0, 0}, width, "\\##ff0000ff#ffffff00#ffffff00#ff0000red#ffffff \\##ff0000ff#00770077#ffffff00#ff7700orange#ffffff \\##ffffff00#00ff00ff#ffffff00#00ff00green#ffffff \\##ffffff00#ffffff00#0000ffff#0000ffblue", .center));
|
||||||
textComponent = try TextInput.init(.{0, 0}, width, 32, "quanturmdoelvloper");
|
textComponent = try TextInput.init(.{0, 0}, width, 32, "quanturmdoelvloper", &apply);
|
||||||
try list.add(textComponent);
|
try list.add(textComponent);
|
||||||
try list.add(try Button.init(.{0, 0}, 100, "Apply", &apply));
|
try list.add(try Button.init(.{0, 0}, 100, "Apply", &apply));
|
||||||
list.finish(.center);
|
list.finish(.center);
|
||||||
|
132
src/gui/windows/chat.zig
Normal file
132
src/gui/windows/chat.zig
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const main = @import("root");
|
||||||
|
const Vec2f = main.vec.Vec2f;
|
||||||
|
|
||||||
|
const gui = @import("../gui.zig");
|
||||||
|
const GuiComponent = gui.GuiComponent;
|
||||||
|
const GuiWindow = gui.GuiWindow;
|
||||||
|
const Button = @import("../components/Button.zig");
|
||||||
|
const Label = GuiComponent.Label;
|
||||||
|
const MutexComponent = GuiComponent.MutexComponent;
|
||||||
|
const TextInput = GuiComponent.TextInput;
|
||||||
|
const VerticalList = @import("../components/VerticalList.zig");
|
||||||
|
|
||||||
|
var components: [1]GuiComponent = undefined;
|
||||||
|
pub var window: GuiWindow = GuiWindow {
|
||||||
|
.contentSize = Vec2f{128, 256},
|
||||||
|
.id = "cubyz:chat",
|
||||||
|
.title = "Chat",
|
||||||
|
.onOpenFn = &onOpen,
|
||||||
|
.onCloseFn = &onClose,
|
||||||
|
.updateFn = &update,
|
||||||
|
.renderFn = &render,
|
||||||
|
.components = &components,
|
||||||
|
.showTitleBar = false,
|
||||||
|
.hasBackground = false,
|
||||||
|
.isHud = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const padding: f32 = 8;
|
||||||
|
const messageTimeout: i32 = 10000;
|
||||||
|
const messageFade: i32 = 1000;
|
||||||
|
|
||||||
|
var mutexComponent: MutexComponent = .{};
|
||||||
|
var history: std.ArrayList(*Label) = undefined;
|
||||||
|
var expirationTime: std.ArrayList(i32) = undefined;
|
||||||
|
var historyStart: u32 = 0;
|
||||||
|
var fadeOutEnd: u32 = 0;
|
||||||
|
var input: *TextInput = undefined;
|
||||||
|
var hideInput: bool = true;
|
||||||
|
|
||||||
|
fn refresh(deleteOld: bool) Allocator.Error!void {
|
||||||
|
std.debug.assert(!mutexComponent.mutex.tryLock()); // mutex must be locked!
|
||||||
|
if(deleteOld) {
|
||||||
|
components[0].mutexComponent.child.verticalList.children.clearRetainingCapacity();
|
||||||
|
components[0].deinit();
|
||||||
|
}
|
||||||
|
var list = try VerticalList.init(.{padding, 16 + padding}, 300, 0);
|
||||||
|
for(history.items[if(hideInput) historyStart else 0 ..]) |msg| {
|
||||||
|
msg.pos = .{0, 0};
|
||||||
|
try list.add(msg);
|
||||||
|
}
|
||||||
|
if(!hideInput) {
|
||||||
|
input.pos = .{0, 0};
|
||||||
|
try list.add(input);
|
||||||
|
}
|
||||||
|
list.finish(.center);
|
||||||
|
list.scrollBar.currentState = 1;
|
||||||
|
try mutexComponent.updateInner(list);
|
||||||
|
components[0] = mutexComponent.toComponent();
|
||||||
|
window.contentSize = components[0].pos() + components[0].size() + @splat(2, @as(f32, padding));
|
||||||
|
gui.updateWindowPositions();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn onOpen() Allocator.Error!void {
|
||||||
|
history = std.ArrayList(*Label).init(main.globalAllocator);
|
||||||
|
expirationTime = std.ArrayList(i32).init(main.globalAllocator);
|
||||||
|
historyStart = 0;
|
||||||
|
input = try TextInput.init(.{0, 0}, 256, 32, "", &sendMessage);
|
||||||
|
mutexComponent.mutex.lock();
|
||||||
|
defer mutexComponent.mutex.unlock();
|
||||||
|
try refresh(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn onClose() void {
|
||||||
|
mutexComponent.mutex.lock();
|
||||||
|
defer mutexComponent.mutex.unlock();
|
||||||
|
for(history.items) |label| {
|
||||||
|
label.deinit();
|
||||||
|
}
|
||||||
|
history.deinit();
|
||||||
|
expirationTime.deinit();
|
||||||
|
input.deinit();
|
||||||
|
components[0].mutexComponent.child.verticalList.children.clearRetainingCapacity();
|
||||||
|
components[0].deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update() Allocator.Error!void {
|
||||||
|
mutexComponent.mutex.lock();
|
||||||
|
defer mutexComponent.mutex.unlock();
|
||||||
|
while(fadeOutEnd < history.items.len and @truncate(i32, std.time.milliTimestamp()) -% expirationTime.items[fadeOutEnd] >= 0) {
|
||||||
|
fadeOutEnd += 1;
|
||||||
|
}
|
||||||
|
for(expirationTime.items[historyStart..fadeOutEnd], history.items[historyStart..fadeOutEnd]) |time, label| {
|
||||||
|
if(@truncate(i32, std.time.milliTimestamp()) -% time >= messageFade) {
|
||||||
|
historyStart += 1;
|
||||||
|
hideInput = main.Window.grabbed;
|
||||||
|
try refresh(true);
|
||||||
|
} else {
|
||||||
|
label.alpha = 1.0 - @intToFloat(f32, @truncate(i32, std.time.milliTimestamp()) -% time)/@intToFloat(f32, messageFade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(hideInput != main.Window.grabbed) {
|
||||||
|
hideInput = main.Window.grabbed;
|
||||||
|
try refresh(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render() Allocator.Error!void {
|
||||||
|
if(!hideInput) {
|
||||||
|
main.graphics.draw.setColor(0x80000000);
|
||||||
|
main.graphics.draw.rect(.{0, 0}, window.contentSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addMessage(message: []const u8) Allocator.Error!void {
|
||||||
|
mutexComponent.mutex.lock();
|
||||||
|
defer mutexComponent.mutex.unlock();
|
||||||
|
try history.append(try Label.init(.{0, 0}, 256, message, .left));
|
||||||
|
try expirationTime.append(@truncate(i32, std.time.milliTimestamp()) +% messageTimeout);
|
||||||
|
try refresh(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sendMessage() void {
|
||||||
|
main.network.Protocols.chat.send(main.game.world.?.conn, input.currentString.items) catch |err| {
|
||||||
|
std.log.err("Got error while trying to send chat message: {s}", .{@errorName(err)});
|
||||||
|
};
|
||||||
|
input.clear() catch |err| {
|
||||||
|
std.log.err("Got error while trying to send chat message: {s}", .{@errorName(err)});
|
||||||
|
};
|
||||||
|
}
|
@ -21,6 +21,7 @@ pub var window = GuiWindow {
|
|||||||
.title = "Multiplayer",
|
.title = "Multiplayer",
|
||||||
.onOpenFn = &onOpen,
|
.onOpenFn = &onOpen,
|
||||||
.onCloseFn = &onClose,
|
.onCloseFn = &onClose,
|
||||||
|
.updateFn = &update,
|
||||||
.components = &components,
|
.components = &components,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ const width: f32 = 420;
|
|||||||
fn flawedDiscoverIpAddress() !void {
|
fn flawedDiscoverIpAddress() !void {
|
||||||
connection = try ConnectionManager.init(12347, true); // TODO: default port
|
connection = try ConnectionManager.init(12347, true); // TODO: default port
|
||||||
ipAddress = try std.fmt.allocPrint(main.globalAllocator, "{}", .{connection.?.externalAddress});
|
ipAddress = try std.fmt.allocPrint(main.globalAllocator, "{}", .{connection.?.externalAddress});
|
||||||
gotIpAddress.store(true, .Monotonic);
|
gotIpAddress.store(true, .Release);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn discoverIpAddress() void {
|
fn discoverIpAddress() void {
|
||||||
@ -94,7 +95,7 @@ pub fn onOpen() Allocator.Error!void {
|
|||||||
ipAddressLabel = try Label.init(.{0, 0}, width, " ", .center);
|
ipAddressLabel = try Label.init(.{0, 0}, width, " ", .center);
|
||||||
try list.add(ipAddressLabel);
|
try list.add(ipAddressLabel);
|
||||||
try list.add(try Button.init(.{0, 0}, 100, "Copy IP", ©Ip));
|
try list.add(try Button.init(.{0, 0}, 100, "Copy IP", ©Ip));
|
||||||
try list.add(try TextInput.init(.{0, 0}, width, 32, settings.lastUsedIPAddress));
|
try list.add(try TextInput.init(.{0, 0}, width, 32, settings.lastUsedIPAddress, &join));
|
||||||
try list.add(try Button.init(.{0, 0}, 100, "Join", &join));
|
try list.add(try Button.init(.{0, 0}, 100, "Join", &join));
|
||||||
list.finish(.center);
|
list.finish(.center);
|
||||||
components[0] = list.toComponent();
|
components[0] = list.toComponent();
|
||||||
@ -127,8 +128,8 @@ pub fn onClose() void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render() void {
|
pub fn update() Allocator.Error!void {
|
||||||
if(gotIpAddress.load(.Monotonic)) {
|
if(gotIpAddress.load(.Acquire)) {
|
||||||
gotIpAddress.store(false, .Monotonic);
|
gotIpAddress.store(false, .Monotonic);
|
||||||
try ipAddressLabel.updateText(ipAddress);
|
try ipAddressLabel.updateText(ipAddress);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const gui = @import("gui");
|
pub const gui = @import("gui");
|
||||||
|
|
||||||
pub const assets = @import("assets.zig");
|
pub const assets = @import("assets.zig");
|
||||||
pub const blocks = @import("blocks.zig");
|
pub const blocks = @import("blocks.zig");
|
||||||
|
@ -1201,6 +1201,38 @@ pub const Protocols: struct {
|
|||||||
// addHeaderAndSendUnimportant(user, TIME_AND_BIOME, data.toString().getBytes(StandardCharsets.UTF_8));
|
// addHeaderAndSendUnimportant(user, TIME_AND_BIOME, data.toString().getBytes(StandardCharsets.UTF_8));
|
||||||
// }
|
// }
|
||||||
},
|
},
|
||||||
|
chat: type = struct {
|
||||||
|
const id: u8 = 10;
|
||||||
|
fn receive(conn: *Connection, data: []const u8) !void {
|
||||||
|
_ = conn;
|
||||||
|
// TODO:
|
||||||
|
// if(conn instanceof User) {
|
||||||
|
// User user = (User)conn;
|
||||||
|
// if(msg.startsWith("/")) {
|
||||||
|
// CommandExecutor.execute(msg, user);
|
||||||
|
// } else {
|
||||||
|
// msg = "["+user.name+"#ffffff] "+msg;
|
||||||
|
// sendToClients(msg);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
try main.gui.windowlist.chat.addMessage(data);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send(conn: *Connection, data: []const u8) !void {
|
||||||
|
try conn.sendImportant(id, data);
|
||||||
|
}
|
||||||
|
// TODO
|
||||||
|
// public void sendToClients(String msg) {
|
||||||
|
// Logger.log("chat", msg, "\033[0;32m");
|
||||||
|
// synchronized(this) {
|
||||||
|
// for(User user : Server.users) {
|
||||||
|
// send(user, msg);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
},
|
||||||
} = .{};
|
} = .{};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user