Compare commits
2 Commits
23111172d8
...
0d546782bb
| Author | SHA1 | Date | |
|---|---|---|---|
| 0d546782bb | |||
| 0ee7be2002 |
@@ -88,6 +88,10 @@ pub fn addZoom(self: *Canvas, value: f32) void {
|
||||
self._zoom = @max(self._zoom, 0.01);
|
||||
}
|
||||
|
||||
pub fn getZoom(self: Canvas) f32 {
|
||||
return self._zoom;
|
||||
}
|
||||
|
||||
pub fn requestRedraw(self: *Canvas) void {
|
||||
self._redraw_pending = true;
|
||||
}
|
||||
@@ -116,23 +120,27 @@ pub fn getZoomedImageSize(self: Canvas) Rect_i {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn contentPointToDocument(self: Canvas, content_point: dvui.Point, natural_scale: f32) ?Point2_f {
|
||||
/// Возвращает координаты точки контента в координатах документа. Всегда возвращает точку,
|
||||
/// даже если она за пределами документа
|
||||
pub fn contentPointToDocument(self: Canvas, content_point: dvui.Point, natural_scale: f32) Point2_f {
|
||||
const img = self.getZoomedImageSize();
|
||||
const px_x = content_point.x * natural_scale - @as(f32, @floatFromInt(img.x));
|
||||
const px_y = content_point.y * natural_scale - @as(f32, @floatFromInt(img.y));
|
||||
return .{
|
||||
.x = px_x / self._zoom,
|
||||
.y = px_y / self._zoom,
|
||||
};
|
||||
}
|
||||
|
||||
/// Возвращает true, если точка контента лежит внутри холста (документа).
|
||||
pub fn isContentPointOnDocument(self: Canvas, content_point: dvui.Point, natural_scale: f32) bool {
|
||||
const img = self.getZoomedImageSize();
|
||||
const left_n = @as(f32, @floatFromInt(img.x)) / natural_scale;
|
||||
const top_n = @as(f32, @floatFromInt(img.y)) / natural_scale;
|
||||
const right_n = @as(f32, @floatFromInt(img.x + img.w)) / natural_scale;
|
||||
const bottom_n = @as(f32, @floatFromInt(img.y + img.h)) / natural_scale;
|
||||
|
||||
if (content_point.x < left_n or content_point.x >= right_n or
|
||||
content_point.y < top_n or content_point.y >= bottom_n)
|
||||
return null;
|
||||
|
||||
const px_x = content_point.x * natural_scale - @as(f32, @floatFromInt(img.x));
|
||||
const px_y = content_point.y * natural_scale - @as(f32, @floatFromInt(img.y));
|
||||
return Point2_f{
|
||||
.x = px_x / self._zoom,
|
||||
.y = px_y / self._zoom,
|
||||
};
|
||||
return content_point.x >= left_n and content_point.x < right_n and
|
||||
content_point.y >= top_n and content_point.y < bottom_n;
|
||||
}
|
||||
|
||||
pub fn updateVisibleImageRect(self: *Canvas, viewport: dvui.Rect, scroll_offset: dvui.Point) bool {
|
||||
|
||||
@@ -99,15 +99,39 @@ fn handleCanvasZoom(canvas: *Canvas, scroll: anytype) void {
|
||||
const ctrl = dvui.currentWindow().modifiers.control();
|
||||
if (!ctrl) return;
|
||||
|
||||
const natural_scale = if (canvas.native_scaling) 1 else dvui.windowNaturalScale();
|
||||
|
||||
for (dvui.events()) |*e| {
|
||||
switch (e.evt) {
|
||||
.mouse => |mouse| {
|
||||
.mouse => |*mouse| {
|
||||
const action = mouse.action;
|
||||
if (dvui.eventMatchSimple(e, scroll.data()) and (action == .wheel_x or action == .wheel_y)) {
|
||||
switch (action) {
|
||||
.wheel_y => |y| {
|
||||
const viewport_pt = scroll.data().contentRectScale().pointFromPhysical(mouse.p);
|
||||
const content_pt = dvui.Point{
|
||||
.x = viewport_pt.x + canvas.scroll.viewport.x,
|
||||
.y = viewport_pt.y + canvas.scroll.viewport.y,
|
||||
};
|
||||
const doc_pt = canvas.contentPointToDocument(content_pt, natural_scale);
|
||||
|
||||
canvas.addZoom(y / 1000);
|
||||
canvas.requestRedraw();
|
||||
|
||||
// Сдвигаем viewport так, чтобы точка под курсором (даже вне холста) не уезжала
|
||||
const new_zoom = canvas.getZoom();
|
||||
const img = canvas.getZoomedImageSize();
|
||||
const new_content_x = (@as(f32, @floatFromInt(img.x)) + doc_pt.x * new_zoom) / natural_scale;
|
||||
const new_content_y = (@as(f32, @floatFromInt(img.y)) + doc_pt.y * new_zoom) / natural_scale;
|
||||
canvas.scroll.viewport.x = new_content_x - viewport_pt.x;
|
||||
canvas.scroll.viewport.y = new_content_y - viewport_pt.y;
|
||||
const viewport_rect = scroll.data().contentRect();
|
||||
const content_w = @as(f32, @floatFromInt(img.x + img.w)) / natural_scale;
|
||||
const content_h = @as(f32, @floatFromInt(img.y + img.h)) / natural_scale;
|
||||
const max_x = @max(0, content_w - viewport_rect.w + canvas.pos.x);
|
||||
const max_y = @max(0, content_h - viewport_rect.h + canvas.pos.y);
|
||||
canvas.scroll.viewport.x = std.math.clamp(canvas.scroll.viewport.x, 0, max_x);
|
||||
canvas.scroll.viewport.y = std.math.clamp(canvas.scroll.viewport.y, 0, max_y);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@@ -133,7 +157,8 @@ fn handleCanvasMouse(canvas: *Canvas, scroll: anytype) void {
|
||||
.x = viewport_pt.x + canvas.scroll.viewport.x,
|
||||
.y = viewport_pt.y + canvas.scroll.viewport.y,
|
||||
};
|
||||
canvas.cursor_document_point = canvas.contentPointToDocument(content_pt, natural_scale);
|
||||
const doc_pt = canvas.contentPointToDocument(content_pt, natural_scale);
|
||||
canvas.cursor_document_point = if (canvas.isContentPointOnDocument(content_pt, natural_scale)) doc_pt else null;
|
||||
if (canvas.cursor_document_point) |point|
|
||||
std.debug.print("cursor_document_point: {}\n", .{point});
|
||||
},
|
||||
|
||||
@@ -66,31 +66,6 @@ pub fn leftPanel(ctx: *WindowContext) void {
|
||||
},
|
||||
);
|
||||
{
|
||||
// Верхняя часть: дерево объектов
|
||||
var tree_section = dvui.box(
|
||||
@src(),
|
||||
.{ .dir = .vertical },
|
||||
.{
|
||||
.expand = .both,
|
||||
.padding = dvui.Rect.all(panel_padding),
|
||||
.corner_radius = dvui.Rect.all(panel_radius),
|
||||
.color_fill = fill_color,
|
||||
.background = true,
|
||||
},
|
||||
);
|
||||
{
|
||||
dvui.label(@src(), "Objects", .{}, .{});
|
||||
var scroll = dvui.scrollArea(
|
||||
@src(),
|
||||
.{ .vertical = .auto },
|
||||
.{ .expand = .vertical, .background = false },
|
||||
);
|
||||
{
|
||||
objectTree(ctx);
|
||||
}
|
||||
scroll.deinit();
|
||||
}
|
||||
tree_section.deinit();
|
||||
|
||||
// Нижняя часть: настройки
|
||||
var settings_section = dvui.box(
|
||||
@@ -98,6 +73,7 @@ pub fn leftPanel(ctx: *WindowContext) void {
|
||||
.{ .dir = .vertical },
|
||||
.{
|
||||
.expand = .horizontal,
|
||||
.gravity_y = 1.0,
|
||||
.margin = .{ .y = 5 },
|
||||
.padding = dvui.Rect.all(panel_padding),
|
||||
.corner_radius = dvui.Rect.all(panel_radius),
|
||||
@@ -130,6 +106,32 @@ pub fn leftPanel(ctx: *WindowContext) void {
|
||||
}
|
||||
}
|
||||
settings_section.deinit();
|
||||
|
||||
// Верхняя часть: дерево объектов
|
||||
var tree_section = dvui.box(
|
||||
@src(),
|
||||
.{ .dir = .vertical },
|
||||
.{
|
||||
.expand = .both,
|
||||
.padding = dvui.Rect.all(panel_padding),
|
||||
.corner_radius = dvui.Rect.all(panel_radius),
|
||||
.color_fill = fill_color,
|
||||
.background = true,
|
||||
},
|
||||
);
|
||||
{
|
||||
dvui.label(@src(), "Objects", .{}, .{});
|
||||
var scroll = dvui.scrollArea(
|
||||
@src(),
|
||||
.{ .vertical = .auto },
|
||||
.{ .expand = .both, .background = false },
|
||||
);
|
||||
{
|
||||
objectTree(ctx);
|
||||
}
|
||||
scroll.deinit();
|
||||
}
|
||||
tree_section.deinit();
|
||||
}
|
||||
panel.deinit();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user