const basic_models = @import("../models/basic_models.zig"); const Point2_f = basic_models.Point2_f; const Canvas = @import("../Canvas.zig"); const Document = @import("../models/Document.zig"); const pipeline = @import("../render/cpu/pipeline.zig"); const Transform = pipeline.Transform; pub const ToolContext = struct { canvas: *Canvas, document_point: Point2_f, selected_object_id: ?u64, pub fn addObject(self: *const ToolContext, template: Document.Object) !void { var obj = template; const local_pos = self.computeLocalPosition(); try obj.setProperty(self.canvas.document.allocator, .{ .data = .{ .position = local_pos } }); try self.canvas.document.addObjectUnderParentId(self.selected_object_id, obj); self.canvas.requestRedraw(); } fn computeLocalPosition(self: *const ToolContext) Point2_f { if (self.selected_object_id) |parent_id| { if (findWorldTransformById(self.canvas.document, parent_id)) |parent_world| { return pipeline.worldToLocalTransform(parent_world, self.document_point.x, self.document_point.y); } } return self.document_point; } }; fn findWorldTransformById(doc: *Document, target_id: u64) ?Transform { const identity = Transform{}; for (doc.objects.items) |*obj| { if (findWorldTransformInTree(obj, identity, target_id)) |t| return t; } return null; } fn findWorldTransformInTree(obj: *const Document.Object, parent: Transform, target_id: u64) ?Transform { const local = Transform.init(obj); const world = Transform.compose(parent, local); if (obj.id == target_id) return world; for (obj.children.items) |*child| { if (findWorldTransformInTree(child, world, target_id)) |t| return t; } return null; } pub const Tool = struct { onCanvasClick: *const fn (*const ToolContext) anyerror!void, };