diff --git a/src/Document.zig b/src/Document.zig new file mode 100644 index 0000000..359deef --- /dev/null +++ b/src/Document.zig @@ -0,0 +1 @@ +// Файл векторного документа diff --git a/src/WindowContext.zig b/src/WindowContext.zig new file mode 100644 index 0000000..df5a241 --- /dev/null +++ b/src/WindowContext.zig @@ -0,0 +1,76 @@ +const std = @import("std"); +const dvui = @import("dvui"); +const Color = dvui.Color; + +const WindowContext = @This(); + +allocator: std.mem.Allocator, +canvas_texture: ?dvui.Texture = null, +canvas_width: u32 = 400, +canvas_height: u32 = 300, + +pub fn init(allocator: std.mem.Allocator) WindowContext { + return .{ + .allocator = allocator, + }; +} + +/// Заполнить canvas случайным цветом на CPU +pub fn fillRandomColor(self: *WindowContext) !void { + var prng = std.Random.DefaultPrng.init(@intCast(std.time.microTimestamp())); + const random = prng.random(); + + // Выделить буфер пиксельных данных + const pixels = try self.allocator.alloc(Color.PMA, @as(usize, self.canvas_width) * self.canvas_height); + defer self.allocator.free(pixels); + + // Заполнить случайными цветами + const r = random.int(u8); + const g = random.int(u8); + const b = random.int(u8); + + var prev: dvui.Color.PMA = .{ + .r = r, + .g = g, + .b = b, + .a = 255, + }; + for (pixels) |*pixel| { + const r_delta = random.intRangeAtMost(i16, -1, 1); + const g_delta = random.intRangeAtMost(i16, -1, 1); + const b_delta = random.intRangeAtMost(i16, -1, 1); + + const r_new: i16 = @as(i16, prev.r) + r_delta; + const g_new: i16 = @as(i16, prev.g) + g_delta; + const b_new: i16 = @as(i16, prev.b) + b_delta; + + pixel.* = .{ + .r = @intCast(std.math.clamp(r_new, 0, 255)), + .g = @intCast(std.math.clamp(g_new, 0, 255)), + .b = @intCast(std.math.clamp(b_new, 0, 255)), + .a = 255, + }; + prev = pixel.*; + } + + // Удалить старую текстуру + if (self.canvas_texture) |tex| { + dvui.Texture.destroyLater(tex); + } + + // Создать новую текстуру из пиксельных данных + self.canvas_texture = try dvui.textureCreate(pixels, self.canvas_width, self.canvas_height, .linear); +} + +/// Отобразить canvas в UI +pub fn render(self: WindowContext, rect: dvui.Rect.Physical) !void { + if (self.canvas_texture) |texture| { + try dvui.renderTexture(texture, .{ .r = rect }, .{}); + } +} + +pub fn deinit(self: *WindowContext) void { + if (self.canvas_texture) |texture| { + dvui.Texture.destroyLater(texture); + } +} diff --git a/src/main.zig b/src/main.zig index c3570e7..3339901 100644 --- a/src/main.zig +++ b/src/main.zig @@ -2,6 +2,8 @@ const std = @import("std"); const builtin = @import("builtin"); const dvui = @import("dvui"); const SDLBackend = @import("sdl-backend"); +const Document = @import("Document.zig"); +const WindowContext = @import("WindowContext.zig"); const sdl_c = SDLBackend.c; const Allocator = std.mem.Allocator; const Color = dvui.Color; @@ -24,9 +26,11 @@ pub fn main() !void { .dark => dvui.Theme.builtin.adwaita_dark, }, }); - defer win.deinit(); + var ctx = WindowContext.init(allocator); + defer ctx.deinit(); + var interrupted = false; main_loop: while (true) { @@ -44,7 +48,7 @@ pub fn main() !void { _ = SDLBackend.c.SDL_SetRenderDrawColor(backend.renderer, 0, 0, 0, 255); _ = SDLBackend.c.SDL_RenderClear(backend.renderer); - const keep_running = gui_frame(); + const keep_running = gui_frame(&ctx); if (!keep_running) break :main_loop; // marks end of dvui frame, don't call dvui functions after this @@ -64,7 +68,7 @@ pub fn main() !void { } } -fn gui_frame() bool { +fn gui_frame(ctx: *WindowContext) bool { for (dvui.events()) |*e| { if (e.evt == .window and e.evt.window.action == .close) return false; if (e.evt == .app and e.evt.app.action == .quit) return false; @@ -83,7 +87,11 @@ fn gui_frame() bool { defer left_panel.deinit(); dvui.label(@src(), "Tools", .{}, .{}); - _ = dvui.button(@src(), "Button", .{}, .{}); + if (dvui.button(@src(), "Fill Random Color", .{}, .{})) { + ctx.fillRandomColor() catch |err| { + std.debug.print("Error filling canvas: {}\n", .{err}); + }; + } } // Правая панель - занимает оставшееся пространство @@ -95,20 +103,40 @@ fn gui_frame() bool { ); defer back.deinit(); - const fill_color = Color.white.opacity(0.5); - var right_panel = dvui.box( - @src(), - .{ .dir = .vertical }, - .{ - .expand = .both, - .background = true, - .corner_radius = dvui.Rect.all(10), - .color_fill = fill_color, - }, - ); - defer right_panel.deinit(); + { + const fill_color = Color.white.opacity(0.5); + var right_panel = dvui.box( + @src(), + .{ .dir = .vertical }, + .{ + .expand = .both, + .background = true, + .corner_radius = dvui.Rect.all(10), + .color_fill = fill_color, + }, + ); + defer right_panel.deinit(); - dvui.label(@src(), "Canvas", .{}, .{ .gravity_x = 0.5 }); + const overlay = dvui.overlay(@src(), .{ + .expand = .both, + }); + defer overlay.deinit(); + + // Отобразить canvas внутри контейнера + if (ctx.canvas_texture) |texture| { + _ = dvui.image(@src(), .{ + .source = .{ .texture = texture }, + }, .{ + .expand = .both, + .min_size_content = .{ + .w = @floatFromInt(ctx.canvas_width), + .h = @floatFromInt(ctx.canvas_height), + }, + }); + } + + dvui.label(@src(), "Canvas", .{}, .{ .gravity_x = 0.5, .gravity_y = 0.0 }); + } } return true; diff --git a/src/render/IRenderEngine.zig b/src/render/IRenderEngine.zig new file mode 100644 index 0000000..2cf24d8 --- /dev/null +++ b/src/render/IRenderEngine.zig @@ -0,0 +1 @@ +// Интерфейс для рендеринга документа