59#include <gdk/gdkkeysyms.h>
148 const int new_version)
160 return _(
"reframe|distortion");
166 _(
"linear, RGB, scene-referred"), _(
"geometric, RGB"),
167 _(
"linear, RGB, scene-referred"));
200 g->clip_w =
p->cw -
p->cx;
202 g->clip_h =
p->ch -
p->cy;
216 const float wd = (float)mod_out.
width;
217 const float ht = (float)mod_out.
height;
219 const float bbox_left =
g->clip_x * wd;
220 const float bbox_top =
g->clip_y * ht;
221 const float bbox_right = (
g->clip_x +
g->clip_w) * wd;
222 const float bbox_bottom = (
g->clip_y +
g->clip_h) * ht;
229 if(mod_out.
width < 1 || mod_out.
height < 1)
return;
231 p->cx =
CLAMPF(points[0] / wd, 0.0f, 0.9f);
232 p->cy =
CLAMPF(points[1] / ht, 0.0f, 0.9f);
233 p->cw =
CLAMPF(points[2] / wd, 0.1f, 1.0f);
234 p->ch =
CLAMPF(points[3] / ht, 0.1f, 1.0f);
262 float wp = mod_out.
width;
263 float hp = mod_out.
height;
264 float points[8] = { 0.0f, 0.0f, wp, hp,
p->cx * wp,
p->cy * hp,
p->cw * wp,
p->ch * hp };
270 g->clip_max_x = fmaxf(points[0], 0.0f);
271 g->clip_max_y = fmaxf(points[1], 0.0f);
272 g->clip_max_w = fminf(points[2] - points[0], 1.0f);
273 g->clip_max_h = fminf(points[3] - points[1], 1.0f);
324 roi_out->
x = roi_in->
width *
d->cx;
325 roi_out->
y = roi_in->
height *
d->cy;
328 if(roi_out->
x < 0) roi_out->
x = 0;
329 if(roi_out->
y < 0) roi_out->
y = 0;
338 *left = roi_in->
width *
d->cx;
343 float *
const restrict points,
size_t points_count)
347 float crop_left = 0.f, crop_top = 0.f;
351 if(crop_top == 0 && crop_left == 0)
return 1;
353 for(
size_t i = 0;
i < points_count * 2;
i += 2)
355 points[
i] -= crop_left;
356 points[
i + 1] -= crop_top;
363 float *
const restrict points,
size_t points_count)
367 float crop_left = 0.f, crop_top = 0.f;
371 if(crop_top == 0 && crop_left == 0)
return 1;
373 for(
size_t i = 0;
i < points_count * 2;
i += 2)
375 points[
i] += crop_left;
376 points[
i + 1] += crop_top;
411 roi_in->
x += iw *
d->cx;
412 roi_in->
y += ih *
d->cy;
414 roi_in->
x = CLAMP(roi_in->
x, 0, (
int)floorf(iw));
415 roi_in->
y = CLAMP(roi_in->
y, 0, (
int)floorf(ih));
433 size_t origin[] = { 0, 0, 0 };
434 size_t region[] = { roi_out->
width, roi_out->
height, 1 };
436 if(err != CL_SUCCESS)
goto error;
462 float left = 0.f,
top = 0.f;
464 if(left == 0.f &&
top == 0.f)
return 1;
465 for(
size_t i = 0;
i < points_count * 2;
i += 2)
468 points[
i + 1] -=
top;
476 float left = 0.f,
top = 0.f;
478 if(left == 0.f &&
top == 0.f)
return 1;
479 for(
size_t i = 0;
i < points_count * 2;
i += 2)
482 points[
i + 1] +=
top;
536 if(text && !g_strcmp0(text, _(
"original image")))
538 int proc_iwd = 0, proc_iht = 0;
541 if(!(proc_iwd > 0 && proc_iht > 0))
return 0.0f;
543 if((
p->ratio_d > 0 && proc_iwd > proc_iht) || (
p->ratio_d < 0 && proc_iwd < proc_iht))
544 return (
float)proc_iwd / (float)proc_iht;
546 return (
float)proc_iht / (float)proc_iwd;
556 if(
p->ratio_d == -2 &&
p->ratio_n == -2)
558 if(
p->cw == 1.0 &&
p->cx == 0.0 &&
p->ch == 1.0 &&
p->cy == 0.0)
566 const float whratio = ((float)(iwd - 2 * interpolation->
width) * (
p->cw -
p->cx))
567 / ((float)(iht - 2 * interpolation->
width) * (
p->ch -
p->cy));
568 const float ri = (float)iwd / (
float)iht;
570 const float prec = 0.0003f;
571 if(fabsf(whratio - 3.0f / 2.0f) < prec)
576 else if(fabsf(whratio - 2.0f / 1.0f) < prec)
581 else if(fabsf(whratio - 7.0f / 5.0f) < prec)
586 else if(fabsf(whratio - 4.0f / 3.0f) < prec)
591 else if(fabsf(whratio - 5.0f / 4.0f) < prec)
596 else if(fabsf(whratio - 1.0f / 1.0f) < prec)
601 else if(fabsf(whratio - 16.0f / 9.0f) < prec)
606 else if(fabsf(whratio - 16.0f / 10.0f) < prec)
611 else if(fabsf(whratio - 244.5f / 203.2f) < prec)
616 else if(fabsf(whratio - sqrtf(2.0f)) < prec)
618 p->ratio_d = 14142136;
619 p->ratio_n = 10000000;
621 else if(fabsf(whratio -
PHI) < prec)
623 p->ratio_d = 16180340;
624 p->ratio_n = 10000000;
626 else if(fabsf(whratio - ri) < prec)
639 if(
p->ratio_d == 0 &&
p->ratio_n == 0)
return -1.0f;
640 float d = 1.0f,
n = 1.0f;
643 d = copysignf(iwd,
p->ratio_d);
653 const float dn = copysignf(
MAX(fabsf(
d), fabsf(
n)),
d);
654 const float nn = copysignf(
MIN(fabsf(
d), fabsf(
n)),
n);
670 if(aspect <= 0)
return;
677 if(iwd < iht) aspect = 1.0f / aspect;
681 double clip_x =
MAX(iwd *
g->clip_x / (
float)iwd, 0.0f);
682 double clip_y =
MAX(iht *
g->clip_y / (
float)iht, 0.0f);
683 double clip_w =
MIN(iwd *
g->clip_w / (
float)iwd, 1.0f);
684 double clip_h =
MIN(iht *
g->clip_h / (
float)iht, 1.0f);
687 const double target_h = (
double)iwd *
g->clip_w / ((
double)iht * aspect);
688 const double target_w = (
double)iht *
g->clip_h * aspect / (
double)iwd;
696 clip_x = clip_x + clip_w - (target_w + clip_w) * .5;
697 clip_y = clip_y + clip_h - (target_h + clip_h) * .5;
698 clip_w = (target_w + clip_w) * .5;
699 clip_h = (target_h + clip_h) * .5;
703 clip_y = clip_y + clip_h - (target_h + clip_h) * .5;
704 clip_w = (target_w + clip_w) * .5;
705 clip_h = (target_h + clip_h) * .5;
709 clip_w = (target_w + clip_w) * .5;
710 clip_h = (target_h + clip_h) * .5;
714 clip_h = (target_h + clip_h) * .5;
715 clip_x = clip_x + clip_w - (target_w + clip_w) * .5;
716 clip_w = (target_w + clip_w) * .5;
721 const double off = target_h - clip_h;
722 clip_h = clip_h + off;
723 clip_y = clip_y - .5 * off;
728 const double off = target_w - clip_w;
729 clip_w = clip_w + off;
730 clip_x = clip_x - .5 * off;
733 if(clip_x < g->clip_max_x)
735 const double prev_clip_h = clip_h;
736 clip_h *= (clip_w + clip_x -
g->clip_max_x) / clip_w;
737 clip_w = clip_w + clip_x -
g->clip_max_x;
738 clip_x =
g->clip_max_x;
739 if(grab &
GRAB_TOP) clip_y += prev_clip_h - clip_h;
741 if(clip_y < g->clip_max_y)
743 const double prev_clip_w = clip_w;
744 clip_w *= (clip_h + clip_y -
g->clip_max_y) / clip_h;
745 clip_h = clip_h + clip_y -
g->clip_max_y;
746 clip_y =
g->clip_max_y;
747 if(grab &
GRAB_LEFT) clip_x += prev_clip_w - clip_w;
749 if(clip_x + clip_w >
g->clip_max_x +
g->clip_max_w)
751 const double prev_clip_h = clip_h;
752 clip_h *= (
g->clip_max_x +
g->clip_max_w - clip_x) / clip_w;
753 clip_w =
g->clip_max_x +
g->clip_max_w - clip_x;
754 if(grab &
GRAB_TOP) clip_y += prev_clip_h - clip_h;
756 if(clip_y + clip_h >
g->clip_max_y +
g->clip_max_h)
758 const double prev_clip_w = clip_w;
759 clip_w *= (
g->clip_max_y +
g->clip_max_h - clip_y) / clip_h;
760 clip_h =
g->clip_max_y +
g->clip_max_h - clip_y;
761 if(grab &
GRAB_LEFT) clip_x += prev_clip_w - clip_w;
763 g->clip_x = fmaxf(clip_x, 0.0f);
764 g->clip_y = fmaxf(clip_y, 0.0f);
765 g->clip_w = fminf(clip_w, 1.0f);
766 g->clip_h = fminf(clip_h, 1.0f);
787 const gboolean has_camera_framing
816 return d->cx ==
p->cx &&
d->cy ==
p->cy &&
d->cw ==
p->cw &&
d->ch ==
p->ch;
822 gboolean sep_found =
FALSE;
823 char *
p = (
char *)num;
830 if(sep_found) *
d *= 10;
833 if(!sep_found && ((*
p ==
',') || (*
p ==
'.')))
837 else if(*
p <
'0' || *
p >
'9')
860 int d = abs(
p->ratio_d),
n =
p->ratio_n;
866 const char *c = text;
867 const char *end = text + strlen(text);
868 while(*c !=
':' && *c !=
'/' && c < end) c++;
873 const int dd = atoi(text);
874 const int nn = atoi(c);
876 if(nn == 0 || dd == 0)
878 dt_control_log(_(
"invalid ratio format. it should be \"number:number\""));
892 if(dd == 0 || nn == 0)
894 dt_control_log(_(
"invalid ratio format. it should be a positive number"));
908 while((nn % 2 == 0) && (dd % 2 == 0))
935 for(
const GList *iter =
g->aspect_list; iter; iter = g_list_next(iter))
938 if(g_strcmp0(aspect->
name, text) == 0)
948 if(
d != abs(
p->ratio_d) ||
n !=
p->ratio_n)
965 for(
const GList *iter =
g->aspect_list; iter; iter = g_list_next(iter))
968 if((aspect->
d ==
d) && (aspect->
n ==
n))
983 snprintf(str,
sizeof(str),
"%d:%d %2.2f", abs(
p->ratio_d), abs(
p->ratio_n),
984 (
float)abs(
p->ratio_d) / (
float)abs(
p->ratio_n));
1005 g->clip_w =
g->clip_x +
g->clip_w -
p->cx;
1011 g->clip_w =
p->cw -
g->clip_x;
1016 g->clip_h =
g->clip_y +
g->clip_h -
p->cy;
1022 g->clip_h =
p->ch -
g->clip_y;
1025 else if(w ==
g->aspect_presets)
1064 if(
p->ratio_d == -1 &&
p->ratio_n == -1)
1070 const int d = abs(
p->ratio_d);
1071 const int n =
p->ratio_n;
1075 for(
const GList *iter =
g->aspect_list; iter; iter = g_list_next(iter))
1078 if((aspect->
d ==
d) && (aspect->
n ==
n))
1092 snprintf(str,
sizeof(str),
"%d:%d %2.2f", abs(
p->ratio_d), abs(
p->ratio_n),
1093 (
float)abs(
p->ratio_d) / (
float)abs(
p->ratio_n));
1110 p->ratio_d = -
p->ratio_d;
1121 g->editing = gtk_toggle_button_get_active(button);
1133 gtk_button_set_label(GTK_BUTTON(button), _(
"Cancel"));
1134 gtk_widget_set_sensitive(
g->commit_button,
TRUE);
1151 gtk_button_set_label(GTK_BUTTON(button), _(
"Edit"));
1152 gtk_widget_set_sensitive(
g->commit_button,
FALSE);
1166 gtk_widget_set_sensitive(
g->commit_button,
FALSE);
1176 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->edit_button),
FALSE);
1177 gtk_button_set_label(GTK_BUTTON(
g->edit_button), _(
"Edit"));
1190 if((a->d == 0 || a->d == 1) && a->n == 0)
return -1;
1192 const float ad =
MAX(a->d, a->n);
1193 const float an =
MIN(a->d, a->n);
1194 const float bd =
MAX(b->d, b->n);
1195 const float bn =
MIN(b->d, b->n);
1196 const float aratio = ad / an;
1197 const float bratio = bd / bn;
1199 if(aratio < bratio)
return -1;
1201 const float prec = 0.0003f;
1202 if(fabsf(aratio - bratio) < prec)
return 0;
1210 if(bdim == 0)
return g_strdup(original);
1212 return g_strdup_printf(
"%s %4.2f", original, (
float)adim / (
float)bdim);
1219 g->aspect_list = NULL;
1220 g->clip_x =
g->clip_y =
g->handle_x =
g->handle_y = 0.0;
1221 g->clip_w =
g->clip_h = 1.0;
1222 g->clip_max_x =
g->clip_max_y = 0.0;
1223 g->clip_max_w =
g->clip_max_h = 1.0;
1234 { _(
"freehand"), 0, 0 },
1235 { _(
"original image"), 1, 0 },
1236 { _(
"square"), 1, 1 },
1237 { _(
"7:6, 6x7"), 7, 6 },
1238 { _(
"10:8 in print"), 2445, 2032 },
1239 { _(
"6:5, 5x6"), 6, 5 },
1240 { _(
"5:4, 4x5, 8x10"), 5, 4 },
1241 { _(
"11x14"), 14, 11 },
1242 { _(
"8.5x11, letter"), 110, 85 },
1243 { _(
"4:3, VGA, TV"), 4, 3 },
1245 { _(
"ISO 216, DIN 476, A4"), 14142136, 10000000 },
1246 { _(
"3:2, 4x6, 35mm"), 3, 2 },
1247 { _(
"16:10, 8x5"), 16, 10 },
1248 { _(
"golden cut"), 16180340, 10000000 },
1249 { _(
"5:3, 12x20"), 5, 3 },
1250 { _(
"16:9, HDTV"), 16, 9 },
1251 { _(
"widescreen"), 185, 100 },
1252 { _(
"2:1, Univisium"), 2, 1 },
1253 { _(
"Cinemascope"), 235, 100 },
1254 { _(
"21:9"), 7, 3 },
1255 { _(
"Anamorphic"), 239, 100 },
1256 { _(
"65:24, XPan"), 65, 24 },
1257 { _(
"3:1, panorama"), 3, 1 },
1258 { _(
"4:1, Polyvision"), 4, 1 },
1263 for(
int i = 0;
i < aspects_count;
i++)
1267 aspect->
d = aspects[
i].
d;
1268 aspect->
n = aspects[
i].
n;
1269 g->aspect_list = g_list_append(
g->aspect_list, aspect);
1274 for(GSList *iter = custom_aspects; iter; iter = g_slist_next(iter))
1278 const char *c = nv->
value;
1279 const char *end = nv->
value + strlen(nv->
value);
1280 while(*c !=
':' && *c !=
'/' && c < end) c++;
1287 if(
n == 0 ||
d == 0)
1289 fprintf(stderr,
"invalid ratio format for `%s'. it should be \"number:number\"\n", nv->
key);
1290 dt_control_log(_(
"invalid ratio format for `%s'. it should be \"number:number\""), nv->
key);
1297 g->aspect_list = g_list_append(
g->aspect_list, aspect);
1301 fprintf(stderr,
"invalid ratio format for `%s'. it should be \"number:number\"\n", nv->
key);
1302 dt_control_log(_(
"invalid ratio format for `%s'. it should be \"number:number\""), nv->
key);
1314 for(GList *iter =
g->aspect_list; iter; iter = g_list_next(iter))
1317 int dd =
MIN(aspect->
d, aspect->
n);
1318 int nn =
MAX(aspect->
d, aspect->
n);
1319 if(dd ==
d && nn ==
n)
1323 GList *prev = g_list_previous(iter);
1324 g->aspect_list = g_list_delete_link(
g->aspect_list, iter);
1326 iter = prev ? prev :
g->aspect_list;
1339 for(GList *iter =
g->aspect_list; iter; iter = g_list_next(iter))
1348 gtk_widget_set_tooltip_text(
g->aspect_presets, _(
"set the aspect ratio\n"
1349 "the list is sorted: from most square to least square\n"
1350 "to enter custom aspect ratio open the combobox and type ratio in x:y or decimal format"));
1353 g_signal_connect(G_OBJECT(
g->aspect_presets),
"quad-pressed", G_CALLBACK(
_event_aspect_flip), self);
1354 gtk_box_pack_start(GTK_BOX(box_enabled),
g->aspect_presets,
TRUE,
TRUE, 0);
1358 g->edit_button = gtk_toggle_button_new_with_label(_(
"Edit"));
1359 g_signal_connect(GTK_TOGGLE_BUTTON(
g->edit_button),
"toggled", G_CALLBACK(
_enter_edit_mode), self);
1360 gtk_box_pack_start(GTK_BOX(box),
g->edit_button,
TRUE,
TRUE, 0);
1363 gtk_box_pack_start(GTK_BOX(box),
g->commit_button,
TRUE,
TRUE, 0);
1364 gtk_widget_set_sensitive(
g->commit_button,
FALSE);
1366 gtk_box_pack_end(GTK_BOX(box_enabled), GTK_WIDGET(box),
TRUE,
TRUE, 0);
1372 "plugins/darkroom/crop/expand_margins",
1374 GTK_BOX(box_enabled), GTK_PACK_END);
1376 self->
gui->
widget = GTK_WIDGET(
g->cs.container);
1381 gtk_widget_set_tooltip_text(
g->cx, _(
"the left margin cannot overlap with the right margin"));
1388 gtk_widget_set_tooltip_text(
g->cw, _(
"the right margin cannot overlap with the left margin"));
1393 gtk_widget_set_tooltip_text(
g->cy, _(
"the top margin cannot overlap with the bottom margin"));
1400 gtk_widget_set_tooltip_text(
g->ch, _(
"the bottom margin cannot overlap with the top margin"));
1416 g->aspect_list = NULL;
1422 const float wd,
const float ht)
1424 if(wd == 0.f || ht == 0.f)
return GRAB_NONE;
1427 if(!(pzx < g->clip_x || pzx >
g->clip_x +
g->clip_w || pzy < g->clip_y || pzy >
g->clip_y +
g->clip_h))
1431 const float x_border = (border == 0.f) ? 0.f : border / wd;
1432 const float y_border = (border == 0.f) ? 0.f : border / ht;
1436 if((pzx >=
g->clip_x) && pzx < g->clip_x + x_border)
1439 if((pzy >=
g->clip_y) && pzy < g->clip_y + y_border)
1442 if((pzx <= g->clip_x +
g->clip_w) && (pzx >
g->clip_w +
g->clip_x - x_border))
1445 if((pzy <= g->clip_y +
g->clip_h) && (pzy >
g->clip_h +
g->clip_y - y_border))
1463 if(
g->wd < 1.0 ||
g->ht < 1.0)
return;
1471 const float guide_x =
g->editing ?
g->clip_x *
g->wd : 0;
1472 const float guide_y =
g->editing ?
g->clip_y *
g->ht : 0;
1473 const float guide_w =
g->editing ?
g->clip_w *
g->wd :
g->wd;
1474 const float guide_h =
g->editing ?
g->clip_h *
g->ht :
g->ht;
1476 dt_guides_draw(cr, guide_x, guide_y, guide_w, guide_h, zoom_scale);
1478 if(!
g->editing)
return;
1481 double border_width = dashes / 2.;
1484 float pzxpy[2] = { (float)pointerx, (
float)pointery };
1486 float pzx = pzxpy[0];
1487 float pzy = pzxpy[1];
1488 cairo_set_line_width(cr, border_width);
1492 cairo_set_source_rgba(cr, .1, .1, .1, .8);
1493 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
1494 const float max_x =
g->clip_max_x *
g->wd;
1495 const float max_y =
g->clip_max_y *
g->ht;
1496 const float max_w =
g->clip_max_w *
g->wd;
1497 const float max_h =
g->clip_max_h *
g->ht;
1498 cairo_rectangle(cr, max_x, max_y, max_w, max_h);
1500 const float clip_x =
g->clip_x *
g->wd - border_width / 2.;
1501 const float clip_y =
g->clip_y *
g->ht - border_width / 2.;
1502 const float clip_w =
g->clip_w *
g->wd + border_width;
1503 const float clip_h =
g->clip_h *
g->ht + border_width;
1504 cairo_rectangle(cr, clip_x, clip_y, clip_w, clip_h);
1507 if(
g->clip_x > .0f ||
g->clip_y > .0f ||
g->clip_w < 1.0f ||
g->clip_h < 1.0f)
1509 const float rect_x =
g->clip_x *
g->wd - border_width / 2.;
1510 const float rect_y =
g->clip_y *
g->ht - border_width / 2.;
1511 const float rect_w =
g->clip_w *
g->wd + border_width;
1512 const float rect_h =
g->clip_h *
g->ht + border_width;
1513 cairo_rectangle(cr, rect_x, rect_y, rect_w, rect_h);
1521 char dimensions[16];
1522 dimensions[0] =
'\0';
1523 PangoLayout *layout;
1525 PangoFontDescription *desc = pango_font_description_copy_static(
dt_bauhaus_get_global()->pango_font_desc);
1526 pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
1527 pango_font_description_set_absolute_size(desc,
DT_PIXEL_APPLY_DPI(16) * PANGO_SCALE / zoom_scale);
1528 layout = pango_cairo_create_layout(cr);
1529 pango_layout_set_font_description(layout, desc);
1534 snprintf(dimensions,
sizeof(dimensions),
"%.0f x %.0f", (
float)procw *
g->clip_w, (
float)proch *
g->clip_h);
1536 pango_layout_set_text(layout, dimensions, -1);
1537 pango_layout_get_pixel_extents(layout, NULL, &ext);
1538 const float text_w = ext.width;
1541 float xp = (
g->clip_x +
g->clip_w * .5f) *
g->wd - text_w * .5f;
1542 float yp = (
g->clip_y +
g->clip_h * .5f) *
g->ht - text_h * .5f;
1549 cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
1550 xp =
CLAMPF(xp, x1 + 2.0 * margin, x2 - text_w - 2.0 * margin);
1551 yp =
CLAMPF(yp, y1 + 2.0 * margin, y2 - text_h - 2.0 * margin);
1553 cairo_set_source_rgba(cr, .5, .5, .5, .9);
1555 cairo_set_source_rgb(cr, .7, .7, .7);
1556 cairo_move_to(cr, xp, yp);
1557 pango_cairo_show_layout(cr, layout);
1558 pango_font_description_free(desc);
1559 g_object_unref(layout);
1569 const float clip_x_px =
g->clip_x *
g->wd;
1570 const float clip_y_px =
g->clip_y *
g->ht;
1571 const float clip_w_px =
g->clip_w *
g->wd;
1572 const float clip_h_px =
g->clip_h *
g->ht;
1573 const float clip_right_px = clip_x_px + clip_w_px;
1574 const float clip_bottom_px = clip_y_px + clip_h_px;
1576 if(grab ==
GRAB_LEFT) cairo_rectangle(cr, clip_x_px, clip_y_px, border, clip_h_px);
1577 if(grab ==
GRAB_TOP) cairo_rectangle(cr, clip_x_px, clip_y_px, clip_w_px, border);
1578 if(grab ==
GRAB_TOP_LEFT) cairo_rectangle(cr, clip_x_px, clip_y_px, border, border);
1579 if(grab ==
GRAB_RIGHT) cairo_rectangle(cr, clip_right_px - border, clip_y_px, border, clip_h_px);
1580 if(grab ==
GRAB_BOTTOM) cairo_rectangle(cr, clip_x_px, clip_bottom_px - border, clip_w_px, border);
1581 if(grab ==
GRAB_BOTTOM_RIGHT) cairo_rectangle(cr, clip_right_px - border, clip_bottom_px - border, border, border);
1582 if(grab ==
GRAB_TOP_RIGHT) cairo_rectangle(cr, clip_right_px - border, clip_y_px, border, border);
1583 if(grab ==
GRAB_BOTTOM_LEFT) cairo_rectangle(cr, clip_x_px, clip_bottom_px - border, border, border);
1591 if(!
g->editing)
return 0;
1593 float pzxpy[2] = { (float)
x, (
float)y };
1595 float pzx = pzxpy[0];
1596 float pzy = pzxpy[1];
1608 const float bzx =
g->button_down_zoom_x;
1609 const float bzy =
g->button_down_zoom_y;
1616 = fminf(
g->clip_max_w +
g->clip_max_x -
g->clip_w,
1617 fmaxf(
g->clip_max_x,
g->handle_x + pzx - bzx));
1621 = fminf(
g->clip_max_h +
g->clip_max_y -
g->clip_h,
1622 fmaxf(
g->clip_max_y,
g->handle_y + pzy - bzy));
1634 xx = (
g->cropping &
GRAB_LEFT) ? (pzx - bzx) : (bzx - pzx);
1636 yy = (
g->cropping &
GRAB_TOP) ? (pzy - bzy) : (bzy - pzy);
1638 float ratio = fmaxf((
g->prev_clip_w - 2.0f * xx) /
g->prev_clip_w,
1639 (
g->prev_clip_h - 2.0f * yy) /
g->prev_clip_h);
1642 if(
g->prev_clip_w * ratio < 0.1f) ratio = 0.1f /
g->prev_clip_w;
1643 if(
g->prev_clip_h * ratio < 0.1f) ratio = 0.1f /
g->prev_clip_h;
1646 if(
g->prev_clip_w * ratio >
g->clip_max_w) ratio =
g->clip_max_w /
g->prev_clip_w;
1647 if(
g->prev_clip_h * ratio >
g->clip_max_h) ratio =
g->clip_max_h /
g->prev_clip_h;
1650 float nx =
g->prev_clip_x - (
g->prev_clip_w * ratio -
g->prev_clip_w) / 2.0f;
1651 float ny =
g->prev_clip_y - (
g->prev_clip_h * ratio -
g->prev_clip_h) / 2.0f;
1652 float nw =
g->prev_clip_w * ratio;
1653 float nh =
g->prev_clip_h * ratio;
1656 nx = fmaxf(nx,
g->clip_max_x);
1658 nx = fminf(nx,
g->clip_max_w +
g->clip_max_x - nw);
1660 ny = fmaxf(ny,
g->clip_max_y);
1662 ny = fminf(ny,
g->clip_max_h +
g->clip_max_y - nh);
1673 const float old_clip_x =
g->clip_x;
1674 g->clip_x = fminf(fmaxf(
g->clip_max_x, pzx -
g->handle_x),
g->clip_x +
g->clip_w - 0.1f);
1675 g->clip_w = old_clip_x +
g->clip_w -
g->clip_x;
1679 const float old_clip_y =
g->clip_y;
1680 g->clip_y = fminf(fmaxf(
g->clip_max_y, pzy -
g->handle_y),
g->clip_y +
g->clip_h - 0.1f);
1681 g->clip_h = old_clip_y +
g->clip_h -
g->clip_y;
1684 g->clip_w = fmaxf(0.1f, fminf(
g->clip_max_w +
g->clip_max_x, pzx -
g->clip_x -
g->handle_x));
1686 g->clip_h = fmaxf(0.1f, fminf(
g->clip_max_h +
g->clip_max_y, pzy -
g->clip_y -
g->handle_y));
1689 if(
g->clip_x +
g->clip_w >
g->clip_max_w +
g->clip_max_x)
1690 g->clip_w =
g->clip_max_w +
g->clip_max_x -
g->clip_x;
1691 if(
g->clip_y +
g->clip_h >
g->clip_max_h +
g->clip_max_y)
1692 g->clip_h =
g->clip_max_h +
g->clip_max_y -
g->clip_y;
1742 if(!
g->editing)
return 0;
1762 if(!
g->editing)
return 0;
1765 if(
type == GDK_2BUTTON_PRESS && which == 1)
1771 float pzxpy[2] = { (float)
x, (
float)y };
1773 float pzx = pzxpy[0];
1774 float pzy = pzxpy[1];
1777 g->button_down_x =
x;
1778 g->button_down_y = y;
1780 g->button_down_zoom_x = pzx;
1781 g->button_down_zoom_y = pzy;
1784 g->prev_clip_x =
g->clip_x;
1785 g->prev_clip_y =
g->clip_y;
1786 g->prev_clip_w =
g->clip_w;
1787 g->prev_clip_h =
g->clip_h;
1806 g->handle_x =
g->clip_x;
1807 g->handle_y =
g->clip_y;
1811 if(
g->cropping &
GRAB_LEFT)
g->handle_x = pzx -
g->clip_x;
1812 if(
g->cropping &
GRAB_TOP)
g->handle_y = pzy -
g->clip_y;
1813 if(
g->cropping &
GRAB_RIGHT)
g->handle_x = pzx - (
g->clip_w +
g->clip_x);
1814 if(
g->cropping &
GRAB_BOTTOM)
g->handle_y = pzy - (
g->clip_h +
g->clip_y);
1836 if(!
g->editing)
return 0;
Handle default and user-set shortcuts (accelerators)
static void error(char *msg)
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
void dt_bauhaus_combobox_set_editable(GtkWidget *widget, int editable)
void dt_bauhaus_combobox_set_text(GtkWidget *widget, const char *text)
int dt_bauhaus_combobox_get(GtkWidget *widget)
void dt_bauhaus_widget_set_quad_toggle(GtkWidget *widget, int toggle)
void dt_bauhaus_slider_set_offset(GtkWidget *widget, float offset)
void dt_bauhaus_slider_set_soft_max(GtkWidget *widget, float val)
void dt_bauhaus_slider_set_soft_min(GtkWidget *widget, float val)
const char * dt_bauhaus_combobox_get_text(GtkWidget *widget)
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
void dt_bauhaus_widget_set_quad_paint(GtkWidget *widget, dt_bauhaus_quad_paint_f f, int paint_flags, void *paint_data)
void dt_bauhaus_slider_set_factor(GtkWidget *widget, float factor)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_gui_new_collapsible_section(dt_gui_collapsible_section_t *cs, const char *confname, const char *label, GtkBox *parent, GtkPackType pack)
Create a collapsible section and pack it into the parent box.
void dt_gui_update_collapsible_section(dt_gui_collapsible_section_t *cs)
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_conf_string_entry_free(gpointer data)
Free one dt_conf_string_entry_t. Shaped as a GDestroyNotify so it can be handed to g_slist_free_full(...
void dt_conf_set_int(const char *name, int val)
GSList * dt_conf_all_string_entries(const char *dir)
Every key under dir, as a list of copies.
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
gboolean dt_image_get_usercrop_oriented(const dt_image_t *img, const dt_image_orientation_t orientation, dt_boundingbox_t box)
dt_image_orientation_t dt_image_get_effective_orientation(const dt_image_t *img)
void dt_control_log(const char *msg,...)
void dt_control_queue_redraw_center()
Request a redraw of the centre view.
void dt_control_hinter_message(const struct dt_control_t *s, const char *message)
void dt_control_navigation_redraw()
Request a redraw of the navigation module's widget.
gboolean dt_control_button_down(int which)
Is mouse button which currently held down?
#define dt_control_change_cursor(cursor)
#define dt_control_queue_cursor(cursor)
struct dt_control_t * dt_control_get_global(void)
int operation_tags_filter()
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void _crop_map_size(const dt_iop_crop_data_t *const d, const dt_iop_roi_t *const roi_in, dt_iop_roi_t *roi_out)
Input rect -> output rect. THE size evaluator.
void distort_mask(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, const float *const in, float *const out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
const char ** description(struct dt_iop_module_t *self)
int distort_backtransform(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, float *const restrict points, size_t points_count)
static gchar * _aspect_format(gchar *original, int adim, int bdim)
int distort_transform(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, float *const restrict points, size_t points_count)
static void _float_to_fract(const char *num, int *n, int *d)
static int _crop_geometry_backtransform(const void *data, const dt_geometry_record_t *const record, dt_geometry_chain_t *chain, float *points, size_t points_count)
static void _crop_offset(const dt_iop_crop_data_t *const d, const dt_iop_roi_t *const roi_in, float *left, float *top)
The translation the crop applies, in the input rect's own pixels.
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static const dt_geometry_vtable_t _crop_geometry_vtable
void gui_reset(struct dt_iop_module_t *self)
gboolean geometry_record(dt_iop_module_t *self, const void *params, dt_geometry_record_t *record)
void gui_update(struct dt_iop_module_t *self)
void gui_init(struct dt_iop_module_t *self)
int button_pressed(struct dt_iop_module_t *self, double x, double y, double pressure, int which, int type, uint32_t state)
static void _crop_resolve(dt_iop_module_t *self, const dt_iop_crop_params_t *const p, dt_iop_crop_data_t *out)
Resolve the effective crop rectangle. THE constructor – see the note above.
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
int button_released(struct dt_iop_module_t *self, double x, double y, int which, uint32_t state)
static void _aspect_apply(dt_iop_module_t *self, _grab_region_t grab)
static void _crop_geometry_map_size(const void *data, const dt_iop_roi_t *const in, dt_iop_roi_t *out)
void reload_defaults(dt_iop_module_t *self)
static void _enter_edit_mode(GtkToggleButton *button, struct dt_iop_module_t *self)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
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)
static void _commit_box(dt_iop_module_t *self, dt_iop_crop_gui_data_t *g, dt_iop_crop_params_t *p)
void gui_cleanup(struct dt_iop_module_t *self)
int mouse_leave(struct dt_iop_module_t *self)
static int _crop_geometry_transform(const void *data, const dt_geometry_record_t *const record, dt_geometry_chain_t *chain, float *points, size_t points_count)
static void _aspect_free(gpointer data)
int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
static void _params_to_gui(dt_iop_crop_params_t *p, dt_iop_crop_gui_data_t *g)
static void _event_aspect_presets_changed(GtkWidget *combo, dt_iop_module_t *self)
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void _event_key_swap(dt_iop_module_t *self)
gboolean has_defaults(struct dt_iop_module_t *self)
static gboolean _set_max_clip(struct dt_iop_module_t *self)
this function initializes the maximum clip rectangle from crop parameters and correct the clip rectan...
int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
int mouse_moved(struct dt_iop_module_t *self, double x, double y, double pressure, int which)
static _grab_region_t _gui_get_grab(float pzx, float pzy, dt_iop_crop_gui_data_t *g, const float border, const float wd, const float ht)
static void _event_commit_clicked(GtkButton *button, dt_iop_module_t *self)
static void _event_aspect_flip(GtkWidget *button, dt_iop_module_t *self)
void modify_roi_in(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *roi_out, dt_iop_roi_t *roi_in)
void modify_roi_out(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_out, const dt_iop_roi_t *roi_in)
static gint _aspect_ratio_cmp(const dt_iop_crop_aspect_t *a, const dt_iop_crop_aspect_t *b)
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
static float _aspect_ratio_get(dt_iop_module_t *self, GtkWidget *combo)
gboolean runtime_data_hash(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
#define dt_dev_add_history_item(dev, module, enable, redraw)
#define dt_dev_pixelpipe_resync_history_all(dev)
int32_t dt_dev_roi_request_preview_height(const dt_develop_t *dev)
int32_t dt_dev_roi_request_preview_width(const dt_develop_t *dev)
void dt_dev_get_processed_size(const dt_develop_t *dev, int *procw, int *proch)
void dt_dev_coordinates_preview_abs_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
int dt_dev_get_thumbnail_size(dt_develop_t *dev)
int dt_dev_distort_backtransform_gui(dt_develop_t *dev, const double iop_order, const int transf_direction, float *points, size_t points_count)
The inverse of dt_dev_distort_transform_gui(), same rules.
float dt_dev_get_overlay_scale(dt_develop_t *dev)
Get the overlay scale factor in GUI logical coordinates.
gboolean dt_dev_module_geometry_gui(dt_develop_t *dev, dt_iop_module_t *module, dt_iop_roi_t *in, dt_iop_roi_t *out)
One module's own input and output rectangles at full resolution, from the geometry service.
int dt_dev_distort_transform_gui(dt_develop_t *dev, const double iop_order, const int transf_direction, float *points, size_t points_count)
The GUI's bounded transform folds, composed by the geometry service.
gboolean dt_dev_clip_roi(dt_develop_t *dev, cairo_t *cr, int32_t width, int32_t height)
Clip the view to the ROI. WARNING: this must be done before any translation.
gboolean dt_dev_rescale_roi(dt_develop_t *dev, cairo_t *cr, int32_t width, int32_t height)
Scale the ROI to fit within given width/height, centered.
void dt_dev_coordinates_widget_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
Coordinate conversion helpers between widget, normalized image, and absolute image spaces.
@ DT_DEV_TRANSFORM_DIR_FORW_EXCL
static void dt_draw_set_color_overlay(cairo_t *cr, gboolean bright, double alpha)
static void dt_gui_draw_rounded_rectangle(cairo_t *cr, float width, float height, float x, float y)
Where things are on the image, answered without a pipeline.
void dt_guides_draw(cairo_t *cr, const float left, const float top, const float width, const float height, const float zoom_scale)
float dt_boundingbox_t[4]
@ DT_IMAGE_AUTO_PRESETS_APPLIED
void dt_iop_copy_image_roi(float *const __restrict__ out, const float *const __restrict__ in, const size_t ch, const dt_iop_roi_t *const __restrict__ roi_in, const dt_iop_roi_t *const __restrict__ roi_out, const int zero_pad)
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
void dt_iop_set_cache_bypass(dt_iop_module_t *module, gboolean state)
void dt_iop_request_focus(dt_iop_module_t *module)
Move darkroom focus to module, or clear it with NULL.
@ IOP_FLAGS_GUIDES_SPECIAL_DRAW
@ IOP_FLAGS_TILING_FULL_ROI
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
static dt_iop_gui_data_t * dt_iop_gui_data(const struct dt_iop_module_t *m)
The module's GUI data blob, NULL-safe for headless callers: IOP process() implementations read it for...
#define IOP_GUI_ALLOC(module)
const struct dt_interpolation * dt_interpolation_new(enum dt_interpolation_type type)
@ DT_INTERPOLATION_USERPREF_WARP
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)
_lib_location_type_t type
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
#define CLAMPF(a, mn, mx)
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
static void * dt_calloc_align(size_t size)
dt_alloc_align() followed by a zero fill.
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst, size_t *region)
#define __OMP_PARALLEL_FOR_SIMD__(...)
const float uint32_t state[4]
One key/value pair handed back by dt_conf_all_string_entries().
struct dt_iop_module_t *void * data
One module instance's contribution, as data.
const dt_geometry_vtable_t * vtable
void(* free_data)(void *data)
A module's geometry, evaluated. Pure functions of the record's own data.
void(* map_size)(const void *data, const dt_iop_roi_t *const in, dt_iop_roi_t *out)
Full-resolution input rect -> output rect. Mirrors modify_roi_out() at scale 1.
GtkWidget * aspect_presets
dt_gui_collapsible_section_t cs
GtkWidget * commit_button
dt_iop_crop_params_t previous_params
dt_iop_params_t * default_params
struct dt_iop_module_gui_t * gui
struct dt_develop_t * dev
Region of interest passed through the pixelpipe.
typedef double((*spd)(unsigned long int wavelength, double TempK))