Кнопки для точек на кривой

This commit is contained in:
2026-03-02 22:22:47 +03:00
parent d1722e3b6b
commit c399d285fb
2 changed files with 137 additions and 25 deletions

View File

@@ -8,6 +8,7 @@ const PropertyData = @import("../models/Property.zig").Data;
const Rect_i = @import("../models/basic_models.zig").Rect_i;
const Tool = @import("../toolbar/Tool.zig");
const RenderStats = @import("../render/RenderStats.zig");
const icons = @import("../icons.zig");
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));
@@ -66,7 +67,10 @@ pub fn canvasView(canvas: *Canvas, selected_object_id: ?u64, content_rect_scale:
var properties_box = dvui.box(
@src(),
.{ .dir = .horizontal },
.{},
.{
.gravity_x = 1.0,
.gravity_y = 0.0,
},
);
{
drawPropertiesPanel(canvas, obj);
@@ -307,13 +311,12 @@ fn drawPropertiesPanel(canvas: *Canvas, selected_object: *Document.Object) void
@src(),
.{ .dir = .vertical },
.{
.gravity_x = 1.0,
.gravity_y = 0.0,
.padding = dvui.Rect.all(8),
.corner_radius = dvui.Rect.all(8),
.background = true,
.color_fill = dvui.Color.black.opacity(0.2),
.min_size_content = .{ .w = 220 },
.min_size_content = .width(300),
.max_size_content = .width(300),
.margin = dvui.Rect{ .w = 32, .y = 16, .h = 100 },
},
);
@@ -394,17 +397,12 @@ fn drawPropertyEditor(canvas: *Canvas, obj: *Document.Object, prop: *const Prope
switch (prop.data) {
.position => |pos| {
var next = pos;
const doc = canvas.document;
const min_x = -doc.size.w;
const max_x = doc.size.w;
const min_y = -doc.size.h;
const max_y = doc.size.h;
var changed = false;
{
var subrow = dvui.box(@src(), .{ .dir = .horizontal }, .{ .expand = .horizontal });
dvui.labelNoFmt(@src(), "x:", .{}, .{});
const T = @TypeOf(next.x);
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.x, .min = @as(T, min_x), .max = @as(T, max_x) }, .{ .expand = .horizontal });
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.x }, .{ .expand = .horizontal });
subrow.deinit();
changed = res.changed or changed;
}
@@ -412,7 +410,7 @@ fn drawPropertyEditor(canvas: *Canvas, obj: *Document.Object, prop: *const Prope
var subrow = dvui.box(@src(), .{ .dir = .horizontal }, .{ .expand = .horizontal });
dvui.labelNoFmt(@src(), "y:", .{}, .{});
const T = @TypeOf(next.y);
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.y, .min = @as(T, min_y), .max = @as(T, max_y) }, .{ .expand = .horizontal });
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.y }, .{ .expand = .horizontal });
subrow.deinit();
changed = res.changed or changed;
}
@@ -483,13 +481,12 @@ fn drawPropertyEditor(canvas: *Canvas, obj: *Document.Object, prop: *const Prope
},
.size => |size| {
var next = size;
const doc = canvas.document;
var changed = false;
{
var subrow = dvui.box(@src(), .{ .dir = .horizontal }, .{ .expand = .horizontal });
dvui.labelNoFmt(@src(), "w:", .{}, .{});
const T = @TypeOf(next.w);
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.w, .min = @as(T, 0.0), .max = @as(T, doc.size.w) }, .{ .expand = .horizontal });
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.w, .min = @as(T, 0.0) }, .{ .expand = .horizontal });
subrow.deinit();
changed = res.changed or changed;
}
@@ -497,7 +494,7 @@ fn drawPropertyEditor(canvas: *Canvas, obj: *Document.Object, prop: *const Prope
var subrow = dvui.box(@src(), .{ .dir = .horizontal }, .{ .expand = .horizontal });
dvui.labelNoFmt(@src(), "h:", .{}, .{});
const T = @TypeOf(next.h);
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.h, .min = @as(T, 0.0), .max = @as(T, doc.size.h) }, .{ .expand = .horizontal });
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.h, .min = @as(T, 0.0) }, .{ .expand = .horizontal });
subrow.deinit();
changed = res.changed or changed;
}
@@ -508,13 +505,12 @@ fn drawPropertyEditor(canvas: *Canvas, obj: *Document.Object, prop: *const Prope
},
.radii => |radii| {
var next = radii;
const doc = canvas.document;
var changed = false;
{
var subrow = dvui.box(@src(), .{ .dir = .horizontal }, .{ .expand = .horizontal });
dvui.labelNoFmt(@src(), "x:", .{}, .{});
const T = @TypeOf(next.x);
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.x, .min = @as(T, 0.0), .max = @as(T, doc.size.w) }, .{ .expand = .horizontal });
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.x, .min = @as(T, 0.0) }, .{ .expand = .horizontal });
subrow.deinit();
changed = res.changed or changed;
}
@@ -522,7 +518,7 @@ fn drawPropertyEditor(canvas: *Canvas, obj: *Document.Object, prop: *const Prope
var subrow = dvui.box(@src(), .{ .dir = .horizontal }, .{ .expand = .horizontal });
dvui.labelNoFmt(@src(), "y:", .{}, .{});
const T = @TypeOf(next.y);
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.y, .min = @as(T, 0.0), .max = @as(T, doc.size.h) }, .{ .expand = .horizontal });
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.y, .min = @as(T, 0.0) }, .{ .expand = .horizontal });
subrow.deinit();
changed = res.changed or changed;
}
@@ -533,17 +529,12 @@ fn drawPropertyEditor(canvas: *Canvas, obj: *Document.Object, prop: *const Prope
},
.end_point => |pt| {
var next = pt;
const doc = canvas.document;
const min_x = -doc.size.w;
const max_x = doc.size.w;
const min_y = -doc.size.h;
const max_y = doc.size.h;
var changed = false;
{
var subrow = dvui.box(@src(), .{ .dir = .horizontal }, .{ .expand = .horizontal });
dvui.labelNoFmt(@src(), "x:", .{}, .{});
const T = @TypeOf(next.x);
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.x, .min = @as(T, min_x), .max = @as(T, max_x) }, .{ .expand = .horizontal });
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.x }, .{ .expand = .horizontal });
subrow.deinit();
changed = res.changed or changed;
}
@@ -551,7 +542,7 @@ fn drawPropertyEditor(canvas: *Canvas, obj: *Document.Object, prop: *const Prope
var subrow = dvui.box(@src(), .{ .dir = .horizontal }, .{ .expand = .horizontal });
dvui.labelNoFmt(@src(), "y:", .{}, .{});
const T = @TypeOf(next.y);
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.y, .min = @as(T, min_y), .max = @as(T, max_y) }, .{ .expand = .horizontal });
const res = dvui.textEntryNumber(@src(), T, .{ .value = &next.y }, .{ .expand = .horizontal });
subrow.deinit();
changed = res.changed or changed;
}
@@ -561,7 +552,127 @@ fn drawPropertyEditor(canvas: *Canvas, obj: *Document.Object, prop: *const Prope
}
},
.points => |points| {
dvui.label(@src(), "Points: {d}", .{points.items.len}, .{});
var list = points.clone(canvas.allocator) catch {
dvui.label(@src(), "Points: {d}", .{points.items.len}, .{});
return;
};
dvui.label(@src(), "Points: {d}", .{list.items.len}, .{});
var changed = false;
var to_delete: ?usize = null;
for (list.items, 0..) |*pt, i| {
// Одна строка: крестик удаления + paned с X/Y пополам
var subrow = dvui.box(
@src(),
.{ .dir = .horizontal },
.{
.expand = .horizontal,
.id_extra = i,
},
);
{
// Крестик удаления
if (dvui.buttonIcon(@src(), "Delete", icons.cross, .{}, .{}, .{
.id_extra = i,
.gravity_y = 0.5,
.margin = .{
.x = 8,
},
})) {
to_delete = i;
}
// Панель с X и Y, разделёнными пополам
var split_ratio: f32 = 0.5;
var paned = dvui.paned(
@src(),
.{
.direction = .horizontal,
.collapsed_size = 0.0,
.split_ratio = &split_ratio,
.handle_size = 0,
},
.{
.expand = .horizontal,
},
);
{
if (paned.showFirst()) {
var x_box = dvui.box(
@src(),
.{ .dir = .horizontal },
.{ .expand = .both },
);
{
dvui.labelNoFmt(@src(), "x:", .{}, .{
.gravity_y = 0.5,
});
const Tx = @TypeOf(pt.x);
const res_x = dvui.textEntryNumber(
@src(),
Tx,
.{ .value = &pt.x },
.{ .expand = .horizontal },
);
changed = res_x.changed or changed;
}
x_box.deinit();
}
if (paned.showSecond()) {
var y_box = dvui.box(
@src(),
.{ .dir = .horizontal },
.{ .expand = .both },
);
{
dvui.labelNoFmt(@src(), "y:", .{}, .{
.gravity_y = 0.5,
});
const Ty = @TypeOf(pt.y);
const res_y = dvui.textEntryNumber(
@src(),
Ty,
.{ .value = &pt.y },
.{ .expand = .horizontal },
);
changed = res_y.changed or changed;
}
y_box.deinit();
}
}
paned.deinit();
}
subrow.deinit();
}
// Удаление выбранной точки
if (to_delete) |idx| {
_ = list.orderedRemove(idx);
changed = true;
}
// Кнопка добавления новой точки (одна на весь список)
if (dvui.button(@src(), "Add point", .{}, .{})) {
const T = @TypeOf(list.items[0]);
const new_point: T = if (list.items.len > 0)
list.items[list.items.len - 1]
else
.{ .x = 0, .y = 0 };
list.append(canvas.allocator, new_point) catch {};
changed = true;
}
if (changed) {
obj.setProperty(canvas.allocator, .{ .data = .{ .points = list } }) catch {
list.deinit(canvas.allocator);
return;
};
canvas.requestRedraw();
} else {
list.deinit(canvas.allocator);
}
},
.fill_rgba => |rgba| {
drawColorEditor(canvas, obj, rgba, true);