Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
print_settings.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2014-2018, 2020-2022 Pascal Obry.
4 Copyright (C) 2015 Jérémy Rosen.
5 Copyright (C) 2015-2016 Roman Lebedev.
6 Copyright (C) 2015-2020 Tobias Ellinghaus.
7 Copyright (C) 2017-2018, 2021-2022 Dan Torop.
8 Copyright (C) 2017, 2019, 2022 luzpaz.
9 Copyright (C) 2018 Maurizio Paglia.
10 Copyright (C) 2018 rawfiner.
11 Copyright (C) 2019 Denis Dyakov.
12 Copyright (C) 2019 Edgardo Hoszowski.
13 Copyright (C) 2019 jakubfi.
14 Copyright (C) 2019 Pascal de Bruijn.
15 Copyright (C) 2019 Philippe Weyland.
16 Copyright (C) 2020, 2022 Aldric Renaudin.
17 Copyright (C) 2020-2022 Diederik Ter Rahe.
18 Copyright (C) 2020 Hubert Kowalski.
19 Copyright (C) 2020 JP Verrue.
20 Copyright (C) 2021 Ralf Brown.
21 Copyright (C) 2022, 2025 Aurélien PIERRE.
22 Copyright (C) 2022 Martin Bařinka.
23 Copyright (C) 2022 Miloš Komarčević.
24 Copyright (C) 2022 Victor Forsiuk.
25
26 darktable is free software: you can redistribute it and/or modify
27 it under the terms of the GNU General Public License as published by
28 the Free Software Foundation, either version 3 of the License, or
29 (at your option) any later version.
30
31 darktable is distributed in the hope that it will be useful,
32 but WITHOUT ANY WARRANTY; without even the implied warranty of
33 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 GNU General Public License for more details.
35
36 You should have received a copy of the GNU General Public License
37 along with darktable. If not, see <http://www.gnu.org/licenses/>.
38*/
39
40#include "widgets/draw.h"
41#include "common/paths.h" // DT_PATH_MAX
43#include "control/control.h"
44#include "common/conf.h"
45#include "caches/mipmap_cache.h"
46#include <glib.h>
47
48#include "widgets/bauhaus.h"
50#include "common/cups_print.h"
52#include "caches/image_cache.h"
53#include "common/logging.h"
54#include "system/macros.h"
55#include "metadata/metadata.h"
57#include "common/pdf.h"
59#include "common/printing.h"
60#include "common/styles.h"
61#include "metadata/tags.h"
63#include "common/utility.h"
64#include "control/jobs.h"
65
66#include "gui/application.h"
67#include "libs/lib.h"
68#include "libs/lib_api.h"
69#include "views/view.h"
70
71#include <glib/gstdio.h>
72#include "widgets/label.h"
75#include "control/signal.h"
76
77DT_MODULE(4)
78
79const char *name(struct dt_lib_module_t *self)
80{
81 return _("print settings");
82}
83
84const char **views(dt_lib_module_t *self)
85{
86 static const char *v[] = {"print", NULL};
87 return v;
88}
89
94
107
108typedef enum _unit_t
109{
113 UNIT_N // needs to be the last one
115
116
117static const float units[UNIT_N] = { 1.0f, 0.1f, 1.0f/25.4f };
118static const gchar *_unit_names[] = { N_("mm"), N_("cm"), N_("inch"), NULL };
119
156
171
173{
174 dt_colorspaces_color_profile_type_t type; // filename is only used for type DT_COLORSPACE_FILE
175 char filename[512]; // icc file name
176 char name[512]; // product name
177 int pos, ppos; // position in combo boxen
179
181{
182 const char *name;
184
186static void _width_changed(GtkWidget *widget, gpointer user_data);
187static void _height_changed(GtkWidget *widget, gpointer user_data);
188static void _x_changed(GtkWidget *widget, gpointer user_data);
189static void _y_changed(GtkWidget *widget, gpointer user_data);
190
191int
193{
194 return 990;
195}
196
197/* get paper dimension for the orientation (in mm) */
198static void _get_page_dimension(dt_print_info_t *prt, float *width, float *height)
199{
200 if(prt->page.landscape)
201 {
202 *width = prt->paper.height;
203 *height = prt->paper.width;
204 }
205 else
206 {
207 *width = prt->paper.width;
208 *height = prt->paper.height;
209 }
210}
211
212static void _precision_by_unit(_unit_t unit, int *n_digits, float *incr, char **format)
213{
214 // this gives us these precisions
215 // unit precision increment
216 // mm 1 1
217 // cm 0.1 0.1
218 // in 0.01 0.05
219 //
220 // This allows for >= 1mm precision display regardless of unit, and
221 // allows for entering common fractions (e.g. 1/4 as .25) for
222 // inches. Increment is kept to 1mm except in the cases of inches,
223 // where we round up from 0.03937 (1mm) to 0.05 to keep to a factor
224 // of a power of ten.
225 *n_digits = ceilf(log10f(1.0f / units[unit]));
226 if(incr)
227 {
228 *incr = roundf(units[unit] * 20.0f) / 20.0f;
229 }
230 if(format)
231 {
232 *format = g_strdup_printf("%%.%df", *n_digits);
233 }
234}
235
236// unit conversion
237
238static float _to_mm(dt_lib_print_settings_t *ps, double value)
239{
240 return value / units[ps->unit];
241}
242
243// horizontal mm to pixels
244static float _mm_to_hscreen(dt_lib_print_settings_t *ps, const float value, const gboolean offset)
245{
246 float width, height;
248
249 return (offset ? ps->imgs.screen.page.x : 0)
250 + (ps->imgs.screen.page.width * value / width);
251}
252
253// vertical mm to pixels
254static float _mm_to_vscreen(dt_lib_print_settings_t *ps, const float value, const gboolean offset)
255{
256 float width, height;
258
259 return (offset ? ps->imgs.screen.page.y : 0)
260 + (ps->imgs.screen.page.height * value / height);
261}
262
263static float _hscreen_to_mm(dt_lib_print_settings_t *ps, const float value, const gboolean offset)
264{
265 float width, height;
267
268 return width * (value - (offset ? ps->imgs.screen.page.x : 0.0f))
269 / ps->imgs.screen.page.width;
270}
271
272static float _vscreen_to_mm(dt_lib_print_settings_t *ps, const float value, const gboolean offset)
273{
274 float width, height;
276
277 return height * (value - (offset ? ps->imgs.screen.page.y : 0.0f))
278 / ps->imgs.screen.page.height;
279}
280
281
282static inline float _percent_unit_of(dt_lib_print_settings_t *ps, float ref, float value)
283{
284 return value * ref * units[ps->unit];
285}
286
287// callbacks for in-memory export
288
295
297{
298 const dt_print_format_t *d = (dt_print_format_t *)data;
299 return d->bpp;
300}
301
303{
304 const dt_print_format_t *d = (dt_print_format_t *)data;
305 return IMAGEIO_RGB | (d->bpp == 8 ? IMAGEIO_INT8 : IMAGEIO_INT16);
306}
307
308static const char *mime(dt_imageio_module_data_t *data)
309{
310 return "memory";
311}
312
313static int write_image(dt_imageio_module_data_t *data, const char *filename, const void *in,
314 dt_colorspaces_color_profile_type_t over_type, const char *over_filename,
315 void *exif, int exif_len, int32_t imgid, int num, int total, dt_dev_pixelpipe_t *pipe,
316 const gboolean export_masks)
317{
319
320 d->params->buf = (uint16_t *)malloc((size_t)3 * (d->bpp == 8?1:2) * d->head.width * d->head.height);
321
322 if(d->bpp == 8)
323 {
324 const uint8_t *in_ptr = (const uint8_t *)in;
325 uint8_t *out_ptr = (uint8_t *)d->params->buf;
326 for(int y = 0; y < d->head.height; y++)
327 {
328 for(int x = 0; x < d->head.width; x++, in_ptr += 4, out_ptr += 3)
329 memcpy(out_ptr, in_ptr, 3);
330 }
331 }
332 else
333 {
334 const uint16_t *in_ptr = (const uint16_t *)in;
335 uint16_t *out_ptr = (uint16_t *)d->params->buf;
336 for(int y = 0; y < d->head.height; y++)
337 {
338 for(int x = 0; x < d->head.width; x++, in_ptr += 4, out_ptr += 3)
339 memcpy(out_ptr, in_ptr, 6);
340 }
341 }
342
343 return 0;
344}
345
346// export image imgid with given max_width & max_height, set iwidth & iheight with the
347// final image size as exported.
348static int _export_image(dt_job_t *job, dt_image_box *img)
349{
351
353 buf.mime = mime;
354 buf.levels = levels;
355 buf.bpp = bpp;
356 buf.write_image = write_image;
357
359 dat.head.max_width = img->max_width;
360 dat.head.max_height = img->max_height;
361 dat.head.style[0] = '\0';
362 dat.bpp = *params->p_icc_profile ? 16 : 8; // set to 16bit when a profile is to be applied
363 dat.params = params;
364
365 if(params->style) g_strlcpy(dat.head.style, params->style, sizeof(dat.head.style));
366
367 // let the user know something is happening
369 dt_control_log(_("processing `%s' for `%s'"), params->job_title, params->prt.printer.name);
370
371 const gboolean export_masks = FALSE;
372 const gboolean is_scaling = FALSE;
373
375 (img->imgid, "unused", &buf, (dt_imageio_module_data_t *)&dat, TRUE, FALSE,
376 TRUE, is_scaling, FALSE, NULL, FALSE, export_masks, params->buf_icc_type,
377 params->buf_icc_profile, params->buf_icc_intent, NULL, NULL, 1, 1, NULL, NULL);
378
379 img->exp_width = dat.head.width;
380 img->exp_height = dat.head.height;
381
382 // we have the exported buffer, let's apply the printer profile
383
384 const dt_colorspaces_color_profile_t *buf_profile =
386 &params->buf_icc_type,
387 params->buf_icc_profile);
388 if(*params->p_icc_profile)
389 {
390 const dt_colorspaces_color_profile_t *pprof =
391 dt_colorspaces_get_profile(params->p_icc_type, params->p_icc_profile,
393 if(IS_NULL_PTR(pprof))
394 {
395 dt_control_log(_("cannot open printer profile `%s'"), params->p_icc_profile);
396 fprintf(stderr, "cannot open printer profile `%s'\n", params->p_icc_profile);
398 return 1;
399 }
400 else
401 {
402 if(IS_NULL_PTR(buf_profile) || IS_NULL_PTR(buf_profile->profile))
403 {
404 dt_control_log(_("error getting output profile for image %d"), img->imgid);
405 fprintf(stderr, "error getting output profile for image %d\n", img->imgid);
407 return 1;
408 }
410 ((void **)&(params->buf), dat.head.width, dat.head.height, dat.bpp, buf_profile->profile,
411 pprof->profile, params->p_icc_intent, params->black_point_compensation))
412 {
413 dt_control_log(_("cannot apply printer profile `%s'"), params->p_icc_profile);
414 fprintf(stderr, "cannot apply printer profile `%s'\n", params->p_icc_profile);
416 return 1;
417 }
418 }
419 }
420
421 img->buf = params->buf;
422 params->buf = NULL;
423
424 return 0;
425}
426
427static void _create_pdf(dt_job_t *job, dt_images_box imgs, const float width, const float height)
428{
430
431 const float page_width = dt_pdf_mm_to_point(width);
432 const float page_height = dt_pdf_mm_to_point(height);
433 const int icc_id = 0;
434
436
437 // create the PDF page
438 dt_pdf_t *pdf = dt_pdf_start(params->pdf_filename, page_width, page_height,
439 params->prt.printer.resolution, DT_PDF_STREAM_ENCODER_FLATE);
440
441/*
442 // ??? should a profile be embedded here?
443 if (*printer_profile)
444 icc_id = dt_pdf_add_icc(pdf, printer_profile);
445*/
446 int32_t count = 0;
447
448 for(int k=0; k<imgs.count; k++)
449 {
450 const int resolution = params->prt.printer.resolution;
451 const dt_image_box *box = &imgs.box[k];
452
453 if(box->imgid > UNKNOWN_IMAGE)
454 {
455 pdf_image[count] =
456 dt_pdf_add_image(pdf, (uint8_t *)box->buf, box->exp_width, box->exp_height,
457 8, icc_id, 0.0);
458
459 // PDF bounding-box has origin on bottom-left
460 pdf_image[count]->bb_x = dt_pdf_pixel_to_point(box->print.x, resolution);
461 pdf_image[count]->bb_y = dt_pdf_pixel_to_point(box->print.y, resolution);
462 pdf_image[count]->bb_width = dt_pdf_pixel_to_point(box->print.width, resolution);
463 pdf_image[count]->bb_height = dt_pdf_pixel_to_point(box->print.height, resolution);
464 count++;
465 }
466 }
467
468 params->pdf_page = dt_pdf_add_page(pdf, pdf_image, count);
469 dt_pdf_finish(pdf, &params->pdf_page, 1);
470
471 // now releases all the buf
472 for(int k=0; k<imgs.count; k++)
473 {
474 dt_image_box *box = &imgs.box[k];
475 dt_free(box->buf);
476 }
477}
478
480{
481 float x = 0.0f, y = 0.0f, swidth = 0.0f, sheight = 0.0f;
482
483 if(ps->last_selected != -1)
484 {
485 dt_image_box *box = &ps->imgs.box[ps->last_selected];
486
487 float width, height;
489
490 x = _percent_unit_of(ps, width, box->pos.x);
491 y = _percent_unit_of(ps, height, box->pos.y);
492 swidth = _percent_unit_of(ps, width, box->pos.width);
493 sheight = _percent_unit_of(ps, height, box->pos.height);
494
495 for(int i=0; i<9; i++)
496 {
498 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ps->dtba[i]), (i == box->alignment));
500 }
501 }
502
504
505 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_x), x);
506
507 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_y), y);
508
509 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_width), swidth);
510
511 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_height), sheight);
512
514}
515
516static int _export_and_setup_pos(dt_job_t *job, dt_image_box *img, const int32_t idx)
517{
519
520 float width, height;
521 _get_page_dimension(&params->prt, &width, &height);
522
523 dt_printing_setup_page(&params->imgs, width, height, params->prt.printer.resolution);
524
525 dt_print(DT_DEBUG_PRINT, "[print] max image size %d x %d (at resolution %d)\n",
526 img->max_width, img->max_height, params->prt.printer.resolution);
527
528 if(_export_image(job, img)) return 1;
529
530 dt_printing_setup_image(&params->imgs, idx,
531 img->imgid, img->exp_width, img->exp_height, img->alignment);
532
533 return 0;
534}
535
536static int _print_job_run(dt_job_t *job)
537{
539
540 // get first image on a box, needed as print leader
541
542 int32_t imgid = UNKNOWN_IMAGE;
543
544 // compute the needed size for picture for the given printer resolution
545
546 for(int k=0; k<params->imgs.count; k++)
547 {
548 if(params->imgs.box[k].imgid > UNKNOWN_IMAGE)
549 {
550 if(imgid == UNKNOWN_IMAGE) imgid = params->imgs.box[k].imgid;
551 if(_export_and_setup_pos(job, &params->imgs.box[k], k))
552 return 1;
553 }
554 }
555
558
559 dt_loc_get_tmp_dir(params->pdf_filename, sizeof(params->pdf_filename));
560 g_strlcat(params->pdf_filename, "/pf.XXXXXX.pdf", sizeof(params->pdf_filename));
561
562 const gint fd = g_mkstemp(params->pdf_filename);
563 if(fd == -1)
564 {
565 dt_control_log(_("failed to create temporary pdf for printing"));
566 fprintf(stderr, "failed to create temporary pdf for printing\n");
567 return 1;
568 }
569 close(fd);
570
571 float width, height;
572 _get_page_dimension(&params->prt, &width, &height);
573
574 _create_pdf(job, params->imgs, width, height);
575
578
579 // send to CUPS
580
581 dt_print_file(imgid, params->pdf_filename, params->job_title, &params->prt);
583
584 // add tag for this image
585
586 char tag[256] = { 0 };
587 guint tagid = 0;
588 snprintf (tag, sizeof(tag), "darktable|printed|%s", params->prt.printer.name);
589 dt_tag_new(tag, &tagid);
590
591 for(int k=0; k<params->imgs.count; k++)
592 {
593 if(params->imgs.box[k].imgid > UNKNOWN_IMAGE)
594 if(dt_tag_attach(tagid, params->imgs.box[k].imgid, FALSE, FALSE))
596
597 /* register print timestamp in cache */
598 dt_image_cache_set_print_timestamp(params->imgs.box[k].imgid);
599 }
600
601 return 0;
602}
603
604static void _page_new_area_clicked(GtkWidget *widget, gpointer user_data)
605{
606 const dt_lib_module_t *self = (dt_lib_module_t *)user_data;
608
609 if(ps->imgs.count == MAX_IMAGE_PER_PAGE)
610 {
611 dt_control_log(_("maximum image per page reached"));
612 return;
613 }
614
615 dt_control_change_cursor(GDK_PLUS);
616 ps->creation = TRUE;
617 ps->has_changed = TRUE;
618}
619
620static void _page_clear_area_clicked(GtkWidget *widget, gpointer user_data)
621{
622 const dt_lib_module_t *self = (dt_lib_module_t *)user_data;
624
625 ps->has_changed = TRUE;
627 gtk_widget_set_sensitive(ps->del, FALSE);
629}
630
631static void _page_delete_area(const dt_lib_module_t *self, const int box_index)
632{
634
635 if(box_index == -1) return;
636
637 for(int k=box_index; k<MAX_IMAGE_PER_PAGE-1; k++)
638 {
639 memcpy(&ps->imgs.box[k], &ps->imgs.box[k+1], sizeof(dt_image_box));
640 }
641 ps->last_selected = -1;
642 ps->selected = -1;
644 ps->imgs.count--;
645
646 if(ps->imgs.count > 0)
647 ps->selected = 0;
648 else
649 gtk_widget_set_sensitive(ps->del, FALSE);
650
652
653 ps->has_changed = TRUE;
655}
656
657static void _page_delete_area_clicked(GtkWidget *widget, gpointer user_data)
658{
659 const dt_lib_module_t *self = (dt_lib_module_t *)user_data;
661
663}
664
665static void _print_job_cleanup(void *p)
666{
667 dt_lib_print_job_t *params = p;
668 if(params->pdf_filename[0]) g_unlink(params->pdf_filename);
669 dt_free(params->pdf_page);
670 dt_free(params->buf);
671 dt_free(params->style);
672 dt_free(params->buf_icc_profile);
673 dt_free(params->p_icc_profile);
674 dt_free(params->job_title);
675 dt_free(params);
676}
677
678static void _print_button_clicked(GtkWidget *widget, gpointer user_data)
679{
680 const dt_lib_module_t *self = (dt_lib_module_t *)user_data;
682
683 int32_t imgid = UNKNOWN_IMAGE;
684
685 // at least one image on a box
686
687 for(int k=0; k<ps->imgs.count; k++)
688 {
689 if(ps->imgs.box[k].imgid > UNKNOWN_IMAGE)
690 {
691 imgid = ps->imgs.box[k].imgid;
692 break;
693 }
694 }
695
696 if(imgid == UNKNOWN_IMAGE)
697 {
698 dt_control_log(_("cannot print until a picture is selected"));
699 return;
700 }
701 if(strlen(ps->prt.printer.name) == 0 || ps->prt.printer.resolution == 0)
702 {
703 dt_control_log(_("cannot print until a printer is selected"));
704 return;
705 }
706 if(ps->prt.paper.width == 0 || ps->prt.paper.height == 0)
707 {
708 dt_control_log(_("cannot print until a paper is selected"));
709 return;
710 }
711
712 dt_job_t *job = dt_control_job_create(&_print_job_run, "print image %d", imgid);
713 if(IS_NULL_PTR(job)) return;
714
715 dt_lib_print_job_t *params = calloc(1, sizeof(dt_lib_print_job_t));
717
718 memcpy(&params->prt, &ps->prt, sizeof(dt_print_info_t));
719 memcpy(&params->imgs, &ps->imgs, sizeof(ps->imgs));
720
721 // what to call the image?
722 GList *res;
723 if((res = dt_metadata_get(imgid, "Xmp.dc.title", NULL)) != NULL)
724 {
725 // FIXME: in metadata_view.c, non-printables are filtered, should we do this here?
726 params->job_title = g_strdup((gchar *)res->data);
727 g_list_free_full(res, dt_free_gpointer);
728 res = NULL;
729 }
730 else
731 {
732 const dt_image_t *img = dt_image_cache_get(imgid, 'r');
733 if(IS_NULL_PTR(img))
734 {
735 // in this case no need to release from cache what we couldn't get
736 dt_control_log(_("cannot get image %d for printing"), imgid);
738 return;
739 }
740 params->job_title = g_strdup(img->filename);
742 }
743 // FIXME: ellipsize title/printer as the export completed message is ellipsized
744 gchar *message = g_strdup_printf(_("processing `%s' for `%s'"), params->job_title, params->prt.printer.name);
745 dt_control_job_add_progress(job, message, TRUE);
746 dt_free(message);
747
748 // FIXME: getting this from conf as w/prior code, but switch to getting from ps
749 params->style = dt_conf_get_string("plugins/print/print/style");
750
751 // FIXME: getting these from conf as w/prior code, but switch to getting them from ps
752 params->buf_icc_type = dt_conf_get_int("plugins/print/print/icctype");
753 params->buf_icc_profile = dt_conf_get_string("plugins/print/print/iccprofile");
754 params->buf_icc_intent = dt_conf_get_int("plugins/print/print/iccintent");
755
756 params->p_icc_type = ps->v_picctype;
757 params->p_icc_profile = g_strdup(ps->v_piccprofile);
758 params->p_icc_intent = ps->v_pintent;
759 params->black_point_compensation = ps->v_black_point_compensation;
760
762}
763
764static void _set_printer(const dt_lib_module_t *self, const char *printer_name)
765{
767
768 dt_get_printer_info(printer_name, &ps->prt.printer);
769
770 // if this is a turboprint printer, disable the printer profile
771
774
775 dt_conf_set_string("plugins/print/print/printer", printer_name);
776
777 // add papers for the given printer
779 if(ps->paper_list)
780 {
781 g_list_free_full(ps->paper_list, dt_free_gpointer);
782 ps->paper_list = NULL;
783 }
784 ps->paper_list = dt_get_papers (&ps->prt.printer);
785 for(const GList *papers = ps->paper_list; papers; papers = g_list_next (papers))
786 {
787 const dt_paper_info_t *p = (dt_paper_info_t *)papers->data;
788 dt_bauhaus_combobox_add(ps->papers, p->common_name);
789 }
790 const char *default_paper = dt_conf_get_string_const("plugins/print/print/paper");
791 if(!dt_bauhaus_combobox_set_from_text(ps->papers, default_paper))
793
794 const gchar *paper_name = dt_bauhaus_combobox_get_text(ps->papers);
795 if(paper_name)
796 {
797 const dt_paper_info_t *paper = dt_get_paper(ps->paper_list, paper_name);
798 if(paper)
799 memcpy(&ps->prt.paper, paper, sizeof(dt_paper_info_t));
800 }
801
802 // add corresponding supported media
804 if(ps->media_list)
805 {
806 g_list_free_full(ps->media_list, dt_free_gpointer);
807 ps->media_list = NULL;
808 }
810 for(const GList *media = ps->media_list; media; media = g_list_next (media))
811 {
812 const dt_medium_info_t *m = (dt_medium_info_t *)media->data;
813 dt_bauhaus_combobox_add(ps->media, m->common_name);
814 }
815 const char *default_medium = dt_conf_get_string_const("plugins/print/print/medium");
816 if(!dt_bauhaus_combobox_set_from_text(ps->media, default_medium))
818
819 const gchar *medium_name = dt_bauhaus_combobox_get_text(ps->media);
820 if(medium_name)
821 {
822 const dt_medium_info_t *medium = dt_get_medium(ps->media_list, medium_name);
823 if(medium)
824 memcpy(&ps->prt.medium, medium, sizeof(dt_medium_info_t));
825 }
826
827 if(ps->prt.paper.width > 0.0f && ps->prt.paper.height > 0.0f && ps->prt.printer.resolution > 0)
828 {
829 float width, height;
832 }
833
835}
836
837static void
839{
840 const gchar *printer_name = dt_bauhaus_combobox_get_text(combo);
841
842 if(printer_name)
843 _set_printer (self, printer_name);
844}
845
846static void
848{
850
851 const gchar *paper_name = dt_bauhaus_combobox_get_text(combo);
852
853 if(IS_NULL_PTR(paper_name)) return;
854
855 const dt_paper_info_t *paper = dt_get_paper(ps->paper_list, paper_name);
856
857 if(paper)
858 memcpy(&ps->prt.paper, paper, sizeof(dt_paper_info_t));
859
860 float width, height;
862
864
865 dt_conf_set_string("plugins/print/print/paper", paper_name);
867
868 _update_slider(ps);
869}
870
871static void
873{
875
876 const gchar *medium_name = dt_bauhaus_combobox_get_text(combo);
877
878 if(IS_NULL_PTR(medium_name)) return;
879
880 const dt_medium_info_t *medium = dt_get_medium(ps->media_list, medium_name);
881
882 if(medium)
883 memcpy(&ps->prt.medium, medium, sizeof(dt_medium_info_t));
884
885 dt_conf_set_string("plugins/print/print/medium", medium_name);
887
888 _update_slider(ps);
889}
890
891static void
893{
895
896 // if widget are created, let's display the current image size
897
898 // FIXME: why doesn't this update when units are changed?
899 if(ps->selected != -1
900 && ps->imgs.box[ps->selected].imgid != UNKNOWN_IMAGE
901 && ps->width && ps->height
902 && ps->info)
903 {
904 const dt_image_box *box = &ps->imgs.box[ps->selected];
905
906 dt_image_pos box_size_mm, box_size;
907 dt_printing_get_image_pos_mm(&ps->imgs, box, &box_size_mm);
908 dt_printing_get_image_pos(&ps->imgs, box, &box_size);
909
910 const double w = box_size_mm.width * units[ps->unit];
911 const double h = box_size_mm.height * units[ps->unit];
912 char *value, *precision;
913 int n_digits;
914 _precision_by_unit(ps->unit, &n_digits, NULL, &precision);
915
916 value = g_strdup_printf(precision, w);
917 gtk_label_set_text(GTK_LABEL(ps->width), value);
918 dt_free(value);
919
920 value = g_strdup_printf(precision, h);
921 gtk_label_set_text(GTK_LABEL(ps->height), value);
922 dt_free(value);
924
925 // compute the image down/up scale and report information
926
927 const float iwidth = box->img_width;
928 const float iheight = box->img_height;
929 const float awidth = box_size.width;
930 const float aheight = box_size.height;
931
932 const double scale = (iwidth <= awidth)
933 ? awidth / iwidth
934 : aheight/ iheight;
935
936 value = g_strdup_printf(_("%3.2f (dpi:%d)"), scale,
937 scale <= 1.0
938 ? (int)ps->prt.printer.resolution
939 : (int)(ps->prt.printer.resolution / scale));
940 gtk_label_set_text(GTK_LABEL(ps->info), value);
941 dt_free(value);
942 }
943}
944
945static void
946_top_border_callback(GtkWidget *spin, gpointer user_data)
947{
948 const dt_lib_module_t *self = (dt_lib_module_t *)user_data;
950 const double value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin));
951
952 dt_conf_set_float("plugins/print/print/top_margin", value);
953
954 ps->prt.page.margin_top = _to_mm(ps, value);
955
956 if(ps->lock_activated == TRUE)
957 {
958 ps->prt.page.margin_bottom = _to_mm(ps, value);
959 ps->prt.page.margin_left = _to_mm(ps, value);
960 ps->prt.page.margin_right = _to_mm(ps, value);
961
962 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_bottom), value);
963 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_left), value);
964 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_right), value);
965
966 dt_conf_set_float("plugins/print/print/bottom_margin", value);
967 dt_conf_set_float("plugins/print/print/left_margin", value);
968 dt_conf_set_float("plugins/print/print/right_margin", value);
969 }
970
971 _update_slider(ps);
972}
973
974static void
975_bottom_border_callback(GtkWidget *spin, gpointer user_data)
976{
977 const dt_lib_module_t *self = (dt_lib_module_t *)user_data;
979 const double value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin));
980
981 dt_conf_set_float("plugins/print/print/bottom_margin", value);
982
983 ps->prt.page.margin_bottom = _to_mm(ps, value);
984 _update_slider(ps);
985}
986
987static void
988_left_border_callback(GtkWidget *spin, gpointer user_data)
989{
990 const dt_lib_module_t *self = (dt_lib_module_t *)user_data;
992 const double value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin));
993
994 dt_conf_set_float("plugins/print/print/left_margin", value);
995
996 ps->prt.page.margin_left = _to_mm(ps, value);
997 _update_slider(ps);
998}
999
1000static void
1001_right_border_callback(GtkWidget *spin, gpointer user_data)
1002{
1003 const dt_lib_module_t *self = (dt_lib_module_t *)user_data;
1005 const double value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin));
1006
1007 dt_conf_set_float("plugins/print/print/right_margin", value);
1008
1009 ps->prt.page.margin_right = _to_mm(ps, value);
1010 _update_slider(ps);
1011}
1012
1013static void
1014_lock_callback(GtkWidget *button, gpointer user_data)
1015{
1016 const dt_lib_module_t *self = (dt_lib_module_t *)user_data;
1018
1019 ps->lock_activated = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
1020
1021 dt_conf_set_bool("plugins/print/print/lock_borders", ps->lock_activated);
1022
1023 gtk_widget_set_sensitive(GTK_WIDGET(ps->b_bottom), !ps->lock_activated);
1024 gtk_widget_set_sensitive(GTK_WIDGET(ps->b_left), !ps->lock_activated);
1025 gtk_widget_set_sensitive(GTK_WIDGET(ps->b_right), !ps->lock_activated);
1026
1027 // get value of top and set it to all other borders
1028
1029 const double value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ps->b_top));
1030 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_bottom), value);
1031 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_left), value);
1032 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_right), value);
1033
1034 _update_slider (ps);
1035}
1036
1037static void
1038_alignment_callback(GtkWidget *tb, gpointer user_data)
1039{
1040 if(dt_gui_widgets_suppressed()) return;
1041
1042 int index=-1;
1043 const dt_lib_module_t *self = (dt_lib_module_t *)user_data;
1045
1046 for(int i=0; i<9; i++)
1047 {
1048 /* block signal handler */
1049 g_signal_handlers_block_by_func(ps->dtba[i],_alignment_callback, user_data);
1050
1051 if(GTK_WIDGET(ps->dtba[i]) == tb)
1052 {
1053 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ps->dtba[i]), TRUE);
1054 index=i;
1055 }
1056 else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ps->dtba[i]), FALSE);
1057
1058 /* unblock signal handler */
1059 g_signal_handlers_unblock_by_func(ps->dtba[i], _alignment_callback, user_data);
1060 }
1061
1062 if(ps->last_selected != -1)
1063 {
1065 ps->imgs.box[ps->last_selected].imgid, 100, 100, index);
1066 }
1067
1068 _update_slider(ps);
1069}
1070
1071static void
1080
1081static void
1086
1087static void
1092
1094{
1095 if(dt_gui_widgets_suppressed()) return;
1096
1098 const float value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ps->grid_size));
1099 dt_conf_set_float("plugins/print/print/grid_size", _to_mm(ps, value));
1100
1102}
1103
1104static void
1106{
1107 if(dt_gui_widgets_suppressed()) return;
1108
1110
1111 const float grid_size = dt_conf_get_float("plugins/print/print/grid_size");
1112
1113 const int unit = dt_bauhaus_combobox_get(combo);
1114 if(unit < 0) return; // shouldn't happen, but it could be -1 if nothing is selected
1115 ps->unit = unit;
1116 dt_conf_set_string("plugins/print/print/unit", _unit_names[unit]);
1117
1118 const double margin_top = ps->prt.page.margin_top;
1119 const double margin_left = ps->prt.page.margin_left;
1120 const double margin_right = ps->prt.page.margin_right;
1121 const double margin_bottom = ps->prt.page.margin_bottom;
1122
1123 int n_digits;
1124 float incr;
1125 _precision_by_unit(ps->unit, &n_digits, &incr, NULL);
1126
1128
1129 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(ps->b_top), n_digits);
1130 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(ps->b_bottom), n_digits);
1131 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(ps->b_left), n_digits);
1132 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(ps->b_right), n_digits);
1133 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(ps->b_top), incr, 10.f*incr);
1134 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(ps->b_bottom), incr, 10.f*incr);
1135 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(ps->b_left), incr, 10.f*incr);
1136 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(ps->b_right), incr, 10.f*incr);
1137
1138 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(ps->b_x), n_digits);
1139 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(ps->b_y), n_digits);
1140 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(ps->b_width), n_digits);
1141 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(ps->b_height), n_digits);
1142 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(ps->b_x), incr, 10.f*incr);
1143 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(ps->b_y), incr, 10.f*incr);
1144 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(ps->b_width), incr, 10.f*incr);
1145 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(ps->b_height), incr, 10.f*incr);
1146
1147 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(ps->grid_size), n_digits);
1148 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(ps->grid_size), incr, 10.f*incr);
1149
1150 _update_slider(ps);
1151
1152 // convert margins to new unit
1153 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_top), margin_top * units[ps->unit]);
1154 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_bottom), margin_bottom * units[ps->unit]);
1155 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_left), margin_left * units[ps->unit]);
1156 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_right), margin_right * units[ps->unit]);
1157
1158 // grid size
1159 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->grid_size), grid_size * units[ps->unit]);
1160
1162
1163 _fill_box_values(ps);
1164}
1165
1166static void
1168{
1170
1171 if(dt_bauhaus_combobox_get(ps->style) == 0)
1172 {
1173 dt_conf_set_string("plugins/print/print/style", "");
1174 }
1175 else
1176 {
1177 const gchar *style = dt_bauhaus_combobox_get_text(ps->style);
1178 dt_conf_set_string("plugins/print/print/style", style);
1179 }
1180
1181 dt_free(ps->v_style);
1182 ps->v_style = dt_conf_get_string("plugins/print/print/style");
1183}
1184
1185static void
1187{
1189 const int pos = dt_bauhaus_combobox_get(widget);
1190 for(const GList *prof = ps->profiles; prof; prof = g_list_next(prof))
1191 {
1193 if(pp->pos == pos)
1194 {
1195 dt_conf_set_int("plugins/print/print/icctype", pp->type);
1196 dt_conf_set_string("plugins/print/print/iccprofile", pp->filename);
1197 dt_free(ps->v_iccprofile);
1198 ps->v_icctype = pp->type;
1199 ps->v_iccprofile = g_strdup(pp->filename);
1200 return;
1201 }
1202 }
1203 dt_conf_set_int("plugins/print/print/icctype", DT_COLORSPACE_NONE);
1204 dt_conf_set_string("plugins/print/print/iccprofile", "");
1205 dt_free(ps->v_iccprofile);
1207 ps->v_iccprofile = g_strdup("");
1208}
1209
1210static void
1212{
1214 const int pos = dt_bauhaus_combobox_get(widget);
1215 for(const GList *prof = ps->profiles; prof; prof = g_list_next(prof))
1216 {
1218 if(pp->ppos == pos)
1219 {
1220 dt_conf_set_int("plugins/print/printer/icctype", pp->type);
1221 dt_conf_set_string("plugins/print/printer/iccprofile", pp->filename);
1223 ps->v_picctype = pp->type;
1224 ps->v_piccprofile = g_strdup(pp->filename);
1225
1226 // activate the black compensation and printer intent
1227 gtk_widget_set_sensitive(GTK_WIDGET(ps->black_point_compensation), TRUE);
1228 return;
1229 }
1230 }
1231 dt_conf_set_int("plugins/print/printer/icctype", DT_COLORSPACE_NONE);
1232 dt_conf_set_string("plugins/print/printer/iccprofile", "");
1235 ps->v_piccprofile = g_strdup("");
1236 gtk_widget_set_sensitive(GTK_WIDGET(ps->black_point_compensation), FALSE);
1237}
1238
1239static void
1241{
1243 const int pos = dt_bauhaus_combobox_get(widget);
1244 dt_conf_set_int("plugins/print/printer/iccintent", pos);
1245 ps->v_pintent = pos;
1246 ps->prt.printer.intent = pos;
1247}
1248
1249static void
1251{
1253 ps->v_black_point_compensation = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ps->black_point_compensation));
1254 dt_conf_set_bool("plugins/print/print/black_point_compensation", ps->v_black_point_compensation);
1255}
1256
1257static void
1259{
1261 const int pos = dt_bauhaus_combobox_get(widget);
1262 // record the intent that will override the out rendering module on export
1263 dt_conf_set_int("plugins/print/print/iccintent", pos - 1);
1264 ps->v_intent = pos - 1;
1265}
1266
1267static void _set_orientation(dt_lib_print_settings_t *ps, int32_t imgid)
1268{
1271 imgid, DT_MIPMAP_0, DT_MIPMAP_BLOCKING, 'r');
1272
1273 // If there's a mipmap available, figure out orientation based upon
1274 // its dimensions. Otherwise, don't touch orientation until the
1275 // mipmap arrives.
1276 if(buf.size != DT_MIPMAP_NONE)
1277 {
1278 ps->prt.page.landscape = (buf.width > buf.height);
1281 }
1282
1285}
1286
1287static void _print_settings_activate_or_update_callback(gpointer instance, int32_t imgid, gpointer user_data)
1288{
1289 const dt_lib_module_t *self = (dt_lib_module_t *)user_data;
1291
1292 // load an image with a simple click on the filmstrip only if a single image is present
1293 if(ps->imgs.count == 1)
1294 {
1295 if(ps->has_changed)
1296 {
1297 dt_printing_setup_image(&ps->imgs, 0, imgid, 100, 100, ps->imgs.box[0].alignment);
1298 }
1299 else
1300 {
1301 _set_orientation(ps, imgid);
1303 ps->imgs.imgid_to_load = imgid;
1305 }
1306 }
1307}
1308
1309static GList* _get_profiles()
1310{
1311 // Create list of profiles
1312 GList *list = NULL;
1313
1315 prof->type = DT_COLORSPACE_SRGB;
1316 dt_utf8_strlcpy(prof->name, _("sRGB (web-safe)"), sizeof(prof->name));
1317 prof->pos = -2;
1318 prof->ppos = -2;
1319 list = g_list_prepend(list, prof);
1320
1321 prof = (dt_lib_export_profile_t *)g_malloc0(sizeof(dt_lib_export_profile_t));
1323 dt_utf8_strlcpy(prof->name, _("Adobe RGB (compatible)"), sizeof(prof->name));
1324 prof->pos = -2;
1325 prof->ppos = -2;
1326 list = g_list_prepend(list, prof);
1327
1328 /* Every on-disk profile, from color/in/ as well as color/out/ -- this list applies no
1329 * direction predicate, only a type filter, which IN|OUT reproduces exactly: a
1330 * DT_COLORSPACE_FILE entry gets the INPUT role from the in/ batch or OUTPUT from the out/
1331 * batch, never neither, and no built-in has type DT_COLORSPACE_FILE. Enumeration order
1332 * is list order, so the resulting menu is unchanged. */
1333 dt_colorprofile_desc_t *file_profiles = NULL;
1334 const size_t n_file_profiles = dt_colorspaces_enumerate_profiles(
1336
1337 for(size_t k = 0; k < n_file_profiles; k++)
1338 {
1339 if(file_profiles[k].type != DT_COLORSPACE_FILE) continue;
1340
1341 prof = (dt_lib_export_profile_t *)g_malloc0(sizeof(dt_lib_export_profile_t));
1342 g_strlcpy(prof->name, file_profiles[k].name, sizeof(prof->name));
1343 g_strlcpy(prof->filename, file_profiles[k].filename, sizeof(prof->filename));
1344 prof->type = DT_COLORSPACE_FILE;
1345 prof->pos = -2;
1346 prof->ppos = -2;
1347 list = g_list_prepend(list, prof);
1348 }
1349 dt_free_align(file_profiles);
1350
1351 return g_list_reverse(list); // list was built in reverse order, so un-reverse it
1352}
1353
1354static void _new_printer_callback(dt_printer_info_t *printer, void *user_data)
1355{
1356 static int count = 0;
1357 const dt_lib_module_t *self = (dt_lib_module_t *)user_data;
1359
1360 char *default_printer = dt_conf_get_string("plugins/print/print/printer");
1361
1362 g_signal_handlers_block_by_func(G_OBJECT(d->printers), G_CALLBACK(_printer_changed), NULL);
1363
1364 dt_bauhaus_combobox_add(d->printers, printer->name);
1365
1366 if(!g_strcmp0(default_printer, printer->name) || default_printer[0]=='\0')
1367 {
1368 dt_bauhaus_combobox_set(d->printers, count);
1369 _set_printer(self, printer->name);
1370 }
1371 count++;
1372 dt_free(default_printer);
1373
1374 g_signal_handlers_unblock_by_func(G_OBJECT(d->printers), G_CALLBACK(_printer_changed), NULL);
1375}
1376
1377void view_enter(struct dt_lib_module_t *self,struct dt_view_t *old_view,struct dt_view_t *new_view)
1378{
1380
1381 // Re-publish the settings payload on each entry so the print view never
1382 // keeps a stale or not-yet-initialized images box between switches.
1384
1385 // user activated a new image via the filmstrip or user entered view
1386 // mode which activates an image: get image_id and orientation
1389
1390 // NOTE: it would be proper to set image_id here to -1, but this seems to make no difference
1391}
1392
1393void view_leave(struct dt_lib_module_t *self,struct dt_view_t *old_view,struct dt_view_t *new_view)
1394{
1397 self);
1398}
1399
1400void _get_control(dt_lib_print_settings_t *ps, float x, float y)
1401{
1402 const float dist = 20.0;
1403
1404 const dt_image_box *b = &ps->imgs.box[ps->selected];
1405
1406 ps->sel_controls = 0;
1407
1408 if(fabsf(b->screen.x - x) < dist)
1409 ps->sel_controls |= BOX_LEFT;
1410
1411 if(fabsf(b->screen.y - y) < dist)
1412 ps->sel_controls |= BOX_TOP;
1413
1414 if(fabsf((b->screen.x + b->screen.width) - x) < dist)
1415 ps->sel_controls |= BOX_RIGHT;
1416
1417 if(fabsf((b->screen.y + b->screen.height) - y) < dist)
1418 ps->sel_controls |= BOX_BOTTOM;
1419
1420 if(ps->sel_controls == 0) ps->sel_controls = BOX_ALL;
1421}
1422
1424{
1426
1427 if(ps->last_selected != -1)
1428 {
1430 }
1431
1432 return 0;
1433}
1434
1435static void _snap_to_grid(dt_lib_print_settings_t *ps, float *x, float *y)
1436{
1437 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ps->snap_grid)))
1438 {
1439 // V lines
1440 const float step = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ps->grid_size)) * units[ps->unit];
1441
1442 // only display the grid if a step of 5 pixels
1443 const float diff = DT_PIXEL_APPLY_DPI(5);
1444
1445 float grid_pos = (float)ps->imgs.screen.page.x;
1446
1447 const float h_step = _mm_to_hscreen(ps, step, FALSE);
1448
1449 while(grid_pos < ps->imgs.screen.page.x + ps->imgs.screen.page.width)
1450 {
1451 if(fabsf(*x - grid_pos) < diff) *x = grid_pos;
1452 grid_pos += h_step;
1453 }
1454
1455 // H lines
1456 grid_pos = (float)ps->imgs.screen.page.y;
1457
1458 const float v_step = _mm_to_vscreen(ps, step, FALSE);
1459
1460 while(grid_pos < ps->imgs.screen.page.y + ps->imgs.screen.page.height)
1461 {
1462 if(fabsf(*y - grid_pos) < diff) *y = grid_pos;
1463 grid_pos += v_step;
1464 }
1465 }
1466 // FIXME: should clamp values to page size here?
1467}
1468
1469int mouse_moved(struct dt_lib_module_t *self, double x, double y, double pressure, int which)
1470{
1472
1473 gboolean expose = FALSE;
1474
1475 if(ps->creation)
1476 dt_control_change_cursor(GDK_PLUS);
1477
1478 if(ps->creation && ps->dragging)
1479 {
1480 ps->x2 = x;
1481 ps->y2 = y;
1482 _snap_to_grid(ps, &ps->x2, &ps->y2);
1483 expose = TRUE;
1484 }
1485 else if(ps->dragging)
1486 {
1487 dt_image_box *b = &ps->imgs.box[ps->selected];
1488 const float dx = x - ps->click_pos_x;
1489 const float dy = y - ps->click_pos_y;
1490 const float coef = dx / b->screen.width;
1491
1492 switch(ps->sel_controls)
1493 {
1494 case BOX_ALL:
1495 ps->x1 = b->screen.x + dx;
1496 ps->y1 = b->screen.y + dy;
1497 ps->x2 = b->screen.x + b->screen.width + dx;
1498 ps->y2 = b->screen.y + b->screen.height + dy;
1499 break;
1500 case BOX_LEFT:
1501 ps->x1 = b->screen.x + dx;
1502 break;
1503 case BOX_TOP:
1504 ps->y1 = b->screen.y + dy;
1505 break;
1506 case BOX_RIGHT:
1507 ps->x2 = b->screen.x + b->screen.width + dx;
1508 break;
1509 case BOX_BOTTOM:
1510 ps->y2 = b->screen.y + b->screen.height + dy;
1511 break;
1512 case BOX_TOP_LEFT:
1513 ps->x1 = b->screen.x + dx;
1514 ps->y1 = b->screen.y + (coef * b->screen.height);
1515 break;
1516 case BOX_TOP_RIGHT:
1517 ps->x2 = b->screen.x + b->screen.width + dx;
1518 ps->y1 = b->screen.y - (coef * b->screen.height);
1519 break;
1520 case BOX_BOTTOM_LEFT:
1521 ps->x1 = b->screen.x + dx;
1522 ps->y2 = b->screen.y + b->screen.height - (coef * b->screen.height);
1523 break;
1524 case BOX_BOTTOM_RIGHT:
1525 ps->x2 = b->screen.x + b->screen.width + dx;
1526 ps->y2 = b->screen.y + b->screen.height + (coef * b->screen.height);
1527 break;
1528 default:
1529 break;
1530 }
1531 expose = TRUE;
1532
1533 _snap_to_grid(ps, &ps->x1, &ps->y1);
1534 _snap_to_grid(ps, &ps->x2, &ps->y2);
1535 }
1536 else if(!ps->creation)
1537 {
1538 const int bidx = dt_printing_get_image_box(&ps->imgs, x, y);
1539 ps->sel_controls = 0;
1540
1541 if(bidx == -1)
1542 {
1543 if(ps->selected != -1) expose = TRUE;
1544 ps->selected = -1;
1545 }
1546 else
1547 {
1548 expose = TRUE;
1549 ps->selected = bidx;
1550 _fill_box_values(ps);
1551 _get_control(ps, x, y);
1552 }
1553 }
1554
1556
1557 return 0;
1558}
1559
1560static void _swap(float *a, float *b)
1561{
1562 const float tmp = *a;
1563 *a = *b;
1564 *b = tmp;
1565}
1566
1567int button_released(struct dt_lib_module_t *self, double x, double y, int which, uint32_t state)
1568{
1570
1571 if(ps->dragging)
1572 {
1573 int idx = -1;
1574
1575 gtk_widget_set_sensitive(ps->del, TRUE);
1576
1577 // handle new area
1578 if(ps->creation)
1579 {
1580 idx = ps->imgs.count++;
1581 }
1582 else if(ps->selected != -1)
1583 {
1584 idx = ps->selected;
1585 }
1586
1587 if(idx != -1)
1588 {
1589 // make sure the area is in the the printable area taking into account the margins
1590
1591 // don't allow a too small area
1592 if(ps->x2 < ps->x1) _swap(&ps->x1, &ps->x2);
1593 if(ps->y2 < ps->y1) _swap(&ps->y1, &ps->y2);
1594
1595 const float dx = ps->x2 - ps->x1;
1596 const float dy = ps->y2 - ps->y1;
1597
1598 dt_printing_setup_box(&ps->imgs, idx, ps->x1, ps->y1, dx, dy);
1599 // make the new created box the last edited one
1600 ps->last_selected = idx;
1601 _fill_box_values(ps);
1602 }
1603 }
1604
1605 _update_slider(ps);
1606
1607 ps->creation = FALSE;
1608 ps->dragging = FALSE;
1609
1610 dt_control_change_cursor(GDK_LEFT_PTR);
1611
1612 return 0;
1613}
1614
1615int button_pressed(struct dt_lib_module_t *self, double x, double y, double pressure,
1616 int which, int type, uint32_t state)
1617{
1619
1620 ps->click_pos_x = x;
1621 ps->click_pos_y = y;
1622 ps->last_selected = -1;
1623
1624 if(ps->creation)
1625 {
1626 ps->dragging = TRUE;
1627 ps->selected = -1;
1628 ps->x1 = ps->x2 = x;
1629 ps->y1 = ps->y2 = y;
1630
1631 _snap_to_grid(ps, &ps->x1, &ps->y1);
1632 }
1633 else if(ps->selected > 0
1634 && (which == 2 || (which == 1 && dt_modifier_is(state, DT_PRIMARY_MASK))))
1635 {
1636 // middle click (or ctrl-click), move selected image down
1637 dt_image_box b;
1638 memcpy(&b, &ps->imgs.box[ps->selected], sizeof(dt_image_box));
1639 memcpy(&ps->imgs.box[ps->selected], &ps->imgs.box[ps->selected-1], sizeof(dt_image_box));
1640 memcpy(&ps->imgs.box[ps->selected-1], &b, sizeof(dt_image_box));
1641 }
1642 else if(ps->selected != -1 && which == 1)
1643 {
1644 dt_image_box *b = &ps->imgs.box[ps->selected];
1645
1646 ps->dragging = TRUE;
1647 ps->x1 = b->screen.x;
1648 ps->y1 = b->screen.y;
1649 ps->x2 = b->screen.x + b->screen.width;
1650 ps->y2 = b->screen.y + b->screen.height;
1651
1652 ps->last_selected = ps->selected;
1653 ps->has_changed = TRUE;
1654
1655 _get_control(ps, x, y);
1656
1657 dt_control_change_cursor(GDK_HAND1);
1658 }
1659 else if(ps->selected != -1 && which == 3)
1660 {
1661 dt_image_box *b = &ps->imgs.box[ps->selected];
1662
1663 // if image present remove it, otherwise remove the box
1664 if(b->imgid != UNKNOWN_IMAGE)
1665 b->imgid = UNKNOWN_IMAGE;
1666 else
1667 _page_delete_area(self, ps->selected);
1668
1669 ps->last_selected = ps->selected;
1670 ps->has_changed = TRUE;
1671 }
1672
1673 return 0;
1674}
1675
1676void _cairo_rectangle(cairo_t *cr, const int sel_controls,
1677 const int x1, const int y1, const int x2, const int y2)
1678{
1679 const float sel_width = DT_PIXEL_APPLY_DPI(3.0);
1680 const float std_width = DT_PIXEL_APPLY_DPI(1.0);
1681
1682 const gboolean all = sel_controls == BOX_ALL;
1683
1684 cairo_move_to(cr, x1, y1);
1685 cairo_set_line_width(cr, (all || sel_controls == BOX_LEFT) ? sel_width : std_width);
1686 cairo_line_to(cr, x1, y2);
1687 cairo_stroke(cr);
1688
1689 cairo_move_to(cr, x1, y2);
1690 cairo_set_line_width(cr, (all || sel_controls == BOX_BOTTOM) ? sel_width : std_width);
1691 cairo_line_to(cr, x2, y2);
1692 cairo_stroke(cr);
1693
1694 cairo_move_to(cr, x2, y2);
1695 cairo_set_line_width(cr, (all || sel_controls == BOX_RIGHT) ? sel_width : std_width);
1696 cairo_line_to(cr, x2, y1);
1697 cairo_stroke(cr);
1698
1699 cairo_move_to(cr, x2, y1);
1700 cairo_set_line_width(cr, (all || sel_controls == BOX_TOP) ? sel_width : std_width);
1701 cairo_line_to(cr, x1, y1);
1702 cairo_stroke(cr);
1703
1704 if(sel_controls == 0)
1705 {
1706 const double dash[] = { DT_PIXEL_APPLY_DPI(3.0), DT_PIXEL_APPLY_DPI(3.0) };
1707 cairo_set_dash(cr, dash, 2, 0);
1708
1709 // no image inside
1710 cairo_move_to(cr, x1, y1);
1711 cairo_line_to(cr, x2, y2);
1712
1713 cairo_move_to(cr, x1, y2);
1714 cairo_line_to(cr, x2, y1);
1715 cairo_stroke(cr);
1716 }
1717
1718 cairo_set_dash(cr, NULL, 0, 0);
1719 cairo_set_line_width(cr, sel_width);
1720
1721 if(sel_controls == BOX_TOP_LEFT)
1722 {
1723 cairo_rectangle (cr, x1, y1, DT_PIXEL_APPLY_DPI(15), DT_PIXEL_APPLY_DPI(15));
1724 cairo_stroke(cr);
1725 }
1726
1727 if(sel_controls == BOX_TOP_RIGHT)
1728 {
1729 cairo_rectangle (cr, x2 - DT_PIXEL_APPLY_DPI(15), y1,
1731 cairo_stroke(cr);
1732 }
1733
1734 if(sel_controls == BOX_BOTTOM_LEFT)
1735 {
1736 cairo_rectangle (cr, x1, y2 - DT_PIXEL_APPLY_DPI(15),
1738 cairo_stroke(cr);
1739 }
1740
1741 if(sel_controls == BOX_BOTTOM_RIGHT)
1742 {
1743 cairo_rectangle (cr, x2 - DT_PIXEL_APPLY_DPI(15), y2 - DT_PIXEL_APPLY_DPI(15),
1745 cairo_stroke(cr);
1746 }
1747}
1748
1749void gui_post_expose(struct dt_lib_module_t *self, cairo_t *cr, int32_t width, int32_t height,
1750 int32_t pointerx, int32_t pointery)
1751{
1753
1754 // display grid
1755
1756 // 1mm
1757
1758 const float step = gtk_spin_button_get_value(GTK_SPIN_BUTTON(ps->grid_size)) / units[ps->unit];
1759
1760 // only display grid if spacing more than 5 pixels
1761 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ps->grid))
1762 && (int)_mm_to_hscreen(ps, step, FALSE) > DT_PIXEL_APPLY_DPI(5))
1763 {
1764 const double dash[] = { DT_PIXEL_APPLY_DPI(5.0), DT_PIXEL_APPLY_DPI(5.0) };
1765 cairo_set_source_rgba(cr, 1, .2, .2, 0.6);
1766
1767 // V lines
1768 float grid_pos = (float)ps->imgs.screen.page.x;
1769
1770 const float h_step = _mm_to_hscreen(ps, step, FALSE);
1771 int n = 0;
1772
1773 while(grid_pos < ps->imgs.screen.page.x + ps->imgs.screen.page.width)
1774 {
1775 cairo_set_dash(cr, dash, ((n % 5) == 0) ? 0 : 2, DT_PIXEL_APPLY_DPI(5));
1776 cairo_set_line_width(cr, ((n % 5) == 0) ? DT_PIXEL_APPLY_DPI(1.0) : DT_PIXEL_APPLY_DPI(0.5));
1777 cairo_move_to(cr, grid_pos, ps->imgs.screen.page.y);
1778 cairo_line_to(cr, grid_pos, ps->imgs.screen.page.y + ps->imgs.screen.page.height);
1779 cairo_stroke(cr);
1780 grid_pos += h_step;
1781 n++;
1782 }
1783
1784 // H lines
1785 grid_pos = (float)ps->imgs.screen.page.y;
1786
1787 const float v_step = _mm_to_vscreen(ps, step, FALSE);
1788 n = 0;
1789
1790 while(grid_pos < ps->imgs.screen.page.y + ps->imgs.screen.page.height)
1791 {
1792 cairo_set_dash(cr, dash, ((n % 5) == 0) ? 0 : 2, DT_PIXEL_APPLY_DPI(5));
1793 cairo_set_line_width(cr, ((n % 5) == 0) ? DT_PIXEL_APPLY_DPI(1.0) : DT_PIXEL_APPLY_DPI(0.5));
1794 cairo_move_to(cr, ps->imgs.screen.page.x, grid_pos);
1795 cairo_line_to(cr, ps->imgs.screen.page.x + ps->imgs.screen.page.width, grid_pos);
1796 cairo_stroke(cr);
1797 grid_pos += v_step;
1798 n++;
1799 }
1800 }
1801
1802 // disable dash
1803 cairo_set_source_rgba(cr, 1, .2, .2, 0.6);
1804 cairo_set_dash(cr, NULL, 0, 0);
1805
1806 for(int k=0; k<ps->imgs.count; k++)
1807 {
1808 dt_image_box *img = &ps->imgs.box[k];
1809
1810 if(k == ps->selected || img->imgid == UNKNOWN_IMAGE)
1811 {
1812 cairo_set_source_rgba(cr, .4, .4, .4, 1.0);
1813 _cairo_rectangle(cr, (k == ps->selected) ? ps->sel_controls : 0,
1814 img->screen.x, img->screen.y,
1815 img->screen.x + img->screen.width, img->screen.y + img->screen.height);
1816 cairo_stroke(cr);
1817 }
1818
1819 if(k == ps->imgs.motion_over)
1820 {
1821 cairo_set_source_rgba(cr, .2, .2, .2, 1.0);
1822 cairo_rectangle(cr, img->screen.x, img->screen.y, img->screen.width, img->screen.height);
1823 cairo_fill(cr);
1824 }
1825 }
1826
1827 // now display new area if any
1828 if(ps->dragging || ps->selected != -1)
1829 {
1830 float dx1, dy1, dx2, dy2, dwidth, dheight; // displayed values
1831 float x1, y1, x2, y2; // box screen coordinates
1832
1833 float pwidth, pheight;
1834 _get_page_dimension(&ps->prt, &pwidth, &pheight);
1835
1836 if(ps->dragging)
1837 {
1838 x1 = ps->x1;
1839 y1 = ps->y1;
1840 x2 = ps->x2;
1841 y2 = ps->y2;
1842
1843 dx1 = _hscreen_to_mm(ps, ps->x1, TRUE) * units[ps->unit];
1844 dy1 = _vscreen_to_mm(ps, ps->y1, TRUE) * units[ps->unit];
1845 dx2 = _hscreen_to_mm(ps, ps->x2, TRUE) * units[ps->unit];
1846 dy2 = _vscreen_to_mm(ps, ps->y2, TRUE) * units[ps->unit];
1847 dwidth = fabsf(dx2 - dx1);
1848 dheight = fabsf(dy2 - dy1);
1849 }
1850 else
1851 {
1852 const dt_image_box *box = &ps->imgs.box[ps->selected];
1853
1854 // we could use a simpler solution but we want to use the same formulae used
1855 // to fill the editable box values to avoid discrepancies between values due
1856 // to rounding errors.
1857
1858 dx1 = _percent_unit_of(ps, pwidth, box->pos.x);
1859 dy1 = _percent_unit_of(ps, pheight, box->pos.y);
1860 dwidth = _percent_unit_of(ps, pwidth, box->pos.width);
1861 dheight = _percent_unit_of(ps, pheight, box->pos.height);
1862 dx2 = dx1 + dwidth;
1863 dy2 = dy1 + dheight;
1864
1865 x1 = box->screen.x;
1866 y1 = box->screen.y;
1867 x2 = box->screen.x + box->screen.width;
1868 y2 = box->screen.y + box->screen.height;
1869 }
1870
1871 cairo_set_source_rgba(cr, .4, .4, .4, 1.0);
1872 _cairo_rectangle(cr, ps->sel_controls, x1, y1, x2, y2);
1873
1874 // display corner coordinates
1875 // FIXME: here and elsewhere eliminate hardcoded RGB values -- use CSS
1876 char dimensions[16];
1877 PangoLayout *layout;
1878 PangoRectangle ext;
1879 PangoFontDescription *desc = pango_font_description_copy_static(dt_bauhaus_get_global()->pango_font_desc);
1880 pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
1881 pango_font_description_set_absolute_size(desc, DT_PIXEL_APPLY_DPI(16) * PANGO_SCALE);
1882 layout = pango_cairo_create_layout(cr);
1883 pango_layout_set_font_description(layout, desc);
1884 const double text_h = DT_PIXEL_APPLY_DPI(16+2);
1885 const double margin = DT_PIXEL_APPLY_DPI(6);
1886 const double dash = DT_PIXEL_APPLY_DPI(4.0);
1887 int n_digits;
1888 char *precision;
1889 _precision_by_unit(ps->unit, &n_digits, NULL, &precision);
1890 double xp, yp;
1891
1892 yp = y1 + (y2 - y1 - text_h) * 0.5;
1893
1894 if(x1 >= ps->imgs.screen.page.x && x1 <= (ps->imgs.screen.page.x + ps->imgs.screen.page.width))
1895 {
1896 snprintf(dimensions, sizeof(dimensions), precision, dx1);
1897 pango_layout_set_text(layout, dimensions, -1);
1898 pango_layout_get_pixel_extents(layout, NULL, &ext);
1899 xp = ps->imgs.screen.page.x + (x1 - text_h - ps->imgs.screen.page.x - ext.width) * 0.5;
1900 if(xp < ps->imgs.screen.page.x + 3 * margin)
1901 {
1902 xp = x1 + 2 * margin;
1903 // somewhat hacky, assumes that all numeric labels are about
1904 // the same width
1905 yp = MIN(y2 - text_h, yp + ext.width + 0.5 * text_h + margin * 3);
1906 }
1907 cairo_set_source_rgba(cr, .7, .7, .7, .9);
1908 cairo_move_to(cr, ps->imgs.screen.page.x, yp + text_h * 0.5);
1909 cairo_line_to(cr, x1, yp + text_h * 0.5);
1910 cairo_stroke_preserve(cr);
1911 cairo_set_source_rgba(cr, .5, .5, .5, .9);
1912 cairo_set_dash(cr, &dash, 1, dash);
1913 cairo_stroke(cr);
1914 cairo_set_dash(cr, NULL, 0, 0);
1915 dt_gui_draw_rounded_rectangle(cr, ext.width + 2 * margin, text_h + 2 * margin, xp - margin, yp - margin);
1916 cairo_set_source_rgb(cr, .8, .8, .8);
1917 cairo_move_to(cr, xp, yp);
1918 pango_cairo_show_layout(cr, layout);
1919 }
1920
1921 if(x2 >= ps->imgs.screen.page.x && x2 <= (ps->imgs.screen.page.x + ps->imgs.screen.page.width))
1922 {
1923 snprintf(dimensions, sizeof(dimensions), precision, pwidth * units[ps->unit] - dx2);
1924 pango_layout_set_text(layout, dimensions, -1);
1925 pango_layout_get_pixel_extents(layout, NULL, &ext);
1926 xp = x2 + (ps->imgs.screen.page.x + ps->imgs.screen.page.width - x2 - ext.width) * 0.5;
1927 if(xp + ext.width + margin > ps->imgs.screen.page.x + ps->imgs.screen.page.width)
1928 xp = x2 - ext.width - 2 * margin;
1929 cairo_set_source_rgba(cr, .7, .7, .7, .9);
1930 cairo_move_to(cr, x2, yp + text_h * 0.5);
1931 cairo_line_to(cr, ps->imgs.screen.page.x + ps->imgs.screen.page.width, yp + text_h * 0.5);
1932 cairo_stroke_preserve(cr);
1933 cairo_set_source_rgba(cr, .5, .5, .5, .9);
1934 cairo_set_dash(cr, &dash, 1, dash);
1935 cairo_stroke(cr);
1936 cairo_set_dash(cr, NULL, 0, 0);
1937 dt_gui_draw_rounded_rectangle(cr, ext.width + 2 * margin, text_h + 2 * margin,
1938 xp - margin, yp - margin);
1939 cairo_set_source_rgb(cr, .8, .8, .8);
1940 cairo_move_to(cr, xp, yp);
1941 pango_cairo_show_layout(cr, layout);
1942 }
1943
1944 xp = x1 + (x2 - x1 - text_h) * 0.5;
1945
1946 if(y1 >= ps->imgs.screen.page.y && y1 <= (ps->imgs.screen.page.y + ps->imgs.screen.page.height))
1947 {
1948 snprintf(dimensions, sizeof(dimensions), precision, dy1);
1949 pango_layout_set_text(layout, dimensions, -1);
1950 pango_layout_get_pixel_extents(layout, NULL, &ext);
1951 yp = ps->imgs.screen.page.y + (y1 - text_h - ps->imgs.screen.page.y - ext.width) * 0.5;
1952 if(yp < ps->imgs.screen.page.y + 3 * margin)
1953 {
1954 xp = MIN(x2 - text_h, xp + ext.width + 0.5 * text_h + margin * 3);
1955 yp = y1 + 2 * margin;
1956 }
1957 cairo_set_source_rgba(cr, .7, .7, .7, .9);
1958 cairo_move_to(cr, xp + text_h * 0.5, ps->imgs.screen.page.y);
1959 cairo_line_to(cr, xp + text_h * 0.5, y1);
1960 cairo_stroke_preserve(cr);
1961 cairo_set_source_rgba(cr, .5, .5, .5, .9);
1962 cairo_set_dash(cr, &dash, 1, dash);
1963 cairo_stroke(cr);
1964 cairo_set_dash(cr, NULL, 0, 0);
1965 dt_gui_draw_rounded_rectangle(cr, text_h + 2 * margin, ext.width + 2 * margin,
1966 xp - margin, yp - margin);
1967 cairo_set_source_rgb(cr, .8, .8, .8);
1968 cairo_move_to(cr, xp + text_h * 0.5, yp + ext.width * 0.5);
1969 cairo_save(cr);
1970 cairo_rotate(cr, -M_PI_2);
1971 cairo_rel_move_to(cr, -0.5 * ext.width, -0.5 * text_h);
1972 pango_cairo_update_layout(cr, layout);
1973 pango_cairo_show_layout(cr, layout);
1974 cairo_restore(cr);
1975 }
1976
1977 if(y2 >= ps->imgs.screen.page.y && y2 <= (ps->imgs.screen.page.y + ps->imgs.screen.page.height))
1978 {
1979 snprintf(dimensions, sizeof(dimensions), precision, pheight * units[ps->unit] - dy2);
1980 pango_layout_set_text(layout, dimensions, -1);
1981 pango_layout_get_pixel_extents(layout, NULL, &ext);
1982 yp = y2 + (ps->imgs.screen.page.y + ps->imgs.screen.page.height - y2 - ext.width) * 0.5;
1983 if(yp + ext.width + margin > ps->imgs.screen.page.y + ps->imgs.screen.page.height)
1984 yp = y2 - ext.width - 2 * margin;
1985 cairo_set_source_rgba(cr, .7, .7, .7, .9);
1986 cairo_move_to(cr, xp + text_h * 0.5, y2);
1987 cairo_line_to(cr, xp + text_h * 0.5, ps->imgs.screen.page.y + ps->imgs.screen.page.height);
1988 cairo_stroke_preserve(cr);
1989 cairo_set_source_rgba(cr, .5, .5, .5, .9);
1990 cairo_set_dash(cr, &dash, 1, dash);
1991 cairo_stroke(cr);
1992 cairo_set_dash(cr, NULL, 0, 0);
1993 dt_gui_draw_rounded_rectangle(cr, text_h + 2 * margin, ext.width + 2 * margin,
1994 xp - margin, yp - margin);
1995 cairo_set_source_rgb(cr, .8, .8, .8);
1996 cairo_move_to(cr, xp + text_h * 0.5, yp + ext.width * 0.5);
1997 cairo_save(cr);
1998 cairo_rotate(cr, -M_PI_2);
1999 cairo_rel_move_to(cr, -0.5 * ext.width, -0.5 * text_h);
2000 pango_cairo_update_layout(cr, layout);
2001 pango_cairo_show_layout(cr, layout);
2002 cairo_restore(cr);
2003 }
2004
2005 // display width and height
2006 snprintf(dimensions, sizeof(dimensions), precision, dwidth);
2007 pango_layout_set_text(layout, dimensions, -1);
2008 pango_layout_get_pixel_extents(layout, NULL, &ext);
2009 xp = (x1 + x2 - ext.width) * .5;
2010 if(y1 > text_h * 0.5 + margin)
2011 yp = y1 - text_h * 0.5;
2012 else
2013 yp = y1 + text_h - 2 * margin;
2014 cairo_set_source_rgba(cr, .5, .5, .5, .9);
2015 dt_gui_draw_rounded_rectangle(cr, ext.width + 2 * margin, text_h + 2 * margin,
2016 xp - margin, yp - margin);
2017 cairo_set_source_rgb(cr, .8, .8, .8);
2018 cairo_move_to(cr, xp, yp);
2019 pango_cairo_show_layout(cr, layout);
2020
2021 snprintf(dimensions, sizeof(dimensions), precision, dheight);
2022 pango_layout_set_text(layout, dimensions, -1);
2023 pango_layout_get_pixel_extents(layout, NULL, &ext);
2024 if(x1 > text_h * 0.5 + margin)
2025 xp = x1 - text_h * 0.5;
2026 else
2027 xp = x1 + text_h - 2 * margin;
2028 yp = (y1 + y2) * .5;
2029 cairo_set_source_rgba(cr, .5, .5, .5, .9);
2030 dt_gui_draw_rounded_rectangle(cr, text_h + 2 * margin, ext.width + 2 * margin,
2031 xp - margin, yp - margin - 0.5 * ext.width);
2032 cairo_set_source_rgb(cr, .8, .8, .8);
2033 cairo_move_to(cr, xp + text_h * 0.5, yp);
2034 cairo_save(cr);
2035 cairo_rotate(cr, -M_PI_2);
2036 cairo_rel_move_to(cr, -0.5 * ext.width, -0.5 * text_h);
2037 pango_cairo_update_layout(cr, layout);
2038 pango_cairo_show_layout(cr, layout);
2039 cairo_restore(cr);
2040
2041 pango_font_description_free(desc);
2042 g_object_unref(layout);
2044 }
2045
2046 if(ps->imgs.screen.borderless)
2047 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ps->borderless), TRUE);
2048 else
2049 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ps->borderless), FALSE);
2050}
2051
2052static void _width_changed(GtkWidget *widget, gpointer user_data)
2053{
2054 if(dt_gui_widgets_suppressed()) return;
2055
2057
2058 const float nv = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
2059 const float nv_mm = nv / units[ps->unit];
2060
2061 dt_image_box *box = &ps->imgs.box[ps->last_selected];
2062
2064 box->screen.x, box->screen.y,
2065 _mm_to_hscreen(ps, nv_mm, FALSE), box->screen.height);
2066
2067 ps->has_changed = TRUE;
2069}
2070
2071static void _height_changed(GtkWidget *widget, gpointer user_data)
2072{
2073 if(dt_gui_widgets_suppressed()) return;
2074
2076
2077 const float nv = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
2078 const float nv_mm = nv / units[ps->unit];
2079
2080 dt_image_box *box = &ps->imgs.box[ps->last_selected];
2081
2083 box->screen.x, box->screen.y,
2084 box->screen.width, _mm_to_vscreen(ps, nv_mm, FALSE));
2085
2086 ps->has_changed = TRUE;
2088}
2089
2090static void _x_changed(GtkWidget *widget, gpointer user_data)
2091{
2092 if(dt_gui_widgets_suppressed()) return;
2093
2095
2096 const float nv = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
2097 const float nv_mm = nv / units[ps->unit];
2098
2099 dt_image_box *box = &ps->imgs.box[ps->last_selected];
2100
2102 _mm_to_hscreen(ps, nv_mm, TRUE), box->screen.y,
2103 box->screen.width, box->screen.height);
2104
2105 ps->has_changed = TRUE;
2107}
2108
2109static void _y_changed(GtkWidget *widget, gpointer user_data)
2110{
2111 if(dt_gui_widgets_suppressed()) return;
2112
2114
2115 const float nv = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
2116 const float nv_mm = nv / units[ps->unit];
2117
2118 dt_image_box *box = &ps->imgs.box[ps->last_selected];
2119
2121 box->screen.x, _mm_to_vscreen(ps, nv_mm, TRUE),
2122 box->screen.width, box->screen.height);
2123
2124 ps->has_changed = TRUE;
2126}
2127
2129{
2131 self->data = d;
2132 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
2133 dt_gui_add_help_link(self->widget, dt_get_help_url("print_overview"));
2134
2135 char datadir[DT_PATH_MAX] = { 0 };
2136 char confdir[DT_PATH_MAX] = { 0 };
2137 dt_loc_get_user_config_dir(confdir, sizeof(confdir));
2138 dt_loc_get_datadir(datadir, sizeof(datadir));
2139 char *system_profile_dir = g_build_filename(datadir, "color", "out", NULL);
2140 char *user_profile_dir = g_build_filename(confdir, "color", "out", NULL);
2141
2142 GtkWidget *label;
2143
2144 d->paper_list = NULL;
2145 d->media_list = NULL;
2146 d->unit = 0;
2147 d->width = d->height = NULL;
2148 d->v_piccprofile = NULL;
2149 d->v_iccprofile = NULL;
2150 d->v_style = NULL;
2151 d->creation = d->dragging = FALSE;
2152 d->selected = -1;
2153 d->last_selected = -1;
2154 d->has_changed = FALSE;
2155
2156 dt_init_print_info(&d->prt);
2158
2159 d->profiles = _get_profiles();
2160
2161 d->imgs.motion_over = -1;
2162
2163 const char *str = dt_conf_get_string_const("plugins/print/print/unit");
2164 const char **names = _unit_names;
2165 for(_unit_t i=0; *names; names++, i++)
2166 if(g_strcmp0(str, *names) == 0)
2167 d->unit = i;
2168
2169 dt_printing_clear_boxes(&d->imgs);
2170
2171 // set all margins + unit from settings
2172
2173 const float top_b = dt_conf_get_float("plugins/print/print/top_margin");
2174 const float bottom_b = dt_conf_get_float("plugins/print/print/bottom_margin");
2175 const float left_b = dt_conf_get_float("plugins/print/print/left_margin");
2176 const float right_b = dt_conf_get_float("plugins/print/print/right_margin");
2177
2178 d->prt.page.margin_top = _to_mm(d, top_b);
2179 d->prt.page.margin_bottom = _to_mm(d, bottom_b);
2180 d->prt.page.margin_left = _to_mm(d, left_b);
2181 d->prt.page.margin_right = _to_mm(d, right_b);
2182
2183 // create the spin-button now as values could be set when the printer has no hardware margin
2184
2185 // FIXME: set digits/increments on all of these by calling _unit_changed() later?
2186 int n_digits;
2187 float incr;
2188 _precision_by_unit(d->unit, &n_digits, &incr, NULL);
2189
2190 d->b_top = gtk_spin_button_new_with_range(0, 1000, incr);
2191 d->b_left = gtk_spin_button_new_with_range(0, 1000, incr);
2192 d->b_right = gtk_spin_button_new_with_range(0, 1000, incr);
2193 d->b_bottom = gtk_spin_button_new_with_range(0, 1000, incr);
2194 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(d->b_top), n_digits);
2195 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(d->b_bottom), n_digits);
2196 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(d->b_left), n_digits);
2197 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(d->b_right), n_digits);
2198
2199 d->b_x = gtk_spin_button_new_with_range(0, 1000, incr);
2200 d->b_y = gtk_spin_button_new_with_range(0, 1000, incr);
2201 d->b_width = gtk_spin_button_new_with_range(0, 1000, incr);
2202 d->b_height = gtk_spin_button_new_with_range(0, 1000, incr);
2203 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(d->b_x), n_digits);
2204 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(d->b_y), n_digits);
2205 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(d->b_width), n_digits);
2206 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(d->b_height), n_digits);
2207
2208 d->grid_size = gtk_spin_button_new_with_range(0, 100, incr);
2209 gtk_spin_button_set_digits(GTK_SPIN_BUTTON(d->grid_size), n_digits);
2210
2211 gtk_entry_set_alignment(GTK_ENTRY(d->b_top), 1);
2212 gtk_entry_set_alignment(GTK_ENTRY(d->b_left), 1);
2213 gtk_entry_set_alignment(GTK_ENTRY(d->b_right), 1);
2214 gtk_entry_set_alignment(GTK_ENTRY(d->b_bottom), 1);
2215
2216 gtk_entry_set_alignment(GTK_ENTRY(d->b_x), 1);
2217 gtk_entry_set_alignment(GTK_ENTRY(d->b_y), 1);
2218 gtk_entry_set_alignment(GTK_ENTRY(d->b_width), 1);
2219 gtk_entry_set_alignment(GTK_ENTRY(d->b_height), 1);
2220
2221 gtk_entry_set_alignment(GTK_ENTRY(d->grid_size), 1);
2222
2223
2225
2226 // create papers combo as filled when adding printers
2228
2229 label = dt_ui_section_label_new(_("printer"));
2230 gtk_box_pack_start(GTK_BOX(self->widget), label, TRUE, TRUE, 0);
2231 dt_gui_add_help_link(self->widget, dt_get_help_url("print_settings_printer"));
2233
2234 gtk_box_pack_start(GTK_BOX(self->widget), d->printers, TRUE, TRUE, 0);
2235 g_signal_connect(G_OBJECT(d->printers), "value-changed", G_CALLBACK(_printer_changed), self);
2236
2238
2240
2241 dt_bauhaus_widget_set_label(d->media, N_("media"));
2242
2243 g_signal_connect(G_OBJECT(d->media), "value-changed", G_CALLBACK(_media_changed), self);
2244 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->media), TRUE, TRUE, 0);
2245
2246 // Add printer profile combo
2247
2249 dt_bauhaus_widget_set_label(d->pprofile, N_("profile"));
2250
2251 int combo_idx, n;
2252
2253 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->pprofile), TRUE, TRUE, 0);
2254 int printer_profile_type = dt_conf_get_int("plugins/print/printer/icctype");
2255 const char *printer_profile = dt_conf_get_string_const("plugins/print/printer/iccprofile");
2256 combo_idx = -1;
2257 n = 0;
2258
2259 dt_bauhaus_combobox_add(d->pprofile, _("color management in printer driver"));
2260 for(const GList *l = d->profiles; l; l = g_list_next(l))
2261 {
2263 // do not add built-in profiles, these are in no way for printing
2264 if(prof->type == DT_COLORSPACE_FILE)
2265 {
2266 dt_bauhaus_combobox_add(d->pprofile, prof->name);
2267 prof->ppos = ++n;
2268 if(prof->type == printer_profile_type &&
2269 (prof->type != DT_COLORSPACE_FILE || !g_strcmp0(prof->filename, printer_profile)))
2270 {
2271 dt_free(d->v_piccprofile);
2272 d->v_picctype = printer_profile_type;
2273 d->v_piccprofile = g_strdup(printer_profile);
2274 combo_idx = n;
2275 }
2276 }
2277 }
2278
2279 // profile not found, maybe a profile has been removed? revert to none
2280 if(combo_idx == -1)
2281 {
2282 dt_conf_set_int("plugins/print/printer/icctype", DT_COLORSPACE_NONE);
2283 dt_conf_set_string("plugins/print/printer/iccprofile", "");
2284 dt_free(d->v_piccprofile);
2285 d->v_picctype = DT_COLORSPACE_NONE;
2286 d->v_piccprofile = g_strdup("");
2287 combo_idx = 0;
2288 }
2289 dt_bauhaus_combobox_set(d->pprofile, combo_idx);
2290
2291 char *tooltip = g_strdup_printf(_("printer ICC profiles in %s or %s"), user_profile_dir, system_profile_dir);
2292 gtk_widget_set_tooltip_text(d->pprofile, tooltip);
2294
2295 g_signal_connect(G_OBJECT(d->pprofile), "value-changed", G_CALLBACK(_printer_profile_changed), (gpointer)self);
2296
2297 // Add printer intent combo
2298
2300 dt_bauhaus_widget_set_label(d->pintent, N_("intent"));
2301 dt_bauhaus_combobox_add(d->pintent, _("perceptual"));
2302 dt_bauhaus_combobox_add(d->pintent, _("relative colorimetric"));
2303 dt_bauhaus_combobox_add(d->pintent, C_("rendering intent", "saturation"));
2304 dt_bauhaus_combobox_add(d->pintent, _("absolute colorimetric"));
2305 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->pintent), TRUE, TRUE, 0);
2306
2307 d->v_pintent = dt_conf_get_int("plugins/print/printer/iccintent");
2308 dt_bauhaus_combobox_set(d->pintent, d->v_pintent);
2309
2310 g_signal_connect (G_OBJECT (d->pintent), "value-changed", G_CALLBACK (_printer_intent_callback), (gpointer)self);
2311 d->prt.printer.intent = d->v_pintent;
2312
2313 d->black_point_compensation = gtk_check_button_new_with_label(_("black point compensation"));
2314 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->black_point_compensation), TRUE, FALSE, 0);
2315 g_signal_connect(d->black_point_compensation, "toggled", G_CALLBACK(_printer_bpc_callback), (gpointer)self);
2316
2317 d->v_black_point_compensation = dt_conf_get_bool("plugins/print/print/black_point_compensation");
2318 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d->black_point_compensation), d->v_black_point_compensation);
2319
2320 gtk_widget_set_tooltip_text(d->black_point_compensation,
2321 _("activate black point compensation when applying the printer profile"));
2322
2323 gtk_widget_set_sensitive(GTK_WIDGET(d->black_point_compensation), combo_idx==0?FALSE:TRUE);
2324
2326
2327 label = dt_ui_section_label_new(_("page"));
2328 gtk_box_pack_start(GTK_BOX(self->widget), label, TRUE, TRUE, 0);
2329 dt_gui_add_help_link(self->widget, dt_get_help_url("print_settings_page"));
2330
2332
2333 dt_bauhaus_widget_set_label(d->papers, N_("paper size"));
2334
2335 g_signal_connect(G_OBJECT(d->papers), "value-changed", G_CALLBACK(_paper_changed), self);
2336 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->papers), TRUE, TRUE, 0);
2337
2339
2341 dt_bauhaus_widget_set_label(d->orientation, N_("orientation"));
2342 dt_bauhaus_combobox_add(d->orientation, _("portrait"));
2343 dt_bauhaus_combobox_add(d->orientation, _("landscape"));
2344 g_signal_connect(G_OBJECT(d->orientation), "value-changed", G_CALLBACK(_orientation_changed), self);
2345 dt_bauhaus_combobox_set(d->orientation, d->prt.page.landscape?1:0);
2346 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->orientation), TRUE, TRUE, 0);
2347
2348 // NOTE: units has no label, which makes for cleaner UI but means that no action can be assigned
2349 GtkWidget *ucomb = dt_bauhaus_combobox_new_full(dt_bauhaus_get_global(), DT_GUI_MODULE(NULL), _("measurement units"), NULL, (int)d->unit,
2350 (GtkCallback)_unit_changed, self, _unit_names);
2351 gtk_box_pack_start(GTK_BOX(self->widget), ucomb, TRUE, TRUE, 0);
2352
2354
2355 GtkWidget *hboxdim = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
2356 label = gtk_label_new(_("image width/height"));
2357 gtk_box_pack_start(GTK_BOX(hboxdim), GTK_WIDGET(label), TRUE, TRUE, DT_PIXEL_APPLY_DPI(3));
2358 d->width = gtk_label_new(_("width"));
2359 gtk_box_pack_start(GTK_BOX(hboxdim), GTK_WIDGET(d->width), TRUE, TRUE, 0);
2360 label = gtk_label_new(_(" x "));
2361 gtk_box_pack_start(GTK_BOX(hboxdim), GTK_WIDGET(label), TRUE, TRUE, 0);
2362 d->height = gtk_label_new(_("height"));
2363 gtk_box_pack_start(GTK_BOX(hboxdim), GTK_WIDGET(d->height), TRUE, TRUE, 0);
2364
2366
2367 GtkWidget *hboxinfo = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
2368 label = gtk_label_new(_("scale factor"));
2369 gtk_box_pack_start(GTK_BOX(hboxinfo), GTK_WIDGET(label), TRUE, TRUE, DT_PIXEL_APPLY_DPI(3));
2370 d->info = gtk_label_new("1.0");
2371 gtk_box_pack_start(GTK_BOX(hboxinfo), GTK_WIDGET(d->info), TRUE, TRUE, 0);
2372 gtk_widget_set_tooltip_text(hboxinfo,
2373 _("image scale factor from native printer DPI:\n"
2374 " < 1 means that it is downscaled (best quality)\n"
2375 " > 1 means that the image is upscaled\n"
2376 " a too large value may result in poor print quality"));
2377
2379
2380 GtkGrid *bds = GTK_GRID(gtk_grid_new());
2381 gtk_grid_set_row_spacing(bds, DT_GUI_BOX_SPACING);
2382 gtk_grid_set_column_spacing(bds, DT_GUI_BOX_SPACING);
2383
2384 d->lock_activated = FALSE;
2385
2386 //d->b_top = gtk_spin_button_new_with_range(0, 10000, 1);
2387 gtk_widget_set_tooltip_text(GTK_WIDGET(d->b_top), _("top margin"));
2388 gtk_grid_attach(bds, GTK_WIDGET(d->b_top), 1, 0, 1, 1);
2389
2390 //d->b_left = gtk_spin_button_new_with_range(0, 10000, 1);
2391 gtk_widget_set_tooltip_text(GTK_WIDGET(d->b_left), _("left margin"));
2392 gtk_grid_attach(bds, GTK_WIDGET(d->b_left), 0, 1, 1, 1);
2393
2394 d->lock_button = GTK_TOGGLE_BUTTON(gtk_toggle_button_new_with_label(_("lock")));
2395 gtk_widget_set_tooltip_text(GTK_WIDGET(d->lock_button), _("change all margins uniformly"));
2396 gtk_grid_attach(bds, GTK_WIDGET(d->lock_button), 1, 1, 1, 1);
2397
2398 //d->b_right = gtk_spin_button_new_with_range(0, 10000, 1);
2399 gtk_widget_set_tooltip_text(GTK_WIDGET(d->b_right), _("right margin"));
2400 gtk_grid_attach(bds, GTK_WIDGET(d->b_right), 2, 1, 1, 1);
2401
2402 //d->b_bottom = gtk_spin_button_new_with_range(0, 10000, 1);
2403 gtk_widget_set_tooltip_text(GTK_WIDGET(d->b_bottom), _("bottom margin"));
2404 gtk_grid_attach(bds, GTK_WIDGET(d->b_bottom), 1, 2, 1, 1);
2405
2406 gtk_widget_set_halign(GTK_WIDGET(bds), GTK_ALIGN_CENTER);
2407 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(bds), TRUE, TRUE, 0);
2408
2409 gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->b_top), top_b);
2410 gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->b_bottom), bottom_b);
2411 gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->b_left), left_b);
2412 gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->b_right), right_b);
2413
2414 g_signal_connect(G_OBJECT (d->b_top), "value-changed",
2415 G_CALLBACK (_top_border_callback), self);
2416 g_signal_connect(G_OBJECT (d->b_bottom), "value-changed",
2417 G_CALLBACK (_bottom_border_callback), self);
2418 g_signal_connect(G_OBJECT (d->b_left), "value-changed",
2419 G_CALLBACK (_left_border_callback), self);
2420 g_signal_connect(G_OBJECT (d->b_right), "value-changed",
2421 G_CALLBACK (_right_border_callback), self);
2422 g_signal_connect(G_OBJECT(d->lock_button), "toggled",
2423 G_CALLBACK(_lock_callback), self);
2424
2425 gtk_widget_set_halign(GTK_WIDGET(hboxdim), GTK_ALIGN_CENTER);
2426 gtk_widget_set_halign(GTK_WIDGET(hboxinfo), GTK_ALIGN_CENTER);
2427
2428 const gboolean lock_active = dt_conf_get_bool("plugins/print/print/lock_borders");
2429 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d->lock_button), lock_active);
2430
2431 // grid & snap grid
2432 {
2433 GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
2434 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
2435
2436 d->grid = gtk_check_button_new_with_label(_("display grid"));
2437 // d->grid_size = gtk_spin_button_new_with_range(0, 100, 0.1);
2438 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(d->grid), TRUE, TRUE, 0);
2439 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(d->grid_size), TRUE, TRUE, 0);
2440
2441 gtk_spin_button_set_value(GTK_SPIN_BUTTON(d->grid_size),
2442 dt_conf_get_float("plugins/print/print/grid_size") * units[d->unit]);
2443
2444 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), TRUE, TRUE, 0);
2445
2446 d->snap_grid = gtk_check_button_new_with_label(_("snap to grid"));
2447 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(d->snap_grid), TRUE, TRUE, 0);
2448
2449 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(vbox), TRUE, TRUE, 0);
2450
2451 g_signal_connect(G_OBJECT(d->grid_size), "value-changed", G_CALLBACK(_grid_size_changed), self);
2452 g_signal_connect(G_OBJECT(d->grid), "toggled", G_CALLBACK(_grid_callback), self);
2453 g_signal_connect(d->snap_grid, "toggled", G_CALLBACK(_snap_grid_callback), (gpointer)self);
2454 }
2455
2456 d->borderless = gtk_check_button_new_with_label(_("borderless mode required"));
2457 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->borderless), TRUE, TRUE, 0);
2458 gtk_widget_set_tooltip_text(d->borderless,
2459 _("indicates that the borderless mode should be activated\n"
2460 "in the printer driver because the selected margins are\n"
2461 "below the printer hardware margins"));
2462 gtk_widget_set_sensitive(d->borderless, FALSE);
2463
2464 // pack image dimension hbox here
2465
2466 label = dt_ui_section_label_new(_("image layout"));
2467 gtk_box_pack_start(GTK_BOX(self->widget), label, TRUE, TRUE, 0);
2468 dt_gui_add_help_link(self->widget, dt_get_help_url("print_image_layout"));
2469
2470 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hboxdim), TRUE, TRUE, 0);
2471 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hboxinfo), TRUE, TRUE, 0);
2472
2474
2475 // Auto-fit: Create the 3x3 gtk table toggle button table...
2476 GtkGrid *bat = GTK_GRID(gtk_grid_new());
2477 gtk_grid_set_row_spacing(bat, DT_GUI_BOX_SPACING);
2478 gtk_grid_set_column_spacing(bat, DT_GUI_BOX_SPACING);
2479 for(int i=0; i<9; i++)
2480 {
2481 d->dtba[i]
2483 gtk_grid_attach (GTK_GRID (bat), GTK_WIDGET (d->dtba[i]), (i%3), i/3, 1, 1);
2484 g_signal_connect (G_OBJECT (d->dtba[i]), "toggled",G_CALLBACK (_alignment_callback), self);
2485 }
2486
2487 GtkWidget *hbox22 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
2488 GtkWidget *label4 = gtk_label_new(_("alignment"));
2489 gtk_box_pack_start(GTK_BOX(hbox22),GTK_WIDGET(label4),TRUE,TRUE,0);
2490 gtk_box_pack_start(GTK_BOX(hbox22), GTK_WIDGET(bat), TRUE, TRUE, 0);
2491 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hbox22), TRUE, TRUE, 0);
2492
2493 // Manual fit
2494 GtkWidget *hfitbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
2495
2496 GtkWidget *mfitbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
2497
2498 GtkGrid *fitbut = GTK_GRID(gtk_grid_new());
2499 gtk_grid_set_row_spacing(fitbut, DT_GUI_BOX_SPACING);
2500 gtk_grid_set_column_spacing(fitbut, DT_GUI_BOX_SPACING);
2501 gtk_grid_set_column_homogeneous(fitbut, TRUE);
2502 gtk_grid_set_row_homogeneous(fitbut, TRUE);
2503
2504 GtkWidget *bnew = dt_action_button_new(self, N_("new image area"), _page_new_area_clicked, self,
2505 _("add a new image area on the page\n"
2506 "click and drag on the page to place the area\n"
2507 "drag&drop image from film strip on it"), 0, 0);
2508
2509 d->del = dt_action_button_new(self, N_("delete image area"), _page_delete_area_clicked, self,
2510 _("delete the currently selected image area"), 0, 0);
2511 gtk_widget_set_sensitive(d->del, FALSE);
2512
2513 GtkWidget *bclear = dt_action_button_new(self, N_("clear layout"), _page_clear_area_clicked, self,
2514 _("remove all image areas from the page"), 0, 0);
2515
2516 gtk_grid_attach(fitbut, GTK_WIDGET(bnew), 0, 0, 2, 1);
2517 gtk_grid_attach(fitbut, GTK_WIDGET(d->del), 0, 1, 1, 1);
2518 gtk_grid_attach(fitbut, GTK_WIDGET(bclear), 1, 1, 1, 1);
2519
2520 gtk_box_pack_start(GTK_BOX(mfitbox), GTK_WIDGET(fitbut), TRUE, TRUE, 0);
2521 gtk_box_pack_start(GTK_BOX(hfitbox), GTK_WIDGET(mfitbox), TRUE, TRUE, 0);
2522
2523 // X x Y
2524 GtkWidget *box;
2525 // FIXME: add labels to x/y/width/height as otherwise are obscure -- and there is the horizontal space to do this
2526
2527 box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
2528 // d->b_x = gtk_spin_button_new_with_range(0, 1000, 1);
2529 gtk_widget_set_tooltip_text(d->b_x, _("image area x origin (in current unit)"));
2530 gtk_entry_set_width_chars(GTK_ENTRY(d->b_x), 5);
2531
2532 // d->b_y = gtk_spin_button_new_with_range(0, 1000, 1);
2533 gtk_widget_set_tooltip_text(d->b_y, _("image area y origin (in current unit)"));
2534 gtk_entry_set_width_chars(GTK_ENTRY(d->b_y), 5);
2535
2536 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(d->b_x), TRUE, TRUE, 0);
2537 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(d->b_y), TRUE, TRUE, 0);
2538
2539 gtk_box_pack_start(GTK_BOX(hfitbox), GTK_WIDGET(box), TRUE, TRUE, 0);
2540
2541 // width x height
2542 box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
2543 // d->b_width = gtk_spin_button_new_with_range(0, 1000, 1);
2544 gtk_widget_set_tooltip_text(d->b_width, _("image area width (in current unit)"));
2545 gtk_entry_set_width_chars(GTK_ENTRY(d->b_width), 5);
2546
2547 // d->b_height = gtk_spin_button_new_with_range(0, 1000, 1);
2548 gtk_widget_set_tooltip_text(d->b_height, _("image area height (in current unit)"));
2549 gtk_entry_set_width_chars(GTK_ENTRY(d->b_height), 5);
2550
2551 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(d->b_width), TRUE, TRUE, 0);
2552 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(d->b_height), TRUE, TRUE, 0);
2553
2554 gtk_box_pack_start(GTK_BOX(hfitbox), GTK_WIDGET(box), TRUE, TRUE, 0);
2555
2556 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hfitbox), TRUE, TRUE, 0);
2557
2558 gtk_widget_add_events(d->b_x, GDK_BUTTON_PRESS_MASK);
2559 gtk_widget_add_events(d->b_y, GDK_BUTTON_PRESS_MASK);
2560 gtk_widget_add_events(d->b_width, GDK_BUTTON_PRESS_MASK);
2561 gtk_widget_add_events(d->b_height, GDK_BUTTON_PRESS_MASK);
2562
2563 g_signal_connect(G_OBJECT(d->b_x), "value-changed", G_CALLBACK(_x_changed), (gpointer)d);
2564 g_signal_connect(G_OBJECT(d->b_y), "value-changed", G_CALLBACK(_y_changed), (gpointer)d);
2565 g_signal_connect(G_OBJECT(d->b_width), "value-changed", G_CALLBACK(_width_changed), (gpointer)d);
2566 g_signal_connect(G_OBJECT(d->b_height), "value-changed", G_CALLBACK(_height_changed), (gpointer)d);
2567
2569
2570 label = dt_ui_section_label_new(_("print settings"));
2571 gtk_box_pack_start(GTK_BOX(self->widget), label, TRUE, TRUE, 0);
2572 dt_gui_add_help_link(self->widget, dt_get_help_url("print_settings"));
2573
2574 // Add export profile combo
2575
2577 dt_bauhaus_widget_set_label(d->profile, N_("profile"));
2578
2579 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->profile), TRUE, TRUE, 0);
2580 dt_bauhaus_combobox_add(d->profile, _("image settings"));
2581
2582 const int icctype = dt_conf_get_int("plugins/print/print/icctype");
2583 const gchar *iccprofile = dt_conf_get_string_const("plugins/print/print/iccprofile");
2584 combo_idx = -1;
2585 n = 0;
2586
2587 for(const GList *l = d->profiles; l; l = g_list_next(l))
2588 {
2590 dt_bauhaus_combobox_add(d->profile, prof->name);
2591 prof->pos = ++n;
2592 if(prof->type == icctype
2593 && (prof->type != DT_COLORSPACE_FILE || !g_strcmp0(prof->filename, iccprofile)))
2594 {
2595 dt_free(d->v_iccprofile);
2596 d->v_icctype = icctype;
2597 d->v_iccprofile = g_strdup(iccprofile);
2598 combo_idx = n;
2599 }
2600 }
2601
2602 if(combo_idx == -1)
2603 {
2604 dt_conf_set_int("plugins/print/print/icctype", DT_COLORSPACE_NONE);
2605 dt_conf_set_string("plugins/print/print/iccprofile", "");
2606 dt_free(d->v_iccprofile);
2607 d->v_icctype = DT_COLORSPACE_NONE;
2608 d->v_iccprofile = g_strdup("");
2609 combo_idx = 0;
2610 }
2611
2612 dt_bauhaus_combobox_set(d->profile, combo_idx);
2613
2614 tooltip = g_strdup_printf(_("output ICC profiles in %s or %s"), user_profile_dir, system_profile_dir);
2615 gtk_widget_set_tooltip_text(d->profile, tooltip);
2617
2618 g_signal_connect(G_OBJECT(d->profile), "value-changed", G_CALLBACK(_profile_changed), (gpointer)self);
2619
2620 // Add export intent combo
2621
2623 dt_bauhaus_widget_set_label(d->intent, N_("intent"));
2624
2625 dt_bauhaus_combobox_add(d->intent, _("image settings"));
2626 dt_bauhaus_combobox_add(d->intent, _("perceptual"));
2627 dt_bauhaus_combobox_add(d->intent, _("relative colorimetric"));
2628 dt_bauhaus_combobox_add(d->intent, C_("rendering intent", "saturation"));
2629 dt_bauhaus_combobox_add(d->intent, _("absolute colorimetric"));
2630 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->intent), TRUE, TRUE, 0);
2631
2632 dt_bauhaus_combobox_set(d->intent, dt_conf_get_int("plugins/print/print/iccintent") + 1);
2633
2634 g_signal_connect (G_OBJECT (d->intent), "value-changed", G_CALLBACK (_intent_callback), (gpointer)self);
2635
2636 // Add export style combo
2637
2639 dt_bauhaus_widget_set_label(d->style, N_("style"));
2640
2641 dt_bauhaus_combobox_add(d->style, _("none"));
2642
2643 GList *styles = dt_styles_get_list("");
2644 const char *current_style = dt_conf_get_string_const("plugins/print/print/style");
2645 combo_idx = -1; n=0;
2646
2647 for(const GList *st_iter = styles; st_iter; st_iter = g_list_next(st_iter))
2648 {
2649 dt_style_t *style=(dt_style_t *)st_iter->data;
2650 dt_bauhaus_combobox_add(d->style, style->name);
2651 n++;
2652 if(g_strcmp0(style->name,current_style)==0)
2653 {
2654 dt_free(d->v_style);
2655 d->v_style = g_strdup(current_style);
2656 combo_idx=n;
2657 }
2658 }
2659 g_list_free_full(styles, dt_style_free);
2660 styles = NULL;
2661 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->style), TRUE, TRUE, 0);
2662 gtk_widget_set_tooltip_text(d->style, _("temporary style to use while printing"));
2663
2664 // style not found, maybe a style has been removed? revert to none
2665 if(combo_idx == -1)
2666 {
2667 dt_conf_set_string("plugins/print/print/style", "");
2668 dt_free(d->v_style);
2669 d->v_style = g_strdup("");
2670 combo_idx=0;
2671 }
2672 dt_bauhaus_combobox_set(d->style, combo_idx);
2673
2674 g_signal_connect (G_OBJECT (d->style), "value-changed",
2675 G_CALLBACK (_style_callback),
2676 (gpointer)self);
2677
2678 // Print button
2679
2680 GtkWidget *button = dt_action_button_new(self, N_("print"), _print_button_clicked, self,
2681 _("print with current settings"), GDK_KEY_p, DT_PRIMARY_MASK);
2682 d->print_button = GTK_BUTTON(button);
2683 gtk_box_pack_start(GTK_BOX(self->widget), button, TRUE, TRUE, 0);
2684 dt_gui_add_help_link(button, dt_get_help_url("print_settings_button"));
2685
2686 dt_free(system_profile_dir);
2687 dt_free(user_profile_dir);
2688
2689 // Let's start the printer discovery now
2690
2692}
2693
2694void *legacy_params(dt_lib_module_t *self, const void *const old_params, const size_t old_params_size,
2695 const int old_version, int *new_version, size_t *new_size)
2696{
2697 if(old_version == 1)
2698 {
2699 // we added the profile type
2700 //
2701 // old format:
2702 // char *printer
2703 // char *paper
2704 // int32_t landscape
2705 // char *f_profile
2706 // int32_t intent
2707 // char *f_pprofile
2708 // <rest>
2709 //
2710 // new format:
2711 // char *printer
2712 // char *paper
2713 // int32_t landscape
2714 // int32_t f_profile_type
2715 // char *f_profile
2716 // int32_t intent
2717 // int32_t f_pprofile_type
2718 // char *f_pprofile
2719 // <rest>
2720
2721 const char *buf = (const char *)old_params;
2722
2723 // printer
2724 const char *printer = buf;
2725 const int32_t printer_len = strlen(printer) + 1;
2726 buf += printer_len;
2727
2728 // paper
2729 const char *paper = buf;
2730 const int32_t paper_len = strlen(paper) + 1;
2731 buf += paper_len;
2732
2733 // landscape
2734 const int32_t landscape = *(int32_t *)buf;
2735 buf += sizeof(int32_t);
2736
2737 // profile
2738 const char *profile = buf;
2739 const int32_t profile_len = strlen(profile) + 1;
2740 buf += profile_len;
2741
2742 // intent
2743 const int32_t intent = *(int32_t *)buf;
2744 buf += sizeof(int32_t);
2745
2746 // pprofile
2747 const char *pprofile = buf;
2748 const int32_t pprofile_len = strlen(pprofile) + 1;
2749 buf += pprofile_len;
2750
2751
2752 // now we got all fields from the start of the buffer and buf points to the beginning or <rest>
2753
2754 // find the new values for the two profiles
2755 dt_colorspaces_color_profile_type_t profile_type, pprofile_type;
2756 const char *profile_filename = "", *pprofile_filename = "";
2757
2758 if(*profile == '\0' || !g_strcmp0(profile, "none"))
2759 {
2760 profile_type = DT_COLORSPACE_NONE;
2761 }
2762 else if(!g_strcmp0(profile, "sRGB"))
2763 {
2764 profile_type = DT_COLORSPACE_SRGB;
2765 }
2766 else if(!g_strcmp0(profile, "adobergb"))
2767 {
2768 profile_type = DT_COLORSPACE_ADOBERGB;
2769 }
2770 else
2771 {
2772 profile_type = DT_COLORSPACE_FILE;
2773 profile_filename = &profile[1]; // the old code had a '/' in the beginning
2774 }
2775
2776 // in theory pprofile can't be srgb or adobergb, but checking for them won't hurt
2777 if(*pprofile == '\0')
2778 {
2779 pprofile_type = DT_COLORSPACE_NONE;
2780 }
2781 else if(!g_strcmp0(pprofile, "sRGB"))
2782 {
2783 pprofile_type = DT_COLORSPACE_SRGB;
2784 }
2785 else if(!g_strcmp0(pprofile, "adobergb"))
2786 {
2787 pprofile_type = DT_COLORSPACE_ADOBERGB;
2788 }
2789 else
2790 {
2791 pprofile_type = DT_COLORSPACE_FILE;
2792 pprofile_filename = &pprofile[1]; // the old code had a '/' in the beginning
2793 }
2794
2795 const int32_t new_profile_len = strlen(profile_filename) + 1;
2796 const int32_t new_pprofile_len = strlen(pprofile_filename) + 1;
2797
2798 // now we got everything to reassemble the new params
2799 size_t new_params_size = old_params_size - profile_len - pprofile_len;
2800 new_params_size += 2 * sizeof(dt_colorspaces_color_profile_type_t);
2801 new_params_size += new_profile_len + new_pprofile_len;
2802 void *new_params = malloc(new_params_size);
2803
2804 size_t pos = 0;
2805 // char *printer
2806 memcpy((uint8_t *)new_params + pos, printer, printer_len);
2807 pos += printer_len;
2808 // char *paper
2809 memcpy((uint8_t *)new_params + pos, paper, paper_len);
2810 pos += paper_len;
2811 // int32_t landscape
2812 memcpy((uint8_t *)new_params + pos, &landscape, sizeof(int32_t));
2813 pos += sizeof(int32_t);
2814 // int32_t f_profile_type
2815 memcpy((uint8_t *)new_params + pos, &profile_type, sizeof(int32_t));
2816 pos += sizeof(int32_t);
2817 // char *f_profile
2818 memcpy((uint8_t *)new_params + pos, profile_filename, new_profile_len);
2819 pos += new_profile_len;
2820 // int32_t intent
2821 memcpy((uint8_t *)new_params + pos, &intent, sizeof(int32_t));
2822 pos += sizeof(int32_t);
2823 // int32_t f_pprofile_type
2824 memcpy((uint8_t *)new_params + pos, &pprofile_type, sizeof(int32_t));
2825 pos += sizeof(int32_t);
2826 // char *f_pprofile
2827 memcpy((uint8_t *)new_params + pos, pprofile_filename, new_pprofile_len);
2828 pos += new_pprofile_len;
2829 // <rest>
2830 memcpy((uint8_t *)new_params + pos, buf, old_params_size - ((char *)buf - (char *)old_params));
2831
2832 *new_size = new_params_size;
2833 *new_version = 2;
2834 return new_params;
2835 }
2836 else if(old_version == 2)
2837 {
2838 // add upscale to params
2839 size_t new_params_size = old_params_size + 1;
2840 void *new_params = calloc(1, new_params_size);
2841
2842 memcpy(new_params, old_params, old_params_size);
2843 // no media type specified
2844 ((char *)new_params)[old_params_size] = '\0';
2845
2846 *new_size = new_params_size;
2847 *new_version = 3;
2848 return new_params;
2849 }
2850 else if(old_version == 3)
2851 {
2852 // no box
2853 size_t new_params_size = old_params_size + sizeof(int32_t) + 4 * sizeof(float);
2854 void *new_params = calloc(1, new_params_size);
2855
2856 memcpy(new_params, old_params, old_params_size);
2857
2858 // single image box specified (there is no way to create a box on the size
2859 // of the page at this stage).
2860 int32_t idx = old_params_size;
2861 *(int32_t *)((uint8_t *)new_params + idx) = 1;
2862 idx += sizeof(int32_t);
2863 *(float *)((uint8_t *)new_params + idx) = 0.05f;
2864 idx += sizeof(float);
2865 *(float *)((uint8_t *)new_params + idx) = 0.05f;
2866 idx += sizeof(float);
2867 *(float *)((uint8_t *)new_params + idx) = 0.90f;
2868 idx += sizeof(float);
2869 *(float *)((uint8_t *)new_params + idx) = 0.90f;
2870 // idx += sizeof(float);
2871
2872 *new_size = new_params_size;
2873 *new_version = 4;
2874 return new_params;
2875 }
2876
2877 return NULL;
2878}
2879
2880int set_params(dt_lib_module_t *self, const void *params, int size)
2881{
2883
2884 if(IS_NULL_PTR(params)) return 1;
2885
2886 // get the parameters buffer
2887 const char *buf = (char *)params;
2888
2889 // get individual items
2890 const char *printer = buf;
2891 if(IS_NULL_PTR(printer)) return 1;
2892 const int32_t printer_len = strlen(printer) + 1;
2893 buf += printer_len;
2894
2895 const char *paper = buf;
2896 if(IS_NULL_PTR(paper)) return 1;
2897 const int32_t paper_len = strlen(paper) + 1;
2898 buf += paper_len;
2899
2900 const int32_t landscape = *(int32_t *)buf;
2901 buf += sizeof(int32_t);
2902
2903 const int32_t f_profile_type = *(int32_t *)buf;
2904 buf += sizeof(int32_t);
2905
2906 const char *f_profile = buf;
2907 if(IS_NULL_PTR(f_profile)) return 1;
2908 const int32_t profile_len = strlen(f_profile) + 1;
2909 buf += profile_len;
2910
2911 const int32_t intent = *(int32_t *)buf;
2912 buf += sizeof(int32_t);
2913
2914 const int32_t f_pprofile_type = *(int32_t *)buf;
2915 buf += sizeof(int32_t);
2916
2917 const char *f_pprofile = buf;
2918 if(IS_NULL_PTR(f_pprofile)) return 1;
2919 const int32_t pprofile_len = strlen(f_pprofile) + 1;
2920 buf += pprofile_len;
2921
2922 const int32_t pintent = *(int32_t *)buf;
2923 buf += sizeof(int32_t);
2924
2925 const int32_t bpc = *(int32_t *)buf;
2926 buf += sizeof(int32_t);
2927
2928 const char *style = buf;
2929 if(IS_NULL_PTR(style)) return 1;
2930 const int32_t style_len = strlen(style) + 1;
2931 buf += style_len;
2932
2933 //const int32_t style_mode = *(int32_t *)buf;
2934 buf += sizeof(int32_t);
2935
2936 const double b_top = *(double *)buf;
2937 buf += sizeof(double);
2938
2939 const double b_bottom = *(double *)buf;
2940 buf += sizeof(double);
2941
2942 const double b_left = *(double *)buf;
2943 buf += sizeof(double);
2944
2945 const double b_right = *(double *)buf;
2946 buf += sizeof(double);
2947
2948 const int32_t alignment = *(int32_t *)buf;
2949 buf += sizeof(int32_t);
2950
2951 const char *media = buf;
2952 if(IS_NULL_PTR(media)) return 1;
2953 const int32_t media_len = strlen(media) + 1;
2954 buf += media_len;
2955
2956 ps->imgs.count = *(int32_t *)buf;
2957 buf += sizeof(int32_t);
2958
2959 for(int k=0; k<ps->imgs.count; k++)
2960 {
2961 ps->imgs.box[k].pos.x = *(float *)buf;
2962 buf += sizeof(float);
2963 ps->imgs.box[k].pos.y = *(float *)buf;
2964 buf += sizeof(float);
2965 ps->imgs.box[k].pos.width = *(float *)buf;
2966 buf += sizeof(float);
2967 ps->imgs.box[k].pos.height = *(float *)buf;
2968 buf += sizeof(float);
2969 }
2970
2971 // ensure that the size is correct
2972 if(size != printer_len + paper_len + media_len + profile_len + pprofile_len + style_len + 8 * sizeof(int32_t) + 4 * sizeof(double) + sizeof(int32_t) + (ps->imgs.count * 4 * sizeof(float)))
2973 return 1;
2974
2975 // set the GUI with corresponding values
2976 if(printer[0] != '\0')
2978
2979 if(paper[0] != '\0')
2981
2982 if(media[0] != '\0')
2984
2985 dt_bauhaus_combobox_set (ps->orientation, landscape);
2986
2988 for(GList *iter = ps->profiles; iter; iter = g_list_next(iter))
2989 {
2991 if(f_profile_type == p->type && (f_profile_type != DT_COLORSPACE_FILE || !g_strcmp0(f_profile, p->filename)))
2992 {
2994 break;
2995 }
2996 }
2997
2998 dt_bauhaus_combobox_set (ps->intent, intent);
2999
3001 for(GList *iter = ps->profiles; iter; iter = g_list_next(iter))
3002 {
3004 if(f_pprofile_type == p->type && (f_pprofile_type != DT_COLORSPACE_FILE || !g_strcmp0(f_pprofile, p->filename)))
3005 {
3007 break;
3008 }
3009 }
3010
3011 dt_bauhaus_combobox_set (ps->pintent, pintent);
3012 ps->prt.printer.intent = pintent;
3013
3014 if(style[0] != '\0')
3016
3017 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_top), b_top * units[ps->unit]);
3018 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_bottom), b_bottom * units[ps->unit]);
3019 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_left), b_left * units[ps->unit]);
3020 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_right), b_right * units[ps->unit]);
3021
3022 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ps->dtba[alignment]), TRUE);
3023 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ps->black_point_compensation), bpc);
3024
3026
3027 return 0;
3028}
3029
3031{
3033
3034 // get the data
3035 const char *printer = dt_bauhaus_combobox_get_text(ps->printers);
3036 const char *paper = dt_bauhaus_combobox_get_text(ps->papers);
3037 const char *media = dt_bauhaus_combobox_get_text(ps->media);
3038 const int32_t profile_pos = dt_bauhaus_combobox_get(ps->profile);
3039 const int32_t intent = dt_bauhaus_combobox_get(ps->intent);
3040 const char *style = dt_bauhaus_combobox_get_text(ps->style);
3041 const int32_t style_mode = 0; // deprecated, kept for compatibility
3042 const int32_t pprofile_pos = dt_bauhaus_combobox_get(ps->pprofile);
3043 const int32_t pintent = dt_bauhaus_combobox_get(ps->pintent);
3044 const int32_t landscape = dt_bauhaus_combobox_get(ps->orientation);
3045 const int32_t bpc = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ps->black_point_compensation));
3046 const double b_top = ps->prt.page.margin_top;
3047 const double b_bottom = ps->prt.page.margin_bottom;
3048 const double b_left = ps->prt.page.margin_left;
3049 const double b_right = ps->prt.page.margin_right;
3050 const int32_t alignment = 0;
3051
3053 const char *profile = "", *pprofile = "";
3054 for(GList *iter = ps->profiles; iter; iter = g_list_next(iter))
3055 {
3057 if(p->pos == profile_pos)
3058 {
3059 profile_type = p->type;
3060 profile = p->filename;
3061 }
3062 if(p->ppos == pprofile_pos)
3063 {
3064 pprofile_type = p->type;
3065 pprofile = p->filename;
3066 }
3067 }
3068
3069 // these will be NULL when no printer is connected/found
3070 if(IS_NULL_PTR(printer)) printer = "";
3071 if(IS_NULL_PTR(paper)) paper = "";
3072 if(IS_NULL_PTR(media)) media = "";
3073
3074 // compute the size of individual items, always get the \0 for strings
3075 const int32_t printer_len = strlen (printer) + 1;
3076 const int32_t paper_len = strlen (paper) + 1;
3077 const int32_t media_len = strlen (media) + 1;
3078 const int32_t profile_len = strlen (profile) + 1;
3079 const int32_t pprofile_len = strlen (pprofile) + 1;
3080 const int32_t style_len = strlen (style) + 1;
3081
3082 // compute the size of all parameters
3083 *size = printer_len + paper_len + media_len + profile_len + pprofile_len + style_len + 8 * sizeof(int32_t) + 4 * sizeof(double) + sizeof(int32_t) + (ps->imgs.count * 4 * sizeof(float));
3084
3085 // allocate the parameter buffer
3086 char *params = (char *)malloc(*size);
3087
3088 int pos = 0;
3089
3090 memcpy(params+pos, printer, printer_len);
3091 pos += printer_len;
3092 memcpy(params+pos, paper, paper_len);
3093 pos += paper_len;
3094 memcpy(params+pos, &landscape, sizeof(int32_t));
3095 pos += sizeof(int32_t);
3096 memcpy(params+pos, &profile_type, sizeof(int32_t));
3097 pos += sizeof(int32_t);
3098 memcpy(params+pos, profile, profile_len);
3099 pos += profile_len;
3100 memcpy(params+pos, &intent, sizeof(int32_t));
3101 pos += sizeof(int32_t);
3102 memcpy(params+pos, &pprofile_type, sizeof(int32_t));
3103 pos += sizeof(int32_t);
3104 memcpy(params+pos, pprofile, pprofile_len);
3105 pos += pprofile_len;
3106 memcpy(params+pos, &pintent, sizeof(int32_t));
3107 pos += sizeof(int32_t);
3108 memcpy(params+pos, &bpc, sizeof(int32_t));
3109 pos += sizeof(int32_t);
3110 memcpy(params+pos, style, style_len);
3111 pos += style_len;
3112 memcpy(params+pos, &style_mode, sizeof(int32_t));
3113 pos += sizeof(int32_t);
3114 memcpy(params+pos, &b_top, sizeof(double));
3115 pos += sizeof(double);
3116 memcpy(params+pos, &b_bottom, sizeof(double));
3117 pos += sizeof(double);
3118 memcpy(params+pos, &b_left, sizeof(double));
3119 pos += sizeof(double);
3120 memcpy(params+pos, &b_right, sizeof(double));
3121 pos += sizeof(double);
3122 memcpy(params+pos, &alignment, sizeof(int32_t));
3123 pos += sizeof(int32_t);
3124 memcpy(params+pos, media, media_len);
3125 pos += media_len;
3126
3127 // boxes
3128 memcpy(params+pos, &ps->imgs.count, sizeof(int32_t));
3129 pos += sizeof(int32_t);
3130
3131 for(int k=0; k<ps->imgs.count; k++)
3132 {
3133 memcpy(params+pos, &ps->imgs.box[k].pos.x, sizeof(float));
3134 pos += sizeof(int32_t);
3135 memcpy(params+pos, &ps->imgs.box[k].pos.y, sizeof(float));
3136 pos += sizeof(int32_t);
3137 memcpy(params+pos, &ps->imgs.box[k].pos.width, sizeof(float));
3138 pos += sizeof(int32_t);
3139 memcpy(params+pos, &ps->imgs.box[k].pos.height, sizeof(float));
3140 pos += sizeof(int32_t);
3141 }
3142
3143 g_assert(pos == *size);
3144
3145 return params;
3146}
3147
3149{
3150 if(IS_NULL_PTR(self->data)) return;
3152
3153 // these can be called on shutdown, resulting in null-pointer
3154 // dereference and division by zero -- not sure what interaction
3155 // makes them called, but better to disconnect and not have segfault
3156 g_signal_handlers_disconnect_by_func(G_OBJECT(ps->b_top), G_CALLBACK(_top_border_callback), self);
3157 g_signal_handlers_disconnect_by_func(G_OBJECT(ps->b_bottom), G_CALLBACK(_bottom_border_callback), self);
3158 g_signal_handlers_disconnect_by_func(G_OBJECT(ps->b_left), G_CALLBACK(_left_border_callback), self);
3159 g_signal_handlers_disconnect_by_func(G_OBJECT(ps->b_right), G_CALLBACK(_right_border_callback), self);
3160
3161 g_list_free_full(ps->profiles, dt_free_gpointer);
3162 ps->profiles = NULL;
3163 g_list_free_full(ps->paper_list, dt_free_gpointer);
3164 ps->paper_list = NULL;
3165 g_list_free_full(ps->media_list, dt_free_gpointer);
3166 ps->media_list = NULL;
3167
3168 dt_free(ps->v_iccprofile);
3170 dt_free(ps->v_style);
3171
3172 dt_free(self->data);
3173}
3174
3176{
3178
3179 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_top), 17 * units[ps->unit]);
3180 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_bottom), 17 * units[ps->unit]);
3181 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_left), 17 * units[ps->unit]);
3182 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->b_right), 17 * units[ps->unit]);
3183 gtk_spin_button_set_value(GTK_SPIN_BUTTON(ps->grid_size), 10 * units[ps->unit]);
3184
3185 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ps->dtba[ALIGNMENT_CENTER]), TRUE);
3192 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ps->black_point_compensation), TRUE);
3193 gtk_widget_set_sensitive(GTK_WIDGET(ps->pintent), TRUE);
3194 gtk_widget_set_sensitive(GTK_WIDGET(ps->black_point_compensation), FALSE);
3195
3196 // reset page orientation to fit the picture if a single one is displayed
3197
3198 const int32_t imgid = (ps->imgs.count > 0) ? ps->imgs.box[0].imgid : -1;
3200 ps->imgs.imgid_to_load = imgid;
3201
3202 ps->creation = ps->dragging = FALSE;
3203 ps->selected = -1;
3204 ps->last_selected = -1;
3205 ps->has_changed = FALSE;
3206
3208}
3209
3210// clang-format off
3211// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
3212// vim: shiftwidth=2 expandtab tabstop=2 cindent
3213// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
3214// clang-format on
Handle default and user-set shortcuts (accelerators)
#define DT_PRIMARY_MASK
void dt_gui_add_help_link(GtkWidget *widget, char *link)
static double dist(double x1, double y1, double x2, double y2)
Definition ashift_lsd.c:250
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
#define m
Definition basecurve.c:283
GtkWidget * dt_bauhaus_combobox_new_full(dt_bauhaus_t *bh, dt_gui_module_t *self, const char *label, const char *tip, int pos, GtkCallback callback, gpointer data, const char **texts)
Definition bauhaus.c:1705
void dt_bauhaus_combobox_clear(GtkWidget *widget)
Definition bauhaus.c:1997
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2136
const char * dt_bauhaus_combobox_get_text(GtkWidget *widget)
Definition bauhaus.c:1970
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2090
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1504
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1698
gboolean dt_bauhaus_combobox_set_from_text(GtkWidget *widget, const char *text)
Definition bauhaus.c:2100
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:1824
static const float x
const float v
const dt_colorspaces_color_profile_t * dt_colorspaces_get_profile(dt_colorspaces_color_profile_type_t type, const char *filename, dt_colorspaces_profile_role_t role)
Resolve a profile identity to its registered entry.
size_t dt_colorspaces_enumerate_profiles(const dt_colorspaces_profile_role_t role, dt_colorprofile_desc_t **out)
Ordered snapshot of every profile registered for one role.
The colour-profile module's API: which profiles exist, and how to apply one.
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
void dt_conf_set_bool(const char *name, int val)
int dt_conf_get_bool(const char *name)
void dt_conf_set_float(const char *name, float val)
float dt_conf_get_float(const char *name)
Float for name, clamped to its declared bounds.
gchar * dt_conf_get_string(const char *name)
Read the stored string for name as a private copy.
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
void dt_conf_set_string(const char *name, const char *val)
const char * dt_conf_get_string_const(const char *name)
Borrow the stored string for name without copying it.
dt_pdf_page_t * dt_pdf_add_page(dt_pdf_t *pdf, dt_pdf_image_t **images, int n_images)
Definition common/pdf.c:457
dt_pdf_image_t * dt_pdf_add_image(dt_pdf_t *pdf, const unsigned char *image, int width, int height, int bpp, int icc_id, float border)
Definition common/pdf.c:375
void dt_pdf_finish(dt_pdf_t *pdf, dt_pdf_page_t **pages, int n_pages)
Definition common/pdf.c:639
dt_pdf_t * dt_pdf_start(const char *filename, float width, float height, float dpi, dt_pdf_stream_encoder_t default_encoder)
Definition common/pdf.c:217
void dt_control_set_mouse_over_id(int32_t value)
Definition control.c:994
void dt_control_log(const char *msg,...)
Definition control.c:824
void dt_control_queue_redraw_center()
Request a redraw of the centre view.
Definition control.c:924
void dt_control_queue_redraw()
Request a redraw of the whole workspace.
Definition control.c:919
#define dt_control_change_cursor(cursor)
Definition control.h:121
struct dt_control_t * dt_control_get_global(void)
Definition darktable.c:651
void dt_get_printer_info(const char *printer_name, dt_printer_info_t *pinfo)
Definition cups_print.c:89
void dt_print_file(const int32_t imgid, const char *filename, const char *job_title, const dt_print_info_t *pinfo)
Definition cups_print.c:428
dt_medium_info_t * dt_get_medium(GList *media, const char *name)
Definition cups_print.c:412
GList * dt_get_media_type(const dt_printer_info_t *printer)
Definition cups_print.c:375
void dt_printers_discovery(void(*cb)(dt_printer_info_t *pr, void *user_data), void *user_data)
Definition cups_print.c:217
dt_paper_info_t * dt_get_paper(GList *papers, const char *name)
Definition cups_print.c:247
GList * dt_get_papers(const dt_printer_info_t *printer)
Definition cups_print.c:273
void dt_init_print_info(dt_print_info_t *pinfo)
Definition cups_print.c:79
@ ALIGNMENT_CENTER
Definition cups_print.h:36
void expose(dt_view_t *self, cairo_t *cri, int32_t width, int32_t height, int32_t pointerx, int32_t pointery)
Definition darkroom.c:897
struct dt_view_manager_t * dt_view_manager_get_global(void)
Definition darktable.c:599
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
Definition darktable.c:646
GHashTable * names
GtkWidget* -> the name the application knows it by.
static void dt_gui_draw_rounded_rectangle(cairo_t *cr, float width, float height, float x, float y)
Definition draw.h:554
const int res
Definition dtpthread.h:351
void dt_loc_get_tmp_dir(char *tmpdir, size_t bufsize)
void dt_loc_get_datadir(char *datadir, size_t bufsize)
void dt_loc_get_user_config_dir(char *configdir, size_t bufsize)
#define DT_GUI_MODULE(x)
#define UNKNOWN_IMAGE
Definition image.h:78
const char * tooltip
Definition image.h:310
void dt_image_cache_set_print_timestamp(const int32_t imgid)
dt_image_t * dt_image_cache_get(const int32_t imgid, char mode)
void dt_image_cache_read_release(const dt_image_t *img)
int bpp
int dt_imageio_export_with_flags(const int32_t imgid, const char *filename, dt_imageio_module_format_t *format, dt_imageio_module_data_t *format_params, const gboolean ignore_exif, const gboolean display_byteorder, const gboolean high_quality, gboolean is_scaling, const gboolean thumbnail_export, const char *filter, const gboolean copy_metadata, const gboolean export_masks, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, dt_imageio_module_storage_t *storage, dt_imageio_module_data_t *storage_params, int num, int total, dt_export_metadata_t *metadata, dt_atomic_int *shutdown)
@ IMAGEIO_INT16
@ IMAGEIO_RGB
@ IMAGEIO_INT8
const dt_colorspaces_color_profile_t * dt_colorspaces_get_output_profile(const int32_t imgid, dt_colorspaces_color_profile_type_t *over_type, const char *over_filename)
dt_job_state_t dt_control_job_get_state(_dt_job_t *job)
Definition jobs.c:105
dt_job_t * dt_control_job_create(dt_job_execute_callback execute, const char *msg,...)
Definition jobs.c:137
int dt_control_add_job(dt_control_t *control, dt_job_queue_t queue_id, _dt_job_t *job)
Definition jobs.c:407
void * dt_control_job_get_params(const _dt_job_t *job)
Definition jobs.c:131
void dt_control_job_set_progress(dt_job_t *job, double value)
Definition jobs.c:628
void dt_control_job_add_progress(dt_job_t *job, const char *message, gboolean cancellable)
Definition jobs.c:614
void dt_control_job_set_params(_dt_job_t *job, void *params, dt_job_destroy_callback callback)
Definition jobs.c:114
void dt_control_job_dispose(_dt_job_t *job)
Definition jobs.c:155
@ DT_JOB_QUEUE_USER_EXPORT
Definition jobs.h:57
@ DT_JOB_STATE_CANCELLED
Definition jobs.h:47
GtkWidget * dt_ui_section_label_new(const gchar *str)
Definition label.c:114
static int precision(double x, double adj)
Definition lens.c:2509
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)
Definition lib.c:1336
_lib_location_type_t type
Definition location.c:1
@ DT_DEBUG_PRINT
Definition logging.h:65
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...
Definition macros.h:96
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
Definition mem_alloc.h:214
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
Definition mem_alloc.h:184
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
GList * dt_metadata_get(const int id, const char *key, uint32_t *count)
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
size_t size
Definition mipmap_cache.c:3
@ DT_MIPMAP_BLOCKING
@ DT_MIPMAP_0
@ DT_MIPMAP_NONE
#define dt_mipmap_cache_get(B, C, D, E, F)
#define dt_mipmap_cache_release(B)
#define DT_MODULE(MODVER)
Instantiate the version handshake every module must export. Use once, at file scope,...
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
#define dt_pdf_pixel_to_point(px, dpi)
Definition pdf.h:45
#define dt_pdf_mm_to_point(mm)
Definition pdf.h:42
@ DT_PDF_STREAM_ENCODER_FLATE
Definition pdf.h:50
const char * name
Definition pdf.h:90
static void _page_delete_area(const dt_lib_module_t *self, const int box_index)
static void _print_job_cleanup(void *p)
_unit_t
@ UNIT_CM
@ UNIT_N
@ UNIT_IN
@ UNIT_MM
void gui_reset(dt_lib_module_t *self)
static GList * _get_profiles()
int set_params(dt_lib_module_t *self, const void *params, int size)
void _get_control(dt_lib_print_settings_t *ps, float x, float y)
void * get_params(dt_lib_module_t *self, int *size)
struct _dialog_description dialog_description_t
static void _printer_changed(GtkWidget *combo, const dt_lib_module_t *self)
static void _left_border_callback(GtkWidget *spin, gpointer user_data)
void gui_post_expose(struct dt_lib_module_t *self, cairo_t *cr, int32_t width, int32_t height, int32_t pointerx, int32_t pointery)
static int _print_job_run(dt_job_t *job)
int mouse_leave(struct dt_lib_module_t *self)
static void _snap_grid_callback(GtkWidget *widget, dt_lib_module_t *self)
static void _print_button_clicked(GtkWidget *widget, gpointer user_data)
static const float units[UNIT_N]
static void _profile_changed(GtkWidget *widget, dt_lib_module_t *self)
static void _paper_changed(GtkWidget *combo, const dt_lib_module_t *self)
static void _grid_size_changed(GtkWidget *widget, dt_lib_module_t *self)
static float _vscreen_to_mm(dt_lib_print_settings_t *ps, const float value, const gboolean offset)
static void _printer_bpc_callback(GtkWidget *widget, dt_lib_module_t *self)
static void _grid_callback(GtkWidget *widget, dt_lib_module_t *self)
static void _y_changed(GtkWidget *widget, gpointer user_data)
static void _top_border_callback(GtkWidget *spin, gpointer user_data)
void _fill_box_values(dt_lib_print_settings_t *ps)
static void _orientation_changed(GtkWidget *combo, dt_lib_module_t *self)
static void _page_delete_area_clicked(GtkWidget *widget, gpointer user_data)
static void _print_settings_activate_or_update_callback(gpointer instance, int32_t imgid, gpointer user_data)
enum _set_controls dt_box_control_set
static void _create_pdf(dt_job_t *job, dt_images_box imgs, const float width, const float height)
static void _x_changed(GtkWidget *widget, gpointer user_data)
void gui_cleanup(dt_lib_module_t *self)
static void _swap(float *a, float *b)
static void _bottom_border_callback(GtkWidget *spin, gpointer user_data)
static float _to_mm(dt_lib_print_settings_t *ps, double value)
static void _width_changed(GtkWidget *widget, gpointer user_data)
static float _mm_to_hscreen(dt_lib_print_settings_t *ps, const float value, const gboolean offset)
static void _set_orientation(dt_lib_print_settings_t *ps, int32_t imgid)
static void _get_page_dimension(dt_print_info_t *prt, float *width, float *height)
static void _alignment_callback(GtkWidget *tb, gpointer user_data)
static void _lock_callback(GtkWidget *button, gpointer user_data)
static float _percent_unit_of(dt_lib_print_settings_t *ps, float ref, float value)
void _cairo_rectangle(cairo_t *cr, const int sel_controls, const int x1, const int y1, const int x2, const int y2)
static void _new_printer_callback(dt_printer_info_t *printer, void *user_data)
static void _style_callback(GtkWidget *widget, dt_lib_module_t *self)
int mouse_moved(struct dt_lib_module_t *self, double x, double y, double pressure, int which)
static void _intent_callback(GtkWidget *widget, dt_lib_module_t *self)
uint32_t container(dt_lib_module_t *self)
_set_controls
@ BOX_BOTTOM
@ BOX_LEFT
@ BOX_TOP
@ BOX_TOP_LEFT
@ BOX_BOTTOM_LEFT
@ BOX_RIGHT
@ BOX_ALL
@ BOX_TOP_RIGHT
@ BOX_BOTTOM_RIGHT
static void _printer_intent_callback(GtkWidget *widget, dt_lib_module_t *self)
static void _printer_profile_changed(GtkWidget *widget, 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)
static void _update_slider(dt_lib_print_settings_t *ps)
static void _precision_by_unit(_unit_t unit, int *n_digits, float *incr, char **format)
static float _hscreen_to_mm(dt_lib_print_settings_t *ps, const float value, const gboolean offset)
static void _media_changed(GtkWidget *combo, const dt_lib_module_t *self)
static const char * mime(dt_imageio_module_data_t *data)
void view_leave(struct dt_lib_module_t *self, struct dt_view_t *old_view, struct dt_view_t *new_view)
void gui_init(dt_lib_module_t *self)
void view_enter(struct dt_lib_module_t *self, struct dt_view_t *old_view, struct dt_view_t *new_view)
int position()
const char ** views(dt_lib_module_t *self)
void * legacy_params(dt_lib_module_t *self, const void *const old_params, const size_t old_params_size, const int old_version, int *new_version, size_t *new_size)
static void _snap_to_grid(dt_lib_print_settings_t *ps, float *x, float *y)
static void _page_clear_area_clicked(GtkWidget *widget, gpointer user_data)
static int levels(dt_imageio_module_data_t *data)
static int write_image(dt_imageio_module_data_t *data, const char *filename, const void *in, dt_colorspaces_color_profile_type_t over_type, const char *over_filename, void *exif, int exif_len, int32_t imgid, int num, int total, dt_dev_pixelpipe_t *pipe, const gboolean export_masks)
static void _page_new_area_clicked(GtkWidget *widget, gpointer user_data)
static void _height_changed(GtkWidget *widget, gpointer user_data)
static int _export_and_setup_pos(dt_job_t *job, dt_image_box *img, const int32_t idx)
static float _mm_to_vscreen(dt_lib_print_settings_t *ps, const float value, const gboolean offset)
static void _right_border_callback(GtkWidget *spin, gpointer user_data)
static int _export_image(dt_job_t *job, dt_image_box *img)
static void _set_printer(const dt_lib_module_t *self, const char *printer_name)
static const gchar * _unit_names[]
int button_released(struct dt_lib_module_t *self, double x, double y, int which, uint32_t state)
static void _unit_changed(GtkWidget *combo, dt_lib_module_t *self)
void dt_printing_get_image_pos(const dt_images_box *imgs, const dt_image_box *img, dt_image_pos *pos)
Definition printing.c:295
int32_t dt_printing_get_image_box(const dt_images_box *imgs, const int x, const int y)
Definition printing.c:68
void dt_printing_clear_box(dt_image_box *img)
Definition printing.c:38
void dt_printing_setup_box(dt_images_box *imgs, const int idx, const float x, const float y, const float width, const float height)
Definition printing.c:157
void dt_printing_setup_image(dt_images_box *imgs, const int idx, const int32_t imgid, const int32_t width, const int32_t height, const dt_alignment_t alignment)
Definition printing.c:307
void dt_printing_setup_page(dt_images_box *imgs, const float page_width, const float page_height, const int resolution)
Definition printing.c:202
void dt_printing_clear_boxes(dt_images_box *imgs)
Definition printing.c:53
void dt_printing_get_image_pos_mm(const dt_images_box *imgs, const dt_image_box *img, dt_image_pos *pos)
Definition printing.c:283
#define MAX_IMAGE_PER_PAGE
Definition printing.h:35
int dt_apply_printer_profile(void **in, uint32_t width, uint32_t height, int bpp, cmsHPROFILE hInProfile, cmsHPROFILE hOutProfile, int intent, gboolean black_point_compensation)
Convert an interleaved RGB buffer from hInProfile to hOutProfile, replacing the caller's buffer with ...
Definition printprof.c:47
The printer-profile application path: the last colour transform an image goes through before it is ha...
dt_iop_color_intent_t
ICC rendering intent, as stored in iop params and in conf.
@ DT_INTENT_PERCEPTUAL
dt_colorspaces_color_profile_type_t
@ DT_COLORSPACE_ADOBERGB
@ DT_COLORSPACE_FILE
A user ICC file on disk; the only type whose filename is meaningful.
@ DT_COLORSPACE_SRGB
sRGB – registered TWICE, and the two entries are not interchangeable.
@ DT_COLORSPACE_NONE
No profile / "take it from the image settings". Never matches a list entry.
@ DT_PROFILE_ROLE_OUTPUT
Listed in the output/export-profile combo (colorout, export).
@ DT_PROFILE_ROLE_INPUT
Listed in the input-profile combo (colorin).
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
Definition signal.h:407
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:386
struct dt_control_signal_t * dt_control_signal_get_global(void)
Definition darktable.c:616
@ DT_SIGNAL_TAG_CHANGED
This signal is raised when a tag is added/deleted/changed
Definition signal.h:133
@ DT_SIGNAL_VIEWMANAGER_FILMSTRIP_ACTIVATE
This signal is raised when a thumb is single-clicked in the filmstrip. Views that want filmstrip clic...
Definition signal.h:106
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
Definition signal.h:396
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
void dt_style_free(gpointer data)
GList * dt_styles_get_list(const char *filter)
const float uint32_t state[4]
dt_image_pos screen
Definition printing.h:51
int32_t exp_height
Definition printing.h:46
int32_t exp_width
Definition printing.h:46
dt_alignment_t alignment
Definition printing.h:49
int32_t max_width
Definition printing.h:45
int32_t img_height
Definition printing.h:48
int32_t imgid
Definition printing.h:44
dt_image_pos pos
Definition printing.h:50
int32_t max_height
Definition printing.h:45
uint16_t * buf
Definition printing.h:53
int32_t img_width
Definition printing.h:48
dt_image_pos print
Definition printing.h:52
float width
Definition printing.h:39
float x
Definition printing.h:39
float height
Definition printing.h:39
float y
Definition printing.h:39
A profile's public identity: what the GUI displays and stores, and nothing else.
char name[512]
translated, display-ready
char filename[DT_IOP_COLOR_ICC_LEN]
"" unless type == DT_COLORSPACE_FILE
One registered profile: its identity, its LCMS handle, and where it sits in each combo box.
cmsHPROFILE profile
the actual profile; NULL for the three category entries
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:386
int32_t imgid_to_load
Definition printing.h:71
dt_image_box box[20]
Definition printing.h:74
int32_t motion_over
Definition printing.h:72
dt_screen_pos screen
Definition printing.h:77
dt_colorspaces_color_profile_type_t type
GModule *void * data
Definition lib.h:79
GtkWidget * widget
Definition lib.h:83
dt_colorspaces_color_profile_type_t p_icc_type
dt_iop_color_intent_t buf_icc_intent
dt_pdf_page_t * pdf_page
dt_colorspaces_color_profile_type_t buf_icc_type
gboolean black_point_compensation
dt_print_info_t prt
char pdf_filename[DT_PATH_MAX]
dt_iop_color_intent_t p_icc_intent
dt_box_control_set sel_controls
GtkWidget * black_point_compensation
GtkToggleButton * lock_button
GtkDarktableToggleButton * dtba[9]
dt_mipmap_size_t size
double margin_bottom
Definition cups_print.h:57
double margin_right
Definition cups_print.h:57
double margin_left
Definition cups_print.h:57
double margin_top
Definition cups_print.h:57
gboolean landscape
Definition cups_print.h:56
float bb_x
Definition pdf.h:74
float bb_width
Definition pdf.h:74
float bb_y
Definition pdf.h:74
float bb_height
Definition pdf.h:74
Definition pdf.h:54
dt_lib_print_job_t * params
dt_imageio_module_data_t head
dt_medium_info_t medium
Definition cups_print.h:75
dt_paper_info_t paper
Definition cups_print.h:74
dt_printer_info_t printer
Definition cups_print.h:72
dt_page_setup_t page
Definition cups_print.h:73
dt_iop_color_intent_t intent
Definition cups_print.h:65
gboolean is_turboprint
Definition cups_print.h:67
gboolean borderless
Definition printing.h:65
dt_image_pos page
Definition printing.h:58
gchar * name
gboolean dt_tag_attach(const guint tagid, const int32_t imgid, const gboolean undo_on, const gboolean group_on)
Definition tags.c:377
gboolean dt_tag_new(const char *name, guint *tagid)
Definition tags.c:164
typedef double((*spd)(unsigned long int wavelength, double TempK))
#define MIN(a, b)
Definition thinplate.c:32
GtkWidget * dtgtk_togglebutton_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
#define DTGTK_TOGGLEBUTTON(obj)
char * dt_get_help_url(char *name)
size_t dt_utf8_strlcpy(char *dest, const char *src, size_t n)
Definition utility.c:293
void dt_view_print_settings(const dt_view_manager_t *vm, dt_print_info_t *pinfo, dt_images_box *imgs)
Definition view.c:1402
gboolean dt_gui_widgets_suppressed(void)
static gboolean dt_modifier_is(GdkModifierType state, const GdkModifierType desired_modifier_mask)
#define dt_gui_freeze_begin()
#define dt_gui_freeze_end()
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
void dtgtk_cairo_paint_alignment(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
@ CPF_SPECIAL_FLAG
@ DT_UI_CONTAINER_PANEL_RIGHT_CENTER