Save/Load the gui layout.

This commit is contained in:
IntegratedQuantum 2023-03-15 22:25:32 +01:00
parent fbb28869f6
commit bb904828e8
6 changed files with 135 additions and 52 deletions

3
.gitignore vendored
View File

@ -3,4 +3,5 @@ saves/
zig-out/
zig-cache/
serverAssets/
settings.json
settings.json
gui_layout.json

View File

@ -16,10 +16,10 @@ const GuiComponent = gui.GuiComponent;
const GuiWindow = @This();
const AttachmentPoint = enum {
lower,
middle,
upper,
pub const AttachmentPoint = enum(u8) {
lower = 0,
middle = 1,
upper = 2,
};
const OrientationLine = struct {

View File

@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator;
const main = @import("root");
const graphics = main.graphics;
const draw = graphics.draw;
const JsonElement = main.JsonElement;
const settings = main.settings;
const vec = main.vec;
const Vec2f = vec.Vec2f;
@ -42,9 +43,13 @@ pub fn init(_allocator: Allocator) !void {
try ScrollBar.__init();
try Slider.__init();
try TextInput.__init();
try load();
}
pub fn deinit() void {
save() catch |err| {
std.log.err("Got error while saving gui layout: {s}", .{@errorName(err)});
};
windowList.deinit();
hudWindows.deinit();
for(openWindows.items) |window| {
@ -59,6 +64,103 @@ pub fn deinit() void {
TextInput.__deinit();
}
fn save() !void {
const guiJson = try JsonElement.initObject(main.threadAllocator);
defer guiJson.free(main.threadAllocator);
for(windowList.items) |window| {
const windowJson = try JsonElement.initObject(main.threadAllocator);
for(window.relativePosition, 0..) |relPos, i| {
const relPosJson = try JsonElement.initObject(main.threadAllocator);
switch(relPos) {
.ratio => |ratio| {
try relPosJson.put("type", "ratio");
try relPosJson.put("ratio", ratio);
},
.attachedToFrame => |attachedToFrame| {
try relPosJson.put("type", "attachedToFrame");
try relPosJson.put("selfAttachmentPoint", @enumToInt(attachedToFrame.selfAttachmentPoint));
try relPosJson.put("otherAttachmentPoint", @enumToInt(attachedToFrame.otherAttachmentPoint));
},
.relativeToWindow => |relativeToWindow| {
try relPosJson.put("type", "relativeToWindow");
try relPosJson.put("reference", relativeToWindow.reference.id);
try relPosJson.put("ratio", relativeToWindow.ratio);
},
.attachedToWindow => |attachedToWindow| {
try relPosJson.put("type", "attachedToWindow");
try relPosJson.put("reference", attachedToWindow.reference.id);
try relPosJson.put("selfAttachmentPoint", @enumToInt(attachedToWindow.selfAttachmentPoint));
try relPosJson.put("otherAttachmentPoint", @enumToInt(attachedToWindow.otherAttachmentPoint));
},
}
try windowJson.put(([_][]const u8{"relPos0", "relPos1"})[i], relPosJson);
}
try windowJson.put("scale", window.scale);
try guiJson.put(window.id, windowJson);
}
const string = try guiJson.toStringEfficient(main.threadAllocator, "");
defer main.threadAllocator.free(string);
var file = try std.fs.cwd().createFile("gui_layout.json", .{});
defer file.close();
try file.writeAll(string);
}
fn load() !void {
const json: JsonElement = blk: {
var file = std.fs.cwd().openFile("gui_layout.json", .{}) catch break :blk JsonElement{.JsonNull={}};
defer file.close();
const fileString = try file.readToEndAlloc(main.threadAllocator, std.math.maxInt(usize));
defer main.threadAllocator.free(fileString);
break :blk JsonElement.parseFromString(main.threadAllocator, fileString);
};
defer json.free(main.threadAllocator);
for(windowList.items) |window| {
const windowJson = json.getChild(window.id);
for(&window.relativePosition, 0..) |*relPos, i| {
const relPosJson = windowJson.getChild(([_][]const u8{"relPos0", "relPos1"})[i]);
const typ = relPosJson.get([]const u8, "type", "ratio");
if(std.mem.eql(u8, typ, "ratio")) {
relPos.* = .{.ratio = relPosJson.get(f32, "ratio", 0.5)};
} else if(std.mem.eql(u8, typ, "attachedToFrame")) {
relPos.* = .{.attachedToFrame = .{
.selfAttachmentPoint = @intToEnum(GuiWindow.AttachmentPoint, relPosJson.get(u8, "selfAttachmentPoint", 0)),
.otherAttachmentPoint = @intToEnum(GuiWindow.AttachmentPoint, relPosJson.get(u8, "otherAttachmentPoint", 0)),
}};
} else if(std.mem.eql(u8, typ, "relativeToWindow")) {
const reference = getWindowById(relPosJson.get([]const u8, "reference", "")) orelse continue;
relPos.* = .{.relativeToWindow = .{
.reference = reference,
.ratio = relPosJson.get(f32, "ratio", 0.5),
}};
} else if(std.mem.eql(u8, typ, "attachedToWindow")) {
const reference = getWindowById(relPosJson.get([]const u8, "reference", "")) orelse continue;
relPos.* = .{.attachedToWindow = .{
.reference = reference,
.selfAttachmentPoint = @intToEnum(GuiWindow.AttachmentPoint, relPosJson.get(u8, "selfAttachmentPoint", 0)),
.otherAttachmentPoint = @intToEnum(GuiWindow.AttachmentPoint, relPosJson.get(u8, "otherAttachmentPoint", 0)),
}};
} else {
std.log.warn("Unknown window attachment type: {s}", .{typ});
}
}
window.scale = windowJson.get(f32, "scale", 1);
}
}
fn getWindowById(id: []const u8) ?*GuiWindow {
for(windowList.items) |window| {
if(std.mem.eql(u8, id, window.id)) {
return window;
}
}
std.log.warn("Could not find window with id: {s}", .{id});
return null;
}
pub fn updateGuiScale() void {
if(settings.guiScale) |guiScale| {
scale = guiScale;

View File

@ -37,7 +37,7 @@ pub const JsonElement = union(JsonType) {
return JsonElement{.JsonArray=list};
}
pub fn getAtIndex(self: *const JsonElement, comptime _type: type, index: usize, replacement: _type) @TypeOf(replacement) {
pub fn getAtIndex(self: *const JsonElement, comptime _type: type, index: usize, replacement: _type) _type {
if(self.* != .JsonArray) {
return replacement;
} else {
@ -61,7 +61,7 @@ pub const JsonElement = union(JsonType) {
}
}
pub fn get(self: *const JsonElement, comptime _type: type, key: []const u8, replacement: _type) @TypeOf(replacement) {
pub fn get(self: *const JsonElement, comptime _type: type, key: []const u8, replacement: _type) _type {
if(self.* != .JsonObject) {
return replacement;
} else {
@ -148,7 +148,12 @@ pub const JsonElement = union(JsonType) {
if(ptr.child == u8 and ptr.size == .Slice) {
return JsonElement{.JsonString=value};
} else {
@compileError("Unknown value type.");
const childInfo = @typeInfo(ptr.child);
if(ptr.size == .One and childInfo == .Array and childInfo.Array.child == u8) {
return JsonElement{.JsonString=value};
} else {
@compileError("Unknown value type.");
}
}
},
.Optional => {

View File

@ -10,7 +10,7 @@ pub const game = @import("game.zig");
pub const graphics = @import("graphics.zig");
pub const itemdrop = @import("itemdrop.zig");
pub const items = @import("items.zig");
pub const JsonElement = @import("json.zig");
pub const JsonElement = @import("json.zig").JsonElement;
pub const models = @import("models.zig");
pub const network = @import("network.zig");
pub const random = @import("random.zig");

View File

@ -75,11 +75,8 @@ pub fn init() !void {
}
}
pub fn deinit() void {
const jsonObject = JsonElement.initObject(main.threadAllocator) catch |err| {
std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)});
return;
};
fn flawedDeinit() !void {
const jsonObject = try JsonElement.initObject(main.threadAllocator);
defer jsonObject.free(main.threadAllocator);
inline for(@typeInfo(@This()).Struct.decls) |decl| {
@ -90,13 +87,9 @@ pub fn deinit() void {
@compileError("Not implemented yet.");
}
if(declType == []const u8) {
jsonObject.putOwnedString(decl.name, @field(@This(), decl.name)) catch |err| {
std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)});
};
try jsonObject.putOwnedString(decl.name, @field(@This(), decl.name));
} else {
jsonObject.put(decl.name, @field(@This(), decl.name)) catch |err| {
std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)});
};
try jsonObject.put(decl.name, @field(@This(), decl.name));
}
if(@typeInfo(declType) == .Pointer) {
if(@typeInfo(declType).Pointer.size == .Slice) {
@ -109,48 +102,30 @@ pub fn deinit() void {
}
// keyboard settings:
const keyboard = JsonElement.initObject(main.threadAllocator) catch |err| {
std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)});
return;
};
const keyboard = try JsonElement.initObject(main.threadAllocator);
inline for(comptime std.meta.fieldNames(@TypeOf(main.keyboard))) |keyName| {
const keyJson = JsonElement.initObject(main.threadAllocator) catch |err| {
std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)});
return;
};
const keyJson = try JsonElement.initObject(main.threadAllocator);
const key = &@field(main.keyboard, keyName);
keyJson.put("key", key.key) catch |err| {
std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)});
};
keyJson.put("mouseButton", key.mouseButton) catch |err| {
std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)});
};
keyJson.put("scancode", key.scancode) catch |err| {
std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)});
};
keyboard.put(keyName, keyJson) catch |err| {
std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)});
};
try keyJson.put("key", key.key);
try keyJson.put("mouseButton", key.mouseButton);
try keyJson.put("scancode", key.scancode);
try keyboard.put(keyName, keyJson);
}
jsonObject.put("keyboard", keyboard) catch |err| {
std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)});
};
try jsonObject.put("keyboard", keyboard);
// Write to file:
const string = jsonObject.toStringEfficient(main.threadAllocator, "") catch |err| {
std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)});
return;
};
const string = try jsonObject.toStringEfficient(main.threadAllocator, "");
defer main.threadAllocator.free(string);
var file = std.fs.cwd().createFile("settings.json", .{}) catch |err| {
std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)});
return;
};
var file = try std.fs.cwd().createFile("settings.json", .{});
defer file.close();
file.writeAll(string) catch |err| {
try file.writeAll(string);
}
pub fn deinit() void {
flawedDeinit() catch |err| {
std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)});
return;
};