Переход на object_id
This commit is contained in:
@@ -12,8 +12,8 @@ pub const OpenDocument = struct {
|
|||||||
document: Document,
|
document: Document,
|
||||||
cpu_render: CpuRenderEngine,
|
cpu_render: CpuRenderEngine,
|
||||||
canvas: Canvas,
|
canvas: Canvas,
|
||||||
/// Выбранный объект в дереве (указатель, не индекс).
|
/// Выбранный объект в дереве (id объекта).
|
||||||
selected_object: ?*Document.Object = null,
|
selected_object_id: ?u64 = null,
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, self: *OpenDocument) void {
|
pub fn init(allocator: std.mem.Allocator, self: *OpenDocument) void {
|
||||||
const default_size = basic_models.Size_f{ .w = 800, .h = 600 };
|
const default_size = basic_models.Size_f{ .w = 800, .h = 600 };
|
||||||
@@ -24,7 +24,7 @@ pub const OpenDocument = struct {
|
|||||||
&self.document,
|
&self.document,
|
||||||
(&self.cpu_render).renderEngine(),
|
(&self.cpu_render).renderEngine(),
|
||||||
);
|
);
|
||||||
self.selected_object = null;
|
self.selected_object_id = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *OpenDocument) void {
|
pub fn deinit(self: *OpenDocument) void {
|
||||||
|
|||||||
@@ -9,12 +9,14 @@ const shape = @import("shape/shape.zig");
|
|||||||
size: Size_f,
|
size: Size_f,
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
objects: std.ArrayList(Object),
|
objects: std.ArrayList(Object),
|
||||||
|
next_object_id: u64,
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, size: Size_f) Document {
|
pub fn init(allocator: std.mem.Allocator, size: Size_f) Document {
|
||||||
return .{
|
return .{
|
||||||
.size = size,
|
.size = size,
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.objects = std.ArrayList(Object).empty,
|
.objects = std.ArrayList(Object).empty,
|
||||||
|
.next_object_id = 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,14 +26,14 @@ pub fn deinit(self: *Document) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn addObject(self: *Document, template: Object) !void {
|
pub fn addObject(self: *Document, template: Object) !void {
|
||||||
const obj = try template.clone(self.allocator);
|
const obj = try template.clone(self.allocator, &self.next_object_id);
|
||||||
try self.objects.append(self.allocator, obj);
|
try self.objects.append(self.allocator, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addShape(self: *Document, parent: ?*Object, shape_kind: Object.ShapeKind) !void {
|
pub fn addShape(self: *Document, parent: ?*Object, shape_kind: Object.ShapeKind) !void {
|
||||||
const obj = try shape.createObject(self.allocator, shape_kind);
|
const obj = try shape.createObject(self.allocator, shape_kind);
|
||||||
if (parent) |p| {
|
if (parent) |p| {
|
||||||
try p.addChild(self.allocator, obj);
|
try p.addChild(self.allocator, obj, &self.next_object_id);
|
||||||
} else {
|
} else {
|
||||||
try self.addObject(obj);
|
try self.addObject(obj);
|
||||||
}
|
}
|
||||||
@@ -50,6 +52,27 @@ pub fn removeObject(self: *Document, obj: *Object) bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Удаляет объект по id. Возвращает true, если объект был найден и удалён.
|
||||||
|
pub fn removeObjectById(self: *Document, obj_id: u64) bool {
|
||||||
|
for (self.objects.items, 0..) |*item, i| {
|
||||||
|
if (item.id == obj_id) {
|
||||||
|
var removed = self.objects.orderedRemove(i);
|
||||||
|
removed.deinit(self.allocator);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (removeFromChildrenById(self.allocator, &item.children, obj_id)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn findObjectById(self: *Document, obj_id: u64) ?*Object {
|
||||||
|
for (self.objects.items) |*item| {
|
||||||
|
if (item.id == obj_id) return item;
|
||||||
|
if (findInChildrenById(&item.children, obj_id)) |found| return found;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
fn removeFromChildren(allocator: std.mem.Allocator, children: *std.ArrayList(Object), obj: *Object) bool {
|
fn removeFromChildren(allocator: std.mem.Allocator, children: *std.ArrayList(Object), obj: *Object) bool {
|
||||||
for (children.items, 0..) |*item, i| {
|
for (children.items, 0..) |*item, i| {
|
||||||
if (item == obj) {
|
if (item == obj) {
|
||||||
@@ -61,3 +84,23 @@ fn removeFromChildren(allocator: std.mem.Allocator, children: *std.ArrayList(Obj
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn removeFromChildrenById(allocator: std.mem.Allocator, children: *std.ArrayList(Object), obj_id: u64) bool {
|
||||||
|
for (children.items, 0..) |*item, i| {
|
||||||
|
if (item.id == obj_id) {
|
||||||
|
var removed = children.orderedRemove(i);
|
||||||
|
removed.deinit(allocator);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (removeFromChildrenById(allocator, &item.children, obj_id)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn findInChildrenById(children: *std.ArrayList(Object), obj_id: u64) ?*Object {
|
||||||
|
for (children.items) |*item| {
|
||||||
|
if (item.id == obj_id) return item;
|
||||||
|
if (findInChildrenById(&item.children, obj_id)) |found| return found;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ pub const defaultCommonProperties: [default_common_data.len]Property = blk: {
|
|||||||
break :blk result;
|
break :blk result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
id: u64,
|
||||||
shape: ShapeKind,
|
shape: ShapeKind,
|
||||||
properties: std.ArrayList(Property),
|
properties: std.ArrayList(Property),
|
||||||
children: std.ArrayList(Object),
|
children: std.ArrayList(Object),
|
||||||
@@ -51,12 +52,12 @@ pub fn setProperty(self: *Object, allocator: std.mem.Allocator, prop: Property)
|
|||||||
return error.PropertyNotFound;
|
return error.PropertyNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addChild(self: *Object, allocator: std.mem.Allocator, template: Object) !void {
|
pub fn addChild(self: *Object, allocator: std.mem.Allocator, template: Object, next_id: *u64) !void {
|
||||||
const obj = try template.clone(allocator);
|
const obj = try template.clone(allocator, next_id);
|
||||||
try self.children.append(allocator, obj);
|
try self.children.append(allocator, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone(self: Object, allocator: std.mem.Allocator) !Object {
|
pub fn clone(self: Object, allocator: std.mem.Allocator, next_id: *u64) !Object {
|
||||||
var properties_list = std.ArrayList(Property).empty;
|
var properties_list = std.ArrayList(Property).empty;
|
||||||
errdefer properties_list.deinit(allocator);
|
errdefer properties_list.deinit(allocator);
|
||||||
for (self.properties.items) |prop| {
|
for (self.properties.items) |prop| {
|
||||||
@@ -66,16 +67,23 @@ pub fn clone(self: Object, allocator: std.mem.Allocator) !Object {
|
|||||||
var children_list = std.ArrayList(Object).empty;
|
var children_list = std.ArrayList(Object).empty;
|
||||||
errdefer children_list.deinit(allocator);
|
errdefer children_list.deinit(allocator);
|
||||||
for (self.children.items) |child| {
|
for (self.children.items) |child| {
|
||||||
try children_list.append(allocator, try child.clone(allocator));
|
try children_list.append(allocator, try child.clone(allocator, next_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
|
.id = allocId(next_id),
|
||||||
.shape = self.shape,
|
.shape = self.shape,
|
||||||
.properties = properties_list,
|
.properties = properties_list,
|
||||||
.children = children_list,
|
.children = children_list,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn allocId(next_id: *u64) u64 {
|
||||||
|
const id = next_id.*;
|
||||||
|
next_id.* += 1;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Object, allocator: std.mem.Allocator) void {
|
pub fn deinit(self: *Object, allocator: std.mem.Allocator) void {
|
||||||
for (self.children.items) |*child| child.deinit(allocator);
|
for (self.children.items) |*child| child.deinit(allocator);
|
||||||
self.children.deinit(allocator);
|
self.children.deinit(allocator);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ fn createWithCommonProperties(allocator: std.mem.Allocator, shape_kind: Object.S
|
|||||||
errdefer properties_list.deinit(allocator);
|
errdefer properties_list.deinit(allocator);
|
||||||
for (defaultCommonProperties) |prop| try properties_list.append(allocator, prop);
|
for (defaultCommonProperties) |prop| try properties_list.append(allocator, prop);
|
||||||
return .{
|
return .{
|
||||||
|
.id = 0,
|
||||||
.shape = shape_kind,
|
.shape = shape_kind,
|
||||||
.properties = properties_list,
|
.properties = properties_list,
|
||||||
.children = std.ArrayList(Object).empty,
|
.children = std.ArrayList(Object).empty,
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ pub fn addRandomShapes(doc: *Document, rng: std.Random) !void {
|
|||||||
if (total_count >= max_total) break;
|
if (total_count >= max_total) break;
|
||||||
var child = try shape.createObject(allocator, randomShapeKind(rng));
|
var child = try shape.createObject(allocator, randomShapeKind(rng));
|
||||||
try randomizeObjectProperties(allocator, &doc.size, &child, rng);
|
try randomizeObjectProperties(allocator, &doc.size, &child, rng);
|
||||||
try obj.addChild(allocator, child);
|
try obj.addChild(allocator, child, &doc.next_object_id);
|
||||||
total_count += 1;
|
total_count += 1;
|
||||||
}
|
}
|
||||||
for (obj.children.items[base_len..]) |*child| {
|
for (obj.children.items[base_len..]) |*child| {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const PropertyData = @import("../models/Property.zig").Data;
|
|||||||
const Rect_i = @import("../models/basic_models.zig").Rect_i;
|
const Rect_i = @import("../models/basic_models.zig").Rect_i;
|
||||||
const Tool = @import("../toolbar/Tool.zig");
|
const Tool = @import("../toolbar/Tool.zig");
|
||||||
|
|
||||||
pub fn canvasView(canvas: *Canvas, selected_object: ?*Document.Object, content_rect_scale: dvui.RectScale) void {
|
pub fn canvasView(canvas: *Canvas, selected_object_id: ?u64, content_rect_scale: dvui.RectScale) void {
|
||||||
var textured = dvui_ext.texturedBox(content_rect_scale, dvui.Rect.all(20));
|
var textured = dvui_ext.texturedBox(content_rect_scale, dvui.Rect.all(20));
|
||||||
{
|
{
|
||||||
var overlay = dvui.overlay(@src(), .{ .expand = .both });
|
var overlay = dvui.overlay(@src(), .{ .expand = .both });
|
||||||
@@ -56,7 +56,8 @@ pub fn canvasView(canvas: *Canvas, selected_object: ?*Document.Object, content_r
|
|||||||
toolbar_box.deinit();
|
toolbar_box.deinit();
|
||||||
|
|
||||||
// Панель свойств поверх scroll (правый верхний угол)
|
// Панель свойств поверх scroll (правый верхний угол)
|
||||||
if (selected_object) |obj| {
|
if (selected_object_id) |obj_id| {
|
||||||
|
if (canvas.document.findObjectById(obj_id)) |obj| {
|
||||||
var properties_box = dvui.box(
|
var properties_box = dvui.box(
|
||||||
@src(),
|
@src(),
|
||||||
.{ .dir = .horizontal },
|
.{ .dir = .horizontal },
|
||||||
@@ -74,6 +75,7 @@ pub fn canvasView(canvas: *Canvas, selected_object: ?*Document.Object, content_r
|
|||||||
// Сохраняем rect панели свойств для следующего кадра — в handleCanvasMouse исключаем из него клики
|
// Сохраняем rect панели свойств для следующего кадра — в handleCanvasMouse исключаем из него клики
|
||||||
canvas.properties_rect_scale = properties_box.data().contentRectScale();
|
canvas.properties_rect_scale = properties_box.data().contentRectScale();
|
||||||
properties_box.deinit();
|
properties_box.deinit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dvui.label(@src(), "Canvas", .{}, .{ .gravity_x = 0.5, .gravity_y = 0.0 });
|
dvui.label(@src(), "Canvas", .{}, .{ .gravity_x = 0.5, .gravity_y = 0.0 });
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ const panel_radius: f32 = 24;
|
|||||||
const fill_color = dvui.Color.black.opacity(0.2);
|
const fill_color = dvui.Color.black.opacity(0.2);
|
||||||
|
|
||||||
const ObjectTreeCallback = union(enum) {
|
const ObjectTreeCallback = union(enum) {
|
||||||
select: *Object,
|
select: u64,
|
||||||
delete: *Object,
|
delete: u64,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn shapeLabel(shape: Object.ShapeKind) []const u8 {
|
fn shapeLabel(shape: Object.ShapeKind) []const u8 {
|
||||||
@@ -26,8 +26,8 @@ fn shapeLabel(shape: Object.ShapeKind) []const u8 {
|
|||||||
|
|
||||||
fn objectTreeRow(open_doc: *WindowContext.OpenDocument, obj: *Object, depth: u32, object_callback: *?ObjectTreeCallback) void {
|
fn objectTreeRow(open_doc: *WindowContext.OpenDocument, obj: *Object, depth: u32, object_callback: *?ObjectTreeCallback) void {
|
||||||
const indent_px = depth * 18;
|
const indent_px = depth * 18;
|
||||||
const is_selected: bool = open_doc.selected_object == obj;
|
const is_selected: bool = open_doc.selected_object_id == obj.id;
|
||||||
const row_id = @intFromPtr(obj);
|
const row_id: usize = @intCast(obj.id);
|
||||||
|
|
||||||
const focus_color = dvui.themeGet().focus;
|
const focus_color = dvui.themeGet().focus;
|
||||||
|
|
||||||
@@ -83,14 +83,14 @@ fn objectTreeRow(open_doc: *WindowContext.OpenDocument, obj: *Object, depth: u32
|
|||||||
.gravity_x = 1.0,
|
.gravity_x = 1.0,
|
||||||
};
|
};
|
||||||
if (dvui.buttonIcon(@src(), "Delete object", icons.trash, .{}, .{}, delete_opts)) {
|
if (dvui.buttonIcon(@src(), "Delete object", icons.trash, .{}, .{}, delete_opts)) {
|
||||||
object_callback.* = .{ .delete = obj };
|
object_callback.* = .{ .delete = obj.id };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
content.deinit();
|
content.deinit();
|
||||||
|
|
||||||
if (select_row) {
|
if (select_row) {
|
||||||
object_callback.* = .{ .select = obj };
|
object_callback.* = .{ .select = obj.id };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
row.deinit();
|
row.deinit();
|
||||||
@@ -113,16 +113,16 @@ fn objectTree(ctx: *WindowContext) void {
|
|||||||
}
|
}
|
||||||
if (object_callback) |callback| {
|
if (object_callback) |callback| {
|
||||||
switch (callback) {
|
switch (callback) {
|
||||||
.select => |obj| {
|
.select => |obj_id| {
|
||||||
if (open_doc.selected_object == obj) {
|
if (open_doc.selected_object_id == obj_id) {
|
||||||
open_doc.selected_object = null;
|
open_doc.selected_object_id = null;
|
||||||
} else {
|
} else {
|
||||||
open_doc.selected_object = obj;
|
open_doc.selected_object_id = obj_id;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.delete => |obj| {
|
.delete => |obj_id| {
|
||||||
_ = doc.removeObject(obj);
|
_ = doc.removeObjectById(obj_id);
|
||||||
open_doc.selected_object = null;
|
open_doc.selected_object_id = null;
|
||||||
open_doc.canvas.requestRedraw();
|
open_doc.canvas.requestRedraw();
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ pub fn rightPanel(ctx: *WindowContext) void {
|
|||||||
const active_doc = ctx.activeDocument();
|
const active_doc = ctx.activeDocument();
|
||||||
if (active_doc) |doc| {
|
if (active_doc) |doc| {
|
||||||
const content_rect_scale = panel.data().contentRectScale();
|
const content_rect_scale = panel.data().contentRectScale();
|
||||||
canvas_view.canvasView(&doc.canvas, doc.selected_object, content_rect_scale);
|
canvas_view.canvasView(&doc.canvas, doc.selected_object_id, content_rect_scale);
|
||||||
} else {
|
} else {
|
||||||
noDocView(ctx);
|
noDocView(ctx);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user