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