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);
|
self._zoom = @max(self._zoom, 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getZoom(self: Canvas) f32 {
|
||||||
|
return self._zoom;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn requestRedraw(self: *Canvas) void {
|
pub fn requestRedraw(self: *Canvas) void {
|
||||||
self._redraw_pending = true;
|
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 img = self.getZoomedImageSize();
|
||||||
const left_n = @as(f32, @floatFromInt(img.x)) / natural_scale;
|
const left_n = @as(f32, @floatFromInt(img.x)) / natural_scale;
|
||||||
const top_n = @as(f32, @floatFromInt(img.y)) / 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 right_n = @as(f32, @floatFromInt(img.x + img.w)) / natural_scale;
|
||||||
const bottom_n = @as(f32, @floatFromInt(img.y + img.h)) / natural_scale;
|
const bottom_n = @as(f32, @floatFromInt(img.y + img.h)) / natural_scale;
|
||||||
|
return content_point.x >= left_n and content_point.x < right_n and
|
||||||
if (content_point.x < left_n or content_point.x >= right_n or
|
content_point.y >= top_n and content_point.y < bottom_n;
|
||||||
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,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateVisibleImageRect(self: *Canvas, viewport: dvui.Rect, scroll_offset: dvui.Point) bool {
|
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();
|
const ctrl = dvui.currentWindow().modifiers.control();
|
||||||
if (!ctrl) return;
|
if (!ctrl) return;
|
||||||
|
|
||||||
|
const natural_scale = if (canvas.native_scaling) 1 else dvui.windowNaturalScale();
|
||||||
|
|
||||||
for (dvui.events()) |*e| {
|
for (dvui.events()) |*e| {
|
||||||
switch (e.evt) {
|
switch (e.evt) {
|
||||||
.mouse => |mouse| {
|
.mouse => |*mouse| {
|
||||||
const action = mouse.action;
|
const action = mouse.action;
|
||||||
if (dvui.eventMatchSimple(e, scroll.data()) and (action == .wheel_x or action == .wheel_y)) {
|
if (dvui.eventMatchSimple(e, scroll.data()) and (action == .wheel_x or action == .wheel_y)) {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
.wheel_y => |y| {
|
.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.addZoom(y / 1000);
|
||||||
canvas.requestRedraw();
|
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 => {},
|
else => {},
|
||||||
}
|
}
|
||||||
@@ -133,7 +157,8 @@ fn handleCanvasMouse(canvas: *Canvas, scroll: anytype) void {
|
|||||||
.x = viewport_pt.x + canvas.scroll.viewport.x,
|
.x = viewport_pt.x + canvas.scroll.viewport.x,
|
||||||
.y = viewport_pt.y + canvas.scroll.viewport.y,
|
.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|
|
if (canvas.cursor_document_point) |point|
|
||||||
std.debug.print("cursor_document_point: {}\n", .{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(
|
var settings_section = dvui.box(
|
||||||
@@ -98,6 +73,7 @@ pub fn leftPanel(ctx: *WindowContext) void {
|
|||||||
.{ .dir = .vertical },
|
.{ .dir = .vertical },
|
||||||
.{
|
.{
|
||||||
.expand = .horizontal,
|
.expand = .horizontal,
|
||||||
|
.gravity_y = 1.0,
|
||||||
.margin = .{ .y = 5 },
|
.margin = .{ .y = 5 },
|
||||||
.padding = dvui.Rect.all(panel_padding),
|
.padding = dvui.Rect.all(panel_padding),
|
||||||
.corner_radius = dvui.Rect.all(panel_radius),
|
.corner_radius = dvui.Rect.all(panel_radius),
|
||||||
@@ -130,6 +106,32 @@ pub fn leftPanel(ctx: *WindowContext) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
settings_section.deinit();
|
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();
|
panel.deinit();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user