Позиция мыши в координатах документа

This commit is contained in:
2026-02-23 22:21:59 +03:00
parent 1dda9c9d15
commit b896a67fd4
2 changed files with 54 additions and 4 deletions

View File

@@ -4,6 +4,7 @@ const dvui = @import("dvui");
const Document = @import("models/Document.zig");
const RenderEngine = @import("render/RenderEngine.zig").RenderEngine;
const ImageRect = @import("models/basic_models.zig").ImageRect;
const Point2 = @import("models/basic_models.zig").Point2;
const Color = dvui.Color;
const Canvas = @This();
@@ -24,6 +25,8 @@ _visible_rect: ?ImageRect = null,
_zoom: f32 = 1,
_redraw_pending: bool = false,
_last_redraw_time_ms: i64 = 0,
/// Позиция курсора в координатах документа (обновляется в handleCanvasMouse). null если вне документа.
cursor_document_point: ?Point2 = null,
pub fn init(allocator: std.mem.Allocator, document: *Document, engine: RenderEngine) Canvas {
return .{
@@ -42,7 +45,7 @@ pub fn deinit(self: *Canvas) void {
/// Заполнить canvas градиентом
pub fn redrawExample(self: *Canvas) !void {
const full = self.getScaledImageSize();
const full = self.getZoomedImageSize();
const vis: ImageRect = self._visible_rect orelse ImageRect{ .x = 0, .y = 0, .w = 0, .h = 0 };
@@ -102,7 +105,7 @@ pub fn processPendingRedraw(self: *Canvas) !void {
try self.redrawExample();
}
pub fn getScaledImageSize(self: Canvas) ImageRect {
pub fn getZoomedImageSize(self: Canvas) ImageRect {
const doc = self.document;
return .{
.x = @intFromFloat(self.pos.x),
@@ -112,6 +115,28 @@ pub fn getScaledImageSize(self: Canvas) ImageRect {
};
}
/// Перевести точку из системы координат контента скролла (natural scale, начало — левый верхний угол скроллируемой области)
/// в координаты документа (единицы документа до зума).
/// Возвращает null, если точка вне области изображения документа.
pub fn contentPointToDocument(self: Canvas, content_point: dvui.Point, natural_scale: f32) ?Point2 {
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{
.x = px_x / self._zoom,
.y = px_y / self._zoom,
};
}
/// Обновить видимую часть изображения (в пикселях холста) и сохранить в `visible_rect`.
///
/// `viewport` и `scroll_offset` ожидаются в *physical* пикселях (т.е. уже умноженные на windowNaturalScale).
@@ -134,7 +159,7 @@ pub fn updateVisibleImageRect(self: *Canvas, viewport: dvui.Rect, scroll_offset:
}
fn computeVisibleImageRect(self: Canvas, viewport: dvui.Rect, scroll_offset: dvui.Point) ImageRect {
const image_rect = self.getScaledImageSize();
const image_rect = self.getZoomedImageSize();
const img_w: u32 = image_rect.w;
const img_h: u32 = image_rect.h;