/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * pikatoolpalette.c * Copyright (C) 2010 Michael Natterer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include #include "libpikabase/pikabase.h" #include "libpikawidgets/pikawidgets.h" #include "widgets-types.h" #include "config/pikaguiconfig.h" #include "core/pika.h" #include "core/pikacontext.h" #include "core/pikacontainer.h" #include "core/pikatoolitem.h" #include "pikatoolbox.h" #include "pikatoolbutton.h" #include "pikatoolpalette.h" #include "pikauimanager.h" #include "pikawidgets-utils.h" #include "pikawindowstrategy.h" #include "pika-intl.h" #define DEFAULT_TOOL_ICON_SIZE GTK_ICON_SIZE_BUTTON #define DEFAULT_BUTTON_RELIEF GTK_RELIEF_NONE typedef struct _PikaToolPalettePrivate PikaToolPalettePrivate; struct _PikaToolPalettePrivate { PikaToolbox *toolbox; GtkWidget *group; GHashTable *buttons; }; #define GET_PRIVATE(p) ((PikaToolPalettePrivate *) pika_tool_palette_get_instance_private ((PikaToolPalette *) (p))) static void pika_tool_palette_finalize (GObject *object); static GtkSizeRequestMode pika_tool_palette_get_request_mode (GtkWidget *widget); static void pika_tool_palette_get_preferred_width (GtkWidget *widget, gint *min_width, gint *pref_width); static void pika_tool_palette_get_preferred_height(GtkWidget *widget, gint *min_width, gint *pref_width); static void pika_tool_palette_height_for_width (GtkWidget *widget, gint width, gint *min_height, gint *pref_height); static void pika_tool_palette_style_updated (GtkWidget *widget); static void pika_tool_palette_tool_add (PikaContainer *container, PikaToolItem *tool_item, PikaToolPalette *palette); static void pika_tool_palette_tool_remove (PikaContainer *container, PikaToolItem *tool_item, PikaToolPalette *palette); static void pika_tool_palette_tool_reorder (PikaContainer *container, PikaToolItem *tool_item, gint index, PikaToolPalette *palette); static void pika_tool_palette_add_button (PikaToolPalette *palette, PikaToolItem *tool_item, gint index); G_DEFINE_TYPE_WITH_PRIVATE (PikaToolPalette, pika_tool_palette, GTK_TYPE_TOOL_PALETTE) #define parent_class pika_tool_palette_parent_class static void pika_tool_palette_class_init (PikaToolPaletteClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->finalize = pika_tool_palette_finalize; widget_class->get_request_mode = pika_tool_palette_get_request_mode; widget_class->get_preferred_width = pika_tool_palette_get_preferred_width; widget_class->get_preferred_height = pika_tool_palette_get_preferred_height; widget_class->get_preferred_height_for_width = pika_tool_palette_height_for_width; widget_class->style_updated = pika_tool_palette_style_updated; gtk_widget_class_install_style_property (widget_class, g_param_spec_enum ("tool-icon-size", NULL, NULL, GTK_TYPE_ICON_SIZE, DEFAULT_TOOL_ICON_SIZE, PIKA_PARAM_READABLE)); gtk_widget_class_install_style_property (widget_class, g_param_spec_enum ("button-relief", NULL, NULL, GTK_TYPE_RELIEF_STYLE, DEFAULT_BUTTON_RELIEF, PIKA_PARAM_READABLE)); } static void pika_tool_palette_init (PikaToolPalette *palette) { PikaToolPalettePrivate *private = GET_PRIVATE (palette); private->buttons = g_hash_table_new (g_direct_hash, g_direct_equal); gtk_tool_palette_set_style (GTK_TOOL_PALETTE (palette), GTK_TOOLBAR_ICONS); } static void pika_tool_palette_finalize (GObject *object) { PikaToolPalettePrivate *private = GET_PRIVATE (object); g_clear_pointer (&private->buttons, g_hash_table_unref); G_OBJECT_CLASS (parent_class)->finalize (object); } static GtkSizeRequestMode pika_tool_palette_get_request_mode (GtkWidget *widget) { return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; } static gint pika_tool_palette_get_n_tools (PikaToolPalette *palette, gint *button_width, gint *button_height, gint *min_columns, gint *min_rows) { PikaToolPalettePrivate *private = GET_PRIVATE (palette); PikaToolItem *tool_item; GHashTableIter iter; GdkMonitor *monitor; GdkRectangle workarea; gint n_tools; gint max_rows; gint max_columns; if (! pika_tool_palette_get_button_size (palette, button_width, button_height)) { /* arbitrary values, just to simplify our callers */ *button_width = 24; *button_height = 24; } n_tools = 0; g_hash_table_iter_init (&iter, private->buttons); while (g_hash_table_iter_next (&iter, (gpointer *) &tool_item, NULL)) { if (pika_tool_item_get_visible (tool_item)) n_tools++; } monitor = pika_widget_get_monitor (GTK_WIDGET (palette)); gdk_monitor_get_workarea (monitor, &workarea); max_columns = (workarea.width * 0.9) / *button_width; max_rows = (workarea.height * 0.7) / *button_height; *min_columns = MAX (1, n_tools / max_rows); *min_rows = MAX (1, n_tools / max_columns); return n_tools; } static void pika_tool_palette_get_preferred_width (GtkWidget *widget, gint *min_width, gint *pref_width) { gint button_width; gint button_height; gint min_columns; gint min_rows; pika_tool_palette_get_n_tools (PIKA_TOOL_PALETTE (widget), &button_width, &button_height, &min_columns, &min_rows); *min_width = min_columns * button_width; *pref_width = min_columns * button_width; } static void pika_tool_palette_get_preferred_height (GtkWidget *widget, gint *min_height, gint *pref_height) { gint button_width; gint button_height; gint min_columns; gint min_rows; pika_tool_palette_get_n_tools (PIKA_TOOL_PALETTE (widget), &button_width, &button_height, &min_columns, &min_rows); *min_height = min_rows * button_height; *pref_height = min_rows * button_height; } static void pika_tool_palette_height_for_width (GtkWidget *widget, gint width, gint *min_height, gint *pref_height) { gint n_tools; gint button_width; gint button_height; gint min_columns; gint min_rows; gint tool_columns; gint tool_rows; n_tools = pika_tool_palette_get_n_tools (PIKA_TOOL_PALETTE (widget), &button_width, &button_height, &min_columns, &min_rows); tool_columns = MAX (min_columns, width / button_width); tool_rows = n_tools / tool_columns; if (n_tools % tool_columns) tool_rows++; *min_height = *pref_height = tool_rows * button_height; } static void pika_tool_palette_style_updated (GtkWidget *widget) { PikaToolPalettePrivate *private = GET_PRIVATE (widget); GtkWidget *tool_button; GHashTableIter iter; GtkReliefStyle relief; GtkIconSize tool_icon_size; GTK_WIDGET_CLASS (parent_class)->style_updated (widget); if (! pika_toolbox_get_context (private->toolbox)) return; gtk_widget_style_get (widget, "button-relief", &relief, "tool-icon-size", &tool_icon_size, NULL); gtk_tool_palette_set_icon_size (GTK_TOOL_PALETTE (widget), tool_icon_size); g_hash_table_iter_init (&iter, private->buttons); while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &tool_button)) { GtkWidget *button = gtk_bin_get_child (GTK_BIN (tool_button)); gtk_button_set_relief (GTK_BUTTON (button), relief); } pika_dock_invalidate_geometry (PIKA_DOCK (private->toolbox)); } /* public functions */ GtkWidget * pika_tool_palette_new (void) { return g_object_new (PIKA_TYPE_TOOL_PALETTE, NULL); } void pika_tool_palette_set_toolbox (PikaToolPalette *palette, PikaToolbox *toolbox) { PikaToolPalettePrivate *private; PikaContext *context; GList *list; g_return_if_fail (PIKA_IS_TOOL_PALETTE (palette)); g_return_if_fail (PIKA_IS_TOOLBOX (toolbox)); private = GET_PRIVATE (palette); private->toolbox = toolbox; context = pika_toolbox_get_context (toolbox); private->group = gtk_tool_item_group_new (_("Tools")); gtk_tool_item_group_set_label_widget (GTK_TOOL_ITEM_GROUP (private->group), NULL); gtk_container_add (GTK_CONTAINER (palette), private->group); gtk_widget_show (private->group); for (list = pika_get_tool_item_ui_iter (context->pika); list; list = g_list_next (list)) { PikaToolItem *tool_item = list->data; pika_tool_palette_add_button (palette, tool_item, -1); } g_signal_connect_object (context->pika->tool_item_ui_list, "add", G_CALLBACK (pika_tool_palette_tool_add), palette, 0); g_signal_connect_object (context->pika->tool_item_ui_list, "remove", G_CALLBACK (pika_tool_palette_tool_remove), palette, 0); g_signal_connect_object (context->pika->tool_item_ui_list, "reorder", G_CALLBACK (pika_tool_palette_tool_reorder), palette, 0); g_signal_connect_object (PIKA_GUI_CONFIG (context->pika->config), "notify::theme", G_CALLBACK (pika_tool_palette_style_updated), palette, G_CONNECT_AFTER | G_CONNECT_SWAPPED); g_signal_connect_object (PIKA_GUI_CONFIG (context->pika->config), "notify::override-theme-icon-size", G_CALLBACK (pika_tool_palette_style_updated), palette, G_CONNECT_AFTER | G_CONNECT_SWAPPED); g_signal_connect_object (PIKA_GUI_CONFIG (context->pika->config), "notify::custom-icon-size", G_CALLBACK (pika_tool_palette_style_updated), palette, G_CONNECT_AFTER | G_CONNECT_SWAPPED); } gboolean pika_tool_palette_get_button_size (PikaToolPalette *palette, gint *width, gint *height) { PikaToolPalettePrivate *private; GHashTableIter iter; GtkWidget *tool_button; g_return_val_if_fail (PIKA_IS_TOOL_PALETTE (palette), FALSE); g_return_val_if_fail (width != NULL, FALSE); g_return_val_if_fail (height != NULL, FALSE); private = GET_PRIVATE (palette); g_hash_table_iter_init (&iter, private->buttons); if (g_hash_table_iter_next (&iter, NULL, (gpointer *) &tool_button)) { GtkRequisition button_requisition; gtk_widget_get_preferred_size (tool_button, &button_requisition, NULL); *width = button_requisition.width; *height = button_requisition.height; return TRUE; } return FALSE; } /* private functions */ static void pika_tool_palette_tool_add (PikaContainer *container, PikaToolItem *tool_item, PikaToolPalette *palette) { pika_tool_palette_add_button ( palette, tool_item, pika_container_get_child_index (container, PIKA_OBJECT (tool_item))); } static void pika_tool_palette_tool_remove (PikaContainer *container, PikaToolItem *tool_item, PikaToolPalette *palette) { PikaToolPalettePrivate *private = GET_PRIVATE (palette); GtkWidget *tool_button; tool_button = g_hash_table_lookup (private->buttons, tool_item); if (tool_button) { g_hash_table_remove (private->buttons, tool_item); gtk_container_remove (GTK_CONTAINER (private->group), tool_button); } } static void pika_tool_palette_tool_reorder (PikaContainer *container, PikaToolItem *tool_item, gint index, PikaToolPalette *palette) { PikaToolPalettePrivate *private = GET_PRIVATE (palette); GtkWidget *tool_button; tool_button = g_hash_table_lookup (private->buttons, tool_item); if (tool_button) { gtk_tool_item_group_set_item_position ( GTK_TOOL_ITEM_GROUP (private->group), GTK_TOOL_ITEM (tool_button), index); } } static void pika_tool_palette_add_button (PikaToolPalette *palette, PikaToolItem *tool_item, gint index) { PikaToolPalettePrivate *private = GET_PRIVATE (palette); GtkToolItem *tool_button; GtkWidget *button; GtkReliefStyle relief; tool_button = pika_tool_button_new (private->toolbox, tool_item); gtk_tool_item_group_insert (GTK_TOOL_ITEM_GROUP (private->group), tool_button, index); gtk_widget_show (GTK_WIDGET (tool_button)); g_object_bind_property (tool_item, "shown", tool_button, "visible-horizontal", G_BINDING_SYNC_CREATE); g_object_bind_property (tool_item, "shown", tool_button, "visible-vertical", G_BINDING_SYNC_CREATE); button = gtk_bin_get_child (GTK_BIN (tool_button)); gtk_widget_style_get (GTK_WIDGET (palette), "button-relief", &relief, NULL); gtk_button_set_relief (GTK_BUTTON (button), relief); g_hash_table_insert (private->buttons, tool_item, tool_button); }