Объекты в документе
This commit is contained in:
@@ -1,9 +1,8 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const basic_models = @import("basic_models.zig");
|
const basic_models = @import("basic_models.zig");
|
||||||
|
const properties = @import("Property.zig");
|
||||||
|
const Property = properties.Property;
|
||||||
const Size = basic_models.Size;
|
const Size = basic_models.Size;
|
||||||
const ObjectCommon = basic_models.ObjectCommon;
|
|
||||||
const Point2 = basic_models.Point2;
|
|
||||||
|
|
||||||
const Document = @This();
|
const Document = @This();
|
||||||
|
|
||||||
size: Size,
|
size: Size,
|
||||||
@@ -36,32 +35,93 @@ pub const Layer = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Layer) void {
|
pub fn deinit(self: *Layer) void {
|
||||||
|
for (self.objects.items) |*obj| obj.deinit(self.allocator);
|
||||||
self.objects.deinit(self.allocator);
|
self.objects.deinit(self.allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Добавить объект в слой (клонирует свойства в allocator слоя).
|
||||||
|
pub fn addObject(self: *Layer, template: Object) !void {
|
||||||
|
const obj = try template.clone(self.allocator);
|
||||||
|
try self.objects.append(self.allocator, obj);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Объект на слое: общие свойства + полиморфные данные по тегу (path, rect, ellipse, ...).
|
/// Тип фигуры: определяет, как RenderEngine интерпретирует свойства и рисует объект.
|
||||||
/// Полиморфизм через tagged union — без наследования и vtable, диспетчеризация через switch (obj.data).
|
pub const ShapeKind = enum {
|
||||||
|
rect,
|
||||||
|
ellipse,
|
||||||
|
line,
|
||||||
|
path,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Объект на слое: тип фигуры + список полиморфных свойств.
|
||||||
|
/// Типы объектов (прямоугольник, эллипс, линия) задаются конструкторами,
|
||||||
|
/// которые создают нужный набор свойств; UI и RenderEngine работают с union Property.
|
||||||
pub const Object = struct {
|
pub const Object = struct {
|
||||||
common: ObjectCommon,
|
shape: ShapeKind,
|
||||||
data: Data,
|
properties: std.ArrayList(Property),
|
||||||
|
|
||||||
pub const Data = union(enum) {
|
/// Найти свойство по тегу и вернуть вариант union (caller делает switch).
|
||||||
path: PathData,
|
pub fn getProperty(self: Object, tag: std.meta.Tag(Property)) ?Property {
|
||||||
rect: RectData,
|
for (self.properties.items) |prop| {
|
||||||
ellipse: EllipseData,
|
if (std.meta.activeTag(prop) == tag) return prop;
|
||||||
};
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// Точки контура (заглушка; позже — владение через Layer/Document allocator)
|
/// Установить свойство: если уже есть с таким тегом — заменить, иначе добавить.
|
||||||
pub const PathData = struct {};
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
pub const RectData = struct {
|
/// Клонировать объект (в т.ч. список свойств) для вставки в другой слой/документ.
|
||||||
width: f32,
|
pub fn clone(self: Object, allocator: std.mem.Allocator) !Object {
|
||||||
height: f32,
|
var list = std.ArrayList(Property).empty;
|
||||||
};
|
errdefer list.deinit(allocator);
|
||||||
|
try list.appendSlice(allocator, self.properties.items);
|
||||||
|
return .{ .shape = self.shape, .properties = list };
|
||||||
|
}
|
||||||
|
|
||||||
pub const EllipseData = struct {
|
pub fn deinit(self: *Object, allocator: std.mem.Allocator) void {
|
||||||
radius_x: f32,
|
self.properties.deinit(allocator);
|
||||||
radius_y: f32,
|
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 };
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Публичные конструкторы: базовый объект + одно свойство фигуры ---
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
62
src/models/Property.zig
Normal file
62
src/models/Property.zig
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// Модель свойств объекта документа.
|
||||||
|
// Каждое свойство — отдельный тип в union; UI и RenderEngine работают с полиморфным Property.
|
||||||
|
// Комплексные значения (размер, радиусы) — один вариант свойства, а не несколько полей.
|
||||||
|
|
||||||
|
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.
|
||||||
|
position: Point2,
|
||||||
|
scale: Scale2,
|
||||||
|
visible: bool,
|
||||||
|
opacity: f32,
|
||||||
|
locked: bool,
|
||||||
|
|
||||||
|
// --- Прямоугольник: один вариант ---
|
||||||
|
size: Size,
|
||||||
|
|
||||||
|
// --- Эллипс: один вариант ---
|
||||||
|
radii: Radii,
|
||||||
|
|
||||||
|
// --- Линия: конечная точка (относительно position) ---
|
||||||
|
end_point: Point2,
|
||||||
|
|
||||||
|
// --- Визуал (опционально для будущего) ---
|
||||||
|
fill_rgba: u32,
|
||||||
|
stroke_rgba: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
/// Общий набор свойств по умолчанию для любого объекта (одно место определения).
|
||||||
|
/// Конструкторы фигур добавляют сначала его, затем специфичные свойства.
|
||||||
|
pub fn defaultCommonProperties() []Property {
|
||||||
|
return .{
|
||||||
|
.{ .position = .{ .x = 0, .y = 0 } },
|
||||||
|
.{ .scale = .{ .scale_x = 1, .scale_y = 1 } },
|
||||||
|
.{ .visible = true },
|
||||||
|
.{ .opacity = 1.0 },
|
||||||
|
.{ .locked = false },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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 "common properties" {
|
||||||
|
const common = defaultCommonProperties();
|
||||||
|
try std.testing.expect(common[0].position.x == 0);
|
||||||
|
try std.testing.expect(common[2].visible == true);
|
||||||
|
}
|
||||||
@@ -17,22 +17,18 @@ pub const Size = struct {
|
|||||||
|
|
||||||
/// Точка в 2D (документные единицы)
|
/// Точка в 2D (документные единицы)
|
||||||
pub const Point2 = struct {
|
pub const Point2 = struct {
|
||||||
|
x: f32 = 0,
|
||||||
|
y: f32 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Радиусы эллипса по осям (одно свойство).
|
||||||
|
pub const Radii = struct {
|
||||||
x: f32,
|
x: f32,
|
||||||
y: f32,
|
y: f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Трансформ объекта: позиция и масштаб (поворот при необходимости добавить отдельно)
|
/// Масштаб объекта
|
||||||
pub const Transform2 = struct {
|
pub const Scale2 = struct {
|
||||||
x: f32 = 0,
|
|
||||||
y: f32 = 0,
|
|
||||||
scale_x: f32 = 1,
|
scale_x: f32 = 1,
|
||||||
scale_y: f32 = 1,
|
scale_y: f32 = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Общие свойства любого объекта на слое (видимость, блокировка, непрозрачность, трансформ)
|
|
||||||
pub const ObjectCommon = struct {
|
|
||||||
transform: Transform2 = .{},
|
|
||||||
visible: bool = true,
|
|
||||||
locked: bool = false,
|
|
||||||
opacity: f32 = 1.0,
|
|
||||||
};
|
|
||||||
|
|||||||
Reference in New Issue
Block a user