From bd58286c98e3886ecdd34214060eb0b9baf195c4 Mon Sep 17 00:00:00 2001 From: Roman Pytkov Date: Mon, 23 Feb 2026 23:01:49 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BD=D1=8B=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=80=D0=B8=D0=B8=20?= =?UTF-8?q?=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D0=B5=20=D0=B8=20=D1=83=D0=BB?= =?UTF-8?q?=D1=83=D1=87=D1=88=D0=B5=D0=BD=D1=8B=20=D0=BC=D0=BE=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Canvas.zig | 17 ----- src/WindowContext.zig | 8 --- src/models/Document.zig | 109 +----------------------------- src/models/Object.zig | 117 +++++++++++++++++++++++++++++++++ src/models/Property.zig | 75 ++++++++++++--------- src/models/basic_models.zig | 3 - src/render/CpuRenderEngine.zig | 19 ++---- src/render/RenderEngine.zig | 1 - src/ui/canvas_view.zig | 2 - src/ui/dvui_ext.zig | 1 - src/ui/frame.zig | 2 - src/ui/left_panel.zig | 1 - src/ui/right_panel.zig | 1 - src/ui/tab_bar.zig | 1 - src/ui/types/TexturedBox.zig | 5 -- 15 files changed, 169 insertions(+), 193 deletions(-) create mode 100644 src/models/Object.zig diff --git a/src/Canvas.zig b/src/Canvas.zig index 527b8c6..e636a6b 100644 --- a/src/Canvas.zig +++ b/src/Canvas.zig @@ -19,13 +19,11 @@ scroll: dvui.ScrollInfo = .{ .horizontal = .auto, }, native_scaling: bool = true, -/// Максимальная частота перерисовки при зуме. 0 = без ограничения. redraw_throttle_ms: u32 = 50, _visible_rect: ?ImageRect = null, _zoom: f32 = 1, _redraw_pending: bool = false, _last_redraw_time_ms: i64 = 0, -/// Позиция курсора в координатах документа (обновляется в handleCanvasMouse). null если вне документа. cursor_document_point: ?Point2 = null, pub fn init(allocator: std.mem.Allocator, document: *Document, engine: RenderEngine) Canvas { @@ -43,7 +41,6 @@ pub fn deinit(self: *Canvas) void { } } -/// Заполнить canvas градиентом pub fn redrawExample(self: *Canvas) !void { const full = self.getZoomedImageSize(); @@ -60,7 +57,6 @@ pub fn redrawExample(self: *Canvas) !void { const new_texture = self.render_engine.example(.{ .w = full.w, .h = full.h }, vis) catch null; if (new_texture) |tex| { - // Удалить старую текстуру if (self.texture) |old_tex| { dvui.Texture.destroyLater(old_tex); } @@ -70,7 +66,6 @@ pub fn redrawExample(self: *Canvas) !void { self._last_redraw_time_ms = std.time.milliTimestamp(); } -// Ресетнуть example изображение в renderEngine pub fn exampleReset(self: *Canvas) !void { self.render_engine.exampleReset(); try self.redrawExample(); @@ -85,12 +80,10 @@ pub fn addZoom(self: *Canvas, value: f32) void { self._zoom = @max(self._zoom, 0.01); } -/// Запросить перерисовку (выполнится с учётом redraw_throttle_ms при вызове processPendingRedraw). pub fn requestRedraw(self: *Canvas) void { self._redraw_pending = true; } -/// Выполнить отложенную перерисовку, если прошло не менее redraw_throttle_ms с прошлой отрисовки. pub fn processPendingRedraw(self: *Canvas) !void { if (!self._redraw_pending) return; if (self.redraw_throttle_ms == 0) { @@ -115,9 +108,6 @@ pub fn getZoomedImageSize(self: Canvas) ImageRect { }; } -/// Перевести точку из системы координат контента скролла (natural scale, начало — левый верхний угол скроллируемой области) -/// в координаты документа (единицы документа до зума). -/// Возвращает null, если точка вне области изображения документа. pub fn contentPointToDocument(self: Canvas, content_point: dvui.Point, natural_scale: f32) ?Point2 { const img = self.getZoomedImageSize(); const left_n = @as(f32, @floatFromInt(img.x)) / natural_scale; @@ -137,11 +127,6 @@ pub fn contentPointToDocument(self: Canvas, content_point: dvui.Point, natural_s }; } -/// Обновить видимую часть изображения (в пикселях холста) и сохранить в `visible_rect`. -/// -/// `viewport` и `scroll_offset` ожидаются в *physical* пикселях (т.е. уже умноженные на windowNaturalScale). -/// -/// После обновления (или если текстуры ещё нет) перерисовывает текстуру, чтобы она содержала только видимую часть. pub fn updateVisibleImageRect(self: *Canvas, viewport: dvui.Rect, scroll_offset: dvui.Point) bool { const next = computeVisibleImageRect(self.*, viewport, scroll_offset); var changed = false; @@ -164,11 +149,9 @@ fn computeVisibleImageRect(self: Canvas, viewport: dvui.Rect, scroll_offset: dvu const img_w: u32 = image_rect.w; const img_h: u32 = image_rect.h; - // Видимый размер всегда равен размеру viewport, но не больше холста const vis_w: u32 = @min(@as(u32, @intFromFloat(viewport.w)), img_w); const vis_h: u32 = @min(@as(u32, @intFromFloat(viewport.h)), img_h); - // Вычисляем x и y на основе scroll_offset, clamped чтобы не выходить за границы const raw_x: i64 = @intFromFloat(scroll_offset.x - @as(f32, @floatFromInt(image_rect.x))); const raw_y: i64 = @intFromFloat(scroll_offset.y - @as(f32, @floatFromInt(image_rect.y))); diff --git a/src/WindowContext.zig b/src/WindowContext.zig index 56bf7b8..b715a6e 100644 --- a/src/WindowContext.zig +++ b/src/WindowContext.zig @@ -7,13 +7,11 @@ const basic_models = @import("models/basic_models.zig"); const WindowContext = @This(); -/// Один открытый документ: документ + свой холст и движок рендера pub const OpenDocument = struct { document: Document, cpu_render: CpuRenderEngine, canvas: Canvas, - /// Инициализировать по месту (canvas хранит указатель на cpu_render этого же экземпляра). pub fn init(allocator: std.mem.Allocator, self: *OpenDocument) void { const default_size = basic_models.Size{ .width = 800, .height = 600 }; self.document = Document.init(allocator, default_size); @@ -29,9 +27,7 @@ pub const OpenDocument = struct { allocator: std.mem.Allocator, frame_index: u64, -/// Список открытых документов (вкладок): указатели на документ+холст documents: std.ArrayList(*OpenDocument), -/// Индекс активной вкладки; null — ни один документ не выбран active_document_index: ?usize, pub fn init(allocator: std.mem.Allocator) !WindowContext { @@ -54,14 +50,12 @@ pub fn deinit(self: *WindowContext) void { self.documents.deinit(self.allocator); } -/// Вернуть указатель на активный открытый документ (null если нет выбранной вкладки). pub fn activeDocument(self: *WindowContext) ?*OpenDocument { const i = self.active_document_index orelse return null; if (i >= self.documents.items.len) return null; return self.documents.items[i]; } -/// Добавить новый документ и сделать его активным. pub fn addNewDocument(self: *WindowContext) !void { const ptr = try self.allocator.create(OpenDocument); errdefer self.allocator.destroy(ptr); @@ -70,14 +64,12 @@ pub fn addNewDocument(self: *WindowContext) !void { self.active_document_index = self.documents.items.len - 1; } -/// Выбрать вкладку по индексу. pub fn setActiveDocument(self: *WindowContext, index: usize) void { if (index < self.documents.items.len) { self.active_document_index = index; } } -/// Закрыть вкладку по индексу; активная вкладка сдвигается при необходимости. pub fn closeDocument(self: *WindowContext, index: usize) void { if (index >= self.documents.items.len) return; const open_doc = self.documents.items[index]; diff --git a/src/models/Document.zig b/src/models/Document.zig index 69d258b..6b58a19 100644 --- a/src/models/Document.zig +++ b/src/models/Document.zig @@ -2,12 +2,14 @@ const std = @import("std"); const basic_models = @import("basic_models.zig"); const properties = @import("Property.zig"); const Property = properties.Property; +const PropertyData = properties.Data; +const Point2 = basic_models.Point2; const Size = basic_models.Size; +const Object = @import("Object.zig"); const Document = @This(); size: Size, allocator: std.mem.Allocator, -/// Корневые объекты документа (вложенность через Object.children). objects: std.ArrayList(Object), pub fn init(allocator: std.mem.Allocator, size: Size) Document { @@ -23,112 +25,7 @@ pub fn deinit(self: *Document) void { self.objects.deinit(self.allocator); } -/// Добавить корневой объект в документ (клонирует в allocator документа). pub fn addObject(self: *Document, template: Object) !void { const obj = try template.clone(self.allocator); try self.objects.append(self.allocator, obj); } - -/// Тип фигуры: определяет, как RenderEngine интерпретирует свойства и рисует объект. -pub const ShapeKind = enum { - rect, - ellipse, - line, - path, -}; - -/// Объект документа: тип фигуры, свойства и вложенные дочерние объекты. -/// Типы объектов задаются конструкторами; UI и RenderEngine работают с union Property. -pub const Object = struct { - shape: ShapeKind, - properties: std.ArrayList(Property), - /// Вложенные объекты (дерево). - children: std.ArrayList(Object), - - /// Найти свойство по тегу и вернуть вариант union (caller делает switch). - pub fn getProperty(self: Object, tag: std.meta.Tag(Property)) ?Property { - for (self.properties.items) |prop| { - if (std.meta.activeTag(prop) == tag) return prop; - } - return null; - } - - /// Установить свойство: если уже есть с таким тегом — заменить, иначе добавить. - pub fn setProperty(self: *Object, allocator: std.mem.Allocator, prop: Property) !void { - for (self.properties.items, 0..) |*p, i| { - if (std.meta.activeTag(p.*) == std.meta.activeTag(prop)) { - self.properties.items[i] = prop; - return; - } - } - try self.properties.append(allocator, prop); - } - - /// Добавить дочерний объект (клонирует в переданный allocator). - pub fn addChild(self: *Object, allocator: std.mem.Allocator, template: Object) !void { - const obj = try template.clone(allocator); - try self.children.append(allocator, obj); - } - - /// Клонировать объект рекурсивно (свойства и дети). - pub fn clone(self: Object, allocator: std.mem.Allocator) !Object { - var properties_list = std.ArrayList(Property).empty; - errdefer properties_list.deinit(allocator); - try properties_list.appendSlice(allocator, self.properties.items); - - var children_list = std.ArrayList(Object).empty; - errdefer children_list.deinit(allocator); - for (self.children.items) |child| { - try children_list.append(allocator, try child.clone(allocator)); - } - - return .{ - .shape = self.shape, - .properties = properties_list, - .children = children_list, - }; - } - - pub fn deinit(self: *Object, allocator: std.mem.Allocator) void { - for (self.children.items) |*child| child.deinit(allocator); - self.children.deinit(allocator); - self.properties.deinit(allocator); - self.* = undefined; - } - - /// Базовый объект с общим набором свойств (для внутреннего использования конструкторами). - fn createWithCommon(allocator: std.mem.Allocator, shape: ShapeKind) !Object { - const common = properties.defaultCommonProperties(); - var properties_list = std.ArrayList(Property).empty; - errdefer properties_list.deinit(allocator); - try properties_list.appendSlice(allocator, &common); - return .{ - .shape = shape, - .properties = properties_list, - .children = std.ArrayList(Object).empty, - }; - } - - // --- Публичные конструкторы: базовый объект + одно свойство фигуры --- - - pub fn createRect(allocator: std.mem.Allocator) !Object { - var obj = try createWithCommon(allocator, .rect); - errdefer obj.deinit(allocator); - try obj.properties.append(allocator, .{ .size = .{ .width = 100, .height = 100 } }); - return obj; - } - - pub fn createEllipse(allocator: std.mem.Allocator) !Object { - var obj = try createWithCommon(allocator, .ellipse); - errdefer obj.deinit(allocator); - try obj.properties.append(allocator, .{ .radii = .{ .x = 50, .y = 50 } }); - return obj; - } - - pub fn createLine(allocator: std.mem.Allocator) !Object { - var obj = try createWithCommon(allocator, .line); - errdefer obj.deinit(allocator); - try obj.properties.append(allocator, .{ .end_point = .{ .x = 100, .y = 0 } }); - return obj; - } -}; diff --git a/src/models/Object.zig b/src/models/Object.zig new file mode 100644 index 0000000..0e14ed6 --- /dev/null +++ b/src/models/Object.zig @@ -0,0 +1,117 @@ +const std = @import("std"); +const basic_models = @import("basic_models.zig"); +const defaultCommonProperties = @import("Property.zig").defaultCommonProperties; +const Property = @import("Property.zig").Property; +const PropertyData = @import("Property.zig").Data; +const Point2 = basic_models.Point2; +const Size = basic_models.Size; +const Object = @This(); + +pub const ShapeKind = enum { + rect, + line, + ellipse, + arc, + broken, +}; + +shape: ShapeKind, +properties: std.ArrayList(Property), +children: std.ArrayList(Object), + +pub fn getProperty(self: Object, tag: std.meta.Tag(PropertyData)) ?*const PropertyData { + for (self.properties.items) |*prop| { + if (std.meta.activeTag(prop.data) == tag) return &prop.data; + } + return null; +} + +pub fn setProperty(self: *Object, allocator: std.mem.Allocator, prop: Property) !void { + for (self.properties.items, 0..) |*p, i| { + if (std.meta.activeTag(p.data) == std.meta.activeTag(prop.data)) { + if (p.data == .points) p.data.points.deinit(allocator); + self.properties.items[i] = prop; + return; + } + } + try self.properties.append(allocator, prop); +} + +pub fn addChild(self: *Object, allocator: std.mem.Allocator, template: Object) !void { + const obj = try template.clone(allocator); + try self.children.append(allocator, obj); +} + +pub fn clone(self: Object, allocator: std.mem.Allocator) !Object { + var properties_list = std.ArrayList(Property).empty; + errdefer properties_list.deinit(allocator); + for (self.properties.items) |prop| { + try properties_list.append(allocator, try prop.clone(allocator)); + } + + var children_list = std.ArrayList(Object).empty; + errdefer children_list.deinit(allocator); + for (self.children.items) |child| { + try children_list.append(allocator, try child.clone(allocator)); + } + + return .{ + .shape = self.shape, + .properties = properties_list, + .children = children_list, + }; +} + +pub fn deinit(self: *Object, allocator: std.mem.Allocator) void { + for (self.children.items) |*child| child.deinit(allocator); + self.children.deinit(allocator); + for (self.properties.items) |*prop| prop.deinit(allocator); + self.properties.deinit(allocator); + self.* = undefined; +} + +fn createWithCommon(allocator: std.mem.Allocator, shape: ShapeKind) !Object { + const common = defaultCommonProperties(); + var properties_list = std.ArrayList(Property).empty; + errdefer properties_list.deinit(allocator); + for (common) |d| try properties_list.append(allocator, .{ .data = d }); + return .{ + .shape = shape, + .properties = properties_list, + .children = std.ArrayList(Object).empty, + }; +} + +pub fn createRect(allocator: std.mem.Allocator) !Object { + var obj = try createWithCommon(allocator, .rect); + errdefer obj.deinit(allocator); + try obj.properties.append(allocator, .{ .data = .{ .size = .{ .width = 100, .height = 100 } } }); + return obj; +} + +pub fn createEllipse(allocator: std.mem.Allocator) !Object { + var obj = try createWithCommon(allocator, .ellipse); + errdefer obj.deinit(allocator); + try obj.properties.append(allocator, .{ .data = .{ .radii = .{ .x = 50, .y = 50 } } }); + return obj; +} + +pub fn createLine(allocator: std.mem.Allocator) !Object { + var obj = try createWithCommon(allocator, .line); + errdefer obj.deinit(allocator); + try obj.properties.append(allocator, .{ .data = .{ .end_point = .{ .x = 100, .y = 0 } } }); + return obj; +} + +pub fn createBrokenLine(allocator: std.mem.Allocator) !Object { + var obj = try createWithCommon(allocator, .broken); + errdefer obj.deinit(allocator); + var points = std.ArrayList(Point2).init(allocator); + try points.appendSlice(allocator, &.{ + .{ .x = 0, .y = 0 }, + .{ .x = 80, .y = 0 }, + .{ .x = 80, .y = 60 }, + }); + try obj.properties.append(allocator, .{ .data = .{ .points = points } }); + return obj; +} diff --git a/src/models/Property.zig b/src/models/Property.zig index 7a879ba..b6512ce 100644 --- a/src/models/Property.zig +++ b/src/models/Property.zig @@ -1,62 +1,73 @@ -// Модель свойств объекта документа. -// Каждое свойство — отдельный тип в union; UI и RenderEngine работают с полиморфным Property. -// Комплексные значения (размер, радиусы) — один вариант свойства, а не несколько полей. - +const std = @import("std"); const basic_models = @import("basic_models.zig"); const Point2 = basic_models.Point2; const Scale2 = basic_models.Scale2; const Size = basic_models.Size; const Radii = basic_models.Radii; -/// Одно свойство объекта: полиморфный union. -/// Варианты — целостные значения (size, radii), не разбитые на отдельные поля. -/// UI перебирает свойства и по тегу показывает нужный редактор; -/// RenderEngine по тегу фигуры читает нужные свойства для отрисовки. -pub const Property = union(enum) { - // --- Общие для всех фигур (см. defaultCommonProperties) --- - /// Левый верхний угол bbox для rect/path; центр для ellipse; начало для line. +pub const Data = union(enum) { position: Point2, + angle: f32, scale: Scale2, visible: bool, opacity: f32, locked: bool, - // --- Прямоугольник: один вариант --- size: Size, - - // --- Эллипс: один вариант --- radii: Radii, - - // --- Линия: конечная точка (относительно position) --- end_point: Point2, - // --- Визуал (опционально для будущего) --- + points: std.ArrayList(Point2), + fill_rgba: u32, stroke_rgba: u32, }; -const std = @import("std"); +pub const Property = struct { + data: Data, -/// Общий набор свойств по умолчанию для любого объекта (одно место определения). -/// Конструкторы фигур добавляют сначала его, затем специфичные свойства. -pub fn defaultCommonProperties() []Property { - return .{ - .{ .position = .{ .x = 0, .y = 0 } }, - .{ .scale = .{ .scale_x = 1, .scale_y = 1 } }, - .{ .visible = true }, - .{ .opacity = 1.0 }, - .{ .locked = false }, - }; + pub fn deinit(self: *Property, allocator: std.mem.Allocator) void { + switch (self.data) { + .points => |*list| list.deinit(allocator), + else => {}, + } + self.* = undefined; + } + + pub fn clone(self: Property, allocator: std.mem.Allocator) !Property { + return switch (self.data) { + .points => |list| .{ + .data = .{ + .points = try list.clone(allocator), + }, + }, + else => .{ .data = self.data }, + }; + } +}; + +const default_common_data: []const Data = .{ + .{ .position = .{ .x = 0, .y = 0 } }, + .{ .angle = 0 }, + .{ .scale = .{ .scale_x = 1, .scale_y = 1 } }, + .{ .visible = true }, + .{ .opacity = 1.0 }, + .{ .locked = false }, +}; + +pub fn defaultCommonProperties() []const Data { + return &default_common_data; } -test "Property is union" { - const p: Property = .{ .opacity = 0.5 }; - try std.testing.expect(p == .opacity); - try std.testing.expect(p.opacity == 0.5); +test "Property wrapper and Data" { + const p = Property{ .data = .{ .opacity = 0.5 } }; + try std.testing.expect(p.data == .opacity); + try std.testing.expect(p.data.opacity == 0.5); } test "common properties" { const common = defaultCommonProperties(); + try std.testing.expect(common[0] == .position); try std.testing.expect(common[0].position.x == 0); try std.testing.expect(common[2].visible == true); } diff --git a/src/models/basic_models.zig b/src/models/basic_models.zig index 6590afb..40bd92c 100644 --- a/src/models/basic_models.zig +++ b/src/models/basic_models.zig @@ -15,19 +15,16 @@ pub const Size = struct { height: f32, }; -/// Точка в 2D (документные единицы) pub const Point2 = struct { x: f32 = 0, y: f32 = 0, }; -/// Радиусы эллипса по осям (одно свойство). pub const Radii = struct { x: f32, y: f32, }; -/// Масштаб объекта pub const Scale2 = struct { scale_x: f32 = 1, scale_y: f32 = 1, diff --git a/src/render/CpuRenderEngine.zig b/src/render/CpuRenderEngine.zig index c9c6195..6f0c416 100644 --- a/src/render/CpuRenderEngine.zig +++ b/src/render/CpuRenderEngine.zig @@ -27,7 +27,6 @@ pub fn init(allocator: Allocator, render_type: Type) CpuRenderEngine { } pub fn exampleReset(self: *CpuRenderEngine) void { - // Сгенерировать случайные цвета градиента var prng = std.Random.DefaultPrng.init(@intCast(std.time.microTimestamp())); const random = prng.random(); self.gradient_start = Color.PMA{ .r = random.int(u8), .g = random.int(u8), .b = random.int(u8), .a = 255 }; @@ -64,12 +63,12 @@ fn renderSquares(self: CpuRenderEngine, pixels: []Color.PMA, canvas_size: ImageS _ = self; const colors = [_]Color.PMA{ - .{ .r = 255, .g = 0, .b = 0, .a = 255 }, // red - .{ .r = 255, .g = 165, .b = 0, .a = 255 }, // orange - .{ .r = 255, .g = 255, .b = 0, .a = 255 }, // yellow - .{ .r = 0, .g = 255, .b = 0, .a = 255 }, // green - .{ .r = 0, .g = 255, .b = 255, .a = 255 }, // cyan - .{ .r = 0, .g = 0, .b = 255, .a = 255 }, // blue + .{ .r = 255, .g = 0, .b = 0, .a = 255 }, + .{ .r = 255, .g = 165, .b = 0, .a = 255 }, + .{ .r = 255, .g = 255, .b = 0, .a = 255 }, + .{ .r = 0, .g = 255, .b = 0, .a = 255 }, + .{ .r = 0, .g = 255, .b = 255, .a = 255 }, + .{ .r = 0, .g = 0, .b = 255, .a = 255 }, }; const squares_num = 5; @@ -106,7 +105,6 @@ fn renderSquares(self: CpuRenderEngine, pixels: []Color.PMA, canvas_size: ImageS const canvas_x = x + visible_rect.x; if (canvas_x >= canvas_size.w) continue; - // Check vertical line index var vertical_index: ?u32 = null; for (0..x_pos.len) |i| { if (canvas_x >= x_pos[i] and canvas_x < x_pos[i] + thikness) { @@ -115,7 +113,6 @@ fn renderSquares(self: CpuRenderEngine, pixels: []Color.PMA, canvas_size: ImageS } } - // Check horizontal line index var horizontal_index: ?u32 = null; for (0..y_pos.len) |i| { if (canvas_y >= y_pos[i] and canvas_y < y_pos[i] + thikness) { @@ -129,7 +126,6 @@ fn renderSquares(self: CpuRenderEngine, pixels: []Color.PMA, canvas_size: ImageS } else if (horizontal_index) |idx| { pixels[y * visible_rect.w + x] = colors[idx]; } else { - // Find square var square_x: u32 = 0; for (0..squares_num) |i| { if (canvas_x >= x_pos[i] + thikness and canvas_x < x_pos[i + 1]) { @@ -161,12 +157,9 @@ pub fn example(self: CpuRenderEngine, canvas_size: ImageSize, visible_rect: Imag const width = visible_rect.w; const height = visible_rect.h; - // Выделить буфер пиксельных данных const pixels = try self._allocator.alloc(Color.PMA, @as(usize, width) * height); defer self._allocator.free(pixels); - // std.debug.print("w={any}, fw={any};\th={any}, fh={any}\n", .{ width, full_w, height, full_h }); - switch (self.type) { .Gradient => self.renderGradient(pixels, width, height, full_w, full_h, visible_rect), .Squares => self.renderSquares(pixels, canvas_size, visible_rect), diff --git a/src/render/RenderEngine.zig b/src/render/RenderEngine.zig index b5a38fe..f9362c8 100644 --- a/src/render/RenderEngine.zig +++ b/src/render/RenderEngine.zig @@ -1,4 +1,3 @@ -// Интерфейс для рендеринга документа const dvui = @import("dvui"); const CpuRenderEngine = @import("CpuRenderEngine.zig"); const basic_models = @import("../models/basic_models.zig"); diff --git a/src/ui/canvas_view.zig b/src/ui/canvas_view.zig index fdabb1b..3dbb391 100644 --- a/src/ui/canvas_view.zig +++ b/src/ui/canvas_view.zig @@ -1,4 +1,3 @@ -// Виджет холста: скролл, текстура, зум по Ctrl+колёсико. const std = @import("std"); const dvui = @import("dvui"); const dvui_ext = @import("dvui_ext.zig"); @@ -120,7 +119,6 @@ fn handleCanvasZoom(canvas: *Canvas, scroll: anytype) void { } } -/// Обрабатывает события мыши: переводит позицию курсора в координаты документа и сохраняет в canvas.cursor_document_point. fn handleCanvasMouse(canvas: *Canvas, scroll: anytype) void { const natural_scale = if (canvas.native_scaling) 1 else dvui.windowNaturalScale(); diff --git a/src/ui/dvui_ext.zig b/src/ui/dvui_ext.zig index e6b37d9..307a39c 100644 --- a/src/ui/dvui_ext.zig +++ b/src/ui/dvui_ext.zig @@ -1,4 +1,3 @@ -// Расширения для dvui const std = @import("std"); const dvui = @import("dvui"); const TexturedBox = @import("./types/TexturedBox.zig"); diff --git a/src/ui/frame.zig b/src/ui/frame.zig index b19fab3..fb35ec7 100644 --- a/src/ui/frame.zig +++ b/src/ui/frame.zig @@ -1,11 +1,9 @@ -// Корневой кадр UI: разметка и сборка панелей. const dvui = @import("dvui"); const WindowContext = @import("../WindowContext.zig"); const tab_bar = @import("tab_bar.zig"); const left_panel = @import("left_panel.zig"); const right_panel = @import("right_panel.zig"); -/// Отрисовать один кадр GUI. Возвращает false при закрытии окна/выходе. pub fn guiFrame(ctx: *WindowContext) bool { for (dvui.events()) |*e| { if (e.evt == .window and e.evt.window.action == .close) return false; diff --git a/src/ui/left_panel.zig b/src/ui/left_panel.zig index 6fd8a7d..7de4bfc 100644 --- a/src/ui/left_panel.zig +++ b/src/ui/left_panel.zig @@ -1,4 +1,3 @@ -// Левая панель: инструменты для активного документа (scaling, тип рендера). const dvui = @import("dvui"); const WindowContext = @import("../WindowContext.zig"); diff --git a/src/ui/right_panel.zig b/src/ui/right_panel.zig index 1619e3d..887bec6 100644 --- a/src/ui/right_panel.zig +++ b/src/ui/right_panel.zig @@ -1,4 +1,3 @@ -// Правая панель: контент документа (холст) или заглушка «Нет документа». const std = @import("std"); const dvui = @import("dvui"); const WindowContext = @import("../WindowContext.zig"); diff --git a/src/ui/tab_bar.zig b/src/ui/tab_bar.zig index c5521d2..59c5501 100644 --- a/src/ui/tab_bar.zig +++ b/src/ui/tab_bar.zig @@ -1,4 +1,3 @@ -// Верхняя строка: вкладки документов + кнопка «Новый». const std = @import("std"); const dvui = @import("dvui"); const WindowContext = @import("../WindowContext.zig"); diff --git a/src/ui/types/TexturedBox.zig b/src/ui/types/TexturedBox.zig index 16b3a90..eea9271 100644 --- a/src/ui/types/TexturedBox.zig +++ b/src/ui/types/TexturedBox.zig @@ -1,4 +1,3 @@ -// Отрисовка дочернего контента как текстуры с параметрами скругления const std = @import("std"); const dvui = @import("dvui"); const TexturedBox = @This(); @@ -26,10 +25,6 @@ pub fn deinit(self: *TexturedBox) void { const tex = dvui.textureFromTarget(picture.texture) catch null; if (tex) |t| { dvui.Texture.destroyLater(t); - // self.rs.r.y -= 2; - // self.rs.r.x -= 2; - // self.rs.r.h += 2; - // self.rs.r.w += 2; dvui.renderTexture(t, self.rs, .{ .corner_radius = self.corner_radius, }) catch {};