Позиция мыши в координатах документа
This commit is contained in:
@@ -4,6 +4,7 @@ const dvui = @import("dvui");
|
|||||||
const Document = @import("models/Document.zig");
|
const Document = @import("models/Document.zig");
|
||||||
const RenderEngine = @import("render/RenderEngine.zig").RenderEngine;
|
const RenderEngine = @import("render/RenderEngine.zig").RenderEngine;
|
||||||
const ImageRect = @import("models/basic_models.zig").ImageRect;
|
const ImageRect = @import("models/basic_models.zig").ImageRect;
|
||||||
|
const Point2 = @import("models/basic_models.zig").Point2;
|
||||||
const Color = dvui.Color;
|
const Color = dvui.Color;
|
||||||
|
|
||||||
const Canvas = @This();
|
const Canvas = @This();
|
||||||
@@ -24,6 +25,8 @@ _visible_rect: ?ImageRect = null,
|
|||||||
_zoom: f32 = 1,
|
_zoom: f32 = 1,
|
||||||
_redraw_pending: bool = false,
|
_redraw_pending: bool = false,
|
||||||
_last_redraw_time_ms: i64 = 0,
|
_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 {
|
pub fn init(allocator: std.mem.Allocator, document: *Document, engine: RenderEngine) Canvas {
|
||||||
return .{
|
return .{
|
||||||
@@ -42,7 +45,7 @@ pub fn deinit(self: *Canvas) void {
|
|||||||
|
|
||||||
/// Заполнить canvas градиентом
|
/// Заполнить canvas градиентом
|
||||||
pub fn redrawExample(self: *Canvas) !void {
|
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 };
|
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();
|
try self.redrawExample();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getScaledImageSize(self: Canvas) ImageRect {
|
pub fn getZoomedImageSize(self: Canvas) ImageRect {
|
||||||
const doc = self.document;
|
const doc = self.document;
|
||||||
return .{
|
return .{
|
||||||
.x = @intFromFloat(self.pos.x),
|
.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`.
|
/// Обновить видимую часть изображения (в пикселях холста) и сохранить в `visible_rect`.
|
||||||
///
|
///
|
||||||
/// `viewport` и `scroll_offset` ожидаются в *physical* пикселях (т.е. уже умноженные на windowNaturalScale).
|
/// `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 {
|
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_w: u32 = image_rect.w;
|
||||||
const img_h: u32 = image_rect.h;
|
const img_h: u32 = image_rect.h;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ pub fn canvasView(canvas: *Canvas, content_rect_scale: dvui.RectScale) void {
|
|||||||
{
|
{
|
||||||
drawCanvasContent(canvas, scroll);
|
drawCanvasContent(canvas, scroll);
|
||||||
handleCanvasZoom(canvas, scroll);
|
handleCanvasZoom(canvas, scroll);
|
||||||
|
handleCanvasMouse(canvas, scroll);
|
||||||
}
|
}
|
||||||
scroll.deinit();
|
scroll.deinit();
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ pub fn canvasView(canvas: *Canvas, content_rect_scale: dvui.RectScale) void {
|
|||||||
|
|
||||||
fn drawCanvasContent(canvas: *Canvas, scroll: anytype) void {
|
fn drawCanvasContent(canvas: *Canvas, scroll: anytype) void {
|
||||||
const natural_scale = if (canvas.native_scaling) 1 else dvui.windowNaturalScale();
|
const natural_scale = if (canvas.native_scaling) 1 else dvui.windowNaturalScale();
|
||||||
const img_size = canvas.getScaledImageSize();
|
const img_size = canvas.getZoomedImageSize();
|
||||||
const viewport_rect = scroll.data().contentRect();
|
const viewport_rect = scroll.data().contentRect();
|
||||||
const scroll_current = dvui.Point{ .x = canvas.scroll.viewport.x, .y = canvas.scroll.viewport.y };
|
const scroll_current = dvui.Point{ .x = canvas.scroll.viewport.x, .y = canvas.scroll.viewport.y };
|
||||||
|
|
||||||
@@ -118,3 +119,27 @@ fn handleCanvasZoom(canvas: *Canvas, scroll: anytype) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Обрабатывает события мыши: переводит позицию курсора в координаты документа и сохраняет в canvas.cursor_document_point.
|
||||||
|
fn handleCanvasMouse(canvas: *Canvas, scroll: anytype) void {
|
||||||
|
const natural_scale = if (canvas.native_scaling) 1 else dvui.windowNaturalScale();
|
||||||
|
|
||||||
|
for (dvui.events()) |*e| {
|
||||||
|
switch (e.evt) {
|
||||||
|
.mouse => |*mouse| {
|
||||||
|
if (mouse.action != .press or mouse.button != .left) continue;
|
||||||
|
if (!dvui.eventMatchSimple(e, scroll.data())) continue;
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
canvas.cursor_document_point = canvas.contentPointToDocument(content_pt, natural_scale);
|
||||||
|
if (canvas.cursor_document_point) |point|
|
||||||
|
std.debug.print("cursor_document_point: {}\n", .{point});
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user