mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-04 03:37:59 -04:00
Text can now be scrolled.
This commit is contained in:
parent
44eed8026d
commit
b8f5b84322
BIN
assets/cubyz/ui/scrollbar.png
Normal file
BIN
assets/cubyz/ui/scrollbar.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 938 B |
@ -62,29 +62,34 @@ pub const draw = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the previous clip.
|
/// Returns the previous clip.
|
||||||
pub fn setClip(newClip: Vec4i) ?Vec4i {
|
pub fn setClip(clipRect: Vec2f) ?Vec4i {
|
||||||
|
var newClip = Vec4i {
|
||||||
|
@floatToInt(i32, translation[0]),
|
||||||
|
main.Window.height - @floatToInt(i32, translation[1] + clipRect[1]*scale),
|
||||||
|
@floatToInt(i32, clipRect[0]*scale),
|
||||||
|
@floatToInt(i32, clipRect[1]*scale),
|
||||||
|
};
|
||||||
|
if(clip) |oldClip| {
|
||||||
|
if (newClip[0] < oldClip[0]) {
|
||||||
|
newClip[2] -= oldClip[0] - newClip[0];
|
||||||
|
newClip[0] += oldClip[0] - newClip[0];
|
||||||
|
}
|
||||||
|
if (newClip[1] < oldClip[1]) {
|
||||||
|
newClip[3] -= oldClip[1] - newClip[1];
|
||||||
|
newClip[1] += oldClip[1] - newClip[1];
|
||||||
|
}
|
||||||
|
if (newClip[0] + newClip[2] > oldClip[0] + oldClip[2]) {
|
||||||
|
newClip[2] -= (newClip[0] + newClip[2]) - (oldClip[0] + oldClip[2]);
|
||||||
|
}
|
||||||
|
if (newClip[1] + newClip[3] > oldClip[1] + oldClip[3]) {
|
||||||
|
newClip[3] -= (newClip[1] + newClip[3]) - (oldClip[1] + oldClip[3]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.glEnable(c.GL_SCISSOR_TEST);
|
||||||
|
}
|
||||||
|
c.glScissor(newClip[0], newClip[1], newClip[2], newClip[3]);
|
||||||
const oldClip = clip;
|
const oldClip = clip;
|
||||||
clip = newClip;
|
clip = newClip;
|
||||||
var clipRef: *Vec4i = &clip.?;
|
|
||||||
if(oldClip == null) {
|
|
||||||
c.glEnable(c.GL_SCISSOR_TEST);
|
|
||||||
} else {
|
|
||||||
if (clipRef.x < oldClip.x) {
|
|
||||||
clipRef.z -= oldClip.x - clipRef.x;
|
|
||||||
clipRef.x += oldClip.x - clipRef.x;
|
|
||||||
}
|
|
||||||
if (clipRef.y < oldClip.y) {
|
|
||||||
clipRef.w -= oldClip.y - clipRef.y;
|
|
||||||
clipRef.y += oldClip.y - clipRef.y;
|
|
||||||
}
|
|
||||||
if (clipRef.x + clipRef.z > oldClip.x + oldClip.z) {
|
|
||||||
clipRef.z -= (clipRef.x + clipRef.z) - (oldClip.x + oldClip.z);
|
|
||||||
}
|
|
||||||
if (clipRef.y + clipRef.w > oldClip.y + oldClip.w) {
|
|
||||||
clipRef.w -= (clipRef.y + clipRef.w) - (oldClip.y + oldClip.w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.glScissor(clipRef.x, clipRef.y, clipRef.z, clipRef.w);
|
|
||||||
return oldClip;
|
return oldClip;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +97,7 @@ pub const draw = struct {
|
|||||||
pub fn restoreClip(previousClip: ?Vec4i) void {
|
pub fn restoreClip(previousClip: ?Vec4i) void {
|
||||||
clip = previousClip;
|
clip = previousClip;
|
||||||
if (clip) |clipRef| {
|
if (clip) |clipRef| {
|
||||||
c.glScissor(clipRef.x, clipRef.y, clipRef.z, clipRef.w);
|
c.glScissor(clipRef[0], clipRef[1], clipRef[2], clipRef[3]);
|
||||||
} else {
|
} else {
|
||||||
c.glDisable(c.GL_SCISSOR_TEST);
|
c.glDisable(c.GL_SCISSOR_TEST);
|
||||||
}
|
}
|
||||||
@ -668,6 +673,16 @@ pub const TextBuffer = struct {
|
|||||||
var lastSpaceIndex: u32 = 0;
|
var lastSpaceIndex: u32 = 0;
|
||||||
for(self.glyphs, 0..) |glyph, i| {
|
for(self.glyphs, 0..) |glyph, i| {
|
||||||
lineWidth += glyph.x_advance;
|
lineWidth += glyph.x_advance;
|
||||||
|
if(glyph.character == ' ') {
|
||||||
|
lastSpaceWidth = lineWidth;
|
||||||
|
lastSpaceIndex = @intCast(u32, i+1);
|
||||||
|
}
|
||||||
|
if(glyph.character == '\n') {
|
||||||
|
try self.lineBreaks.append(.{.index = @intCast(u32, i+1), .width = lineWidth - spaceCharacterWidth});
|
||||||
|
lineWidth = 0;
|
||||||
|
lastSpaceIndex = 0;
|
||||||
|
lastSpaceWidth = 0;
|
||||||
|
}
|
||||||
if(lineWidth > scaledMaxWidth) {
|
if(lineWidth > scaledMaxWidth) {
|
||||||
if(lastSpaceIndex != 0) {
|
if(lastSpaceIndex != 0) {
|
||||||
lineWidth -= lastSpaceWidth;
|
lineWidth -= lastSpaceWidth;
|
||||||
@ -681,16 +696,6 @@ pub const TextBuffer = struct {
|
|||||||
lastSpaceWidth = 0;
|
lastSpaceWidth = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(glyph.character == ' ') {
|
|
||||||
lastSpaceWidth = lineWidth;
|
|
||||||
lastSpaceIndex = @intCast(u32, i+1);
|
|
||||||
}
|
|
||||||
if(glyph.character == '\n') {
|
|
||||||
try self.lineBreaks.append(.{.index = @intCast(u32, i+1), .width = lineWidth - spaceCharacterWidth});
|
|
||||||
lineWidth = 0;
|
|
||||||
lastSpaceIndex = 0;
|
|
||||||
lastSpaceWidth = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.width = maxLineWidth;
|
self.width = maxLineWidth;
|
||||||
try self.lineBreaks.append(.{.index = @intCast(u32, self.glyphs.len), .width = lineWidth});
|
try self.lineBreaks.append(.{.index = @intCast(u32, self.glyphs.len), .width = lineWidth});
|
||||||
|
@ -8,6 +8,7 @@ pub const Button = @import("components/Button.zig");
|
|||||||
pub const CheckBox = @import("components/CheckBox.zig");
|
pub const CheckBox = @import("components/CheckBox.zig");
|
||||||
pub const Label = @import("components/Label.zig");
|
pub const Label = @import("components/Label.zig");
|
||||||
pub const Slider = @import("components/Slider.zig");
|
pub const Slider = @import("components/Slider.zig");
|
||||||
|
pub const ScrollBar = @import("components/ScrollBar.zig");
|
||||||
pub const TextInput = @import("components/TextInput.zig");
|
pub const TextInput = @import("components/TextInput.zig");
|
||||||
pub const VerticalList = @import("components/VerticalList.zig");
|
pub const VerticalList = @import("components/VerticalList.zig");
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ const Impl = union(enum) {
|
|||||||
button: Button,
|
button: Button,
|
||||||
checkBox: CheckBox,
|
checkBox: CheckBox,
|
||||||
label: Label,
|
label: Label,
|
||||||
|
scrollBar: ScrollBar,
|
||||||
slider: Slider,
|
slider: Slider,
|
||||||
textInput: TextInput,
|
textInput: TextInput,
|
||||||
verticalList: VerticalList,
|
verticalList: VerticalList,
|
||||||
|
104
src/gui/components/ScrollBar.zig
Normal file
104
src/gui/components/ScrollBar.zig
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const main = @import("root");
|
||||||
|
const graphics = main.graphics;
|
||||||
|
const draw = graphics.draw;
|
||||||
|
const Image = graphics.Image;
|
||||||
|
const Shader = graphics.Shader;
|
||||||
|
const TextBuffer = graphics.TextBuffer;
|
||||||
|
const Texture = graphics.Texture;
|
||||||
|
const random = main.random;
|
||||||
|
const vec = main.vec;
|
||||||
|
const Vec2f = vec.Vec2f;
|
||||||
|
|
||||||
|
const gui = @import("../gui.zig");
|
||||||
|
const GuiComponent = gui.GuiComponent;
|
||||||
|
const Button = GuiComponent.Button;
|
||||||
|
const Label = GuiComponent.Label;
|
||||||
|
|
||||||
|
const ScrollBar = @This();
|
||||||
|
|
||||||
|
const fontSize: f32 = 16;
|
||||||
|
|
||||||
|
var texture: Texture = undefined;
|
||||||
|
|
||||||
|
// TODO: Scroll wheel support.
|
||||||
|
|
||||||
|
currentState: f32,
|
||||||
|
button: Button,
|
||||||
|
buttonSize: Vec2f,
|
||||||
|
buttonPos: Vec2f = .{0, 0},
|
||||||
|
mouseAnchor: f32 = undefined,
|
||||||
|
|
||||||
|
pub fn __init() !void {
|
||||||
|
texture = Texture.init();
|
||||||
|
const image = try Image.readFromFile(main.threadAllocator, "assets/cubyz/ui/scrollbar.png");
|
||||||
|
defer image.deinit(main.threadAllocator);
|
||||||
|
try texture.generate(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
.pos = pos,
|
||||||
|
.size = size,
|
||||||
|
.impl = .{.scrollBar = self}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: ScrollBar) void {
|
||||||
|
self.button.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
if(value != self.currentState) {
|
||||||
|
self.currentState = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 mainButtonReleased(self: *ScrollBar, _: Vec2f, _: Vec2f, _: Vec2f) void {
|
||||||
|
self.button.mainButtonReleased(undefined, undefined, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(self: *ScrollBar, pos: Vec2f, size: Vec2f, 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 range: f32 = size[1] - self.buttonSize[1];
|
||||||
|
self.setButtonPosFromValue(size);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
try self.button.render(pos + self.buttonPos, self.buttonSize, mousePosition);
|
||||||
|
}
|
@ -13,9 +13,12 @@ const Vec2f = vec.Vec2f;
|
|||||||
const gui = @import("../gui.zig");
|
const gui = @import("../gui.zig");
|
||||||
const GuiComponent = gui.GuiComponent;
|
const GuiComponent = gui.GuiComponent;
|
||||||
const Button = GuiComponent.Button;
|
const Button = GuiComponent.Button;
|
||||||
|
const ScrollBar = GuiComponent.ScrollBar;
|
||||||
|
|
||||||
const TextInput = @This();
|
const TextInput = @This();
|
||||||
|
|
||||||
|
const scrollBarWidth = 5;
|
||||||
|
const border: f32 = 3;
|
||||||
const fontSize: f32 = 16;
|
const fontSize: f32 = 16;
|
||||||
|
|
||||||
var texture: Texture = undefined;
|
var texture: Texture = undefined;
|
||||||
@ -26,7 +29,10 @@ selectionStart: ?u32 = null,
|
|||||||
currentString: std.ArrayList(u8),
|
currentString: std.ArrayList(u8),
|
||||||
textBuffer: TextBuffer,
|
textBuffer: TextBuffer,
|
||||||
maxWidth: f32,
|
maxWidth: f32,
|
||||||
|
maxHeight: f32,
|
||||||
textSize: Vec2f = undefined,
|
textSize: Vec2f = undefined,
|
||||||
|
scrollBar: ScrollBar,
|
||||||
|
scrollBarSize: Vec2f,
|
||||||
|
|
||||||
pub fn __init() !void {
|
pub fn __init() !void {
|
||||||
texture = Texture.init();
|
texture = Texture.init();
|
||||||
@ -39,19 +45,21 @@ pub fn __deinit() void {
|
|||||||
texture.deinit();
|
texture.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this scrollable.
|
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);
|
||||||
pub fn init(pos: Vec2f, maxWidth: f32, text: []const u8) Allocator.Error!GuiComponent {
|
|
||||||
var self = TextInput {
|
var self = TextInput {
|
||||||
.currentString = std.ArrayList(u8).init(gui.allocator),
|
.currentString = std.ArrayList(u8).init(gui.allocator),
|
||||||
.textBuffer = try TextBuffer.init(gui.allocator, text, .{}, true, .left),
|
.textBuffer = try TextBuffer.init(gui.allocator, text, .{}, true, .left),
|
||||||
.maxWidth = maxWidth,
|
.maxWidth = maxWidth,
|
||||||
|
.maxHeight = maxHeight,
|
||||||
|
.scrollBar = scrollBarComponent.impl.scrollBar,
|
||||||
|
.scrollBarSize = scrollBarComponent.size,
|
||||||
};
|
};
|
||||||
try self.currentString.appendSlice(text);
|
try self.currentString.appendSlice(text);
|
||||||
self.textSize = try self.textBuffer.calculateLineBreaks(fontSize, maxWidth);
|
self.textSize = try self.textBuffer.calculateLineBreaks(fontSize, maxWidth - 2*border - scrollBarWidth);
|
||||||
return GuiComponent {
|
return GuiComponent {
|
||||||
.pos = pos,
|
.pos = pos,
|
||||||
.size = self.textSize,
|
.size = .{maxWidth, maxHeight},
|
||||||
.impl = .{.textInput = self}
|
.impl = .{.textInput = self}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -59,15 +67,23 @@ pub fn init(pos: Vec2f, maxWidth: f32, text: []const u8) Allocator.Error!GuiComp
|
|||||||
pub fn deinit(self: TextInput) void {
|
pub fn deinit(self: TextInput) void {
|
||||||
self.textBuffer.deinit();
|
self.textBuffer.deinit();
|
||||||
self.currentString.deinit();
|
self.currentString.deinit();
|
||||||
|
self.scrollBar.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mainButtonPressed(self: *TextInput, pos: Vec2f, _: Vec2f, mousePosition: Vec2f) void {
|
pub fn mainButtonPressed(self: *TextInput, pos: Vec2f, size: Vec2f, 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);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
self.cursor = null;
|
self.cursor = null;
|
||||||
self.selectionStart = self.textBuffer.mousePosToIndex(mousePosition - pos, self.currentString.items.len);
|
self.selectionStart = self.textBuffer.mousePosToIndex(mousePosition - pos, self.currentString.items.len);
|
||||||
self.pressed = true;
|
self.pressed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mainButtonReleased(self: *TextInput, pos: Vec2f, _: Vec2f, mousePosition: Vec2f) void {
|
pub fn mainButtonReleased(self: *TextInput, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) void {
|
||||||
if(self.pressed) {
|
if(self.pressed) {
|
||||||
self.cursor = self.textBuffer.mousePosToIndex(mousePosition - pos, self.currentString.items.len);
|
self.cursor = self.textBuffer.mousePosToIndex(mousePosition - pos, self.currentString.items.len);
|
||||||
if(self.cursor == self.selectionStart) {
|
if(self.cursor == self.selectionStart) {
|
||||||
@ -75,6 +91,9 @@ pub fn mainButtonReleased(self: *TextInput, pos: Vec2f, _: Vec2f, mousePosition:
|
|||||||
}
|
}
|
||||||
self.pressed = false;
|
self.pressed = false;
|
||||||
gui.setSelectedTextInput(self);
|
gui.setSelectedTextInput(self);
|
||||||
|
} else if(self.textSize[1] > self.maxHeight - 2*border) {
|
||||||
|
self.scrollBar.mainButtonReleased(.{size[0] - border - scrollBarWidth, border}, self.scrollBarSize, mousePosition - pos);
|
||||||
|
gui.setSelectedTextInput(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +105,7 @@ pub fn deselect(self: *TextInput) void {
|
|||||||
fn reloadText(self: *TextInput) !void {
|
fn reloadText(self: *TextInput) !void {
|
||||||
self.textBuffer.deinit();
|
self.textBuffer.deinit();
|
||||||
self.textBuffer = try TextBuffer.init(gui.allocator, self.currentString.items, .{}, true, .left);
|
self.textBuffer = try TextBuffer.init(gui.allocator, self.currentString.items, .{}, true, .left);
|
||||||
self.textSize = try self.textBuffer.calculateLineBreaks(fontSize, self.maxWidth);
|
self.textSize = try self.textBuffer.calculateLineBreaks(fontSize, self.maxWidth - 2*border - scrollBarWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn moveCursorLeft(self: *TextInput, mods: main.Key.Modifiers) void {
|
fn moveCursorLeft(self: *TextInput, mods: main.Key.Modifiers) void {
|
||||||
@ -131,6 +150,7 @@ pub fn left(self: *TextInput, mods: main.Key.Modifiers) void {
|
|||||||
self.moveCursorLeft(mods);
|
self.moveCursorLeft(mods);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.ensureCursorVisibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,6 +192,7 @@ pub fn right(self: *TextInput, mods: main.Key.Modifiers) void {
|
|||||||
self.moveCursorRight(mods);
|
self.moveCursorRight(mods);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.ensureCursorVisibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,6 +218,7 @@ pub fn down(self: *TextInput, mods: main.Key.Modifiers) void {
|
|||||||
self.moveCursorVertically(1);
|
self.moveCursorVertically(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.ensureCursorVisibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,6 +240,7 @@ pub fn up(self: *TextInput, mods: main.Key.Modifiers) void {
|
|||||||
self.moveCursorVertically(-1);
|
self.moveCursorVertically(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.ensureCursorVisibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,6 +270,7 @@ pub fn gotoStart(self: *TextInput, mods: main.Key.Modifiers) void {
|
|||||||
self.moveCursorToStart(mods);
|
self.moveCursorToStart(mods);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.ensureCursorVisibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,6 +300,7 @@ pub fn gotoEnd(self: *TextInput, mods: main.Key.Modifiers) void {
|
|||||||
self.moveCursorToEnd(mods);
|
self.moveCursorToEnd(mods);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.ensureCursorVisibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,6 +312,7 @@ fn deleteSelection(self: *TextInput) void {
|
|||||||
self.currentString.replaceRange(start, end - start, &[0]u8{}) catch unreachable;
|
self.currentString.replaceRange(start, end - start, &[0]u8{}) catch unreachable;
|
||||||
self.cursor.? = start;
|
self.cursor.? = start;
|
||||||
self.selectionStart = null;
|
self.selectionStart = null;
|
||||||
|
self.ensureCursorVisibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,6 +326,7 @@ pub fn deleteLeft(self: *TextInput, _: main.Key.Modifiers) void {
|
|||||||
self.reloadText() catch |err| {
|
self.reloadText() catch |err| {
|
||||||
std.log.err("Error while deleting text: {s}", .{@errorName(err)});
|
std.log.err("Error while deleting text: {s}", .{@errorName(err)});
|
||||||
};
|
};
|
||||||
|
self.ensureCursorVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deleteRight(self: *TextInput, _: main.Key.Modifiers) void {
|
pub fn deleteRight(self: *TextInput, _: main.Key.Modifiers) void {
|
||||||
@ -312,6 +339,7 @@ pub fn deleteRight(self: *TextInput, _: main.Key.Modifiers) void {
|
|||||||
self.reloadText() catch |err| {
|
self.reloadText() catch |err| {
|
||||||
std.log.err("Error while deleting text: {s}", .{@errorName(err)});
|
std.log.err("Error while deleting text: {s}", .{@errorName(err)});
|
||||||
};
|
};
|
||||||
|
self.ensureCursorVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inputCharacter(self: *TextInput, character: u21) !void {
|
pub fn inputCharacter(self: *TextInput, character: u21) !void {
|
||||||
@ -322,6 +350,7 @@ pub fn inputCharacter(self: *TextInput, character: u21) !void {
|
|||||||
try self.currentString.insertSlice(cursor.*, utf8);
|
try self.currentString.insertSlice(cursor.*, utf8);
|
||||||
try self.reloadText();
|
try self.reloadText();
|
||||||
cursor.* += @intCast(u32, utf8.len);
|
cursor.* += @intCast(u32, utf8.len);
|
||||||
|
self.ensureCursorVisibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,6 +363,7 @@ pub fn copy(self: *TextInput, mods: main.Key.Modifiers) void {
|
|||||||
main.Window.setClipboardString(self.currentString.items[start..end]);
|
main.Window.setClipboardString(self.currentString.items[start..end]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.ensureCursorVisibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,6 +378,7 @@ pub fn paste(self: *TextInput, mods: main.Key.Modifiers) void {
|
|||||||
self.reloadText() catch |err| {
|
self.reloadText() catch |err| {
|
||||||
std.log.err("Error while pasting text: {s}", .{@errorName(err)});
|
std.log.err("Error while pasting text: {s}", .{@errorName(err)});
|
||||||
};
|
};
|
||||||
|
self.ensureCursorVisibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,6 +389,7 @@ pub fn cut(self: *TextInput, mods: main.Key.Modifiers) void {
|
|||||||
self.reloadText() catch |err| {
|
self.reloadText() catch |err| {
|
||||||
std.log.err("Error while cutting text: {s}", .{@errorName(err)});
|
std.log.err("Error while cutting text: {s}", .{@errorName(err)});
|
||||||
};
|
};
|
||||||
|
self.ensureCursorVisibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,6 +397,23 @@ pub fn newline(self: *TextInput, _: main.Key.Modifiers) void {
|
|||||||
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)});
|
||||||
};
|
};
|
||||||
|
self.ensureCursorVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ensureCursorVisibility(self: *TextInput) void {
|
||||||
|
if(self.textSize[1] > self.maxHeight - 2*border) {
|
||||||
|
var y: f32 = 0;
|
||||||
|
const diff = self.textSize[1] - (self.maxHeight - 2*border);
|
||||||
|
y -= diff*self.scrollBar.currentState;
|
||||||
|
if(self.cursor) |cursor| {
|
||||||
|
var cursorPos = y + self.textBuffer.indexToCursorPos(cursor)[1];
|
||||||
|
if(cursorPos < 0) {
|
||||||
|
self.scrollBar.currentState += cursorPos/diff;
|
||||||
|
} else if(cursorPos + 16 >= self.maxHeight - 2*border) {
|
||||||
|
self.scrollBar.currentState += (cursorPos + 16 - (self.maxHeight - 2*border))/diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(self: *TextInput, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) !void {
|
pub fn render(self: *TextInput, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) !void {
|
||||||
@ -373,18 +422,28 @@ pub fn render(self: *TextInput, pos: Vec2f, size: Vec2f, mousePosition: Vec2f) !
|
|||||||
Button.shader.bind();
|
Button.shader.bind();
|
||||||
draw.setColor(0xff000000);
|
draw.setColor(0xff000000);
|
||||||
draw.customShadedRect(Button.buttonUniforms, pos, size);
|
draw.customShadedRect(Button.buttonUniforms, pos, size);
|
||||||
|
const oldTranslation = draw.setTranslation(pos);
|
||||||
|
defer draw.restoreTranslation(oldTranslation);
|
||||||
|
const oldClip = draw.setClip(size);
|
||||||
|
defer draw.restoreClip(oldClip);
|
||||||
|
|
||||||
try self.textBuffer.render(pos[0], pos[1], fontSize);
|
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);
|
||||||
|
}
|
||||||
|
try self.textBuffer.render(textPos[0], textPos[1], fontSize);
|
||||||
if(self.pressed) {
|
if(self.pressed) {
|
||||||
self.cursor = self.textBuffer.mousePosToIndex(mousePosition - pos, self.currentString.items.len);
|
self.cursor = self.textBuffer.mousePosToIndex(mousePosition - pos, self.currentString.items.len);
|
||||||
}
|
}
|
||||||
if(self.cursor) |cursor| {
|
if(self.cursor) |cursor| {
|
||||||
|
var cursorPos = textPos + self.textBuffer.indexToCursorPos(cursor);
|
||||||
if(self.selectionStart) |selectionStart| {
|
if(self.selectionStart) |selectionStart| {
|
||||||
draw.setColor(0x440000ff);
|
draw.setColor(0x440000ff);
|
||||||
try self.textBuffer.drawSelection(pos, @min(selectionStart, cursor), @max(selectionStart, cursor));
|
try self.textBuffer.drawSelection(textPos, @min(selectionStart, cursor), @max(selectionStart, cursor));
|
||||||
}
|
}
|
||||||
draw.setColor(0xff000000);
|
draw.setColor(0xff000000);
|
||||||
const cursorPos = pos + self.textBuffer.indexToCursorPos(cursor);
|
|
||||||
draw.line(cursorPos, cursorPos + Vec2f{0, 16});
|
draw.line(cursorPos, cursorPos + Vec2f{0, 16});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,6 +10,7 @@ const Vec2f = vec.Vec2f;
|
|||||||
|
|
||||||
const Button = @import("components/Button.zig");
|
const Button = @import("components/Button.zig");
|
||||||
const CheckBox = @import("components/CheckBox.zig");
|
const CheckBox = @import("components/CheckBox.zig");
|
||||||
|
const ScrollBar = @import("components/ScrollBar.zig");
|
||||||
const Slider = @import("components/Slider.zig");
|
const Slider = @import("components/Slider.zig");
|
||||||
const TextInput = @import("components/TextInput.zig");
|
const TextInput = @import("components/TextInput.zig");
|
||||||
pub const GuiComponent = @import("GuiComponent.zig");
|
pub const GuiComponent = @import("GuiComponent.zig");
|
||||||
@ -36,6 +37,7 @@ pub fn init(_allocator: Allocator) !void {
|
|||||||
try GuiWindow.__init();
|
try GuiWindow.__init();
|
||||||
try Button.__init();
|
try Button.__init();
|
||||||
try CheckBox.__init();
|
try CheckBox.__init();
|
||||||
|
try ScrollBar.__init();
|
||||||
try Slider.__init();
|
try Slider.__init();
|
||||||
try TextInput.__init();
|
try TextInput.__init();
|
||||||
}
|
}
|
||||||
@ -50,6 +52,7 @@ pub fn deinit() void {
|
|||||||
GuiWindow.__deinit();
|
GuiWindow.__deinit();
|
||||||
Button.__deinit();
|
Button.__deinit();
|
||||||
CheckBox.__deinit();
|
CheckBox.__deinit();
|
||||||
|
ScrollBar.__deinit();
|
||||||
Slider.__deinit();
|
Slider.__deinit();
|
||||||
TextInput.__deinit();
|
TextInput.__deinit();
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ const padding: f32 = 8;
|
|||||||
pub fn onOpen() Allocator.Error!void {
|
pub fn onOpen() Allocator.Error!void {
|
||||||
var list = try VerticalList.init();
|
var list = try VerticalList.init();
|
||||||
// TODO Please change your name bla bla
|
// TODO Please change your name bla bla
|
||||||
try list.add(try TextInput.init(.{0, 16}, 128, "gr da jkwa hfeka fuei \n ofuiewo\natg78o4ea74e8t\nz57 t4738qa0 47a80 t47803a t478aqv t487 5t478a0 tg478a09 t748ao t7489a rt4e5 okv5895 678v54vgvo6r z8or z578v rox74et8ys9otv 4z3789so z4oa9t z489saoyt z"));
|
try list.add(try TextInput.init(.{0, 16}, 128, 256, "gr da jkwa hfeka fuei \n ofuiewo\natg78o4ea74e8t\nz57 t4738qa0 47a80 t47803a t478aqv t487 5t478a0 tg478a09 t748ao t7489a rt4e5 okv5895 678v54vgvo6r z8or z578v rox74et8ys9otv 4z3789so z4oa9t z489saoyt z"));
|
||||||
// TODO: Done button.
|
// TODO: Done button.
|
||||||
components[0] = list.toComponent(.{padding, padding});
|
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));
|
||||||
|
@ -421,12 +421,12 @@ pub fn main() !void {
|
|||||||
var gpa = std.heap.GeneralPurposeAllocator(.{.thread_safe=false}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{.thread_safe=false}){};
|
||||||
threadAllocator = gpa.allocator();
|
threadAllocator = gpa.allocator();
|
||||||
defer if(gpa.deinit()) {
|
defer if(gpa.deinit()) {
|
||||||
@panic("Memory leak");
|
std.log.err("Memory leak", .{});
|
||||||
};
|
};
|
||||||
var global_gpa = std.heap.GeneralPurposeAllocator(.{.thread_safe=true}){};
|
var global_gpa = std.heap.GeneralPurposeAllocator(.{.thread_safe=true}){};
|
||||||
globalAllocator = global_gpa.allocator();
|
globalAllocator = global_gpa.allocator();
|
||||||
defer if(global_gpa.deinit()) {
|
defer if(global_gpa.deinit()) {
|
||||||
@panic("Memory leak");
|
std.log.err("Memory leak", .{});
|
||||||
};
|
};
|
||||||
|
|
||||||
// init logging.
|
// init logging.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user