53#define DT_IOPORDER_GRAPH_NODE_WIDTH DT_PIXEL_APPLY_DPI(260)
54#define DT_IOPORDER_GRAPH_NODE_STEP DT_PIXEL_APPLY_DPI(300)
55#define DT_IOPORDER_GRAPH_LEFT_MARGIN DT_PIXEL_APPLY_DPI(60)
56#define DT_IOPORDER_GRAPH_TOP_MARGIN DT_PIXEL_APPLY_DPI(68)
57#define DT_IOPORDER_GRAPH_MIN_WIDTH DT_PIXEL_APPLY_DPI(640)
58#define DT_IOPORDER_GRAPH_HEIGHT DT_PIXEL_APPLY_DPI(540)
59#define DT_IOPORDER_BAND_HEIGHT DT_PIXEL_APPLY_DPI(26)
60#define DT_IOPORDER_MASK_ARROW_OFFSET DT_PIXEL_APPLY_DPI(12)
61#define DT_IOPORDER_MASK_BOTTOM_MARGIN DT_PIXEL_APPLY_DPI(56)
117 GtkSelectionData *selection_data, guint info, guint time,
122 guint time, gpointer user_data);
124 guint time, gpointer user_data);
127 GtkSelectionData *selection_data, guint info, guint time,
149 if(hitem && hitem->module == module)
return TRUE;
188 if(piece && piece->module == module)
return piece;
205 return _(
"32-bit float");
207 return _(
"16-bit integer");
209 return _(
"8-bit integer");
212 return _(
"unknown type");
231 return _(
"Display RGB");
243 return _(
"unknown colorspace");
255 if(
IS_NULL_PTR(dsc))
return g_strdup(_(
"no runtime descriptor"));
259 if(dsc->
filters == 9u)
return g_strdup(_(
"X-Trans passthrough"));
260 if(dsc->
filters != 0u)
return g_strdup(_(
"Bayer passthrough"));
261 return g_strdup(_(
"no RAW flags"));
264 if(dsc->
filters == 9u)
return g_strdup(_(
"RAW X-Trans"));
265 if(dsc->
filters != 0u)
return g_strdup(_(
"RAW Bayer"));
266 return g_strdup(_(
"RAW monochrome"));
281 const char *display_colorspace)
284 return g_strdup_printf(_(
"%s:\n- runtime descriptor unavailable"), prefix);
287 gchar *text = g_strdup_printf(_(
"%s:\n\t- %s\n\t- %u channels\n\t- %s\n"
288 "\t- max RGB:\n\t\t%.3f\n\t\t%.3f\n\t\t%.3f\n\t- %s"),
290 display_colorspace ? display_colorspace : _(
"runtime unavailable"),
312 const gboolean colorin_crossed,
315 const gboolean after_module)
324 const gboolean in_pipeline_rgb = colorin_crossed || (after_module && !strcmp(module->
op,
"colorin"));
349 return _(
"Sensor RGB");
351 return _(
"Pipeline RGB");
353 return _(
"Display RGB");
355 return _(
"CIE Lab 1976");
357 return _(
"runtime unavailable");
362 return _(
"runtime unavailable");
379 *color = (GdkRGBA){ 0.30, 0.30, 0.30, 0.90 };
382 *color = (GdkRGBA){ 0.14, 0.56, 0.20, 0.96 };
385 *color = (GdkRGBA){ 0.10, 0.38, 0.78, 0.96 };
388 *color = (GdkRGBA){ 0.78, 0.38, 0.10, 0.96 };
391 *color = (GdkRGBA){ 0.72, 0.54, 0.10, 0.96 };
397 *color = (GdkRGBA){ 0.38, 0.38, 0.38, 0.90 };
416 if(profile_a == profile_b)
return TRUE;
437 const gboolean colorin_crossed,
440 const gboolean after_module)
448 const gboolean in_pipeline_rgb = colorin_crossed || (after_module && !strcmp(module->
op,
"colorin"));
470 if(
IS_NULL_PTR(label))
return g_strdup(_(
"runtime unavailable"));
474 if(
IS_NULL_PTR(profile_name) || profile_name[0] ==
'\0')
return g_strdup(label);
476 return g_strdup_printf(
"%s - %s", label, profile_name);
502 d->current_mode =
kind;
513 "SELECT op_params, name"
515 " WHERE operation='ioporder'"
516 " ORDER BY writeprotect DESC, LOWER(name), rowid",
521 while(sqlite3_step(stmt) == SQLITE_ROW)
523 const char *params = (
const char *)sqlite3_column_blob(stmt, 0);
524 const int32_t params_len = sqlite3_column_bytes(stmt, 0);
525 const char *preset_name = (
const char *)sqlite3_column_text(stmt, 1);
532 if(!g_strcmp0(iop_order_list, preset_text))
534 d->current_mode = index;
535 name = g_strdup(preset_name);
543 sqlite3_finalize(stmt);
564 if(!
d->preset_combo ||
IS_NULL_PTR(
d->toolbar_label))
return;
568 gtk_label_set_text(GTK_LABEL(
d->toolbar_label), current_name);
570 d->refreshing_toolbar =
TRUE;
571 gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(
d->preset_combo));
572 gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(
d->preset_combo),
"__custom__", _(
"custom order"));
574 gchar *active_id = g_strdup(
"__custom__");
580 " WHERE operation='ioporder' AND op_version=?1"
581 " ORDER BY writeprotect DESC, LOWER(name), rowid",
587 while(sqlite3_step(stmt) == SQLITE_ROW)
589 const char *preset_name = (
const char *)sqlite3_column_text(stmt, 0);
590 gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(
d->preset_combo), preset_name, preset_name);
591 if(!g_strcmp0(current_name, preset_name))
594 active_id = g_strdup(preset_name);
597 sqlite3_finalize(stmt);
599 gtk_combo_box_set_active_id(GTK_COMBO_BOX(
d->preset_combo), active_id);
600 d->refreshing_toolbar =
FALSE;
615 GList *children = gtk_container_get_children(GTK_CONTAINER(
d->graph_fixed));
616 for(GList *iter = children; iter; iter = g_list_next(iter))
618 gtk_widget_destroy(GTK_WIDGET(iter->data));
620 g_list_free(children);
648 d->toolbar_label = NULL;
649 d->preset_combo = NULL;
650 d->graph_scroll = NULL;
651 d->graph_overlay = NULL;
652 d->graph_drawing = NULL;
653 d->graph_fixed = NULL;
654 d->drag_source = NULL;
710 if(!node || !GTK_IS_TOGGLE_BUTTON(node->module->off))
return;
712 const gboolean active = gtk_toggle_button_get_active(togglebutton);
713 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(node->module->off)) != active)
714 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(node->module->off), active);
726 if(!node || !GTK_IS_TOGGLE_BUTTON(node->module->mask_indicator))
return;
728 const gboolean active = gtk_toggle_button_get_active(togglebutton);
729 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(node->module->mask_indicator)) != active)
730 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(node->module->mask_indicator), active);
742 if(!node || !node->module)
return;
746 GDK_GRAVITY_SOUTH_EAST, GDK_GRAVITY_NORTH_EAST);
760 const char *display_in,
761 const char *display_out)
764 node->module =
module;
767 GtkWidget *event_box = gtk_event_box_new();
772 gchar **split_name = g_strsplit(clean_name,
"-", -1);
773 gchar *module_name = g_strjoinv(
" ", split_name);
774 GtkWidget *label = gtk_label_new(module_name);
776 GtkWidget *instance = gtk_label_new(instance_name);
783 gtk_widget_set_name(body,
"module-header");
787 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE);
790 gtk_widget_set_hexpand(event_box,
FALSE);
791 gtk_widget_set_halign(event_box, GTK_ALIGN_START);
794 gtk_label_set_text(GTK_LABEL(label), module_name);
795 gtk_widget_set_halign(label, GTK_ALIGN_START);
796 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
797 gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
798 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
799 gtk_widget_set_name(label,
"iop-panel-label");
801 gtk_widget_set_halign(instance, GTK_ALIGN_START);
802 gtk_widget_set_visible(instance, instance_name[0] !=
'\0');
803 gtk_label_set_xalign(GTK_LABEL(instance), 0.0f);
804 gtk_label_set_ellipsize(GTK_LABEL(instance), PANGO_ELLIPSIZE_MIDDLE);
805 gtk_label_set_line_wrap(GTK_LABEL(instance),
FALSE);
808 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
enable), module->
enabled);
810 gtk_widget_set_valign(
enable, GTK_ALIGN_CENTER);
812 const gboolean show_masks = (
module->flags() & IOP_FLAGS_SUPPORTS_BLENDING) == IOP_FLAGS_SUPPORTS_BLENDING
813 && module->blend_params
814 && module->blend_params->mask_mode > DEVELOP_MASK_ENABLED;
815 const gboolean show_mask_preview =
module->request_mask_display
816 & (DT_DEV_PIXELPIPE_DISPLAY_MASK | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL);
817 gtk_widget_set_visible(mask, show_masks);
818 gtk_widget_set_sensitive(mask, show_masks && module->
enabled);
819 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mask), show_mask_preview);
820 gtk_widget_set_valign(mask, GTK_ALIGN_CENTER);
821 gtk_widget_set_valign(presets, GTK_ALIGN_CENTER);
823 gtk_widget_set_tooltip_text(
enable, _(
"toggle module"));
824 gtk_widget_set_tooltip_text(mask, _(
"display mask"));
825 gtk_widget_set_tooltip_text(presets, _(
"module presets"));
828 gtk_box_pack_start(GTK_BOX(header), label,
TRUE,
TRUE, 0);
829 gtk_box_pack_end(GTK_BOX(header), presets,
FALSE,
FALSE, 0);
830 gtk_box_pack_end(GTK_BOX(header), mask,
FALSE,
FALSE, 0);
834 GtkWidget *info_in = gtk_label_new(text_in);
835 GtkWidget *info_out = gtk_label_new(text_out);
839 g_strfreev(split_name);
843 gtk_label_set_xalign(GTK_LABEL(info_in), 0.0f);
844 gtk_label_set_xalign(GTK_LABEL(info_out), 0.0f);
845 gtk_label_set_line_wrap(GTK_LABEL(info_in),
TRUE);
846 gtk_label_set_line_wrap(GTK_LABEL(info_out),
TRUE);
847 gtk_label_set_justify(GTK_LABEL(info_in), GTK_JUSTIFY_LEFT);
848 gtk_label_set_justify(GTK_LABEL(info_out), GTK_JUSTIFY_LEFT);
850 gtk_box_pack_start(GTK_BOX(body), header,
FALSE,
FALSE, 0);
851 gtk_box_pack_start(GTK_BOX(body), instance,
FALSE,
FALSE, 0);
852 gtk_box_pack_start(GTK_BOX(body), info_in,
FALSE,
FALSE, 0);
853 gtk_box_pack_start(GTK_BOX(body), info_out,
FALSE,
FALSE, 0);
854 gtk_container_add(GTK_CONTAINER(frame), body);
855 gtk_container_add(GTK_CONTAINER(event_box), frame);
868 g_object_set_data(G_OBJECT(event_box),
"dt-ioporder-module", module);
888 GtkWidget *event_box = gtk_event_box_new();
895 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE);
897 gtk_widget_set_halign(event_box, GTK_ALIGN_START);
898 gtk_widget_set_valign(event_box, GTK_ALIGN_CENTER);
903 gtk_widget_set_name(body,
"ioporder-endpoint");
907 gtk_widget_set_halign(title, GTK_ALIGN_CENTER);
908 gtk_widget_set_valign(title, GTK_ALIGN_CENTER);
909 gtk_label_set_xalign(GTK_LABEL(title), 0.5f);
910 gtk_widget_set_name(title,
"iop-panel-label");
912 gtk_box_pack_start(GTK_BOX(body), title,
TRUE,
TRUE, 0);
913 gtk_container_add(GTK_CONTAINER(frame), body);
914 gtk_container_add(GTK_CONTAINER(event_box), frame);
941 int visible_count = 0;
943 gboolean colorin_crossed =
FALSE;
945 const int base_x =
x;
948 int module_header_center_y = 0;
961 const char *display_in
964 const char *display_out
968 d->nodes = g_list_append(
d->nodes, node);
972 gtk_drag_dest_set(node->
event_box, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
984 if(module_header_center_y == 0)
986 GtkRequisition minimum = { 0 }, natural = { 0 };
987 gtk_widget_get_preferred_size(node->
header, &minimum, &natural);
993 if(!strcmp(module->op,
"colorin")) colorin_crossed =
TRUE;
996 if(module_header_center_y > 0)
997 endpoint_y = module_header_center_y - endpoint_height / 2;
1000 d->nodes = g_list_prepend(
d->nodes, base_node);
1001 gtk_fixed_put(GTK_FIXED(
d->graph_fixed), base_node->
event_box, base_x, endpoint_y);
1002 gtk_widget_show_all(base_node->
event_box);
1007 d->nodes = g_list_append(
d->nodes, screen_node);
1008 gtk_fixed_put(GTK_FIXED(
d->graph_fixed), screen_node->
event_box, screen_x, endpoint_y);
1009 gtk_widget_show_all(screen_node->
event_box);
1019 if(
d->window &&
d->graph_scroll)
1021 GdkDisplay *display = gtk_widget_get_display(
d->window);
1022 GdkWindow *window = gtk_widget_get_window(
d->window);
1026 GdkMonitor *monitor = (display && window) ? gdk_display_get_monitor_at_window(display, window) : NULL;
1029 monitor = gdk_display_get_primary_monitor(display);
1030 if(
IS_NULL_PTR(monitor) && gdk_display_get_n_monitors(display) > 0)
1031 monitor = gdk_display_get_monitor(display, 0);
1034 GdkRectangle geometry = { 0 };
1036 gdk_monitor_get_workarea(monitor, &geometry);
1038 const int viewport_width = geometry.width > 0 ? (int)(geometry.width * 0.88) :
DT_PIXEL_APPLY_DPI(1120);
1039 const int viewport_height = geometry.height > 0 ? (int)(geometry.height * 0.70) :
DT_PIXEL_APPLY_DPI(440);
1040 const int graph_width =
MIN(total_width, viewport_width);
1045 gtk_widget_set_size_request(
d->graph_scroll, graph_width, graph_height);
1046 gtk_window_resize(GTK_WINDOW(
d->window), wanted_width, wanted_height);
1048 gtk_widget_queue_draw(
d->graph_drawing);
1062 const double width,
const double height,
const double radius)
1066 cairo_new_sub_path(cr);
1067 cairo_arc(cr,
x +
width -
r, y +
r,
r, -M_PI_2, 0.0);
1070 cairo_arc(cr,
x +
r, y +
r,
r,
M_PI, 3.0 * M_PI_2);
1071 cairo_close_path(cr);
1087 PangoLayout *layout = gtk_widget_create_pango_layout(widget, text);
1088 cairo_move_to(cr,
x, y);
1089 pango_cairo_show_layout(cr, layout);
1090 g_object_unref(layout);
1103 const double x2,
const double y2)
1105 cairo_move_to(cr, x1, y1);
1106 cairo_line_to(cr, x2, y2);
1109 const double angle = atan2(y2 - y1, x2 - x1);
1112 cairo_move_to(cr, x2, y2);
1113 cairo_line_to(cr, x2 - arrow * cos(angle -
M_PI / 6.0), y2 - arrow * sin(angle -
M_PI / 6.0));
1114 cairo_move_to(cr, x2, y2);
1115 cairo_line_to(cr, x2 - arrow * cos(angle +
M_PI / 6.0), y2 - arrow * sin(angle +
M_PI / 6.0));
1130 const double dx,
const double dy)
1132 GtkAllocation area = { 0 };
1133 gtk_widget_get_allocation(widget, &area);
1135 const double span = fabs(dx - sx);
1138 const double c1x = sx + (dx - sx) * 0.25;
1139 const double c2x = sx + (dx - sx) * 0.75;
1141 cairo_move_to(cr, sx, sy);
1142 cairo_curve_to(cr, c1x, cy, c2x, cy, dx, dy);
1146 const double tx = dx - c2x;
1147 const double ty = dy - cy;
1148 const double angle = atan2(ty, tx);
1150 cairo_move_to(cr, dx, dy);
1151 cairo_line_to(cr, dx - arrow * cos(angle -
M_PI / 6.0), dy - arrow * sin(angle -
M_PI / 6.0));
1152 cairo_move_to(cr, dx, dy);
1153 cairo_line_to(cr, dx - arrow * cos(angle +
M_PI / 6.0), dy - arrow * sin(angle +
M_PI / 6.0));
1156 const double mx = (sx + dx) * 0.5;
1159 cairo_set_source_rgba(cr, 0.12, 0.12, 0.12, 0.85);
1163 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
1185 GtkAllocation area = { 0 };
1186 gtk_widget_get_allocation(widget, &area);
1188 gtk_render_background(gtk_widget_get_style_context(widget), cr, 0.0, 0.0, area.width, area.height);
1192 cairo_set_source_rgb(cr, 0.85, 0.85, 0.85);
1194 _(
"No active or history modules are currently available."));
1202 gboolean colorin_crossed =
FALSE;
1206 gchar *segment_label = NULL;
1207 GdkRGBA segment_color = { 0 };
1208 double segment_x = 0.0;
1209 double segment_width = 0.0;
1212 for(GList *iter =
d->nodes; iter; iter = g_list_next(iter))
1216 GtkAllocation alloc = { 0 };
1217 gtk_widget_get_allocation(node->
event_box, &alloc);
1226 GdkRGBA band_color = { 0 };
1234 cairo_set_source_rgba(cr, segment_color.red, segment_color.green, segment_color.blue, segment_color.alpha);
1238 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
1243 segment_kind = band_kind;
1245 segment_profile = profile_info;
1246 segment_label = band_text;
1247 segment_color = band_color;
1248 segment_x = alloc.x;
1249 segment_width = alloc.width;
1254 segment_width = alloc.x + alloc.width - segment_x;
1256 if(!strcmp(node->module->op,
"colorin")) colorin_crossed =
TRUE;
1261 cairo_set_source_rgba(cr, segment_color.red, segment_color.green, segment_color.blue, segment_color.alpha);
1265 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
1270 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.22);
1274 for(GList *iter =
d->nodes; iter; iter = g_list_next(iter))
1279 GtkAllocation alloc = { 0 };
1280 gtk_widget_get_allocation(node->
event_box, &alloc);
1287 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.90);
1292 for(GList *iter =
d->nodes; iter && g_list_next(iter); iter = g_list_next(iter))
1296 GtkAllocation alloc_a = { 0 }, alloc_b = { 0 }, head_a = { 0 }, head_b = { 0 };
1297 gtk_widget_get_allocation(node_a->
event_box, &alloc_a);
1298 gtk_widget_get_allocation(node_b->
event_box, &alloc_b);
1299 gtk_widget_get_allocation(node_a->
header, &head_a);
1300 gtk_widget_get_allocation(node_b->
header, &head_b);
1301 const double arrow_y_a = node_a->
is_endpoint ? alloc_a.y + alloc_a.height * 0.5
1302 : alloc_a.y + head_a.y + head_a.height * 0.5;
1303 const double arrow_y_b = node_b->
is_endpoint ? alloc_b.y + alloc_b.height * 0.5
1304 : alloc_b.y + head_b.y + head_b.height * 0.5;
1312 cairo_set_source_rgba(cr, 0.95, 0.54, 0.13, 0.92);
1316 for(GList *iter =
d->nodes; iter; iter = g_list_next(iter))
1319 if(source->
is_endpoint || !source->module)
continue;
1320 GtkAllocation source_alloc = { 0 };
1321 gtk_widget_get_allocation(source->
event_box, &source_alloc);
1323 for(GList *consumers =
d->nodes; consumers; consumers = g_list_next(consumers))
1327 if(sink->module->raster_mask.sink.source != source->module)
continue;
1329 GtkAllocation sink_alloc = { 0 };
1330 gtk_widget_get_allocation(sink->
event_box, &sink_alloc);
1333 source_alloc.x + source_alloc.width * 0.5,
1335 sink_alloc.x + sink_alloc.width * 0.5,
1340 if(
d->drag_source &&
d->drag_dest &&
d->drag_source !=
d->drag_dest)
1342 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.95);
1346 for(GList *iter =
d->nodes; iter; iter = g_list_next(iter))
1349 if(node->module !=
d->drag_dest)
continue;
1351 GtkAllocation alloc = { 0 };
1352 gtk_widget_get_allocation(node->
event_box, &alloc);
1353 const double x =
d->drag_source->iop_order <
d->drag_dest->iop_order
1377 GtkSelectionData *selection_data, guint info, guint time,
1381 gtk_selection_data_set(selection_data, gdk_atom_intern(
"ioporder-node",
TRUE), 32,
1382 (
const guchar *)&
value, 1);
1396 d->drag_source = (
dt_iop_module_t *)g_object_get_data(G_OBJECT(widget),
"dt-ioporder-module");
1397 d->drag_dest = NULL;
1398 gtk_widget_queue_draw(
d->graph_drawing);
1412 d->drag_source = NULL;
1413 d->drag_dest = NULL;
1414 gtk_widget_queue_draw(
d->graph_drawing);
1429 guint time, gpointer user_data)
1436 gboolean can_move =
FALSE;
1437 if(module_src && module_dest && module_src != module_dest)
1445 d->drag_dest = can_move ? module_dest : NULL;
1446 gtk_widget_queue_draw(
d->graph_drawing);
1447 gdk_drag_status(dc, can_move ? GDK_ACTION_COPY : 0, time);
1463 guint time, gpointer user_data)
1465 gtk_drag_get_data(widget, dc, gdk_atom_intern(
"ioporder-node",
TRUE), time);
1481 d->drag_dest = NULL;
1482 gtk_widget_queue_draw(
d->graph_drawing);
1502 GtkSelectionData *selection_data, guint info, guint time,
1510 if(module_src && module_dest && module_src != module_dest)
1519 d->drag_source = NULL;
1520 d->drag_dest = NULL;
1536 GtkWidget *dialog = gtk_dialog_new_with_buttons(_(
"save module order preset"), parent,
1537 GTK_DIALOG_DESTROY_WITH_PARENT,
1538 _(
"_cancel"), GTK_RESPONSE_CANCEL,
1539 _(
"_save"), GTK_RESPONSE_ACCEPT, NULL);
1540 GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1543 gtk_entry_set_activates_default(GTK_ENTRY(entry),
TRUE);
1544 gtk_widget_set_hexpand(entry,
TRUE);
1545 gtk_widget_set_tooltip_text(entry, _(
"preset name"));
1547 gtk_widget_show_all(dialog);
1549 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
1552 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
1554 const char *preset_name = gtk_entry_get_text(GTK_ENTRY(entry));
1555 if(preset_name && preset_name[0] !=
'\0')
1558 void *params = self->get_params(self, &
size);
1565 gtk_widget_destroy(dialog);
1578 self->gui_reset(self);
1592 if(
d->refreshing_toolbar)
return;
1594 const gchar *preset_name = gtk_combo_box_get_active_id(combo);
1595 if(!preset_name || !strcmp(preset_name,
"__custom__"))
1614 if(
d->window)
return;
1616 GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1621 GtkWidget *preset_combo = gtk_combo_box_text_new();
1623 GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL);
1625 GtkWidget *drawing = gtk_drawing_area_new();
1628 gtk_window_set_title(GTK_WINDOW(window), _(
"module order"));
1631 gtk_window_set_destroy_with_parent(GTK_WINDOW(window),
TRUE);
1634 gtk_widget_set_halign(label, GTK_ALIGN_START);
1635 gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
1637 gtk_widget_set_hexpand(preset_combo,
TRUE);
1638 gtk_widget_set_hexpand(scroll,
TRUE);
1639 gtk_widget_set_vexpand(scroll,
TRUE);
1640 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1641 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_IN);
1647 gtk_box_pack_start(GTK_BOX(toolbar), label,
FALSE,
FALSE, 0);
1649 gtk_box_pack_start(GTK_BOX(toolbar), preset_combo,
TRUE,
TRUE, 0);
1652 gtk_overlay_add_overlay(GTK_OVERLAY(overlay), fixed);
1653 gtk_container_add(GTK_CONTAINER(overlay), drawing);
1654 gtk_container_add(GTK_CONTAINER(scroll), overlay);
1656 gtk_box_pack_start(GTK_BOX(root), toolbar,
FALSE,
FALSE, 0);
1657 gtk_box_pack_start(GTK_BOX(root), scroll,
TRUE,
TRUE, 0);
1658 gtk_container_add(GTK_CONTAINER(window), root);
1660 g_signal_connect(window,
"delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
1668 d->toolbar_label = label;
1669 d->preset_combo = preset_combo;
1670 d->graph_scroll = scroll;
1671 d->graph_overlay = overlay;
1672 d->graph_drawing = drawing;
1673 d->graph_fixed = fixed;
1694 gtk_widget_show_all(
d->window);
1695 gtk_window_present(GTK_WINDOW(
d->window));
1722 const char *changed_module = (
const char *)module_name;
1723 if(changed_module && strcmp(changed_module, self->
plugin_name) != 0)
return;
1731 return _(
"module order");
1736 static const char *
v[] = {
"special", NULL };
1758 self->
data = (
void *)
d;
1760 d->current_mode = -1;
1786 if(
d->window) gtk_widget_destroy(
d->window);
1808 char *params = NULL;
1864 *
size = (int)p_size;
static const dt_adaptation_t kind
static void add_preset(dt_iop_module_so_t *self, const char *name, const char *pi, const int version, const char *bpi, const int blendop_version)
const char * dt_colorspaces_get_name(dt_colorspaces_color_profile_type_t type, const char *filename)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void reset(dt_view_t *self)
#define DT_MODULE(MODVER)
static void dt_free_gpointer(gpointer ptr)
static gchar * delete_underscore(const char *s)
static const dt_aligned_pixel_simd_t value
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
sqlite3 * dt_database_get(const dt_database_t *db)
#define DT_DEBUG_SQLITE3_PREPARE_V2(a, b, c, d, e)
#define DT_DEBUG_SQLITE3_BIND_INT(a, b, c)
gchar * dt_dev_get_multi_name(const struct dt_iop_module_t *module)
void dtgtk_cairo_paint_module_switch_on(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_presets(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_showmask(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_module_switch(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dt_gui_menu_popup(GtkMenu *menu, GtkWidget *button, GdkGravity widget_anchor, GdkGravity menu_anchor)
void dt_capitalize_label(gchar *text)
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
void dt_gui_presets_popup_menu_show_for_module(dt_iop_module_t *module)
static gboolean enable(dt_image_t *image)
gboolean dt_iop_is_hidden(dt_iop_module_t *module)
gboolean dt_iop_gui_move_module_before(dt_iop_module_t *module, dt_iop_module_t *module_next, const char *reason)
Move a module before another one and commit the GUI-side effects.
gboolean dt_iop_gui_move_module_after(dt_iop_module_t *module, dt_iop_module_t *module_prev, const char *reason)
Move a module after another one and commit the GUI-side effects.
gboolean dt_iop_gui_commit_iop_order_change(dt_develop_t *dev, dt_iop_module_t *module, gboolean enable, gboolean write_history, const char *reason)
Commit the GUI-side consequences of an IOP-order change.
static gboolean dt_iop_colorspace_is_rgb(const dt_iop_colorspace_type_t cst)
void * dt_ioppr_serialize_iop_order_list(GList *iop_order_list, size_t *size)
Serialize an order list into a binary blob (used for presets).
GList * dt_ioppr_get_iop_order_list_version(dt_iop_order_t version)
Return the built-in order list for a given version.
gboolean dt_ioppr_check_can_move_before_iop(GList *iop_list, dt_iop_module_t *module, dt_iop_module_t *module_next)
Validate whether module can be moved before module_next.
gboolean dt_ioppr_check_can_move_after_iop(GList *iop_list, dt_iop_module_t *module, dt_iop_module_t *module_prev)
Validate whether module can be moved after module_prev.
dt_iop_order_t dt_ioppr_get_iop_order_list_kind(GList *iop_order_list)
Determine the kind of an order list by inspecting its content.
char * dt_ioppr_serialize_text_iop_order_list(GList *iop_order_list)
Serialize an order list to a text representation.
const char * dt_iop_order_string(const dt_iop_order_t order)
Return the human-readable name for an IOP order enum value.
GList * dt_ioppr_deserialize_iop_order_list(const char *buf, size_t size)
Deserialize an order list from a binary blob.
void dt_ioppr_change_iop_order(struct dt_develop_t *dev, const int32_t imgid, GList *new_iop_list)
Replace the current order list with a new one and persist it.
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_output_profile_info(const struct dt_dev_pixelpipe_t *pipe)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_work_profile_info(const struct dt_dev_pixelpipe_t *pipe)
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_input_profile_info(const struct dt_dev_pixelpipe_t *pipe)
static gboolean _ioporder_drag_drop(GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint time, gpointer user_data)
Request the drag payload when dropping on a graph node.
static gchar * _ioporder_descriptor_to_text(const char *prefix, const dt_iop_buffer_dsc_t *dsc, const char *display_colorspace)
Build the descriptor list shown below each module node.
#define DT_IOPORDER_GRAPH_HEIGHT
static void _ioporder_free_graph_node(gpointer data)
Release one graph node descriptor.
void gui_reset(dt_lib_module_t *self)
#define DT_IOPORDER_GRAPH_LEFT_MARGIN
int set_params(dt_lib_module_t *self, const void *params, int size)
static gboolean _ioporder_module_in_history(const dt_iop_module_t *module)
Return TRUE when a module already exists in history.
void * get_params(dt_lib_module_t *self, int *size)
#define DT_IOPORDER_MASK_ARROW_OFFSET
static gchar * _ioporder_get_current_order_name(dt_lib_module_t *self)
Retrieve the display name of the current pipeline order.
static void _ioporder_add_preset(GtkButton *button, gpointer user_data)
Save the current pipeline order as a named preset.
static void _ioporder_init_popup(dt_lib_module_t *self)
Build the popup window lazily on first use.
#define DT_IOPORDER_BAND_HEIGHT
static dt_ioporder_runtime_band_kind_t _ioporder_runtime_band_kind(const gboolean raw_input, const gboolean colorin_crossed, const dt_iop_module_t *module, const dt_iop_buffer_dsc_t *dsc, const gboolean after_module)
Classify one runtime descriptor into a stable band kind.
static gboolean _ioporder_same_runtime_profile(const dt_iop_order_iccprofile_info_t *profile_a, const dt_iop_order_iccprofile_info_t *profile_b)
Compare two profile descriptors for lifecycle segment merging.
static const char * _ioporder_colorspace_to_string(const dt_iop_colorspace_type_t cst)
Return a human-readable colorspace string for a pixel descriptor.
#define DT_IOPORDER_MASK_BOTTOM_MARGIN
static void _ioporder_reset_order(GtkButton *button, gpointer user_data)
Reset the current order to the default v3.0 order.
static void _ioporder_set_enable_button_icon(GtkWidget *widget, dt_iop_module_t *module)
Apply the same enable-button icon policy used by module headers.
static void _ioporder_refresh_callback(gpointer instance, gpointer user_data)
Central refresh callback for develop-side state changes.
dt_ioporder_runtime_band_kind_t
@ DT_IOPORDER_RUNTIME_BAND_UNAVAILABLE
@ DT_IOPORDER_RUNTIME_BAND_LAB
@ DT_IOPORDER_RUNTIME_BAND_NONE
@ DT_IOPORDER_RUNTIME_BAND_PIPELINE_RGB
@ DT_IOPORDER_RUNTIME_BAND_RAW
@ DT_IOPORDER_RUNTIME_BAND_SENSOR_RGB
@ DT_IOPORDER_RUNTIME_BAND_DISPLAY_RGB
@ DT_IOPORDER_RUNTIME_BAND_OTHER
static void _ioporder_draw_rounded_rect(cairo_t *cr, const double x, const double y, const double width, const double height, const double radius)
Draw a filled rounded rectangle.
static void _ioporder_draw_label(GtkWidget *widget, cairo_t *cr, const double x, const double y, const char *text)
Draw a short label with the widget font on the graph background.
void show_popup(dt_lib_module_t *self)
Open the popup window owned by the ioporder lib.
static void _ioporder_draw_sequence_arrow(cairo_t *cr, const double x1, const double y1, const double x2, const double y2)
Draw a straight sequence arrow between two consecutive module nodes.
static void _ioporder_refresh_toolbar(dt_lib_module_t *self)
Refresh the preset combo and status label in the popup toolbar.
void gui_cleanup(dt_lib_module_t *self)
static void _ioporder_node_toggle_enable(GtkToggleButton *togglebutton, gpointer user_data)
Proxy the module enable state through the real darkroom header widget.
static void _ioporder_apply_preset(GtkComboBox *combo, gpointer user_data)
Apply the preset selected in the popup toolbar combo box.
static gboolean _ioporder_drag_motion(GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint time, gpointer user_data)
Validate the potential drop target while dragging across graph nodes.
static dt_dev_pixelpipe_iop_t * _ioporder_get_preview_piece(dt_iop_module_t *module)
Map a module instance to its preview-pipe piece.
static void _ioporder_drag_leave(GtkWidget *widget, GdkDragContext *dc, guint time, gpointer user_data)
Clear drop feedback when leaving a graph node during drag.
static void _ioporder_runtime_band_color(const dt_ioporder_runtime_band_kind_t kind, GdkRGBA *color)
Pick the color used by the colorspace lifecycle band.
static dt_ioporder_graph_node_t * _ioporder_create_graph_node(dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece, const char *display_in, const char *display_out)
Create one interactive graph node mirroring a module header.
static const char * _ioporder_type_to_string(const dt_iop_buffer_type_t datatype)
Return a human-readable datatype string for a pixel descriptor.
static const dt_iop_order_iccprofile_info_t * _ioporder_runtime_band_profile_info(const gboolean raw_input, const gboolean colorin_crossed, const dt_iop_module_t *module, const dt_iop_buffer_dsc_t *dsc, const gboolean after_module)
Pick the RGB profile metadata that matches one runtime band segment.
static void _ioporder_clear_graph(dt_lib_ioporder_t *d)
Destroy every node widget and free the node descriptors.
void init_presets(dt_lib_module_t *self)
#define DT_IOPORDER_GRAPH_NODE_STEP
static void _ioporder_rebuild_graph(dt_lib_module_t *self)
Refresh the full graph contents from the current darkroom pipeline.
static gchar * _ioporder_raw_flags_to_string(const dt_iop_buffer_dsc_t *dsc)
Format the RAW-specific flags carried by a pixel descriptor.
uint32_t container(dt_lib_module_t *self)
gboolean preset_autoapply(dt_lib_module_t *self)
static void _ioporder_draw_mask_arrow(GtkWidget *widget, cairo_t *cr, const double sx, const double sy, const double dx, const double dy)
Draw a curved raster-mask dependency arrow between two nodes.
static gchar * _ioporder_runtime_band_text(const char *label, const dt_iop_order_iccprofile_info_t *profile_info)
Build the text shown in one colorspace-band segment.
static dt_ioporder_graph_node_t * _ioporder_create_endpoint_node(const char *label)
Create a compact endpoint node used for the graph boundaries.
static void _ioporder_node_toggle_mask(GtkToggleButton *togglebutton, gpointer user_data)
Proxy raster/drawn mask preview toggling through the real module header.
static void _ioporder_node_show_presets(GtkButton *button, gpointer user_data)
Open the standard module preset popup from a graph node.
static const guint _ioporder_target_count
void gui_init(dt_lib_module_t *self)
#define DT_IOPORDER_GRAPH_MIN_WIDTH
const char ** views(dt_lib_module_t *self)
static void _ioporder_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer user_data)
Track the module being dragged from the graph.
static void _ioporder_presets_changed_callback(gpointer instance, gpointer module_name, gpointer user_data)
Refresh the preset toolbar when ioporder presets change.
int expandable(dt_lib_module_t *self)
#define DT_IOPORDER_GRAPH_NODE_WIDTH
static gboolean _ioporder_module_is_graph_visible(const dt_iop_module_t *module)
Apply the active-pipe visibility policy used by modulegroups.
#define DT_IOPORDER_GRAPH_TOP_MARGIN
@ DT_IOPORDER_DND_TARGET_NODE
static gboolean _ioporder_graph_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
Paint the graph background, runtime bands, fences, and arrows.
static const char * _ioporder_runtime_band_label(const dt_ioporder_runtime_band_kind_t kind, const dt_iop_buffer_dsc_t *dsc)
Return the user-visible label for one runtime band kind.
static void _ioporder_popup_destroy(GtkWidget *widget, gpointer user_data)
Drop cached popup widget pointers once GTK destroys the popup.
static void _ioporder_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer user_data)
Reset drag feedback when the source drag ends.
static void _ioporder_drag_data_received(GtkWidget *widget, GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time, gpointer user_data)
Commit a module reorder after dropping on another graph node.
static const GtkTargetEntry _ioporder_target_list[]
static void _ioporder_drag_data_get(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time, gpointer user_data)
Handle drag-data export for the graph node drag and drop.
gboolean dt_handle_dialog_enter(GtkWidget *widget, GdkEventKey *event, gpointer data)
void dt_lib_presets_add(const char *name, const char *plugin_name, const int32_t version, const void *params, const int32_t params_size, gboolean readonly)
gboolean dt_lib_presets_apply(const gchar *preset, const gchar *module_name, int module_version)
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
@ DT_SIGNAL_DEVELOP_INITIALIZE
This signal is raised when darktable.develop is initialized.
@ DT_SIGNAL_DEVELOP_HISTORY_CHANGE
This signal is raised when develop history is changed no param, no returned value.
@ DT_SIGNAL_DEVELOP_IMAGE_CHANGED
This signal is raised when image is changed in darkroom.
@ DT_SIGNAL_DEVELOP_PREVIEW_PIPE_FINISHED
This signal is raised when develop preview pipe process is finished no param, no returned value.
@ DT_SIGNAL_DEVELOP_MODULE_MOVED
This signal is raised when order of modules in pipeline is changed.
@ DT_SIGNAL_PRESETS_CHANGED
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
struct _GtkWidget GtkWidget
struct dt_gui_gtk_t * gui
const struct dt_database_t * db
struct dt_control_signal_t * signals
struct dt_develop_t * develop
dt_iop_buffer_dsc_t dsc_out
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
struct dt_dev_pixelpipe_t * preview_pipe
GtkMenu * presets_popup_menu
dt_iop_buffer_type_t datatype
dt_aligned_pixel_t processed_maximum
int32_t hide_enable_button
GModule *dt_dev_operation_t op
dt_colorspaces_color_profile_type_t type
char filename[DT_IOP_COLOR_ICC_LEN]
dt_iop_module_t *dt_dev_pixelpipe_iop_t * piece
GtkWidget * toolbar_label
dt_iop_module_t * drag_dest
GtkWidget * graph_drawing
GtkWidget * graph_overlay
dt_iop_module_t * drag_source
gboolean refreshing_toolbar
@ DT_UI_CONTAINER_PANEL_LEFT_CENTER