1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimptoolpalette.c
5 * Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program 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
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <gegl.h>
24 #include <gtk/gtk.h>
25
26 #include "libgimpwidgets/gimpwidgets.h"
27
28 #include "widgets-types.h"
29
30 #include "config/gimpguiconfig.h"
31
32 #include "core/gimp.h"
33 #include "core/gimpcontext.h"
34 #include "core/gimpcontainer.h"
35 #include "core/gimptoolitem.h"
36
37 #include "gimptoolbox.h"
38 #include "gimptoolbutton.h"
39 #include "gimptoolpalette.h"
40 #include "gimpuimanager.h"
41 #include "gimpwidgets-utils.h"
42 #include "gimpwindowstrategy.h"
43
44 #include "gimp-intl.h"
45
46
47 #define DEFAULT_TOOL_ICON_SIZE GTK_ICON_SIZE_BUTTON
48 #define DEFAULT_BUTTON_RELIEF GTK_RELIEF_NONE
49
50
51 typedef struct _GimpToolPalettePrivate GimpToolPalettePrivate;
52
53 struct _GimpToolPalettePrivate
54 {
55 GimpToolbox *toolbox;
56
57 GtkWidget *group;
58 GHashTable *buttons;
59
60 gint tool_rows;
61 gint tool_columns;
62 };
63
64 #define GET_PRIVATE(p) ((GimpToolPalettePrivate *) gimp_tool_palette_get_instance_private ((GimpToolPalette *) (p)))
65
66
67 static void gimp_tool_palette_finalize (GObject *object);
68
69 static void gimp_tool_palette_size_allocate (GtkWidget *widget,
70 GtkAllocation *allocation);
71 static void gimp_tool_palette_style_set (GtkWidget *widget,
72 GtkStyle *previous_style);
73
74 static void gimp_tool_palette_tool_add (GimpContainer *container,
75 GimpToolItem *tool_item,
76 GimpToolPalette *palette);
77 static void gimp_tool_palette_tool_remove (GimpContainer *container,
78 GimpToolItem *tool_item,
79 GimpToolPalette *palette);
80 static void gimp_tool_palette_tool_reorder (GimpContainer *container,
81 GimpToolItem *tool_item,
82 gint index,
83 GimpToolPalette *palette);
84
85 static void gimp_tool_palette_config_menu_mode_notify (GimpGuiConfig *config,
86 const GParamSpec *pspec,
87 GimpToolPalette *palette);
88 static void gimp_tool_palette_config_size_changed (GimpGuiConfig *config,
89 GimpToolPalette *palette);
90
91 static void gimp_tool_palette_add_button (GimpToolPalette *palette,
92 GimpToolItem *tool_item,
93 gint index);
94
95 static gboolean gimp_tool_palette_get_show_menu_on_hover (GimpToolPalette *palette);
96 static void gimp_tool_palette_update_show_menu_on_hover (GimpToolPalette *palette);
97
98
G_DEFINE_TYPE_WITH_PRIVATE(GimpToolPalette,gimp_tool_palette,GTK_TYPE_TOOL_PALETTE)99 G_DEFINE_TYPE_WITH_PRIVATE (GimpToolPalette, gimp_tool_palette,
100 GTK_TYPE_TOOL_PALETTE)
101
102 #define parent_class gimp_tool_palette_parent_class
103
104
105 static void
106 gimp_tool_palette_class_init (GimpToolPaletteClass *klass)
107 {
108 GObjectClass *object_class = G_OBJECT_CLASS (klass);
109 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
110
111 object_class->finalize = gimp_tool_palette_finalize;
112
113 widget_class->size_allocate = gimp_tool_palette_size_allocate;
114 widget_class->style_set = gimp_tool_palette_style_set;
115
116 gtk_widget_class_install_style_property (widget_class,
117 g_param_spec_enum ("tool-icon-size",
118 NULL, NULL,
119 GTK_TYPE_ICON_SIZE,
120 DEFAULT_TOOL_ICON_SIZE,
121 GIMP_PARAM_READABLE));
122
123 gtk_widget_class_install_style_property (widget_class,
124 g_param_spec_enum ("button-relief",
125 NULL, NULL,
126 GTK_TYPE_RELIEF_STYLE,
127 DEFAULT_BUTTON_RELIEF,
128 GIMP_PARAM_READABLE));
129 }
130
131 static void
gimp_tool_palette_init(GimpToolPalette * palette)132 gimp_tool_palette_init (GimpToolPalette *palette)
133 {
134 GimpToolPalettePrivate *private = GET_PRIVATE (palette);
135
136 private->buttons = g_hash_table_new (g_direct_hash, g_direct_equal);
137
138 gtk_tool_palette_set_style (GTK_TOOL_PALETTE (palette), GTK_TOOLBAR_ICONS);
139 }
140
141 static void
gimp_tool_palette_finalize(GObject * object)142 gimp_tool_palette_finalize (GObject *object)
143 {
144 GimpToolPalettePrivate *private = GET_PRIVATE (object);
145
146 g_clear_pointer (&private->buttons, g_hash_table_unref);
147
148 if (private->toolbox)
149 {
150 GimpContext *context = gimp_toolbox_get_context (private->toolbox);
151
152 if (context)
153 {
154 g_signal_handlers_disconnect_by_func (
155 context->gimp->config,
156 G_CALLBACK (gimp_tool_palette_config_menu_mode_notify),
157 object);
158 g_signal_handlers_disconnect_by_func (
159 context->gimp->config,
160 G_CALLBACK (gimp_tool_palette_config_size_changed),
161 object);
162 }
163 }
164
165 G_OBJECT_CLASS (parent_class)->finalize (object);
166 }
167
168 static void
gimp_tool_palette_size_allocate(GtkWidget * widget,GtkAllocation * allocation)169 gimp_tool_palette_size_allocate (GtkWidget *widget,
170 GtkAllocation *allocation)
171 {
172 GimpToolPalette *palette = GIMP_TOOL_PALETTE (widget);
173 GimpToolPalettePrivate *private = GET_PRIVATE (widget);
174 gint button_width;
175 gint button_height;
176
177 GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
178
179 if (gimp_tool_palette_get_button_size (palette,
180 &button_width, &button_height))
181 {
182 GimpToolItem *tool_item;
183 GHashTableIter iter;
184 gint n_tools;
185 gint tool_rows;
186 gint tool_columns;
187
188 n_tools = 0;
189
190 g_hash_table_iter_init (&iter, private->buttons);
191
192 while (g_hash_table_iter_next (&iter, (gpointer *) &tool_item, NULL))
193 {
194 if (gimp_tool_item_get_visible (tool_item))
195 n_tools++;
196 }
197
198 tool_columns = MAX (1, (allocation->width / button_width));
199 tool_rows = n_tools / tool_columns;
200
201 if (n_tools % tool_columns)
202 tool_rows++;
203
204 if (private->tool_rows != tool_rows ||
205 private->tool_columns != tool_columns)
206 {
207 private->tool_rows = tool_rows;
208 private->tool_columns = tool_columns;
209
210 gtk_widget_set_size_request (widget, -1,
211 tool_rows * button_height);
212
213 gimp_tool_palette_update_show_menu_on_hover (palette);
214 }
215 }
216 }
217
218 static void
gimp_tool_palette_style_set(GtkWidget * widget,GtkStyle * previous_style)219 gimp_tool_palette_style_set (GtkWidget *widget,
220 GtkStyle *previous_style)
221 {
222 GimpToolPalettePrivate *private = GET_PRIVATE (widget);
223 Gimp *gimp;
224 GtkWidget *tool_button;
225 GHashTableIter iter;
226 GtkReliefStyle relief;
227
228 GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
229
230 if (! gimp_toolbox_get_context (private->toolbox))
231 return;
232
233 gimp = gimp_toolbox_get_context (private->toolbox)->gimp;
234
235 gtk_widget_style_get (widget,
236 "button-relief", &relief,
237 NULL);
238
239 gimp_tool_palette_config_size_changed (GIMP_GUI_CONFIG (gimp->config),
240 GIMP_TOOL_PALETTE (widget));
241
242 g_hash_table_iter_init (&iter, private->buttons);
243
244 while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &tool_button))
245 {
246 GtkWidget *button = gtk_bin_get_child (GTK_BIN (tool_button));
247
248 gtk_button_set_relief (GTK_BUTTON (button), relief);
249 }
250
251 gimp_dock_invalidate_geometry (GIMP_DOCK (private->toolbox));
252 }
253
254
255 /* public functions */
256
257 GtkWidget *
gimp_tool_palette_new(void)258 gimp_tool_palette_new (void)
259 {
260 return g_object_new (GIMP_TYPE_TOOL_PALETTE, NULL);
261 }
262
263 void
gimp_tool_palette_set_toolbox(GimpToolPalette * palette,GimpToolbox * toolbox)264 gimp_tool_palette_set_toolbox (GimpToolPalette *palette,
265 GimpToolbox *toolbox)
266 {
267 GimpToolPalettePrivate *private;
268 GimpContext *context;
269 GList *list;
270
271 g_return_if_fail (GIMP_IS_TOOL_PALETTE (palette));
272 g_return_if_fail (GIMP_IS_TOOLBOX (toolbox));
273
274 private = GET_PRIVATE (palette);
275
276 if (private->toolbox)
277 {
278 context = gimp_toolbox_get_context (private->toolbox);
279
280 g_signal_handlers_disconnect_by_func (
281 GIMP_GUI_CONFIG (context->gimp->config),
282 G_CALLBACK (gimp_tool_palette_config_menu_mode_notify),
283 palette);
284 g_signal_handlers_disconnect_by_func (
285 GIMP_GUI_CONFIG (context->gimp->config),
286 G_CALLBACK (gimp_tool_palette_config_size_changed),
287 palette);
288 }
289
290 private->toolbox = toolbox;
291
292 context = gimp_toolbox_get_context (toolbox);
293
294 private->group = gtk_tool_item_group_new (_("Tools"));
295 gtk_tool_item_group_set_label_widget (GTK_TOOL_ITEM_GROUP (private->group),
296 NULL);
297 gtk_container_add (GTK_CONTAINER (palette), private->group);
298 gtk_widget_show (private->group);
299
300 for (list = gimp_get_tool_item_ui_iter (context->gimp);
301 list;
302 list = g_list_next (list))
303 {
304 GimpToolItem *tool_item = list->data;
305
306 gimp_tool_palette_add_button (palette, tool_item, -1);
307 }
308
309 g_signal_connect_object (context->gimp->tool_item_ui_list, "add",
310 G_CALLBACK (gimp_tool_palette_tool_add),
311 palette, 0);
312 g_signal_connect_object (context->gimp->tool_item_ui_list, "remove",
313 G_CALLBACK (gimp_tool_palette_tool_remove),
314 palette, 0);
315 g_signal_connect_object (context->gimp->tool_item_ui_list, "reorder",
316 G_CALLBACK (gimp_tool_palette_tool_reorder),
317 palette, 0);
318
319 g_signal_connect (GIMP_GUI_CONFIG (context->gimp->config),
320 "notify::toolbox-group-menu-mode",
321 G_CALLBACK (gimp_tool_palette_config_menu_mode_notify),
322 palette);
323 gimp_tool_palette_update_show_menu_on_hover (palette);
324
325 /* Update the toolbox icon size on config change. */
326 g_signal_connect (GIMP_GUI_CONFIG (context->gimp->config),
327 "size-changed",
328 G_CALLBACK (gimp_tool_palette_config_size_changed),
329 palette);
330 gimp_tool_palette_config_size_changed (GIMP_GUI_CONFIG (context->gimp->config),
331 palette);
332 }
333
334 gboolean
gimp_tool_palette_get_button_size(GimpToolPalette * palette,gint * width,gint * height)335 gimp_tool_palette_get_button_size (GimpToolPalette *palette,
336 gint *width,
337 gint *height)
338 {
339 GimpToolPalettePrivate *private;
340 GHashTableIter iter;
341 GtkWidget *tool_button;
342
343 g_return_val_if_fail (GIMP_IS_TOOL_PALETTE (palette), FALSE);
344 g_return_val_if_fail (width != NULL, FALSE);
345 g_return_val_if_fail (height != NULL, FALSE);
346
347 private = GET_PRIVATE (palette);
348
349 g_hash_table_iter_init (&iter, private->buttons);
350
351 if (g_hash_table_iter_next (&iter, NULL, (gpointer *) &tool_button))
352 {
353 GtkRequisition button_requisition;
354
355 gtk_widget_size_request (tool_button, &button_requisition);
356
357 *width = button_requisition.width;
358 *height = button_requisition.height;
359
360 return TRUE;
361 }
362
363 return FALSE;
364 }
365
366
367 /* private functions */
368
369 static void
gimp_tool_palette_tool_add(GimpContainer * container,GimpToolItem * tool_item,GimpToolPalette * palette)370 gimp_tool_palette_tool_add (GimpContainer *container,
371 GimpToolItem *tool_item,
372 GimpToolPalette *palette)
373 {
374 gimp_tool_palette_add_button (
375 palette,
376 tool_item,
377 gimp_container_get_child_index (container, GIMP_OBJECT (tool_item)));
378 }
379
380 static void
gimp_tool_palette_tool_remove(GimpContainer * container,GimpToolItem * tool_item,GimpToolPalette * palette)381 gimp_tool_palette_tool_remove (GimpContainer *container,
382 GimpToolItem *tool_item,
383 GimpToolPalette *palette)
384 {
385 GimpToolPalettePrivate *private = GET_PRIVATE (palette);
386 GtkWidget *tool_button;
387
388 tool_button = g_hash_table_lookup (private->buttons, tool_item);
389
390 if (tool_button)
391 {
392 g_hash_table_remove (private->buttons, tool_item);
393
394 gtk_container_remove (GTK_CONTAINER (private->group), tool_button);
395 }
396 }
397
398 static void
gimp_tool_palette_tool_reorder(GimpContainer * container,GimpToolItem * tool_item,gint index,GimpToolPalette * palette)399 gimp_tool_palette_tool_reorder (GimpContainer *container,
400 GimpToolItem *tool_item,
401 gint index,
402 GimpToolPalette *palette)
403 {
404 GimpToolPalettePrivate *private = GET_PRIVATE (palette);
405 GtkWidget *tool_button;
406
407 tool_button = g_hash_table_lookup (private->buttons, tool_item);
408
409 if (tool_button)
410 {
411 gtk_tool_item_group_set_item_position (
412 GTK_TOOL_ITEM_GROUP (private->group),
413 GTK_TOOL_ITEM (tool_button), index);
414 }
415 }
416
417 static void
gimp_tool_palette_config_menu_mode_notify(GimpGuiConfig * config,const GParamSpec * pspec,GimpToolPalette * palette)418 gimp_tool_palette_config_menu_mode_notify (GimpGuiConfig *config,
419 const GParamSpec *pspec,
420 GimpToolPalette *palette)
421 {
422 gimp_tool_palette_update_show_menu_on_hover (palette);
423 }
424
425 static void
gimp_tool_palette_config_size_changed(GimpGuiConfig * config,GimpToolPalette * palette)426 gimp_tool_palette_config_size_changed (GimpGuiConfig *config,
427 GimpToolPalette *palette)
428 {
429 GimpIconSize size;
430 GtkIconSize tool_icon_size;
431
432 size = gimp_gui_config_detect_icon_size (config);
433 /* Match GimpIconSize with GtkIconSize for the toolbox icons. */
434 switch (size)
435 {
436 case GIMP_ICON_SIZE_SMALL:
437 tool_icon_size = GTK_ICON_SIZE_SMALL_TOOLBAR;
438 break;
439 case GIMP_ICON_SIZE_MEDIUM:
440 tool_icon_size = GTK_ICON_SIZE_LARGE_TOOLBAR;
441 break;
442 case GIMP_ICON_SIZE_LARGE:
443 tool_icon_size = GTK_ICON_SIZE_DND;
444 break;
445 case GIMP_ICON_SIZE_HUGE:
446 tool_icon_size = GTK_ICON_SIZE_DIALOG;
447 break;
448 default:
449 /* GIMP_ICON_SIZE_DEFAULT:
450 * let's use the size set by the theme. */
451 gtk_widget_style_get (GTK_WIDGET (palette),
452 "tool-icon-size", &tool_icon_size,
453 NULL);
454 break;
455 }
456
457 gtk_tool_palette_set_icon_size (GTK_TOOL_PALETTE (palette), tool_icon_size);
458 }
459
460 static void
gimp_tool_palette_add_button(GimpToolPalette * palette,GimpToolItem * tool_item,gint index)461 gimp_tool_palette_add_button (GimpToolPalette *palette,
462 GimpToolItem *tool_item,
463 gint index)
464 {
465 GimpToolPalettePrivate *private = GET_PRIVATE (palette);
466 GtkToolItem *tool_button;
467 GtkWidget *button;
468 GtkReliefStyle relief;
469
470 tool_button = gimp_tool_button_new (private->toolbox, tool_item);
471 gtk_tool_item_group_insert (GTK_TOOL_ITEM_GROUP (private->group),
472 tool_button, index);
473 gimp_tool_button_set_show_menu_on_hover (
474 GIMP_TOOL_BUTTON (tool_button),
475 gimp_tool_palette_get_show_menu_on_hover (palette));
476 gtk_widget_show (GTK_WIDGET (tool_button));
477
478 g_object_bind_property (tool_item, "shown",
479 tool_button, "visible-horizontal",
480 G_BINDING_SYNC_CREATE);
481 g_object_bind_property (tool_item, "shown",
482 tool_button, "visible-vertical",
483 G_BINDING_SYNC_CREATE);
484
485 button = gtk_bin_get_child (GTK_BIN (tool_button));
486
487 gtk_widget_style_get (GTK_WIDGET (palette),
488 "button-relief", &relief,
489 NULL);
490
491 gtk_button_set_relief (GTK_BUTTON (button), relief);
492
493 g_hash_table_insert (private->buttons, tool_item, tool_button);
494 }
495
496 static gboolean
gimp_tool_palette_get_show_menu_on_hover(GimpToolPalette * palette)497 gimp_tool_palette_get_show_menu_on_hover (GimpToolPalette *palette)
498 {
499 GimpToolPalettePrivate *private = GET_PRIVATE (palette);
500
501 if (private->toolbox)
502 {
503 GimpContext *context = gimp_toolbox_get_context (private->toolbox);
504
505 if (context)
506 {
507 GimpGuiConfig *config = GIMP_GUI_CONFIG (context->gimp->config);
508
509 switch (config->toolbox_group_menu_mode)
510 {
511 case GIMP_TOOL_GROUP_MENU_MODE_SHOW_ON_CLICK:
512 return FALSE;
513
514 case GIMP_TOOL_GROUP_MENU_MODE_SHOW_ON_HOVER:
515 return TRUE;
516
517 case GIMP_TOOL_GROUP_MENU_MODE_SHOW_ON_HOVER_SINGLE_COLUMN:
518 return private->tool_columns == 1;
519 }
520 }
521 }
522
523 return FALSE;
524 }
525
526 static void
gimp_tool_palette_update_show_menu_on_hover(GimpToolPalette * palette)527 gimp_tool_palette_update_show_menu_on_hover (GimpToolPalette *palette)
528 {
529 GimpToolPalettePrivate *private = GET_PRIVATE (palette);
530 GHashTableIter iter;
531 GimpToolButton *tool_button;
532 gboolean show_menu_on_hover;
533
534 show_menu_on_hover = gimp_tool_palette_get_show_menu_on_hover (palette);
535
536 g_hash_table_iter_init (&iter, private->buttons);
537
538 while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &tool_button))
539 {
540 gimp_tool_button_set_show_menu_on_hover (tool_button, show_menu_on_hover);
541 }
542 }
543