json сохранение

This commit is contained in:
2026-02-27 01:49:40 +03:00
parent 50821c8046
commit b7f7108f63
4 changed files with 477 additions and 0 deletions

89
src/ui/menu_bar.zig Normal file
View File

@@ -0,0 +1,89 @@
const std = @import("std");
const dvui = @import("dvui");
const WindowContext = @import("../WindowContext.zig");
const document_json = @import("../persistence/document_json.zig");
pub fn menuBar(ctx: *WindowContext) void {
var m = dvui.menu(@src(), .horizontal, .{ .background = true, .expand = .horizontal });
defer m.deinit();
if (dvui.menuItemLabel(@src(), "File", .{ .submenu = true }, .{ .expand = .none })) |r| {
var fm = dvui.floatingMenu(@src(), .{ .from = r }, .{});
defer fm.deinit();
if (dvui.menuItemLabel(@src(), "Open", .{}, .{ .expand = .horizontal }) != null) {
m.close();
openDocumentDialog(ctx);
}
if (dvui.menuItemLabel(@src(), "Save As", .{}, .{ .expand = .horizontal }) != null) {
m.close();
saveAsDialog(ctx);
}
}
}
fn openDocumentDialog(ctx: *WindowContext) void {
const path_z = dvui.dialogNativeFileOpen(ctx.allocator, .{
.title = "Open",
.filters = &.{ "*.json" },
.filter_description = "JSON files",
}) catch |err| {
std.debug.print("Open dialog error: {}\n", .{err});
return;
} orelse return;
defer ctx.allocator.free(path_z);
const path = path_z[0..path_z.len];
const doc = document_json.loadFromFile(ctx.allocator, path) catch |err| {
std.debug.print("Open file error: {}\n", .{err});
return;
};
ctx.addDocument(doc) catch |err| {
std.debug.print("Add document error: {}\n", .{err});
return;
};
}
fn saveAsDialog(ctx: *WindowContext) void {
const open_doc = ctx.activeDocument() orelse return;
const path_z = dvui.dialogNativeFileSave(ctx.allocator, .{
.title = "Save As",
.filters = &.{ "*.json" },
.filter_description = "JSON files",
}) catch |err| {
std.debug.print("Save dialog error: {}\n", .{err});
return;
} orelse return;
defer ctx.allocator.free(path_z);
const path_raw = path_z[0..path_z.len];
const resolved = ensureJsonPath(ctx.allocator, path_raw) catch |err| {
std.debug.print("Save path error: {}\n", .{err});
return;
};
defer if (resolved.owned) ctx.allocator.free(resolved.path);
document_json.saveToFile(&open_doc.document, resolved.path) catch |err| {
std.debug.print("Save file error: {}\n", .{err});
return;
};
}
const ResolvedPath = struct {
path: []const u8,
owned: bool,
};
fn ensureJsonPath(allocator: std.mem.Allocator, path: []const u8) !ResolvedPath {
if (endsWithIgnoreCase(path, ".json")) {
return .{ .path = path, .owned = false };
}
const joined = try std.mem.concat(allocator, u8, &.{ path, ".json" });
return .{ .path = joined, .owned = true };
}
fn endsWithIgnoreCase(haystack: []const u8, needle: []const u8) bool {
if (haystack.len < needle.len) return false;
return std.ascii.eqlIgnoreCase(haystack[haystack.len - needle.len ..], needle);
}