1 /* LIBGIMP - The GIMP Library
2 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
3 *
4 * gimpimagecombobox.c
5 * Copyright (C) 2004 Sven Neumann <sven@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 * Lesser 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
26 #include <gegl.h>
27 #include <gtk/gtk.h>
28
29 #include "libgimpwidgets/gimpwidgets.h"
30
31 #include "gimp.h"
32
33 #include "gimpuitypes.h"
34 #include "gimpimagecombobox.h"
35 #include "gimppixbuf.h"
36
37
38 /**
39 * SECTION: gimpimagecombobox
40 * @title: GimpImageComboBox
41 * @short_description: A widget providing a popup menu of images.
42 *
43 * A widget providing a popup menu of images.
44 **/
45
46
47 #define THUMBNAIL_SIZE 24
48 #define WIDTH_REQUEST 200
49
50
51 typedef struct _GimpImageComboBoxClass GimpImageComboBoxClass;
52
53 struct _GimpImageComboBox
54 {
55 GimpIntComboBox parent_instance;
56
57 GimpImageConstraintFunc constraint;
58 gpointer data;
59 };
60
61 struct _GimpImageComboBoxClass
62 {
63 GimpIntComboBoxClass parent_class;
64 };
65
66
67 static void gimp_image_combo_box_populate (GimpImageComboBox *combo_box);
68 static void gimp_image_combo_box_model_add (GtkListStore *store,
69 gint num_images,
70 gint32 *images,
71 GimpImageConstraintFunc constraint,
72 gpointer data);
73
74 static void gimp_image_combo_box_drag_data_received (GtkWidget *widget,
75 GdkDragContext *context,
76 gint x,
77 gint y,
78 GtkSelectionData *selection,
79 guint info,
80 guint time);
81
82 static void gimp_image_combo_box_changed (GimpImageComboBox *combo_box);
83
84
85 static const GtkTargetEntry target = { "application/x-gimp-image-id", 0 };
86
87
G_DEFINE_TYPE(GimpImageComboBox,gimp_image_combo_box,GIMP_TYPE_INT_COMBO_BOX)88 G_DEFINE_TYPE (GimpImageComboBox, gimp_image_combo_box, GIMP_TYPE_INT_COMBO_BOX)
89
90
91 static void
92 gimp_image_combo_box_class_init (GimpImageComboBoxClass *klass)
93 {
94 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
95
96 widget_class->drag_data_received = gimp_image_combo_box_drag_data_received;
97 }
98
99 static void
gimp_image_combo_box_init(GimpImageComboBox * combo_box)100 gimp_image_combo_box_init (GimpImageComboBox *combo_box)
101 {
102 gtk_drag_dest_set (GTK_WIDGET (combo_box),
103 GTK_DEST_DEFAULT_HIGHLIGHT |
104 GTK_DEST_DEFAULT_MOTION |
105 GTK_DEST_DEFAULT_DROP,
106 &target, 1,
107 GDK_ACTION_COPY);
108 }
109
110 /**
111 * gimp_image_combo_box_new:
112 * @constraint: a #GimpImageConstraintFunc or %NULL
113 * @data: a pointer that is passed to @constraint
114 *
115 * Creates a new #GimpIntComboBox filled with all currently opened
116 * images. If a @constraint function is specified, it is called for
117 * each image and only if the function returns %TRUE, the image is
118 * added to the combobox.
119 *
120 * You should use gimp_int_combo_box_connect() to initialize and
121 * connect the combo. Use gimp_int_combo_box_set_active() to get the
122 * active image ID and gimp_int_combo_box_get_active() to retrieve the
123 * ID of the selected image.
124 *
125 * Return value: a new #GimpIntComboBox.
126 *
127 * Since: 2.2
128 **/
129 GtkWidget *
gimp_image_combo_box_new(GimpImageConstraintFunc constraint,gpointer data)130 gimp_image_combo_box_new (GimpImageConstraintFunc constraint,
131 gpointer data)
132 {
133 GimpImageComboBox *combo_box;
134
135 combo_box = g_object_new (GIMP_TYPE_IMAGE_COMBO_BOX,
136 "width-request", WIDTH_REQUEST,
137 "ellipsize", PANGO_ELLIPSIZE_MIDDLE,
138 NULL);
139
140 combo_box->constraint = constraint;
141 combo_box->data = data;
142
143 gimp_image_combo_box_populate (combo_box);
144
145 g_signal_connect (combo_box, "changed",
146 G_CALLBACK (gimp_image_combo_box_changed),
147 NULL);
148
149 return GTK_WIDGET (combo_box);
150 }
151
152 static void
gimp_image_combo_box_populate(GimpImageComboBox * combo_box)153 gimp_image_combo_box_populate (GimpImageComboBox *combo_box)
154 {
155 GtkTreeModel *model;
156 GtkTreeIter iter;
157 gint32 *images;
158 gint num_images;
159
160 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
161
162 images = gimp_image_list (&num_images);
163
164 gimp_image_combo_box_model_add (GTK_LIST_STORE (model),
165 num_images, images,
166 combo_box->constraint,
167 combo_box->data);
168
169 g_free (images);
170
171 if (gtk_tree_model_get_iter_first (model, &iter))
172 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
173 }
174
175 static void
gimp_image_combo_box_model_add(GtkListStore * store,gint num_images,gint32 * images,GimpImageConstraintFunc constraint,gpointer data)176 gimp_image_combo_box_model_add (GtkListStore *store,
177 gint num_images,
178 gint32 *images,
179 GimpImageConstraintFunc constraint,
180 gpointer data)
181 {
182 GtkTreeIter iter;
183 gint i;
184
185 for (i = 0; i < num_images; i++)
186 {
187 if (! constraint || (* constraint) (images[i], data))
188 {
189 gchar *image_name = gimp_image_get_name (images[i]);
190 gchar *label;
191 GdkPixbuf *thumb;
192
193 label = g_strdup_printf ("%s-%d", image_name, images[i]);
194
195 g_free (image_name);
196
197 thumb = gimp_image_get_thumbnail (images[i],
198 THUMBNAIL_SIZE, THUMBNAIL_SIZE,
199 GIMP_PIXBUF_SMALL_CHECKS);
200
201 gtk_list_store_append (store, &iter);
202 gtk_list_store_set (store, &iter,
203 GIMP_INT_STORE_VALUE, images[i],
204 GIMP_INT_STORE_LABEL, label,
205 GIMP_INT_STORE_PIXBUF, thumb,
206 -1);
207
208 if (thumb)
209 g_object_unref (thumb);
210
211 g_free (label);
212 }
213 }
214 }
215
216 static void
gimp_image_combo_box_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * selection,guint info,guint time)217 gimp_image_combo_box_drag_data_received (GtkWidget *widget,
218 GdkDragContext *context,
219 gint x,
220 gint y,
221 GtkSelectionData *selection,
222 guint info,
223 guint time)
224 {
225 gint length = gtk_selection_data_get_length (selection);
226 gchar *str;
227
228 if (gtk_selection_data_get_format (selection) != 8 || length < 1)
229 {
230 g_warning ("%s: received invalid image ID data", G_STRFUNC);
231 return;
232 }
233
234 str = g_strndup ((const gchar *) gtk_selection_data_get_data (selection),
235 length);
236
237 if (g_utf8_validate (str, -1, NULL))
238 {
239 gint pid;
240 gint ID;
241
242 if (sscanf (str, "%i:%i", &pid, &ID) == 2 &&
243 pid == gimp_getpid ())
244 {
245 gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (widget), ID);
246 }
247 }
248
249 g_free (str);
250 }
251
252 static void
gimp_image_combo_box_changed(GimpImageComboBox * combo_box)253 gimp_image_combo_box_changed (GimpImageComboBox *combo_box)
254 {
255 gint image_ID;
256
257 if (gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (combo_box),
258 &image_ID))
259 {
260 if (! gimp_image_is_valid (image_ID))
261 {
262 GtkTreeModel *model;
263
264 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
265
266 g_signal_stop_emission_by_name (combo_box, "changed");
267
268 gtk_list_store_clear (GTK_LIST_STORE (model));
269 gimp_image_combo_box_populate (combo_box);
270 }
271 }
272 }
273