1 /* LIBGIMP - The GIMP Library
2 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
3 *
4 * gimppageselector.c
5 * Copyright (C) 2005 Michael Natterer <mitch@gimp.org>
6 *
7 * This library is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 3 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see
19 * <https://www.gnu.org/licenses/>.
20 */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <gegl.h>
28 #include <gtk/gtk.h>
29
30 #include "gimpwidgetstypes.h"
31
32 #include "gimpicons.h"
33 #include "gimppageselector.h"
34 #include "gimppropwidgets.h"
35 #include "gimpwidgets.h"
36 #include "gimp3migration.h"
37
38 #include "libgimp/libgimp-intl.h"
39
40
41 /**
42 * SECTION: gimppageselector
43 * @title: GimpPageSelector
44 * @short_description: A widget to select pages from multi-page things.
45 *
46 * Use this for example for specifying what pages to import from
47 * a PDF or PS document.
48 **/
49
50
51 enum
52 {
53 SELECTION_CHANGED,
54 ACTIVATE,
55 LAST_SIGNAL
56 };
57
58 enum
59 {
60 PROP_0,
61 PROP_N_PAGES,
62 PROP_TARGET
63 };
64
65 enum
66 {
67 COLUMN_PAGE_NO,
68 COLUMN_THUMBNAIL,
69 COLUMN_LABEL,
70 COLUMN_LABEL_SET
71 };
72
73
74 typedef struct
75 {
76 gint n_pages;
77 GimpPageSelectorTarget target;
78
79 GtkListStore *store;
80 GtkWidget *view;
81
82 GtkWidget *count_label;
83 GtkWidget *range_entry;
84
85 GdkPixbuf *default_thumbnail;
86 } GimpPageSelectorPrivate;
87
88 #define GIMP_PAGE_SELECTOR_GET_PRIVATE(obj) \
89 ((GimpPageSelectorPrivate *) ((GimpPageSelector *) (obj))->priv)
90
91
92 static void gimp_page_selector_finalize (GObject *object);
93 static void gimp_page_selector_get_property (GObject *object,
94 guint property_id,
95 GValue *value,
96 GParamSpec *pspec);
97 static void gimp_page_selector_set_property (GObject *object,
98 guint property_id,
99 const GValue *value,
100 GParamSpec *pspec);
101
102 static void gimp_page_selector_selection_changed (GtkIconView *icon_view,
103 GimpPageSelector *selector);
104 static void gimp_page_selector_item_activated (GtkIconView *icon_view,
105 GtkTreePath *path,
106 GimpPageSelector *selector);
107 static gboolean gimp_page_selector_range_focus_out (GtkEntry *entry,
108 GdkEventFocus *fevent,
109 GimpPageSelector *selector);
110 static void gimp_page_selector_range_activate (GtkEntry *entry,
111 GimpPageSelector *selector);
112 static gint gimp_page_selector_int_compare (gconstpointer a,
113 gconstpointer b);
114 static void gimp_page_selector_print_range (GString *string,
115 gint start,
116 gint end);
117
118 static GdkPixbuf * gimp_page_selector_add_frame (GtkWidget *widget,
119 GdkPixbuf *pixbuf);
120
121
122 G_DEFINE_TYPE_WITH_PRIVATE (GimpPageSelector, gimp_page_selector, GTK_TYPE_BOX)
123
124 #define parent_class gimp_page_selector_parent_class
125
126 static guint selector_signals[LAST_SIGNAL] = { 0 };
127
128
129 static void
gimp_page_selector_class_init(GimpPageSelectorClass * klass)130 gimp_page_selector_class_init (GimpPageSelectorClass *klass)
131 {
132 GObjectClass *object_class = G_OBJECT_CLASS (klass);
133 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
134
135 object_class->finalize = gimp_page_selector_finalize;
136 object_class->get_property = gimp_page_selector_get_property;
137 object_class->set_property = gimp_page_selector_set_property;
138
139 klass->selection_changed = NULL;
140 klass->activate = NULL;
141
142 /**
143 * GimpPageSelector::selection-changed:
144 * @widget: the object which received the signal.
145 *
146 * This signal is emitted whenever the set of selected pages changes.
147 *
148 * Since: 2.4
149 **/
150 selector_signals[SELECTION_CHANGED] =
151 g_signal_new ("selection-changed",
152 G_TYPE_FROM_CLASS (klass),
153 G_SIGNAL_RUN_FIRST,
154 G_STRUCT_OFFSET (GimpPageSelectorClass, selection_changed),
155 NULL, NULL,
156 g_cclosure_marshal_VOID__VOID,
157 G_TYPE_NONE, 0);
158
159 /**
160 * GimpPageSelector::activate:
161 * @widget: the object which received the signal.
162 *
163 * The "activate" signal on GimpPageSelector is an action signal. It
164 * is emitted when a user double-clicks an item in the page selection.
165 *
166 * Since: 2.4
167 */
168 selector_signals[ACTIVATE] =
169 g_signal_new ("activate",
170 G_OBJECT_CLASS_TYPE (object_class),
171 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
172 G_STRUCT_OFFSET (GimpPageSelectorClass, activate),
173 NULL, NULL,
174 g_cclosure_marshal_VOID__VOID,
175 G_TYPE_NONE, 0);
176 widget_class->activate_signal = selector_signals[ACTIVATE];
177
178 /**
179 * GimpPageSelector:n-pages:
180 *
181 * The number of pages of the document to open.
182 *
183 * Since: 2.4
184 **/
185 g_object_class_install_property (object_class, PROP_N_PAGES,
186 g_param_spec_int ("n-pages",
187 "N Pages",
188 "The number of pages to open",
189 0, G_MAXINT, 0,
190 GIMP_PARAM_READWRITE));
191
192 /**
193 * GimpPageSelector:target:
194 *
195 * The target to open the document to.
196 *
197 * Since: 2.4
198 **/
199 g_object_class_install_property (object_class, PROP_TARGET,
200 g_param_spec_enum ("target",
201 "Target",
202 "the target to open to",
203 GIMP_TYPE_PAGE_SELECTOR_TARGET,
204 GIMP_PAGE_SELECTOR_TARGET_LAYERS,
205 GIMP_PARAM_READWRITE));
206 }
207
208 static void
gimp_page_selector_init(GimpPageSelector * selector)209 gimp_page_selector_init (GimpPageSelector *selector)
210 {
211 GimpPageSelectorPrivate *priv;
212 GtkWidget *vbox;
213 GtkWidget *sw;
214 GtkWidget *hbox;
215 GtkWidget *hbbox;
216 GtkWidget *button;
217 GtkWidget *label;
218 GtkWidget *combo;
219
220 selector->priv = gimp_page_selector_get_instance_private (selector);
221
222 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
223
224 priv->n_pages = 0;
225 priv->target = GIMP_PAGE_SELECTOR_TARGET_LAYERS;
226
227 gtk_orientable_set_orientation (GTK_ORIENTABLE (selector),
228 GTK_ORIENTATION_VERTICAL);
229
230 gtk_box_set_spacing (GTK_BOX (selector), 12);
231
232 /* Pages */
233
234 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
235 gtk_box_pack_start (GTK_BOX (selector), vbox, TRUE, TRUE, 0);
236 gtk_widget_show (vbox);
237
238 sw = gtk_scrolled_window_new (NULL, NULL);
239 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
240 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
241 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
242 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
243 gtk_widget_show (sw);
244
245 priv->store = gtk_list_store_new (4,
246 G_TYPE_INT,
247 GDK_TYPE_PIXBUF,
248 G_TYPE_STRING,
249 G_TYPE_BOOLEAN);
250
251 priv->view = gtk_icon_view_new_with_model (GTK_TREE_MODEL (priv->store));
252 gtk_icon_view_set_text_column (GTK_ICON_VIEW (priv->view),
253 COLUMN_LABEL);
254 gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (priv->view),
255 COLUMN_THUMBNAIL);
256 gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (priv->view),
257 GTK_SELECTION_MULTIPLE);
258 gtk_container_add (GTK_CONTAINER (sw), priv->view);
259 gtk_widget_show (priv->view);
260
261 g_signal_connect (priv->view, "selection-changed",
262 G_CALLBACK (gimp_page_selector_selection_changed),
263 selector);
264 g_signal_connect (priv->view, "item-activated",
265 G_CALLBACK (gimp_page_selector_item_activated),
266 selector);
267
268 /* Count label */
269
270 priv->count_label = gtk_label_new (_("Nothing selected"));
271 gtk_label_set_xalign (GTK_LABEL (priv->count_label), 0.0);
272 gimp_label_set_attributes (GTK_LABEL (priv->count_label),
273 PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
274 -1);
275 gtk_box_pack_start (GTK_BOX (vbox), priv->count_label, FALSE, FALSE, 0);
276 gtk_widget_show (priv->count_label);
277
278 /* Select all button & range entry */
279
280 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
281 gtk_box_pack_start (GTK_BOX (selector), hbox, FALSE, FALSE, 0);
282 gtk_widget_show (hbox);
283
284 hbbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
285 gtk_box_pack_start (GTK_BOX (hbox), hbbox, FALSE, FALSE, 0);
286 gtk_widget_show (hbbox);
287
288 button = gtk_button_new_with_mnemonic (_("Select _All"));
289 gtk_box_pack_start (GTK_BOX (hbbox), button, FALSE, FALSE, 0);
290 gtk_widget_show (button);
291
292 g_signal_connect_swapped (button, "clicked",
293 G_CALLBACK (gimp_page_selector_select_all),
294 selector);
295
296 priv->range_entry = gtk_entry_new ();
297 gtk_widget_set_size_request (priv->range_entry, 80, -1);
298 gtk_box_pack_end (GTK_BOX (hbox), priv->range_entry, TRUE, TRUE, 0);
299 gtk_widget_show (priv->range_entry);
300
301 g_signal_connect (priv->range_entry, "focus-out-event",
302 G_CALLBACK (gimp_page_selector_range_focus_out),
303 selector);
304 g_signal_connect (priv->range_entry, "activate",
305 G_CALLBACK (gimp_page_selector_range_activate),
306 selector);
307
308 label = gtk_label_new_with_mnemonic (_("Select _range:"));
309 gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
310 gtk_widget_show (label);
311
312 gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->range_entry);
313
314 /* Target combo */
315
316 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
317 gtk_box_pack_start (GTK_BOX (selector), hbox, FALSE, FALSE, 0);
318 gtk_widget_show (hbox);
319
320 label = gtk_label_new_with_mnemonic (_("Open _pages as"));
321 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
322 gtk_widget_show (label);
323
324 combo = gimp_prop_enum_combo_box_new (G_OBJECT (selector), "target", -1, -1);
325 gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
326 gtk_widget_show (combo);
327
328 gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
329
330 priv->default_thumbnail =
331 gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
332 "text-x-generic", 32, 0, NULL);
333 }
334
335 static void
gimp_page_selector_finalize(GObject * object)336 gimp_page_selector_finalize (GObject *object)
337 {
338 GimpPageSelectorPrivate *priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (object);
339
340 g_clear_object (&priv->default_thumbnail);
341
342 G_OBJECT_CLASS (parent_class)->finalize (object);
343 }
344
345 static void
gimp_page_selector_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)346 gimp_page_selector_get_property (GObject *object,
347 guint property_id,
348 GValue *value,
349 GParamSpec *pspec)
350 {
351 GimpPageSelectorPrivate *priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (object);
352
353 switch (property_id)
354 {
355 case PROP_N_PAGES:
356 g_value_set_int (value, priv->n_pages);
357 break;
358 case PROP_TARGET:
359 g_value_set_enum (value, priv->target);
360 break;
361 default:
362 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
363 break;
364 }
365 }
366
367 static void
gimp_page_selector_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)368 gimp_page_selector_set_property (GObject *object,
369 guint property_id,
370 const GValue *value,
371 GParamSpec *pspec)
372 {
373 GimpPageSelector *selector = GIMP_PAGE_SELECTOR (object);
374 GimpPageSelectorPrivate *priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (object);
375
376 switch (property_id)
377 {
378 case PROP_N_PAGES:
379 gimp_page_selector_set_n_pages (selector, g_value_get_int (value));
380 break;
381 case PROP_TARGET:
382 priv->target = g_value_get_enum (value);
383 break;
384 default:
385 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
386 break;
387 }
388 }
389
390
391 /* public functions */
392
393 /**
394 * gimp_page_selector_new:
395 *
396 * Creates a new #GimpPageSelector widget.
397 *
398 * Returns: Pointer to the new #GimpPageSelector widget.
399 *
400 * Since: 2.4
401 **/
402 GtkWidget *
gimp_page_selector_new(void)403 gimp_page_selector_new (void)
404 {
405 return g_object_new (GIMP_TYPE_PAGE_SELECTOR, NULL);
406 }
407
408 /**
409 * gimp_page_selector_set_n_pages:
410 * @selector: Pointer to a #GimpPageSelector.
411 * @n_pages: The number of pages.
412 *
413 * Sets the number of pages in the document to open.
414 *
415 * Since: 2.4
416 **/
417 void
gimp_page_selector_set_n_pages(GimpPageSelector * selector,gint n_pages)418 gimp_page_selector_set_n_pages (GimpPageSelector *selector,
419 gint n_pages)
420 {
421 GimpPageSelectorPrivate *priv;
422
423 g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
424 g_return_if_fail (n_pages >= 0);
425
426 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
427
428 if (n_pages != priv->n_pages)
429 {
430 GtkTreeIter iter;
431 gint i;
432
433 if (n_pages < priv->n_pages)
434 {
435 for (i = n_pages; i < priv->n_pages; i++)
436 {
437 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
438 &iter, NULL, n_pages);
439 gtk_list_store_remove (priv->store, &iter);
440 }
441 }
442 else
443 {
444 for (i = priv->n_pages; i < n_pages; i++)
445 {
446 gchar *text;
447
448 text = g_strdup_printf (_("Page %d"), i + 1);
449
450 gtk_list_store_append (priv->store, &iter);
451 gtk_list_store_set (priv->store, &iter,
452 COLUMN_PAGE_NO, i,
453 COLUMN_THUMBNAIL, priv->default_thumbnail,
454 COLUMN_LABEL, text,
455 COLUMN_LABEL_SET, FALSE,
456 -1);
457
458 g_free (text);
459 }
460 }
461
462 priv->n_pages = n_pages;
463
464 g_object_notify (G_OBJECT (selector), "n-pages");
465 }
466 }
467
468 /**
469 * gimp_page_selector_get_n_pages:
470 * @selector: Pointer to a #GimpPageSelector.
471 *
472 * Returns: the number of pages in the document to open.
473 *
474 * Since: 2.4
475 **/
476 gint
gimp_page_selector_get_n_pages(GimpPageSelector * selector)477 gimp_page_selector_get_n_pages (GimpPageSelector *selector)
478 {
479 GimpPageSelectorPrivate *priv;
480
481 g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), 0);
482
483 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
484
485 return priv->n_pages;
486 }
487
488 /**
489 * gimp_page_selector_set_target:
490 * @selector: Pointer to a #GimpPageSelector.
491 * @target: How to open the selected pages.
492 *
493 * Since: 2.4
494 **/
495 void
gimp_page_selector_set_target(GimpPageSelector * selector,GimpPageSelectorTarget target)496 gimp_page_selector_set_target (GimpPageSelector *selector,
497 GimpPageSelectorTarget target)
498 {
499 GimpPageSelectorPrivate *priv;
500
501 g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
502 g_return_if_fail (target <= GIMP_PAGE_SELECTOR_TARGET_IMAGES);
503
504 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
505
506 if (target != priv->target)
507 {
508 priv->target = target;
509
510 g_object_notify (G_OBJECT (selector), "target");
511 }
512 }
513
514 /**
515 * gimp_page_selector_get_target:
516 * @selector: Pointer to a #GimpPageSelector.
517 *
518 * Returns: How the selected pages should be opened.
519 *
520 * Since: 2.4
521 **/
522 GimpPageSelectorTarget
gimp_page_selector_get_target(GimpPageSelector * selector)523 gimp_page_selector_get_target (GimpPageSelector *selector)
524 {
525 GimpPageSelectorPrivate *priv;
526
527 g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector),
528 GIMP_PAGE_SELECTOR_TARGET_LAYERS);
529
530 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
531
532 return priv->target;
533 }
534
535 /**
536 * gimp_page_selector_set_page_thumbnail:
537 * @selector: Pointer to a #GimpPageSelector.
538 * @page_no: The number of the page to set the thumbnail for.
539 * @thumbnail: The thumbnail pixbuf.
540 *
541 * Sets the thumbnail for given @page_no. A default "page" icon will
542 * be used if no page thumbnail is set.
543 *
544 * Since: 2.4
545 **/
546 void
gimp_page_selector_set_page_thumbnail(GimpPageSelector * selector,gint page_no,GdkPixbuf * thumbnail)547 gimp_page_selector_set_page_thumbnail (GimpPageSelector *selector,
548 gint page_no,
549 GdkPixbuf *thumbnail)
550 {
551 GimpPageSelectorPrivate *priv;
552 GtkTreeIter iter;
553
554 g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
555 g_return_if_fail (thumbnail == NULL || GDK_IS_PIXBUF (thumbnail));
556
557 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
558
559 g_return_if_fail (page_no >= 0 && page_no < priv->n_pages);
560
561 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
562 &iter, NULL, page_no);
563
564 if (! thumbnail)
565 {
566 thumbnail = g_object_ref (priv->default_thumbnail);
567 }
568 else
569 {
570 thumbnail = gimp_page_selector_add_frame (GTK_WIDGET (selector),
571 thumbnail);
572 }
573
574 gtk_list_store_set (priv->store, &iter,
575 COLUMN_THUMBNAIL, thumbnail,
576 -1);
577 g_clear_object (&thumbnail);
578 }
579
580 /**
581 * gimp_page_selector_get_page_thumbnail:
582 * @selector: Pointer to a #GimpPageSelector.
583 * @page_no: The number of the page to get the thumbnail for.
584 *
585 * Returns: The page's thumbnail, or %NULL if none is set. The returned
586 * pixbuf is owned by #GimpPageSelector and must not be
587 * unref'ed when no longer needed.
588 *
589 * Since: 2.4
590 **/
591 GdkPixbuf *
gimp_page_selector_get_page_thumbnail(GimpPageSelector * selector,gint page_no)592 gimp_page_selector_get_page_thumbnail (GimpPageSelector *selector,
593 gint page_no)
594 {
595 GimpPageSelectorPrivate *priv;
596 GdkPixbuf *thumbnail;
597 GtkTreeIter iter;
598
599 g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), NULL);
600
601 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
602
603 g_return_val_if_fail (page_no >= 0 && page_no < priv->n_pages, NULL);
604
605 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
606 &iter, NULL, page_no);
607 gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
608 COLUMN_THUMBNAIL, &thumbnail,
609 -1);
610
611 if (thumbnail)
612 g_object_unref (thumbnail);
613
614 if (thumbnail == priv->default_thumbnail)
615 return NULL;
616
617 return thumbnail;
618 }
619
620 /**
621 * gimp_page_selector_set_page_label:
622 * @selector: Pointer to a #GimpPageSelector.
623 * @page_no: The number of the page to set the label for.
624 * @label: The label.
625 *
626 * Sets the label of the specified page.
627 *
628 * Since: 2.4
629 **/
630 void
gimp_page_selector_set_page_label(GimpPageSelector * selector,gint page_no,const gchar * label)631 gimp_page_selector_set_page_label (GimpPageSelector *selector,
632 gint page_no,
633 const gchar *label)
634 {
635 GimpPageSelectorPrivate *priv;
636 GtkTreeIter iter;
637 gchar *tmp;
638
639 g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
640
641 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
642
643 g_return_if_fail (page_no >= 0 && page_no < priv->n_pages);
644
645 if (! label)
646 tmp = g_strdup_printf (_("Page %d"), page_no + 1);
647 else
648 tmp = (gchar *) label;
649
650 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
651 &iter, NULL, page_no);
652 gtk_list_store_set (priv->store, &iter,
653 COLUMN_LABEL, tmp,
654 COLUMN_LABEL_SET, label != NULL,
655 -1);
656
657 if (! label)
658 g_free (tmp);
659 }
660
661 /**
662 * gimp_page_selector_get_page_label:
663 * @selector: Pointer to a #GimpPageSelector.
664 * @page_no: The number of the page to get the thumbnail for.
665 *
666 * Returns: The page's label, or %NULL if none is set. This is a newly
667 * allocated string that should be g_free()'d when no longer
668 * needed.
669 *
670 * Since: 2.4
671 **/
672 gchar *
gimp_page_selector_get_page_label(GimpPageSelector * selector,gint page_no)673 gimp_page_selector_get_page_label (GimpPageSelector *selector,
674 gint page_no)
675 {
676 GimpPageSelectorPrivate *priv;
677 GtkTreeIter iter;
678 gchar *label;
679 gboolean label_set;
680
681 g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), NULL);
682
683 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
684
685 g_return_val_if_fail (page_no >= 0 && page_no < priv->n_pages, NULL);
686
687 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
688 &iter, NULL, page_no);
689 gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
690 COLUMN_LABEL, &label,
691 COLUMN_LABEL_SET, &label_set,
692 -1);
693
694 if (! label_set)
695 {
696 g_free (label);
697 label = NULL;
698 }
699
700 return label;
701 }
702
703 /**
704 * gimp_page_selector_select_all:
705 * @selector: Pointer to a #GimpPageSelector.
706 *
707 * Selects all pages.
708 *
709 * Since: 2.4
710 **/
711 void
gimp_page_selector_select_all(GimpPageSelector * selector)712 gimp_page_selector_select_all (GimpPageSelector *selector)
713 {
714 GimpPageSelectorPrivate *priv;
715
716 g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
717
718 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
719
720 gtk_icon_view_select_all (GTK_ICON_VIEW (priv->view));
721 }
722
723 /**
724 * gimp_page_selector_unselect_all:
725 * @selector: Pointer to a #GimpPageSelector.
726 *
727 * Unselects all pages.
728 *
729 * Since: 2.4
730 **/
731 void
gimp_page_selector_unselect_all(GimpPageSelector * selector)732 gimp_page_selector_unselect_all (GimpPageSelector *selector)
733 {
734 GimpPageSelectorPrivate *priv;
735
736 g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
737
738 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
739
740 gtk_icon_view_unselect_all (GTK_ICON_VIEW (priv->view));
741 }
742
743 /**
744 * gimp_page_selector_select_page:
745 * @selector: Pointer to a #GimpPageSelector.
746 * @page_no: The number of the page to select.
747 *
748 * Adds a page to the selection.
749 *
750 * Since: 2.4
751 **/
752 void
gimp_page_selector_select_page(GimpPageSelector * selector,gint page_no)753 gimp_page_selector_select_page (GimpPageSelector *selector,
754 gint page_no)
755 {
756 GimpPageSelectorPrivate *priv;
757 GtkTreeIter iter;
758 GtkTreePath *path;
759
760 g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
761
762 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
763
764 g_return_if_fail (page_no >= 0 && page_no < priv->n_pages);
765
766 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
767 &iter, NULL, page_no);
768 path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
769
770 gtk_icon_view_select_path (GTK_ICON_VIEW (priv->view), path);
771
772 gtk_tree_path_free (path);
773 }
774
775 /**
776 * gimp_page_selector_unselect_page:
777 * @selector: Pointer to a #GimpPageSelector.
778 * @page_no: The number of the page to unselect.
779 *
780 * Removes a page from the selection.
781 *
782 * Since: 2.4
783 **/
784 void
gimp_page_selector_unselect_page(GimpPageSelector * selector,gint page_no)785 gimp_page_selector_unselect_page (GimpPageSelector *selector,
786 gint page_no)
787 {
788 GimpPageSelectorPrivate *priv;
789 GtkTreeIter iter;
790 GtkTreePath *path;
791
792 g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
793
794 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
795
796 g_return_if_fail (page_no >= 0 && page_no < priv->n_pages);
797
798 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
799 &iter, NULL, page_no);
800 path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
801
802 gtk_icon_view_unselect_path (GTK_ICON_VIEW (priv->view), path);
803
804 gtk_tree_path_free (path);
805 }
806
807 /**
808 * gimp_page_selector_page_is_selected:
809 * @selector: Pointer to a #GimpPageSelector.
810 * @page_no: The number of the page to check.
811 *
812 * Returns: %TRUE if the page is selected, %FALSE otherwise.
813 *
814 * Since: 2.4
815 **/
816 gboolean
gimp_page_selector_page_is_selected(GimpPageSelector * selector,gint page_no)817 gimp_page_selector_page_is_selected (GimpPageSelector *selector,
818 gint page_no)
819 {
820 GimpPageSelectorPrivate *priv;
821 GtkTreeIter iter;
822 GtkTreePath *path;
823 gboolean selected;
824
825 g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), FALSE);
826
827 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
828
829 g_return_val_if_fail (page_no >= 0 && page_no < priv->n_pages, FALSE);
830
831 gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (priv->store),
832 &iter, NULL, page_no);
833 path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->store), &iter);
834
835 selected = gtk_icon_view_path_is_selected (GTK_ICON_VIEW (priv->view),
836 path);
837
838 gtk_tree_path_free (path);
839
840 return selected;
841 }
842
843 /**
844 * gimp_page_selector_get_selected_pages:
845 * @selector: Pointer to a #GimpPageSelector.
846 * @n_selected_pages: Returns the number of selected pages.
847 *
848 * Returns: A sorted array of page numbers of selected pages. Use g_free() if
849 * you don't need the array any longer.
850 *
851 * Since: 2.4
852 **/
853 gint *
gimp_page_selector_get_selected_pages(GimpPageSelector * selector,gint * n_selected_pages)854 gimp_page_selector_get_selected_pages (GimpPageSelector *selector,
855 gint *n_selected_pages)
856 {
857 GimpPageSelectorPrivate *priv;
858 GList *selected;
859 GList *list;
860 gint *array;
861 gint i;
862
863 g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), NULL);
864 g_return_val_if_fail (n_selected_pages != NULL, NULL);
865
866 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
867
868 selected = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (priv->view));
869
870 *n_selected_pages = g_list_length (selected);
871 array = g_new0 (gint, *n_selected_pages);
872
873 for (list = selected, i = 0; list; list = g_list_next (list), i++)
874 {
875 gint *indices = gtk_tree_path_get_indices (list->data);
876
877 array[i] = indices[0];
878 }
879
880 qsort (array, *n_selected_pages, sizeof (gint),
881 gimp_page_selector_int_compare);
882
883 g_list_free_full (selected, (GDestroyNotify) gtk_tree_path_free);
884
885 return array;
886 }
887
888 /**
889 * gimp_page_selector_select_range:
890 * @selector: Pointer to a #GimpPageSelector.
891 * @range: A string representing the set of selected pages.
892 *
893 * Selects the pages described by @range. The range string is a
894 * user-editable list of pages and ranges, e.g. "1,3,5-7,9-12,14".
895 * Note that the page numbering in the range string starts with 1,
896 * not 0.
897 *
898 * Invalid pages and ranges will be silently ignored, duplicate and
899 * overlapping pages and ranges will be merged.
900 *
901 * Since: 2.4
902 **/
903 void
gimp_page_selector_select_range(GimpPageSelector * selector,const gchar * range)904 gimp_page_selector_select_range (GimpPageSelector *selector,
905 const gchar *range)
906 {
907 GimpPageSelectorPrivate *priv;
908 gchar **ranges;
909
910 g_return_if_fail (GIMP_IS_PAGE_SELECTOR (selector));
911
912 priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
913
914 if (! range)
915 range = "";
916
917 g_signal_handlers_block_by_func (priv->view,
918 gimp_page_selector_selection_changed,
919 selector);
920
921 gimp_page_selector_unselect_all (selector);
922
923 ranges = g_strsplit (range, ",", -1);
924
925 if (ranges)
926 {
927 gint i;
928
929 for (i = 0; ranges[i] != NULL; i++)
930 {
931 gchar *range = g_strstrip (ranges[i]);
932 gchar *dash;
933
934 dash = strchr (range, '-');
935
936 if (dash)
937 {
938 gchar *from;
939 gchar *to;
940 gint page_from = -1;
941 gint page_to = -1;
942
943 *dash = '\0';
944
945 from = g_strstrip (range);
946 to = g_strstrip (dash + 1);
947
948 if (sscanf (from, "%i", &page_from) != 1 && strlen (from) == 0)
949 page_from = 1;
950
951 if (sscanf (to, "%i", &page_to) != 1 && strlen (to) == 0)
952 page_to = priv->n_pages;
953
954 if (page_from > 0 &&
955 page_to > 0 &&
956 page_from <= page_to &&
957 page_from <= priv->n_pages)
958 {
959 gint page_no;
960
961 page_from = MAX (page_from, 1) - 1;
962 page_to = MIN (page_to, priv->n_pages) - 1;
963
964 for (page_no = page_from; page_no <= page_to; page_no++)
965 gimp_page_selector_select_page (selector, page_no);
966 }
967 }
968 else
969 {
970 gint page_no;
971
972 if (sscanf (range, "%i", &page_no) == 1 &&
973 page_no >= 1 &&
974 page_no <= priv->n_pages)
975 {
976 gimp_page_selector_select_page (selector, page_no - 1);
977 }
978 }
979 }
980
981 g_strfreev (ranges);
982 }
983
984 g_signal_handlers_unblock_by_func (priv->view,
985 gimp_page_selector_selection_changed,
986 selector);
987
988 gimp_page_selector_selection_changed (GTK_ICON_VIEW (priv->view), selector);
989 }
990
991 /**
992 * gimp_page_selector_get_selected_range:
993 * @selector: Pointer to a #GimpPageSelector.
994 *
995 * Returns: A newly allocated string representing the set of selected
996 * pages. See gimp_page_selector_select_range() for the
997 * format of the string.
998 *
999 * Since: 2.4
1000 **/
1001 gchar *
gimp_page_selector_get_selected_range(GimpPageSelector * selector)1002 gimp_page_selector_get_selected_range (GimpPageSelector *selector)
1003 {
1004 gint *pages;
1005 gint n_pages;
1006 GString *string;
1007
1008 g_return_val_if_fail (GIMP_IS_PAGE_SELECTOR (selector), NULL);
1009
1010 string = g_string_new ("");
1011
1012 pages = gimp_page_selector_get_selected_pages (selector, &n_pages);
1013
1014 if (pages)
1015 {
1016 gint range_start, range_end;
1017 gint last_printed;
1018 gint i;
1019
1020 range_start = pages[0];
1021 range_end = pages[0];
1022 last_printed = -1;
1023
1024 for (i = 1; i < n_pages; i++)
1025 {
1026 if (pages[i] > range_end + 1)
1027 {
1028 gimp_page_selector_print_range (string,
1029 range_start, range_end);
1030
1031 last_printed = range_end;
1032 range_start = pages[i];
1033 }
1034
1035 range_end = pages[i];
1036 }
1037
1038 if (range_end != last_printed)
1039 gimp_page_selector_print_range (string, range_start, range_end);
1040
1041 g_free (pages);
1042 }
1043
1044 return g_string_free (string, FALSE);
1045 }
1046
1047
1048 /* private functions */
1049
1050 static void
gimp_page_selector_selection_changed(GtkIconView * icon_view,GimpPageSelector * selector)1051 gimp_page_selector_selection_changed (GtkIconView *icon_view,
1052 GimpPageSelector *selector)
1053 {
1054 GimpPageSelectorPrivate *priv = GIMP_PAGE_SELECTOR_GET_PRIVATE (selector);
1055 GList *selected;
1056 gint n_selected;
1057 gchar *range;
1058
1059 selected = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (priv->view));
1060 n_selected = g_list_length (selected);
1061 g_list_free_full (selected, (GDestroyNotify) gtk_tree_path_free);
1062
1063 if (n_selected == 0)
1064 {
1065 gtk_label_set_text (GTK_LABEL (priv->count_label),
1066 _("Nothing selected"));
1067 }
1068 else if (n_selected == 1)
1069 {
1070 gtk_label_set_text (GTK_LABEL (priv->count_label),
1071 _("One page selected"));
1072 }
1073 else
1074 {
1075 gchar *text;
1076
1077 if (n_selected == priv->n_pages)
1078 text = g_strdup_printf (ngettext ("%d page selected",
1079 "All %d pages selected", n_selected),
1080 n_selected);
1081 else
1082 text = g_strdup_printf (ngettext ("%d page selected",
1083 "%d pages selected",
1084 n_selected),
1085 n_selected);
1086
1087 gtk_label_set_text (GTK_LABEL (priv->count_label), text);
1088 g_free (text);
1089 }
1090
1091 range = gimp_page_selector_get_selected_range (selector);
1092 gtk_entry_set_text (GTK_ENTRY (priv->range_entry), range);
1093 g_free (range);
1094
1095 gtk_editable_set_position (GTK_EDITABLE (priv->range_entry), -1);
1096
1097 g_signal_emit (selector, selector_signals[SELECTION_CHANGED], 0);
1098 }
1099
1100 static void
gimp_page_selector_item_activated(GtkIconView * icon_view,GtkTreePath * path,GimpPageSelector * selector)1101 gimp_page_selector_item_activated (GtkIconView *icon_view,
1102 GtkTreePath *path,
1103 GimpPageSelector *selector)
1104 {
1105 g_signal_emit (selector, selector_signals[ACTIVATE], 0);
1106 }
1107
1108 static gboolean
gimp_page_selector_range_focus_out(GtkEntry * entry,GdkEventFocus * fevent,GimpPageSelector * selector)1109 gimp_page_selector_range_focus_out (GtkEntry *entry,
1110 GdkEventFocus *fevent,
1111 GimpPageSelector *selector)
1112 {
1113 gimp_page_selector_range_activate (entry, selector);
1114
1115 return FALSE;
1116 }
1117
1118 static void
gimp_page_selector_range_activate(GtkEntry * entry,GimpPageSelector * selector)1119 gimp_page_selector_range_activate (GtkEntry *entry,
1120 GimpPageSelector *selector)
1121 {
1122 gimp_page_selector_select_range (selector, gtk_entry_get_text (entry));
1123 }
1124
1125 static gint
gimp_page_selector_int_compare(gconstpointer a,gconstpointer b)1126 gimp_page_selector_int_compare (gconstpointer a,
1127 gconstpointer b)
1128 {
1129 return *(gint*)a - *(gint*)b;
1130 }
1131
1132 static void
gimp_page_selector_print_range(GString * string,gint start,gint end)1133 gimp_page_selector_print_range (GString *string,
1134 gint start,
1135 gint end)
1136 {
1137 if (string->len != 0)
1138 g_string_append_c (string, ',');
1139
1140 if (start == end)
1141 g_string_append_printf (string, "%d", start + 1);
1142 else
1143 g_string_append_printf (string, "%d-%d", start + 1, end + 1);
1144 }
1145
1146 static void
draw_frame_row(GdkPixbuf * frame_image,gint target_width,gint source_width,gint source_v_position,gint dest_v_position,GdkPixbuf * result_pixbuf,gint left_offset,gint height)1147 draw_frame_row (GdkPixbuf *frame_image,
1148 gint target_width,
1149 gint source_width,
1150 gint source_v_position,
1151 gint dest_v_position,
1152 GdkPixbuf *result_pixbuf,
1153 gint left_offset,
1154 gint height)
1155 {
1156 gint remaining_width = target_width;
1157 gint h_offset = 0;
1158
1159 while (remaining_width > 0)
1160 {
1161 gint slab_width = (remaining_width > source_width ?
1162 source_width : remaining_width);
1163
1164 gdk_pixbuf_copy_area (frame_image,
1165 left_offset, source_v_position,
1166 slab_width, height,
1167 result_pixbuf,
1168 left_offset + h_offset, dest_v_position);
1169
1170 remaining_width -= slab_width;
1171 h_offset += slab_width;
1172 }
1173 }
1174
1175 /* utility to draw the middle section of the frame in a loop */
1176 static void
draw_frame_column(GdkPixbuf * frame_image,gint target_height,gint source_height,gint source_h_position,gint dest_h_position,GdkPixbuf * result_pixbuf,gint top_offset,int width)1177 draw_frame_column (GdkPixbuf *frame_image,
1178 gint target_height,
1179 gint source_height,
1180 gint source_h_position,
1181 gint dest_h_position,
1182 GdkPixbuf *result_pixbuf,
1183 gint top_offset, int width)
1184 {
1185 gint remaining_height = target_height;
1186 gint v_offset = 0;
1187
1188 while (remaining_height > 0)
1189 {
1190 gint slab_height = (remaining_height > source_height ?
1191 source_height : remaining_height);
1192
1193 gdk_pixbuf_copy_area (frame_image,
1194 source_h_position, top_offset,
1195 width, slab_height,
1196 result_pixbuf,
1197 dest_h_position, top_offset + v_offset);
1198
1199 remaining_height -= slab_height;
1200 v_offset += slab_height;
1201 }
1202 }
1203
1204 static GdkPixbuf *
stretch_frame_image(GdkPixbuf * frame_image,gint left_offset,gint top_offset,gint right_offset,gint bottom_offset,gint dest_width,gint dest_height)1205 stretch_frame_image (GdkPixbuf *frame_image,
1206 gint left_offset,
1207 gint top_offset,
1208 gint right_offset,
1209 gint bottom_offset,
1210 gint dest_width,
1211 gint dest_height)
1212 {
1213 GdkPixbuf *pixbuf;
1214 gint frame_width, frame_height;
1215 gint target_width, target_frame_width;
1216 gint target_height, target_frame_height;
1217
1218 frame_width = gdk_pixbuf_get_width (frame_image);
1219 frame_height = gdk_pixbuf_get_height (frame_image );
1220
1221 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
1222 dest_width, dest_height);
1223 gdk_pixbuf_fill (pixbuf, 0);
1224
1225 target_width = dest_width - left_offset - right_offset;
1226 target_height = dest_height - top_offset - bottom_offset;
1227 target_frame_width = frame_width - left_offset - right_offset;
1228 target_frame_height = frame_height - top_offset - bottom_offset;
1229
1230 left_offset += MIN (target_width / 4, target_frame_width / 4);
1231 right_offset += MIN (target_width / 4, target_frame_width / 4);
1232 top_offset += MIN (target_height / 4, target_frame_height / 4);
1233 bottom_offset += MIN (target_height / 4, target_frame_height / 4);
1234
1235 target_width = dest_width - left_offset - right_offset;
1236 target_height = dest_height - top_offset - bottom_offset;
1237 target_frame_width = frame_width - left_offset - right_offset;
1238 target_frame_height = frame_height - top_offset - bottom_offset;
1239
1240 /* draw the left top corner and top row */
1241 gdk_pixbuf_copy_area (frame_image,
1242 0, 0, left_offset, top_offset,
1243 pixbuf, 0, 0);
1244 draw_frame_row (frame_image, target_width, target_frame_width,
1245 0, 0,
1246 pixbuf,
1247 left_offset, top_offset);
1248
1249 /* draw the right top corner and left column */
1250 gdk_pixbuf_copy_area (frame_image,
1251 frame_width - right_offset, 0,
1252 right_offset, top_offset,
1253
1254 pixbuf,
1255 dest_width - right_offset, 0);
1256 draw_frame_column (frame_image, target_height, target_frame_height, 0, 0,
1257 pixbuf, top_offset, left_offset);
1258
1259 /* draw the bottom right corner and bottom row */
1260 gdk_pixbuf_copy_area (frame_image,
1261 frame_width - right_offset, frame_height - bottom_offset,
1262 right_offset, bottom_offset,
1263 pixbuf,
1264 dest_width - right_offset, dest_height - bottom_offset);
1265 draw_frame_row (frame_image, target_width, target_frame_width,
1266 frame_height - bottom_offset, dest_height - bottom_offset,
1267 pixbuf, left_offset, bottom_offset);
1268
1269 /* draw the bottom left corner and the right column */
1270 gdk_pixbuf_copy_area (frame_image,
1271 0, frame_height - bottom_offset,
1272 left_offset, bottom_offset,
1273 pixbuf,
1274 0, dest_height - bottom_offset);
1275 draw_frame_column (frame_image, target_height, target_frame_height,
1276 frame_width - right_offset, dest_width - right_offset,
1277 pixbuf, top_offset, right_offset);
1278
1279 return pixbuf;
1280 }
1281
1282 #define FRAME_LEFT 2
1283 #define FRAME_TOP 2
1284 #define FRAME_RIGHT 4
1285 #define FRAME_BOTTOM 4
1286
1287 static GdkPixbuf *
gimp_page_selector_add_frame(GtkWidget * widget,GdkPixbuf * pixbuf)1288 gimp_page_selector_add_frame (GtkWidget *widget,
1289 GdkPixbuf *pixbuf)
1290 {
1291 GdkPixbuf *frame;
1292 gint width, height;
1293
1294 width = gdk_pixbuf_get_width (pixbuf);
1295 height = gdk_pixbuf_get_height (pixbuf);
1296
1297 frame = g_object_get_data (G_OBJECT (widget), "frame");
1298
1299 if (! frame)
1300 {
1301 GError *error = NULL;
1302
1303 frame = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
1304 GIMP_ICON_FRAME, 64, 0, &error);
1305 if (error)
1306 {
1307 g_printerr ("%s: %s\n", G_STRFUNC, error->message);
1308 g_error_free (error);
1309 }
1310 g_return_val_if_fail (frame, NULL);
1311 g_object_set_data_full (G_OBJECT (widget), "frame", frame,
1312 (GDestroyNotify) g_object_unref);
1313 }
1314
1315 frame = stretch_frame_image (frame,
1316 FRAME_LEFT,
1317 FRAME_TOP,
1318 FRAME_RIGHT,
1319 FRAME_BOTTOM,
1320 width + FRAME_LEFT + FRAME_RIGHT,
1321 height + FRAME_TOP + FRAME_BOTTOM);
1322
1323 gdk_pixbuf_copy_area (pixbuf, 0, 0, width, height,
1324 frame, FRAME_LEFT, FRAME_TOP);
1325
1326 return frame;
1327 }
1328