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 = dt_control_get_dev_zoom(); int closeup = dt_control_get_dev_closeup(); float zoom_x = dt_control_get_dev_zoom_x(); float zoom_y = dt_control_get_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_control_set_dev_zoom_x(zoom_x); dt_control_set_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(); } }
int mouse_moved(struct dt_iop_module_t *self, double x, double y, double pressure, int which) { dt_iop_graduatednd_gui_data_t *g = (dt_iop_graduatednd_gui_data_t *)self->gui_data; dt_dev_zoom_t zoom = dt_control_get_dev_zoom(); int closeup = dt_control_get_dev_closeup(); float zoom_scale = dt_dev_get_zoom_scale(self->dev, zoom, closeup ? 2 : 1, 1); float pzx, pzy; dt_dev_get_pointer_zoom_pos(self->dev, x, y, &pzx, &pzy); pzx += 0.5f; pzy += 0.5f; // are we dragging something ? if(g->dragging > 0) { if(g->dragging == 1) { // we are dragging xa,ya g->xa = pzx; g->ya = pzy; } else if(g->dragging == 2) { // we are dragging xb,yb g->xb = pzx; g->yb = pzy; } else if(g->dragging == 3) { // we are dragging the entire line g->xa += pzx - g->oldx; g->xb += pzx - g->oldx; g->ya += pzy - g->oldy; g->yb += pzy - g->oldy; g->oldx = pzx; g->oldy = pzy; } } else { g->selected = 0; const float ext = DT_PIXEL_APPLY_DPI(0.02f) / zoom_scale; // are we near extermity ? if(pzy > g->ya - ext && pzy < g->ya + ext && pzx > g->xa - ext && pzx < g->xa + ext) { g->selected = 1; } else if(pzy > g->yb - ext && pzy < g->yb + ext && pzx > g->xb - ext && pzx < g->xb + ext) { g->selected = 2; } else if(dist_seg(g->xa, g->ya, g->xb, g->yb, pzx, pzy) < ext * ext * 0.5) g->selected = 3; } dt_control_queue_redraw_center(); return 1; }
static int dt_circle_events_mouse_moved(struct dt_iop_module_t *module, float pzx, float pzy, double pressure, int which, dt_masks_form_t *form, int parentid, dt_masks_form_gui_t *gui, int index) { if(gui->form_dragging || gui->source_dragging) { dt_control_queue_redraw_center(); return 1; } else if(!gui->creation) { dt_dev_zoom_t zoom = dt_control_get_dev_zoom(); int closeup = dt_control_get_dev_closeup(); float zoom_scale = dt_dev_get_zoom_scale(darktable.develop, zoom, 1<<closeup, 1); float as = 0.005f / zoom_scale * darktable.develop->preview_pipe->backbuf_width; int in, inb, near, ins; dt_circle_get_distance(pzx * darktable.develop->preview_pipe->backbuf_width, pzy * darktable.develop->preview_pipe->backbuf_height, as, gui, index, &in, &inb, &near, &ins); if(ins) { gui->form_selected = TRUE; gui->source_selected = TRUE; gui->border_selected = FALSE; } else if(inb) { gui->form_selected = TRUE; gui->border_selected = TRUE; gui->source_selected = FALSE; } else if(in) { gui->form_selected = TRUE; gui->border_selected = FALSE; gui->source_selected = FALSE; } else { gui->form_selected = FALSE; gui->border_selected = FALSE; gui->source_selected = FALSE; } dt_control_queue_redraw_center(); if(!gui->form_selected && !gui->border_selected) return 0; if(gui->edit_mode != DT_MASKS_EDIT_FULL) return 0; return 1; } // add a preview when creating a circle else if(gui->creation) { dt_control_queue_redraw_center(); return 1; } return 0; }
static void _lib_snapshots_add_button_clicked_callback(GtkWidget *widget, gpointer user_data) { dt_lib_module_t *self = (dt_lib_module_t*)user_data; dt_lib_snapshots_t *d = (dt_lib_snapshots_t *)self->data; /* backup last snapshot slot */ dt_lib_snapshot_t last = d->snapshot[d->size-1]; /* rotate slots down to make room for new one on top */ for (int k = d->size-1; k > 0; k--) { GtkWidget *b = d->snapshot[k].button; d->snapshot[k] = d->snapshot[k-1]; d->snapshot[k].button = b; gtk_button_set_label(GTK_BUTTON(d->snapshot[k].button), gtk_button_get_label(GTK_BUTTON(d->snapshot[k-1].button))); } /* update top slot with new snapshot */ char label[64]; GtkWidget *b = d->snapshot[0].button; d->snapshot[0] = last; d->snapshot[0].button = b; const gchar *name = _("original"); if (darktable.develop->history_end > 0) { dt_iop_module_t *module = ((dt_dev_history_item_t *)g_list_nth_data(darktable.develop->history, darktable.develop->history_end-1))->module; if (module) name = module->name(); else name = _("unknown"); } g_snprintf(label,sizeof(label),"%s (%d)", name, darktable.develop->history_end); gtk_button_set_label(GTK_BUTTON(d->snapshot[0].button), label); dt_lib_snapshot_t *s = d->snapshot + 0; s->zoom_y = dt_control_get_dev_zoom_y(); s->zoom_x = dt_control_get_dev_zoom_x(); s->zoom = dt_control_get_dev_zoom(); s->closeup = dt_control_get_dev_closeup(); s->zoom_scale = dt_control_get_dev_zoom_scale(); /* update slots used */ if (d->num_snapshots != d->size) d->num_snapshots++; /* show active snapshot slots */ for (uint32_t k=0; k < d->num_snapshots; k++) gtk_widget_show(d->snapshot[k].button); /* request a new snapshot for top slot */ dt_dev_snapshot_request(darktable.develop, (const char *)&d->snapshot[0].filename); }
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(); }
static void _lib_duplicate_thumb_press_callback(GtkWidget *widget, GdkEventButton *event, dt_lib_module_t *self) { dt_lib_duplicate_t *d = (dt_lib_duplicate_t *)self->data; int imgid = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),"imgid")); if(event->button == 1) { if(event->type == GDK_BUTTON_PRESS) { dt_develop_t *dev = darktable.develop; if(!dev) return; dt_dev_zoom_t zoom; int closeup; float zoom_x, zoom_y; closeup = dt_control_get_dev_closeup(); float scale = 0; zoom = DT_ZOOM_FIT; scale = dt_dev_get_zoom_scale(dev, DT_ZOOM_FIT, 1.0, 0); 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(); dt_dev_invalidate(darktable.develop); d->imgid = imgid; dt_control_queue_redraw_center(); } else if(event->type == GDK_2BUTTON_PRESS) { // to select the duplicate, we reuse the filmstrip proxy _do_select(imgid); } } }
static int dt_group_events_mouse_moved(struct dt_iop_module_t *module, float pzx, float pzy, double pressure, int which, dt_masks_form_t *form, dt_masks_form_gui_t *gui) { dt_dev_zoom_t zoom = dt_control_get_dev_zoom(); int closeup = dt_control_get_dev_closeup(); float zoom_scale = dt_dev_get_zoom_scale(darktable.develop, zoom, closeup ? 2 : 1, 1); float as = 0.005f / zoom_scale * darktable.develop->preview_pipe->backbuf_width; // we first don't do anything if we are inside a scrolling session if(gui->scrollx != 0.0f && gui->scrolly != 0.0f) { float as2 = 0.015f / zoom_scale; if((gui->scrollx - pzx < as2 && gui->scrollx - pzx > -as2) && (gui->scrolly - pzy < as2 && gui->scrolly - pzy > -as2)) return 1; gui->scrollx = gui->scrolly = 0.0f; } // if a form is in edit mode, we first execute the corresponding event if(gui->group_edited >= 0) { // we get the form dt_masks_point_group_t *fpt = (dt_masks_point_group_t *)g_list_nth_data(form->points, gui->group_edited); dt_masks_form_t *sel = dt_masks_get_from_id(darktable.develop, fpt->formid); if(!sel) return 0; int rep = 0; if(sel->type & DT_MASKS_CIRCLE) rep = dt_circle_events_mouse_moved(module, pzx, pzy, pressure, which, sel, fpt->parentid, gui, gui->group_edited); else if(sel->type & DT_MASKS_PATH) rep = dt_path_events_mouse_moved(module, pzx, pzy, pressure, which, sel, fpt->parentid, gui, gui->group_edited); else if(sel->type & DT_MASKS_GRADIENT) rep = dt_gradient_events_mouse_moved(module, pzx, pzy, pressure, which, sel, fpt->parentid, gui, gui->group_edited); else if(sel->type & DT_MASKS_ELLIPSE) rep = dt_ellipse_events_mouse_moved(module, pzx, pzy, pressure, which, sel, fpt->parentid, gui, gui->group_edited); else if(sel->type & DT_MASKS_BRUSH) rep = dt_brush_events_mouse_moved(module, pzx, pzy, pressure, which, sel, fpt->parentid, gui, gui->group_edited); if(rep) return 1; // if a point is in state editing, then we don't want that another form can be selected if(gui->point_edited >= 0) return 0; } // now we check if we are near a form GList *fpts = g_list_first(form->points); int pos = 0; gui->form_selected = gui->border_selected = FALSE; gui->source_selected = gui->source_dragging = FALSE; gui->pivot_selected = FALSE; gui->feather_selected = -1; gui->point_edited = gui->point_selected = -1; gui->seg_selected = -1; gui->point_border_selected = -1; gui->group_edited = gui->group_selected = -1; while(fpts) { dt_masks_point_group_t *fpt = (dt_masks_point_group_t *)fpts->data; dt_masks_form_t *sel = dt_masks_get_from_id(darktable.develop, fpt->formid); int inside, inside_border, near, inside_source; inside = inside_border = inside_source = 0; near = -1; float xx = pzx * darktable.develop->preview_pipe->backbuf_width, yy = pzy * darktable.develop->preview_pipe->backbuf_height; if(sel->type & DT_MASKS_CIRCLE) dt_circle_get_distance(xx, yy, as, gui, pos, &inside, &inside_border, &near, &inside_source); else if(sel->type & DT_MASKS_PATH) dt_path_get_distance(xx, yy, as, gui, pos, g_list_length(sel->points), &inside, &inside_border, &near, &inside_source); else if(sel->type & DT_MASKS_GRADIENT) dt_gradient_get_distance(xx, yy, as, gui, pos, &inside, &inside_border, &near, &inside_source); else if(sel->type & DT_MASKS_ELLIPSE) dt_ellipse_get_distance(xx, yy, as, gui, pos, &inside, &inside_border, &near, &inside_source); else if(sel->type & DT_MASKS_BRUSH) dt_brush_get_distance(xx, yy, as, gui, pos, g_list_length(sel->points), &inside, &inside_border, &near, &inside_source); if(inside || inside_border || near >= 0 || inside_source) { gui->group_edited = gui->group_selected = pos; if(sel->type & DT_MASKS_CIRCLE) return dt_circle_events_mouse_moved(module, pzx, pzy, pressure, which, sel, fpt->parentid, gui, pos); else if(sel->type & DT_MASKS_PATH) return dt_path_events_mouse_moved(module, pzx, pzy, pressure, which, sel, fpt->parentid, gui, pos); else if(sel->type & DT_MASKS_GRADIENT) return dt_gradient_events_mouse_moved(module, pzx, pzy, pressure, which, sel, fpt->parentid, gui, pos); else if(sel->type & DT_MASKS_ELLIPSE) return dt_ellipse_events_mouse_moved(module, pzx, pzy, pressure, which, sel, fpt->parentid, gui, pos); else if(sel->type & DT_MASKS_BRUSH) return dt_brush_events_mouse_moved(module, pzx, pzy, pressure, which, sel, fpt->parentid, gui, pos); } fpts = g_list_next(fpts); pos++; } dt_control_queue_redraw_center(); return 0; }
void gui_post_expose(struct dt_iop_module_t *self, cairo_t *cr, int32_t width, int32_t height, int32_t pointerx, int32_t pointery) { dt_develop_t *dev = self->dev; dt_iop_graduatednd_gui_data_t *g = (dt_iop_graduatednd_gui_data_t *)self->gui_data; dt_iop_graduatednd_params_t *p = (dt_iop_graduatednd_params_t *)self->params; float wd = dev->preview_pipe->backbuf_width; float ht = dev->preview_pipe->backbuf_height; float zoom_y = dt_control_get_dev_zoom_y(); float zoom_x = dt_control_get_dev_zoom_x(); dt_dev_zoom_t zoom = dt_control_get_dev_zoom(); int closeup = dt_control_get_dev_closeup(); float zoom_scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2 : 1, 1); cairo_translate(cr, width / 2.0, height / 2.0f); cairo_scale(cr, zoom_scale, zoom_scale); cairo_translate(cr, -.5f * wd - zoom_x * wd, -.5f * ht - zoom_y * ht); // we get the extremities of the line if(g->define == 0) { if(!set_points_from_grad(self, &g->xa, &g->ya, &g->xb, &g->yb, p->rotation, p->offset)) return; g->define = 1; } float xa = g->xa * wd, xb = g->xb * wd, ya = g->ya * ht, yb = g->yb * ht; // the lines cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); if(g->selected == 3 || g->dragging == 3) cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(5.0) / zoom_scale); else cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(3.0) / zoom_scale); cairo_set_source_rgba(cr, .3, .3, .3, .8); cairo_move_to(cr, xa, ya); cairo_line_to(cr, xb, yb); cairo_stroke(cr); if(g->selected == 3 || g->dragging == 3) cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.0) / zoom_scale); else cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.0) / zoom_scale); cairo_set_source_rgba(cr, .8, .8, .8, .8); cairo_move_to(cr, xa, ya); cairo_line_to(cr, xb, yb); cairo_stroke(cr); // the extremities float x1, y1, x2, y2; float l = sqrt((xb - xa) * (xb - xa) + (yb - ya) * (yb - ya)); const float ext = wd * 0.01f / zoom_scale; x1 = xa + (xb - xa) * ext / l; y1 = ya + (yb - ya) * ext / l; x2 = (xa + x1) / 2.0; y2 = (ya + y1) / 2.0; y2 += (x1 - xa); x2 -= (y1 - ya); cairo_move_to(cr, xa, ya); cairo_line_to(cr, x1, y1); cairo_line_to(cr, x2, y2); cairo_close_path(cr); cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.0) / zoom_scale); if(g->selected == 1 || g->dragging == 1) cairo_set_source_rgba(cr, .8, .8, .8, 1.0); else cairo_set_source_rgba(cr, .8, .8, .8, .5); cairo_fill_preserve(cr); if(g->selected == 1 || g->dragging == 1) cairo_set_source_rgba(cr, .3, .3, .3, 1.0); else cairo_set_source_rgba(cr, .3, .3, .3, .5); cairo_stroke(cr); x1 = xb - (xb - xa) * ext / l; y1 = yb - (yb - ya) * ext / l; x2 = (xb + x1) / 2.0; y2 = (yb + y1) / 2.0; y2 += (xb - x1); x2 -= (yb - y1); cairo_move_to(cr, xb, yb); cairo_line_to(cr, x1, y1); cairo_line_to(cr, x2, y2); cairo_close_path(cr); cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.0) / zoom_scale); if(g->selected == 2 || g->dragging == 2) cairo_set_source_rgba(cr, .8, .8, .8, 1.0); else cairo_set_source_rgba(cr, .8, .8, .8, .5); cairo_fill_preserve(cr); if(g->selected == 2 || g->dragging == 2) cairo_set_source_rgba(cr, .3, .3, .3, 1.0); else cairo_set_source_rgba(cr, .3, .3, .3, .5); cairo_stroke(cr); }
static gboolean _lib_navigation_expose_callback(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { dt_lib_module_t *self = (dt_lib_module_t *)user_data; dt_lib_navigation_t *d = (dt_lib_navigation_t *)self->data; const int inset = DT_NAVIGATION_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width, height = allocation.height; dt_develop_t *dev = darktable.develop; if(dev->preview_status != DT_DEV_PIXELPIPE_VALID) return FALSE; /* get the current style */ GtkStyle *style = gtk_rc_get_style_by_paths(gtk_settings_get_default(), NULL, "GtkWidget", GTK_TYPE_WIDGET); if(!style) style = gtk_rc_get_style(widget); cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(cst); /* fill background */ cairo_set_source_rgb(cr, style->bg[0].red / 65535.0, style->bg[0].green / 65535.0, style->bg[0].blue / 65535.0); cairo_paint(cr); width -= 2 * inset; height -= 2 * inset; cairo_translate(cr, inset, inset); /* draw navigation image if available */ if(dev->preview_pipe->backbuf && (dev->preview_status == DT_DEV_PIXELPIPE_VALID)) { dt_pthread_mutex_t *mutex = &dev->preview_pipe->backbuf_mutex; dt_pthread_mutex_lock(mutex); const int wd = dev->preview_pipe->backbuf_width; const int ht = dev->preview_pipe->backbuf_height; const float scale = fminf(width / (float)wd, height / (float)ht); const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, wd); cairo_surface_t *surface = cairo_image_surface_create_for_data(dev->preview_pipe->backbuf, CAIRO_FORMAT_RGB24, wd, ht, stride); cairo_translate(cr, width / 2.0, height / 2.0f); cairo_scale(cr, scale, scale); cairo_translate(cr, -.5f * wd, -.5f * ht); // draw shadow around float alpha = 1.0f; for(int k = 0; k < 4; k++) { cairo_rectangle(cr, -k / scale, -k / scale, wd + 2 * k / scale, ht + 2 * k / scale); cairo_set_source_rgba(cr, 0, 0, 0, alpha); alpha *= 0.6f; cairo_fill(cr); } cairo_rectangle(cr, 0, 0, wd - 2, ht - 1); cairo_set_source_surface(cr, surface, 0, 0); cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_FAST); cairo_fill(cr); cairo_surface_destroy(surface); dt_pthread_mutex_unlock(mutex); // draw box where we are dt_dev_zoom_t zoom = dt_control_get_dev_zoom(); int closeup = dt_control_get_dev_closeup(); float zoom_x = dt_control_get_dev_zoom_x(); float zoom_y = dt_control_get_dev_zoom_y(); const float min_scale = dt_dev_get_zoom_scale(dev, DT_ZOOM_FIT, closeup ? 2.0 : 1.0, 0); const float cur_scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2.0 : 1.0, 0); // avoid numerical instability for small resolutions: double h, w; if(cur_scale > min_scale) { float boxw = 1, boxh = 1; dt_dev_check_zoom_bounds(darktable.develop, &zoom_x, &zoom_y, zoom, closeup, &boxw, &boxh); cairo_translate(cr, wd * (.5f + zoom_x), ht * (.5f + zoom_y)); cairo_set_source_rgb(cr, 0., 0., 0.); cairo_set_line_width(cr, 1.f / scale); boxw *= wd; boxh *= ht; cairo_rectangle(cr, -boxw / 2 - 1, -boxh / 2 - 1, boxw + 2, boxh + 2); cairo_stroke(cr); cairo_set_source_rgb(cr, 1., 1., 1.); cairo_rectangle(cr, -boxw / 2, -boxh / 2, boxw, boxh); cairo_stroke(cr); } if(fabsf(cur_scale - min_scale) > 0.001f) { /* Zoom % */ cairo_identity_matrix(cr); cairo_translate(cr, 0, height); cairo_set_source_rgba(cr, 1., 1., 1., 0.5); cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size(cr, DT_PIXEL_APPLY_DPI(11)); char zoomline[5]; snprintf(zoomline, sizeof(zoomline), "%.0f%%", cur_scale * 100); cairo_text_extents_t ext; cairo_text_extents(cr, zoomline, &ext); h = d->zoom_h = ext.height; w = d->zoom_w = ext.width; cairo_move_to(cr, width - w - h * 1.1, 0); cairo_save(cr); cairo_set_line_width(cr, 2.0); cairo_set_source_rgb(cr, style->bg[0].red / 65535.0, style->bg[0].green / 65535.0, style->bg[0].blue / 65535.0); cairo_text_path(cr, zoomline); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_fill(cr); cairo_restore(cr); } else { // draw the zoom-to-fit icon cairo_identity_matrix(cr); cairo_translate(cr, 0, height); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_text_extents_t ext; cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size(cr, DT_PIXEL_APPLY_DPI(11)); cairo_text_extents(cr, "100%", &ext); // dummy text, just to get the height h = d->zoom_h = ext.height; w = h * 1.5; float sp = h * 0.6; d->zoom_w = w + sp; cairo_move_to(cr, width - w - h - sp, -1.0 * h); cairo_rectangle(cr, width - w - h - sp, -1.0 * h, w, h); cairo_set_source_rgb(cr, 0.2, 0.2, 0.2); cairo_fill(cr); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_move_to(cr, width - w * 0.8 - h - sp, -1.0 * h); cairo_line_to(cr, width - w - h - sp, -1.0 * h); cairo_line_to(cr, width - w - h - sp, -0.7 * h); cairo_stroke(cr); cairo_move_to(cr, width - w - h - sp, -0.3 * h); cairo_line_to(cr, width - w - h - sp, 0); cairo_line_to(cr, width - w * 0.8 - h - sp, 0); cairo_stroke(cr); cairo_move_to(cr, width - w * 0.2 - h - sp, 0); cairo_line_to(cr, width - h - sp, 0); cairo_line_to(cr, width - h - sp, -0.3 * h); cairo_stroke(cr); cairo_move_to(cr, width - h - sp, -0.7 * h); cairo_line_to(cr, width - h - sp, -1.0 * h); cairo_line_to(cr, width - w * 0.2 - h - sp, -1.0 * h); cairo_stroke(cr); } cairo_move_to(cr, width - 0.95 * h, -0.9 * h); cairo_line_to(cr, width - 0.05 * h, -0.9 * h); cairo_line_to(cr, width - 0.5 * h, -0.1 * h); cairo_fill(cr); } /* blit memsurface into widget */ cairo_destroy(cr); cairo_t *cr_pixmap = gdk_cairo_create(gtk_widget_get_window(widget)); cairo_set_source_surface(cr_pixmap, cst, 0, 0); cairo_paint(cr_pixmap); cairo_destroy(cr_pixmap); cairo_surface_destroy(cst); return TRUE; }
static int dt_ellipse_events_mouse_moved(struct dt_iop_module_t *module, float pzx, float pzy, double pressure, int which, dt_masks_form_t *form, int parentid, dt_masks_form_gui_t *gui, int index) { if(gui->form_dragging || gui->form_rotating || gui->source_dragging || gui->point_dragging >= 1) { gui->posx = pzx * darktable.develop->preview_pipe->backbuf_width; gui->posy = pzy * darktable.develop->preview_pipe->backbuf_height; dt_control_queue_redraw_center(); return 1; } else if(!gui->creation) { dt_dev_zoom_t zoom = dt_control_get_dev_zoom(); int closeup = dt_control_get_dev_closeup(); float zoom_scale = dt_dev_get_zoom_scale(darktable.develop, zoom, closeup ? 2 : 1, 1); float as = 0.005f / zoom_scale * darktable.develop->preview_pipe->backbuf_width; float x = pzx * darktable.develop->preview_pipe->backbuf_width; float y = pzy * darktable.develop->preview_pipe->backbuf_height; int in, inb, near, ins; dt_ellipse_get_distance(pzx * darktable.develop->preview_pipe->backbuf_width, pzy * darktable.develop->preview_pipe->backbuf_height, as, gui, index, &in, &inb, &near, &ins); if(ins) { gui->form_selected = TRUE; gui->source_selected = TRUE; gui->border_selected = FALSE; } else if(inb) { gui->form_selected = TRUE; gui->border_selected = TRUE; gui->source_selected = FALSE; } else if(in) { gui->form_selected = TRUE; gui->border_selected = FALSE; gui->source_selected = FALSE; } else { gui->form_selected = FALSE; gui->border_selected = FALSE; gui->source_selected = FALSE; } // see if we are close to one of the anchor points gui->point_selected = -1; if(gui->form_selected) { dt_masks_form_gui_points_t *gpt = (dt_masks_form_gui_points_t *)g_list_nth_data(gui->points, index); for(int i = 1; i < 5; i++) { if(x - gpt->points[i * 2] > -as && x - gpt->points[i * 2] < as && y - gpt->points[i * 2 + 1] > -as && y - gpt->points[i * 2 + 1] < as) { gui->point_selected = i; break; } } } dt_control_queue_redraw_center(); if(!gui->form_selected && !gui->border_selected) return 0; if(gui->edit_mode != DT_MASKS_EDIT_FULL) return 0; return 1; } return 0; }
static int dt_gradient_events_mouse_moved(struct dt_iop_module_t *module, float pzx, float pzy, double pressure, int which, dt_masks_form_t *form, int parentid, dt_masks_form_gui_t *gui, int index) { if (gui->form_dragging || gui->form_rotating) { gui->posx = pzx*darktable.develop->preview_pipe->backbuf_width; gui->posy = pzy*darktable.develop->preview_pipe->backbuf_height; dt_control_queue_redraw_center(); return 1; } else if (!gui->creation) { dt_dev_zoom_t zoom = dt_control_get_dev_zoom(); int closeup = dt_control_get_dev_closeup(); float zoom_scale = dt_dev_get_zoom_scale(darktable.develop, zoom, closeup ? 2 : 1, 1); float as = 0.005f/zoom_scale*darktable.develop->preview_pipe->backbuf_width; int in,inb,near,ins; float x = pzx*darktable.develop->preview_pipe->backbuf_width; float y = pzy*darktable.develop->preview_pipe->backbuf_height; dt_gradient_get_distance(x, y, as, gui, index, &in, &inb, &near, &ins); dt_masks_form_gui_points_t *gpt = (dt_masks_form_gui_points_t *) g_list_nth_data(gui->points,index); if(gpt && (x - gpt->points[2])*(x - gpt->points[2])+(y - gpt->points[3])*(y - gpt->points[3]) < as*as) { gui->pivot_selected = TRUE; gui->form_selected = TRUE; gui->border_selected = FALSE; } else if(gpt && (x - gpt->points[4])*(x - gpt->points[4])+(y - gpt->points[5])*(y - gpt->points[5]) < as*as) { gui->pivot_selected = TRUE; gui->form_selected = TRUE; gui->border_selected = FALSE; } else if (in) { gui->pivot_selected = FALSE; gui->form_selected = TRUE; gui->border_selected = FALSE; } else if (inb) { gui->pivot_selected = FALSE; gui->form_selected = TRUE; gui->border_selected = TRUE; } else { gui->pivot_selected = FALSE; gui->form_selected = FALSE; gui->border_selected = FALSE; } dt_control_queue_redraw_center(); if (!gui->form_selected && !gui->border_selected) return 0; if (gui->edit_mode != DT_MASKS_EDIT_FULL) return 0; return 1; } return 0; }
static gboolean _lib_navigation_draw_callback(GtkWidget *widget, cairo_t *crf, gpointer user_data) { dt_lib_module_t *self = (dt_lib_module_t *)user_data; dt_lib_navigation_t *d = (dt_lib_navigation_t *)self->data; const int inset = DT_NAVIGATION_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width, height = allocation.height; dt_develop_t *dev = darktable.develop; /* double buffering of image data: only take new data if valid */ if(dev->preview_pipe->backbuf && dev->preview_status == DT_DEV_PIXELPIPE_VALID) { /* re-allocate in case of changed image dimensions */ if(d->buffer == NULL || dev->preview_pipe->backbuf_width != d->wd || dev->preview_pipe->backbuf_height != d->ht) { g_free(d->buffer); d->wd = dev->preview_pipe->backbuf_width; d->ht = dev->preview_pipe->backbuf_height; d->buffer = g_malloc0((size_t)d->wd * d->ht * 4 * sizeof(unsigned char)); } /* update buffer if new data is available */ if(d->buffer && dev->preview_pipe->input_timestamp > d->timestamp) { dt_pthread_mutex_t *mutex = &dev->preview_pipe->backbuf_mutex; dt_pthread_mutex_lock(mutex); memcpy(d->buffer, dev->preview_pipe->backbuf, (size_t)d->wd * d->ht * 4 * sizeof(unsigned char)); d->timestamp = dev->preview_pipe->input_timestamp; dt_pthread_mutex_unlock(mutex); } } /* get the current style */ cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(cst); GtkStyleContext *context = gtk_widget_get_style_context(widget); gtk_render_background(context, cr, 0, 0, allocation.width, allocation.height); width -= 2 * inset; height -= 2 * inset; cairo_translate(cr, inset, inset); /* draw navigation image if available */ if(d->buffer) { cairo_save(cr); const int wd = d->wd; const int ht = d->ht; const float scale = fminf(width / (float)wd, height / (float)ht); const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, wd); cairo_surface_t *surface = cairo_image_surface_create_for_data(d->buffer, CAIRO_FORMAT_RGB24, wd, ht, stride); cairo_translate(cr, width / 2.0, height / 2.0f); cairo_scale(cr, scale, scale); cairo_translate(cr, -.5f * wd, -.5f * ht); // draw shadow around float alpha = 1.0f; for(int k = 0; k < 4; k++) { cairo_rectangle(cr, -k / scale, -k / scale, wd + 2 * k / scale, ht + 2 * k / scale); cairo_set_source_rgba(cr, 0, 0, 0, alpha); alpha *= 0.6f; cairo_fill(cr); } cairo_rectangle(cr, 0, 0, wd - 2, ht - 1); cairo_set_source_surface(cr, surface, 0, 0); cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_FAST); cairo_fill(cr); cairo_surface_destroy(surface); // draw box where we are dt_dev_zoom_t zoom = dt_control_get_dev_zoom(); int closeup = dt_control_get_dev_closeup(); float zoom_x = dt_control_get_dev_zoom_x(); float zoom_y = dt_control_get_dev_zoom_y(); const float min_scale = dt_dev_get_zoom_scale(dev, DT_ZOOM_FIT, closeup ? 2.0 : 1.0, 0); const float cur_scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2.0 : 1.0, 0); // avoid numerical instability for small resolutions: double h, w; if(cur_scale > min_scale) { float boxw = 1, boxh = 1; dt_dev_check_zoom_bounds(darktable.develop, &zoom_x, &zoom_y, zoom, closeup, &boxw, &boxh); cairo_translate(cr, wd * (.5f + zoom_x), ht * (.5f + zoom_y)); cairo_set_source_rgb(cr, 0., 0., 0.); cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.f / scale)); boxw *= wd; boxh *= ht; cairo_rectangle(cr, -boxw / 2 - 1, -boxh / 2 - 1, boxw + 2, boxh + 2); cairo_stroke(cr); cairo_set_source_rgb(cr, 1., 1., 1.); cairo_rectangle(cr, -boxw / 2, -boxh / 2, boxw, boxh); cairo_stroke(cr); } cairo_restore(cr); if(fabsf(cur_scale - min_scale) > 0.001f) { /* Zoom % */ PangoLayout *layout; PangoRectangle ink; PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc); pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD); layout = pango_cairo_create_layout(cr); const float fontsize = DT_PIXEL_APPLY_DPI(11); pango_font_description_set_absolute_size(desc, fontsize * PANGO_SCALE); pango_layout_set_font_description(layout, desc); cairo_translate(cr, 0, height); cairo_set_source_rgba(cr, 1., 1., 1., 0.5); cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); char zoomline[5]; snprintf(zoomline, sizeof(zoomline), "%.0f%%", cur_scale * 100); pango_layout_set_text(layout, zoomline, -1); pango_layout_get_pixel_extents(layout, &ink, NULL); h = d->zoom_h = ink.height; w = d->zoom_w = ink.width; cairo_move_to(cr, width - w - h * 1.1 - ink.x, - fontsize); cairo_save(cr); cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.0)); GdkRGBA *color; gtk_style_context_get(context, gtk_widget_get_state_flags(widget), "background-color", &color, NULL); gdk_cairo_set_source_rgba(cr, color); pango_cairo_layout_path(cr, layout); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_fill(cr); cairo_restore(cr); gdk_rgba_free(color); pango_font_description_free(desc); g_object_unref(layout); } else { // draw the zoom-to-fit icon cairo_translate(cr, 0, height); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); static int height = -1; if(height == -1) { PangoLayout *layout; PangoRectangle ink; PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc); pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD); layout = pango_cairo_create_layout(cr); pango_font_description_set_absolute_size(desc, DT_PIXEL_APPLY_DPI(11) * PANGO_SCALE); pango_layout_set_font_description(layout, desc); pango_layout_set_text(layout, "100%", -1); // dummy text, just to get the height pango_layout_get_pixel_extents(layout, &ink, NULL); height = ink.height; pango_font_description_free(desc); g_object_unref(layout); } h = d->zoom_h = height; w = h * 1.5; float sp = h * 0.6; d->zoom_w = w + sp; cairo_move_to(cr, width - w - h - sp, -1.0 * h); cairo_rectangle(cr, width - w - h - sp, -1.0 * h, w, h); cairo_set_source_rgb(cr, 0.2, 0.2, 0.2); cairo_fill(cr); cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.0)); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_move_to(cr, width - w * 0.8 - h - sp, -1.0 * h); cairo_line_to(cr, width - w - h - sp, -1.0 * h); cairo_line_to(cr, width - w - h - sp, -0.7 * h); cairo_stroke(cr); cairo_move_to(cr, width - w - h - sp, -0.3 * h); cairo_line_to(cr, width - w - h - sp, 0); cairo_line_to(cr, width - w * 0.8 - h - sp, 0); cairo_stroke(cr); cairo_move_to(cr, width - w * 0.2 - h - sp, 0); cairo_line_to(cr, width - h - sp, 0); cairo_line_to(cr, width - h - sp, -0.3 * h); cairo_stroke(cr); cairo_move_to(cr, width - h - sp, -0.7 * h); cairo_line_to(cr, width - h - sp, -1.0 * h); cairo_line_to(cr, width - w * 0.2 - h - sp, -1.0 * h); cairo_stroke(cr); } cairo_move_to(cr, width - 0.95 * h, -0.9 * h); cairo_line_to(cr, width - 0.05 * h, -0.9 * h); cairo_line_to(cr, width - 0.5 * h, -0.1 * h); cairo_fill(cr); } /* blit memsurface into widget */ cairo_destroy(cr); cairo_set_source_surface(crf, cst, 0, 0); cairo_paint(crf); cairo_surface_destroy(cst); return TRUE; }