+ K rotateby[k][k]= 1;
+ rotateby[0][2]= dx;
+ rotateby[1][2]= dy;
+
+ gsl_blas_dgemm(CblasNoTrans,CblasNoTrans, 1.0,
+ &rotateby_gsl,&transform_gsl, 0.0,&qr_gsl);
+ gsl_linalg_QR_decomp(&qr_gsl, &tau_gsl);
+ gsl_linalg_QR_unpack(&qr_gsl, &tau_gsl,
+ &transform_gsl, &rotateby_gsl /*dummy*/);
+
+ printf("drag_rotate_delta...\n");
+ show();
+}
+DRAG_SAVING(rotate, transform);
+
+static void drag_scale_delta(double dx, double dy) {
+ scale *= pow(3.0, dy);
+ show();
+}
+DRAG_SAVING(scale, scale);
+
+static const Drag *drag= &drag_none;
+
+static int drag_last_x, drag_last_y;
+
+static void drag_position(int x, int y) {
+ drag->delta((x - drag_last_x) * 1.0 / wmaxdim,
+ (y - drag_last_y) * 1.0 / wmaxdim);
+ drag_last_x= x;
+ drag_last_y= y;
+}
+
+static void event_button(XButtonEvent *e) {
+ if (e->window != window || !e->same_screen) return;
+ if (e->type == ButtonPress) {
+ if (e->state || drag != &drag_none) {
+ printf("drag=%s press state=0x%lx abandon\n",
+ drag->name, (unsigned long)e->state);
+ drag->abandon();
+ drag= &drag_none;
+ return;
+ }
+ switch (e->button) {
+ case Button1: drag= &drag_rotate; break;
+ case Button2: drag= &drag_scale; break;
+ default: printf("unknown drag start %d\n", e->button);
+ }
+ printf("drag=%s press button=%lu start %d,%d\n",
+ drag->name, (unsigned long)e->button, e->x, e->y);
+ drag_last_x= e->x;
+ drag_last_y= e->y;
+ drag->start();
+ }
+ if (e->type == ButtonRelease) {
+ printf("drag=%s release %d,%d\n", drag->name, e->x, e->y);
+ drag_position(e->x, e->y);
+ drag->conclude();
+ drag= &drag_none;
+ }
+}
+
+static void event_motion(int x, int y) {
+ printf("drag=%s motion %d,%d\n", drag->name, x, y);
+ drag_position(x,y);
+}
+
+static void event_config(XConfigureEvent *e) { printf("configure\n"); }
+