Зум к курсору
This commit is contained in:
@@ -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});
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user