61#define DT_LIB_SNAPSHOTS_COUNT 4
62#define SNAP_LOG(...) dt_print(DT_DEBUG_DEV, __VA_ARGS__)
63#define HANDLE_SIZE DT_PIXEL_APPLY_DPI_DPP(36)
136 SNAP_LOG(
"[snapshots] capture failed: invalid inputs snapshot=%p source=%p\n", (
void *)snapshot,
152 GList *history_copy = NULL;
153 GList *iop_order_copy = NULL;
154 int32_t history_end = 0;
167 history_copy, iop_order_copy, history_end);
170 SNAP_LOG(
"[snapshots] capture: imgid=%d history_end=%d image=%s\n",
178 return _(
"Snapshots");
183 static const char *
v[] = {
"darkroom", NULL};
198static void _draw_sym(cairo_t *cr,
float x,
float y, gboolean vertical, gboolean inverted)
200 const double inv = inverted ? -0.1 : 1.0;
204 pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
206 PangoLayout *layout = pango_cairo_create_layout(cr);
207 pango_layout_set_font_description(layout, desc);
208 pango_layout_set_text(layout, C_(
"snapshot sign",
"S"), -1);
209 pango_layout_get_pixel_extents(layout, &ink, NULL);
217 pango_cairo_show_layout(cr, layout);
218 pango_font_description_free(desc);
219 g_object_unref(layout);
230 if(
d->selected >= 1 &&
d->selected <=
d->size)
235 float image_box[4] = { 0.0f };
237 if(image_box[2] <= 0.0f || image_box[3] <= 0.0f)
return;
238 d->vp_x = image_box[0];
239 d->vp_y = image_box[1];
240 d->vp_width = image_box[2];
241 d->vp_height = image_box[3];
243 const double split_x = CLAMP(
d->vp_xpointer, 0.0, 1.0);
244 const double split_y = CLAMP(
d->vp_ypointer, 0.0, 1.0);
249 double w =
d->vp_width;
250 double h =
d->vp_height;
253 x =
d->inverted ?
d->vp_x +
d->vp_width * split_x :
d->vp_x;
254 w =
d->inverted ?
d->vp_width * (1.0 - split_x) :
d->vp_width * split_x;
258 y =
d->inverted ?
d->vp_y +
d->vp_height * split_y :
d->vp_y;
259 h =
d->inverted ?
d->vp_height * (1.0 - split_y) :
d->vp_height * split_y;
268 cairo_set_line_width(cri, 1.);
272 const double lx =
d->vp_x +
d->vp_width * split_x;
273 const double center =
d->vp_y + 0.5 *
d->vp_height;
275 cairo_move_to(cri, lx,
d->vp_y);
276 cairo_line_to(cri, lx,
d->vp_y +
d->vp_height);
281 cairo_move_to(cri, lx, center -
size);
282 cairo_line_to(cri, lx - (
size * 1.2), center);
283 cairo_line_to(cri, lx, center +
size);
284 cairo_close_path(cri);
291 const double ly =
d->vp_y +
d->vp_height * split_y;
292 const double center =
d->vp_x + 0.5 *
d->vp_width;
294 cairo_move_to(cri,
d->vp_x, ly);
295 cairo_line_to(cri,
d->vp_x +
d->vp_width, ly);
300 cairo_move_to(cri, center -
size, ly);
301 cairo_line_to(cri, center, ly - (
size * 1.2));
302 cairo_line_to(cri, center +
size, ly);
303 cairo_close_path(cri);
313 const gint rx = (
d->vertical ?
d->vp_x +
d->vp_width * split_x :
d->vp_x +
d->vp_width * 0.5)
315 const gint ry = (
d->vertical ?
d->vp_y +
d->vp_height * 0.5 :
d->vp_y +
d->vp_height * split_y)
319 cairo_set_line_width(cri, 0.5);
344 if(!visible_picker &&
d->selected > 0 && which == 1)
349 d->hover_rotation =
FALSE;
363 if(which != 1)
return 0;
369 if(!visible_picker &&
d->selected > 0)
371 if(
d->on_going)
return 1;
372 if(
d->vp_width <= 0.0 ||
d->vp_height <= 0.0)
return 0;
373 if(x < d->vp_x ||
x >
d->vp_x +
d->vp_width || y < d->vp_y || y >
d->vp_y +
d->vp_height)
return 0;
375 const double xp = CLAMP((
x -
d->vp_x) /
d->vp_width, 0.0, 1.0);
376 const double yp = CLAMP((y -
d->vp_y) /
d->vp_height, 0.0, 1.0);
378 if(
d->hover_rotation)
383 d->vertical = !
d->vertical;
414 if(!visible_picker &&
d->selected > 0)
416 if(
d->vp_width <= 0.0 ||
d->vp_height <= 0.0)
return 0;
417 const double xp = CLAMP((
x -
d->vp_x) /
d->vp_width, 0.0, 1.0);
418 const double yp = CLAMP((y -
d->vp_y) /
d->vp_height, 0.0, 1.0);
419 d->hover_rotation =
FALSE;
423 const double split_x = CLAMP(
d->vp_xpointer, 0.0, 1.0);
424 const double split_y = CLAMP(
d->vp_ypointer, 0.0, 1.0);
426 const double rxc =
d->vertical ?
d->vp_x +
d->vp_width * split_x :
d->vp_x +
d->vp_width * 0.5;
427 const double ryc =
d->vertical ?
d->vp_y +
d->vp_height * 0.5 :
d->vp_y +
d->vp_height * split_y;
428 const double dx =
x - rxc;
429 const double dy = y - ryc;
430 d->hover_rotation = (dx * dx + dy * dy) < (handle_mouse * handle_mouse);
448 d->num_snapshots = 0;
450 d->hover_rotation =
FALSE;
452 for(uint32_t
k = 0;
k <
d->size;
k++)
455 gtk_widget_hide(
d->snapshot[
k].row);
456 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->snapshot[
k].button),
FALSE);
466 self->
data = (
void *)
d;
475 d->vp_xpointer = 0.5;
476 d->vp_ypointer = 0.5;
481 d->hover_rotation =
FALSE;
488 _(
"take snapshot to compare with another image "
489 "or the same image at another stage of development"), 0, 0);
491 for(
int k = 0;
k <
d->size;
k++)
493 d->snapshot[
k].button = gtk_toggle_button_new_with_label(
"");
494 GtkWidget *label = gtk_bin_get_child(GTK_BIN(
d->snapshot[
k].button));
495 gtk_widget_set_halign(label, GTK_ALIGN_START);
496 gtk_label_set_xalign(GTK_LABEL(label), 0);
497 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_MIDDLE);
498 gtk_widget_set_hexpand(
d->snapshot[
k].button,
TRUE);
500 g_signal_connect(G_OBJECT(
d->snapshot[
k].button),
"clicked",
503 g_object_set_data(G_OBJECT(
d->snapshot[
k].button),
"snapshot", GINT_TO_POINTER(
k + 1));
507 d->snapshot[
k].delete_button = gtk_button_new();
508 gtk_button_set_relief(GTK_BUTTON(
d->snapshot[
k].delete_button), GTK_RELIEF_NONE);
509 gtk_button_set_image(GTK_BUTTON(
d->snapshot[
k].delete_button),
510 gtk_image_new_from_icon_name(
"user-trash-symbolic", GTK_ICON_SIZE_MENU));
511 gtk_widget_set_tooltip_text(
d->snapshot[
k].delete_button, _(
"remove this snapshot"));
512 g_object_set_data(G_OBJECT(
d->snapshot[
k].delete_button),
"snapshot", GINT_TO_POINTER(
k + 1));
513 g_signal_connect(G_OBJECT(
d->snapshot[
k].delete_button),
"clicked",
516 d->snapshot[
k].row = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
517 gtk_box_pack_start(GTK_BOX(
d->snapshot[
k].row),
d->snapshot[
k].button,
TRUE,
TRUE, 0);
518 gtk_box_pack_start(GTK_BOX(
d->snapshot[
k].row),
d->snapshot[
k].delete_button,
FALSE,
FALSE, 0);
520 gtk_box_pack_start(GTK_BOX(
d->snapshots_box),
d->snapshot[
k].row,
FALSE,
FALSE, 0);
521 gtk_widget_set_no_show_all(
d->snapshot[
k].row,
TRUE);
525 gtk_box_pack_start(GTK_BOX(self->
widget),
528 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(
d->take_button),
TRUE,
TRUE, 0);
550 if(
d->size <= 0)
return;
554 for(
int k =
d->size - 1;
k > 0;
k--)
559 d->snapshot[
k] =
d->snapshot[
k - 1];
560 d->snapshot[
k].row =
r;
561 d->snapshot[
k].button = b;
562 d->snapshot[
k].delete_button = db;
563 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(
d->snapshot[
k].button))),
564 gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(
d->snapshot[
k - 1].button)))));
572 d->snapshot[0] = last;
573 d->snapshot[0].
row =
r;
574 d->snapshot[0].button = b;
575 d->snapshot[0].delete_button = db;
576 const gchar *
name = _(
"original");
577 gchar *dynamic_name = NULL;
592 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(
d->snapshot[0].button))), label);
602 if(
d->num_snapshots !=
d->size)
d->num_snapshots++;
608 for(uint32_t
k = 0;
k <
d->num_snapshots;
k++)
610 gtk_widget_show(
d->snapshot[
k].row);
611 gtk_widget_show(
d->snapshot[
k].button);
612 gtk_widget_show(
d->snapshot[
k].delete_button);
623 const uint32_t which = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),
"snapshot"));
624 if(which < 1 || which >
d->num_snapshots)
return;
625 const uint32_t
p = which - 1;
627 if(
d->selected == which)
d->selected = 0;
628 else if(
d->selected > which)
d->selected--;
640 for(uint32_t
k =
p;
k <
d->num_snapshots - 1;
k++)
645 d->snapshot[
k] =
d->snapshot[
k + 1];
646 d->snapshot[
k].row =
r;
647 d->snapshot[
k].button = b;
648 d->snapshot[
k].delete_button = db;
649 gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(
d->snapshot[
k].button))),
650 gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(
d->snapshot[
k + 1].button)))));
651 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->snapshot[
k].button), (
k + 1) ==
d->selected);
657 const uint32_t last =
d->num_snapshots - 1;
659 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->snapshot[last].button),
FALSE);
660 gtk_widget_hide(
d->snapshot[last].row);
671 int which = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),
"snapshot"));
674 if(gtk_toggle_button_get_active(widget))
677 for(uint32_t
k = 0;
k <
d->size;
k++)
678 if(GTK_WIDGET(widget) !=
d->snapshot[
k].button)
679 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
d->snapshot[
k].button),
FALSE);
684 else if(
d->selected == (uint32_t)which)
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
gboolean dt_iop_color_picker_is_visible(const dt_develop_t *dev)
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
void dt_control_change_cursor_by_name_and_flush(const char *curs_str)
Apply a named cursor immediatelly and flush display updates for immediate feedback.
void dt_control_commit_cursor()
void dt_control_queue_cursor_by_name(const char *curs_str)
Queue a GTK named cursor for the next cursor commit.
uint32_t view(const dt_view_t *self)
#define DT_MODULE(MODVER)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
int32_t dt_dev_get_history_end_ext(struct dt_develop_t *dev)
Get the current history end index (GUI perspective).
void dt_dev_snapshot_draw(dt_dev_snapshot_t *snap, cairo_t *cri, struct dt_develop_t *dev, int32_t width, int32_t height, double clip_x, double clip_y, double clip_w, double clip_h)
void dt_dev_snapshot_clear(dt_dev_snapshot_t *snap)
gboolean dt_dev_snapshot_capture(dt_dev_snapshot_t *snap, int32_t imgid, float scale, GList *history_override, GList *iop_order_override, int32_t history_end_override)
void dt_dev_get_image_box_in_widget(const dt_develop_t *dev, const int32_t width, const int32_t height, float *box)
Get the displayed image rectangle in darkroom widget coordinates.
gchar * dt_history_item_get_name(const struct dt_iop_module_t *module)
static void dt_draw_set_color_overlay(cairo_t *cr, gboolean bright, double alpha)
void dtgtk_cairo_paint_refresh(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
static int dt_pthread_rwlock_unlock(dt_pthread_rwlock_t *rwlock)
static int dt_pthread_rwlock_rdlock(dt_pthread_rwlock_t *rwlock)
GtkWidget * dt_ui_scroll_wrap(GtkWidget *w, gint min_size, char *config_str, dt_ui_resize_mode_t mode)
Wrap a scrollable content widget in a recessed, vertically resizable scrolled window.
#define DT_GUI_MOUSE_EFFECT_RADIUS
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
GList * dt_history_duplicate(GList *hist)
Deep-copy a history list.
GList * dt_ioppr_iop_order_copy_deep(GList *iop_order_list)
Deep-copy an order list.
GtkWidget * dt_action_button_new(dt_lib_module_t *self, const gchar *label, gpointer callback, gpointer data, const gchar *tooltip, guint accel_key, GdkModifierType mods)
float *const restrict const size_t k
static int _lib_snapshot_rotation_cnt
void gui_reset(dt_lib_module_t *self)
static void _draw_sym(cairo_t *cr, float x, float y, gboolean vertical, gboolean inverted)
static void _lib_snapshots_add_button_clicked_callback(GtkWidget *widget, gpointer user_data)
static int _lib_snapshot_capture_state(dt_lib_snapshot_t *snapshot, dt_develop_t *source)
static void _lib_snapshots_toggled_callback(GtkToggleButton *widget, gpointer user_data)
static void _lib_snapshot_reset_fields(dt_lib_snapshot_t *snap)
static void _lib_snapshots_delete_button_clicked_callback(GtkWidget *widget, gpointer user_data)
void gui_cleanup(dt_lib_module_t *self)
static void _lib_snapshot_clear_state(dt_lib_snapshot_t *snap)
int mouse_moved(dt_lib_module_t *self, double x, double y, double pressure, int which)
uint32_t container(dt_lib_module_t *self)
int button_pressed(struct dt_lib_module_t *self, double x, double y, double pressure, int which, int type, uint32_t state)
void gui_init(dt_lib_module_t *self)
const char ** views(dt_lib_module_t *self)
void gui_post_expose(dt_lib_module_t *self, cairo_t *cri, int32_t width, int32_t height, int32_t pointerx, int32_t pointery)
int button_released(struct dt_lib_module_t *self, double x, double y, int which, uint32_t state)
struct _GtkWidget GtkWidget
const float uint32_t state[4]
struct dt_bauhaus_t * bauhaus
struct dt_develop_t * develop
struct dt_view_manager_t * view_manager
PangoFontDescription * pango_font_desc
cairo_surface_t * display_image
dt_pthread_rwlock_t history_mutex
GtkWidget * delete_button
dt_lib_snapshot_t * snapshot
GtkWidget * snapshots_box
struct dt_view_manager_t::@69 proxy
void(* set_default_cursor)(struct dt_view_t *view, double x, double y)
struct dt_view_manager_t::@69::@72 darkroom
@ DT_UI_CONTAINER_PANEL_LEFT_CENTER