diff --git a/src/application/applicationstate.c b/src/application/applicationstate.c index fb3c9c5..c5263e0 100644 --- a/src/application/applicationstate.c +++ b/src/application/applicationstate.c @@ -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); diff --git a/src/application/applicationstate.h b/src/application/applicationstate.h index c4d3a08..21a8520 100644 --- a/src/application/applicationstate.h +++ b/src/application/applicationstate.h @@ -27,7 +27,7 @@ typedef struct VektorAppState { VektorShapeBuffer* shapeBuffer; // View space VektorCanvas* canvas; - + VektorCanvasRenderInfo* renderInfo; } VektorAppState; void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut); diff --git a/src/ui/vektorcanvas.c b/src/ui/vektorcanvas.c index 7b38c1c..844e306 100644 --- a/src/ui/vektorcanvas.c +++ b/src/ui/vektorcanvas.c @@ -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); } diff --git a/src/ui/vektorcanvas.h b/src/ui/vektorcanvas.h index e70c05e..873f7d3 100644 --- a/src/ui/vektorcanvas.h +++ b/src/ui/vektorcanvas.h @@ -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;