void _lib_navigation_set_position(dt_lib_module_t *self, double x, double y, int wd, int ht) { dt_lib_navigation_t *d = ( dt_lib_navigation_t *)self->data; dt_dev_zoom_t zoom; int closeup; float zoom_x, zoom_y; DT_CTL_GET_GLOBAL(zoom, dev_zoom); DT_CTL_GET_GLOBAL(closeup, dev_closeup); DT_CTL_GET_GLOBAL(zoom_x, dev_zoom_x); DT_CTL_GET_GLOBAL(zoom_y, dev_zoom_y); if(d->dragging && zoom != DT_ZOOM_FIT) { const int inset = DT_NAVIGATION_INSET; const float width = wd - 2*inset, height = ht - 2*inset; const dt_develop_t *dev = darktable.develop; int iwd, iht; dt_dev_get_processed_size(dev, &iwd, &iht); zoom_x = fmaxf(-.5, fminf(((x-inset)/width - .5f)/(iwd*fminf(wd/(float)iwd, ht/(float)iht)/(float)wd), .5)); zoom_y = fmaxf(-.5, fminf(((y-inset)/height - .5f)/(iht*fminf(wd/(float)iwd, ht/(float)iht)/(float)ht), .5)); dt_dev_check_zoom_bounds(darktable.develop, &zoom_x, &zoom_y, zoom, closeup, NULL, NULL); DT_CTL_SET_GLOBAL(dev_zoom_x, zoom_x); DT_CTL_SET_GLOBAL(dev_zoom_y, zoom_y); /* redraw myself */ gtk_widget_queue_draw(self->widget); /* redraw pipe */ dt_dev_invalidate(darktable.develop); dt_control_queue_redraw_center(); } }
float dt_dev_get_zoom_scale(dt_develop_t *dev, dt_dev_zoom_t zoom, int closeup_factor, int preview) { float zoom_scale; // set processed width to something useful while image is not there yet: int procw, proch; dt_dev_get_processed_size(dev, &procw, &proch); const float w = preview ? dev->preview_pipe->backbuf_width : procw; const float h = preview ? dev->preview_pipe->backbuf_height : proch; switch(zoom) { case DT_ZOOM_FIT: zoom_scale = fminf(dev->width/w, dev->height/h); break; case DT_ZOOM_FILL: zoom_scale = fmaxf(dev->width/w, dev->height/h); break; case DT_ZOOM_1: zoom_scale = closeup_factor; if(preview) zoom_scale *= dev->preview_pipe->iscale / dev->preview_downsampling; break; default: // DT_ZOOM_FREE DT_CTL_GET_GLOBAL(zoom_scale, dev_zoom_scale); if(preview) zoom_scale *= dev->preview_pipe->iscale / dev->preview_downsampling; break; } return zoom_scale; }
void scrolled(dt_view_t *self, double x, double y, int up, int state) { const int32_t capwd = darktable.thumbnail_width; const int32_t capht = darktable.thumbnail_height; dt_develop_t *dev = (dt_develop_t *)self->data; const int32_t width_i = self->width; const int32_t height_i = self->height; if(width_i > capwd) x += (capwd-width_i) *.5f; if(height_i > capht) y += (capht-height_i)*.5f; int handled = 0; if(dev->gui_module && dev->gui_module->scrolled) handled = dev->gui_module->scrolled(dev->gui_module, x, y, up, state); if(handled) return; // free zoom dt_dev_zoom_t zoom; int closeup, procw, proch; float zoom_x, zoom_y; DT_CTL_GET_GLOBAL(zoom, dev_zoom); DT_CTL_GET_GLOBAL(closeup, dev_closeup); DT_CTL_GET_GLOBAL(zoom_x, dev_zoom_x); DT_CTL_GET_GLOBAL(zoom_y, dev_zoom_y); dt_dev_get_processed_size(dev, &procw, &proch); float scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2.0 : 1.0, 0); const float minscale = dt_dev_get_zoom_scale(dev, DT_ZOOM_FIT, 1.0, 0); // offset from center now (current zoom_{x,y} points there) float mouse_off_x = x - .5*dev->width, mouse_off_y = y - .5*dev->height; zoom_x += mouse_off_x/(procw*scale); zoom_y += mouse_off_y/(proch*scale); zoom = DT_ZOOM_FREE; closeup = 0; if(up) { if (scale == 1.0f) return; else scale += .1f*(1.0f - minscale); } else { if (scale == minscale) return; else scale -= .1f*(1.0f - minscale); } DT_CTL_SET_GLOBAL(dev_zoom_scale, scale); if(scale > 0.99) zoom = DT_ZOOM_1; if(scale < minscale + 0.01) zoom = DT_ZOOM_FIT; if(zoom != DT_ZOOM_1) { zoom_x -= mouse_off_x/(procw*scale); zoom_y -= mouse_off_y/(proch*scale); } dt_dev_check_zoom_bounds(dev, &zoom_x, &zoom_y, zoom, closeup, NULL, NULL); DT_CTL_SET_GLOBAL(dev_zoom, zoom); DT_CTL_SET_GLOBAL(dev_closeup, closeup); if(zoom != DT_ZOOM_1) { DT_CTL_SET_GLOBAL(dev_zoom_x, zoom_x); DT_CTL_SET_GLOBAL(dev_zoom_y, zoom_y); } dt_dev_invalidate(dev); dt_control_queue_redraw(); }
static void _zoom_preset_change(int val) { // dt_lib_module_t *self = (dt_lib_module_t *)user_data; dt_develop_t *dev = darktable.develop; if(!dev) return; dt_dev_zoom_t zoom; int closeup, procw, proch; float zoom_x, zoom_y; zoom = dt_control_get_dev_zoom(); closeup = dt_control_get_dev_closeup(); zoom_x = dt_control_get_dev_zoom_x(); zoom_y = dt_control_get_dev_zoom_y(); dt_dev_get_processed_size(dev, &procw, &proch); float scale = 0; zoom_x = 0.0f; //+= (1.0/scale)*(x - .5f*dev->width )/procw; zoom_y = 0.0f; //+= (1.0/scale)*(y - .5f*dev->height)/proch; if(val == 0) { scale = 0.5 * dt_dev_get_zoom_scale(dev, DT_ZOOM_FIT, 1.0, 0); zoom = DT_ZOOM_FREE; } else if(val == 1) { zoom = DT_ZOOM_FIT; scale = dt_dev_get_zoom_scale(dev, DT_ZOOM_FIT, 1.0, 0); } else if(val == 2) { scale = dt_dev_get_zoom_scale(dev, DT_ZOOM_1, 1.0, 0); zoom = DT_ZOOM_1; } else if(val == 3) { scale = 2.0f; zoom = DT_ZOOM_FREE; } dt_dev_check_zoom_bounds(dev, &zoom_x, &zoom_y, zoom, closeup, NULL, NULL); dt_control_set_dev_zoom_scale(scale); dt_control_set_dev_zoom(zoom); dt_control_set_dev_closeup(closeup); dt_control_set_dev_zoom_x(zoom_x); dt_control_set_dev_zoom_y(zoom_y); dt_dev_invalidate(dev); dt_control_queue_redraw(); }
void dt_dev_get_pointer_zoom_pos(dt_develop_t *dev, const float px, const float py, float *zoom_x, float *zoom_y) { dt_dev_zoom_t zoom; int closeup, procw, proch; float zoom2_x, zoom2_y; DT_CTL_GET_GLOBAL(zoom, dev_zoom); DT_CTL_GET_GLOBAL(closeup, dev_closeup); DT_CTL_GET_GLOBAL(zoom2_x, dev_zoom_x); DT_CTL_GET_GLOBAL(zoom2_y, dev_zoom_y); dt_dev_get_processed_size(dev, &procw, &proch); const float scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2.0 : 1.0, 0); // offset from center now (current zoom_{x,y} points there) const float mouse_off_x = px - .5*dev->width, mouse_off_y = py - .5*dev->height; zoom2_x += mouse_off_x/(procw*scale); zoom2_y += mouse_off_y/(proch*scale); *zoom_x = zoom2_x; *zoom_y = zoom2_y; }
void dt_dev_check_zoom_bounds(dt_develop_t *dev, float *zoom_x, float *zoom_y, dt_dev_zoom_t zoom, int closeup, float *boxww, float *boxhh) { int procw, proch; dt_dev_get_processed_size(dev, &procw, &proch); float boxw = 1, boxh = 1; // viewport in normalised space // if(zoom == DT_ZOOM_1) // { // const float imgw = (closeup ? 2 : 1)*procw; // const float imgh = (closeup ? 2 : 1)*proch; // const float devw = MIN(imgw, dev->width); // const float devh = MIN(imgh, dev->height); // boxw = fminf(1.0, devw/imgw); // boxh = fminf(1.0, devh/imgh); // } if(zoom == DT_ZOOM_FIT) { *zoom_x = *zoom_y = 0.0f; boxw = boxh = 1.0f; } else { const float scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2 : 1, 0); const float imgw = procw; const float imgh = proch; const float devw = dev->width; const float devh = dev->height; boxw = devw/(imgw*scale); boxh = devh/(imgh*scale); } if(*zoom_x < boxw/2 - .5) *zoom_x = boxw/2 - .5; if(*zoom_x > .5 - boxw/2) *zoom_x = .5 - boxw/2; if(*zoom_y < boxh/2 - .5) *zoom_y = boxh/2 - .5; if(*zoom_y > .5 - boxh/2) *zoom_y = .5 - boxh/2; if(boxw > 1.0) *zoom_x = 0.f; if(boxh > 1.0) *zoom_y = 0.f; if(boxww) *boxww = boxw; if(boxhh) *boxhh = boxh; }
int button_pressed(dt_view_t *self, double x, double y, int which, int type, uint32_t state) { const int32_t capwd = darktable.thumbnail_width; const int32_t capht = darktable.thumbnail_height; dt_develop_t *dev = (dt_develop_t *)self->data; const int32_t width_i = self->width; const int32_t height_i = self->height; if(width_i > capwd) x += (capwd-width_i) *.5f; if(height_i > capht) y += (capht-height_i)*.5f; int handled = 0; if(dev->gui_module && dev->gui_module->request_color_pick && which == 1) { float zoom_x, zoom_y; dt_dev_get_pointer_zoom_pos(dev, x, y, &zoom_x, &zoom_y); if(darktable.lib->proxy.colorpicker.size) { dev->gui_module->color_picker_box[0] = .5f+zoom_x; dev->gui_module->color_picker_box[1] = .5f+zoom_y; dev->gui_module->color_picker_box[2] = .5f+zoom_x; dev->gui_module->color_picker_box[3] = .5f+zoom_y; } else { dev->gui_module->color_picker_point[0] = .5f+zoom_x; dev->gui_module->color_picker_point[1] = .5f+zoom_y; dev->preview_pipe->changed |= DT_DEV_PIPE_SYNCH; dt_dev_invalidate_all(dev); } dt_control_queue_redraw(); return 1; } if(dev->gui_module && dev->gui_module->button_pressed) handled = dev->gui_module->button_pressed(dev->gui_module, x, y, which, type, state); if(handled) return handled; if(which == 1 && type == GDK_2BUTTON_PRESS) return 0; if(which == 1) { dt_control_change_cursor(GDK_HAND1); return 1; } if(which == 2) { // zoom to 1:1 2:1 and back dt_dev_zoom_t zoom; int closeup, procw, proch; float zoom_x, zoom_y; DT_CTL_GET_GLOBAL(zoom, dev_zoom); DT_CTL_GET_GLOBAL(closeup, dev_closeup); DT_CTL_GET_GLOBAL(zoom_x, dev_zoom_x); DT_CTL_GET_GLOBAL(zoom_y, dev_zoom_y); dt_dev_get_processed_size(dev, &procw, &proch); const float scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2 : 1, 0); zoom_x += (1.0/scale)*(x - .5f*dev->width )/procw; zoom_y += (1.0/scale)*(y - .5f*dev->height)/proch; if(zoom == DT_ZOOM_1) { if(!closeup) closeup = 1; else { zoom = DT_ZOOM_FIT; zoom_x = zoom_y = 0.0f; closeup = 0; } } else zoom = DT_ZOOM_1; dt_dev_check_zoom_bounds(dev, &zoom_x, &zoom_y, zoom, closeup, NULL, NULL); DT_CTL_SET_GLOBAL(dev_zoom, zoom); DT_CTL_SET_GLOBAL(dev_closeup, closeup); DT_CTL_SET_GLOBAL(dev_zoom_x, zoom_x); DT_CTL_SET_GLOBAL(dev_zoom_y, zoom_y); dt_dev_invalidate(dev); return 1; } return 0; }
void mouse_moved(dt_view_t *self, double x, double y, int which) { const int32_t capwd = darktable.thumbnail_width; const int32_t capht = darktable.thumbnail_height; dt_develop_t *dev = (dt_develop_t *)self->data; // if we are not hovering over a thumbnail in the filmstrip -> show metadata of opened image. int32_t mouse_over_id = -1; DT_CTL_GET_GLOBAL(mouse_over_id, lib_image_mouse_over_id); if(mouse_over_id == -1) { mouse_over_id = dev->image_storage.id; DT_CTL_SET_GLOBAL(lib_image_mouse_over_id, mouse_over_id); } dt_control_t *ctl = darktable.control; const int32_t width_i = self->width; const int32_t height_i = self->height; int32_t offx = 0.0f, offy = 0.0f; if(width_i > capwd) offx = (capwd-width_i) *.5f; if(height_i > capht) offy = (capht-height_i)*.5f; int handled = 0; x += offx; y += offy; if(dev->gui_module && dev->gui_module->request_color_pick && ctl->button_down && ctl->button_down_which == 1) { // module requested a color box float zoom_x, zoom_y, bzoom_x, bzoom_y; dt_dev_get_pointer_zoom_pos(dev, x, y, &zoom_x, &zoom_y); dt_dev_get_pointer_zoom_pos(dev, ctl->button_x + offx, ctl->button_y + offy, &bzoom_x, &bzoom_y); if(darktable.lib->proxy.colorpicker.size) { dev->gui_module->color_picker_box[0] = fmaxf(0.0, fminf(.5f+bzoom_x, .5f+zoom_x)); dev->gui_module->color_picker_box[1] = fmaxf(0.0, fminf(.5f+bzoom_y, .5f+zoom_y)); dev->gui_module->color_picker_box[2] = fminf(1.0, fmaxf(.5f+bzoom_x, .5f+zoom_x)); dev->gui_module->color_picker_box[3] = fminf(1.0, fmaxf(.5f+bzoom_y, .5f+zoom_y)); } else { dev->gui_module->color_picker_point[0] = .5f + zoom_x; dev->gui_module->color_picker_point[1] = .5f + zoom_y; } dev->preview_pipe->changed |= DT_DEV_PIPE_SYNCH; dt_dev_invalidate_all(dev); dt_control_queue_redraw(); return; } if(dev->gui_module && dev->gui_module->mouse_moved) handled = dev->gui_module->mouse_moved(dev->gui_module, x, y, which); if(handled) return; if(darktable.control->button_down && darktable.control->button_down_which == 1) { // depending on dev_zoom, adjust dev_zoom_x/y. dt_dev_zoom_t zoom; int closeup; DT_CTL_GET_GLOBAL(zoom, dev_zoom); DT_CTL_GET_GLOBAL(closeup, dev_closeup); int procw, proch; dt_dev_get_processed_size(dev, &procw, &proch); const float scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2 : 1, 0); float old_zoom_x, old_zoom_y; DT_CTL_GET_GLOBAL(old_zoom_x, dev_zoom_x); DT_CTL_GET_GLOBAL(old_zoom_y, dev_zoom_y); float zx = old_zoom_x - (1.0/scale)*(x - ctl->button_x - offx)/procw; float zy = old_zoom_y - (1.0/scale)*(y - ctl->button_y - offy)/proch; dt_dev_check_zoom_bounds(dev, &zx, &zy, zoom, closeup, NULL, NULL); DT_CTL_SET_GLOBAL(dev_zoom_x, zx); DT_CTL_SET_GLOBAL(dev_zoom_y, zy); ctl->button_x = x - offx; ctl->button_y = y - offy; dt_dev_invalidate(dev); dt_control_queue_redraw(); } }