feat: add canvas pan and rotate
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -27,7 +27,7 @@ typedef struct VektorAppState {
|
||||
VektorShapeBuffer* shapeBuffer;
|
||||
// View space
|
||||
VektorCanvas* canvas;
|
||||
|
||||
VektorCanvasRenderInfo* renderInfo;
|
||||
} VektorAppState;
|
||||
|
||||
void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user