feat: add canvas pan and rotate

This commit is contained in:
2026-03-10 18:44:11 +00:00
parent 858a1f2c1a
commit b0930c9e02
4 changed files with 117 additions and 13 deletions

View File

@@ -103,7 +103,8 @@ static void canvas_onclick(GtkGestureClick* gesture, int n_press, double x,
}
void vektor_appstate_canvas_click(VektorAppState* state, double x, double y) {
V2 pos = (V2){x, y};
V2 pos =
m33_transform(m33_inverse(state->renderInfo->canvasMat), (V2){x, y});
begin_click_dispatch:
if (state->selectedTool == VektorLineTool) {
@@ -234,12 +235,16 @@ void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) {
stateOut->selectedShape = NULL;
VektorCanvasRenderInfo* renderInfo = malloc(sizeof(VektorCanvasRenderInfo));
renderInfo->zoom = 1;
renderInfo->panX = 0;
renderInfo->panY = 0;
renderInfo->rotation = 0;
m33_to_gl4(m33_identity(), renderInfo->canvasTransform);
renderInfo->selectedShape = &(stateOut->selectedShape);
renderInfo->shapes = stateOut->shapeBuffer;
renderInfo->startupTime = stateOut->startupTime;
renderInfo->canvasMat = m33_identity();
vektor_canvas_init(wstate, stateOut->canvas, renderInfo);
stateOut->renderInfo = renderInfo;
// link all the buttons
g_signal_connect(G_OBJECT(wstate->workspaceButtonLineTool), "clicked",
G_CALLBACK(appstate_set_tool), data_linetool);

View File

@@ -27,7 +27,7 @@ typedef struct VektorAppState {
VektorShapeBuffer* shapeBuffer;
// View space
VektorCanvas* canvas;
VektorCanvasRenderInfo* renderInfo;
} VektorAppState;
void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut);

View File

@@ -246,23 +246,100 @@ static void on_scroll(GtkEventControllerScroll* controller, double dx,
GdkModifierType state = gtk_event_controller_get_current_event_state(
GTK_EVENT_CONTROLLER(controller));
if (state & GDK_CONTROL_MASK) {
// if (state & GDK_CONTROL_MASK) {
if (dy < 0)
s->zoom *= 0.9f;
else if (dy > 0)
s->zoom *= 1.1f;
if (dy < 0)
s->zoom *= 1.1f;
else if (dy > 0)
s->zoom *= 0.9f;
M33 mat = m33_scale(s->zoom, s->zoom);
M33 mat =
m33_mul(m33_translate(s->panX, s->panY),
m33_mul(m33_rotate(s->rotation), m33_scale(s->zoom, s->zoom)));
// M33 mat = m33_mul(m33_mul(m33_scale(s->zoom, s->zoom),
// m33_translate(s->panX, s->panY)),
// m33_rotate(s->rotation));
m33_to_gl4(mat, s->canvasTransform);
s->canvasMat = mat;
m33_to_gl4(mat, s->canvasTransform);
GtkWidget* widget =
gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller));
gtk_gl_area_queue_render(GTK_GL_AREA(widget));
// }
}
GtkWidget* widget =
gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller));
gtk_gl_area_queue_render(GTK_GL_AREA(widget));
static void on_pan_begin(GtkGestureDrag* gesture, double start_x,
double start_y, gpointer user_data) {
VektorCanvasRenderInfo* s = user_data;
GdkModifierType state = gtk_event_controller_get_current_event_state(
GTK_EVENT_CONTROLLER(gesture));
if (!(state & GDK_SHIFT_MASK)) {
s->drag_start_x = s->panX;
s->drag_start_y = s->panY;
} else {
double x, y;
gtk_gesture_drag_get_start_point(gesture, &x, &y);
s->mouse_start_x = x;
s->mouse_start_y = y;
double cx = VKTR_CANVAS_WIDTH * 0.5;
double cy = VKTR_CANVAS_HEIGHT * 0.5;
double dx = x - cx;
double dy = y - cy;
s->dragStartAngle = atan2(dy, dx);
s->dragStartRotation = s->rotation;
}
}
static void on_pan_drag(GtkGestureDrag* gesture, double offset_x,
double offset_y, gpointer user_data) {
VektorCanvasRenderInfo* s = user_data;
GdkModifierType state = gtk_event_controller_get_current_event_state(
GTK_EVENT_CONTROLLER(gesture));
if (!(state & GDK_SHIFT_MASK)) {
s->panX = s->drag_start_x + offset_x / (80 * s->zoom);
s->panY = s->drag_start_y - offset_y / (80 * s->zoom);
M33 mat = m33_mul(
m33_translate(s->panX, s->panY),
m33_mul(m33_rotate(s->rotation), m33_scale(s->zoom, s->zoom)));
m33_to_gl4(mat, s->canvasTransform);
s->canvasMat = mat;
} else {
double x, y;
gtk_gesture_drag_get_offset(gesture, &x, &y);
double mx = s->mouse_start_x + x;
double my = s->mouse_start_y + y;
double cx = VKTR_CANVAS_WIDTH * 0.5;
double cy = VKTR_CANVAS_HEIGHT * 0.5;
double dx = mx - cx;
double dy = my - cy;
double angle = -atan2(dy, dx);
s->rotation = s->dragStartRotation + (angle - s->dragStartAngle);
M33 mat = m33_mul(
m33_translate(s->panX, s->panY),
m33_mul(m33_rotate(s->rotation), m33_scale(s->zoom, s->zoom)));
m33_to_gl4(mat, s->canvasTransform);
s->canvasMat = mat;
}
GtkWidget* widget =
gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture));
gtk_gl_area_queue_render(GTK_GL_AREA(widget));
}
void vektor_canvas_init(VektorWidgetState* state, VektorCanvas* canvasOut,
VektorCanvasRenderInfo* renderInfo) {
canvasOut->canvasWidget = state->workspaceCanvas;
@@ -287,4 +364,13 @@ void vektor_canvas_init(VektorWidgetState* state, VektorCanvas* canvasOut,
gtk_widget_add_controller(GTK_WIDGET(canvasOut->canvasWidget), scroll);
g_signal_connect(scroll, "scroll", G_CALLBACK(on_scroll), renderInfo);
GtkGesture* pan = gtk_gesture_drag_new();
gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(pan), GDK_BUTTON_MIDDLE);
gtk_widget_add_controller(GTK_WIDGET(canvasOut->canvasWidget),
GTK_EVENT_CONTROLLER(pan));
g_signal_connect(pan, "drag-begin", G_CALLBACK(on_pan_begin), renderInfo);
g_signal_connect(pan, "drag-update", G_CALLBACK(on_pan_drag), renderInfo);
}

View File

@@ -4,6 +4,7 @@
#include "../core/raster.h"
#include "../util/color.h"
#include "gtk/gtk.h"
#include "src/core/matrix.h"
#include "src/core/primitives.h"
#include "uicontroller.h"
@@ -26,6 +27,18 @@ typedef struct VektorCanvasRenderInfo {
// a pointer to appstate->selectedShape
VektorShape** selectedShape;
float zoom;
float panX;
float panY;
float rotation;
float dragStartRotation;
double dragStartAngle;
double drag_start_x;
double drag_start_y;
double mouse_start_x;
double mouse_start_y;
M33 canvasMat;
float canvasTransform[16];
} VektorCanvasRenderInfo;