2020-01-29 11:52:17 -08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
|
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
|
*
|
|
|
|
|
* gimptoolbutton.c
|
|
|
|
|
* Copyright (C) 2020 Ell
|
|
|
|
|
*
|
|
|
|
|
* 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 <https://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include <gegl.h>
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
#include "libgimpbase/gimpbase.h"
|
|
|
|
|
#include "libgimpmath/gimpmath.h"
|
|
|
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
app, tools: allow creating demo "scenarios" from the AppStream metadata.
The idea is to add some "demo" attribute to a list item inside the
<release> tag, since we already decided that (for now at least) we'd
keep a strict "intro + list" logics, as we did until now.
This demo attribute uses an internal format to specify successive
widgets to blink (like a demo path towards a feature). For now, what it
allows is:
* raise the toolbox, select a tool and blink the tool button.
* raise a dockable, blink any widgets in there.
Now it is still limited and needs to evolve. In particular:
* What happens if the blinked tool button was explicitly removed from
Preferences? Should we re-add it for the demo? And once done, should
we remove it again? Then should we select back the tool previously
selected?
* What happens if the dockable widget is not visible? Should we allow
changing the settings to be able to demo correctly the new/changed
settings? Should it be temporary? If temporary, it can be annoying as
you'd still have to look attentively the demo to find back the path to
the new settings. If not temporary, some people may dislike we touch
their settings.
* What if docks are hidden? Should we unhide them, then hide them back
after demo time?
Also regarding the implementation: originally I wanted to just grab the
demo attribute directly from the AppStream metadata file, but I realized
that appstream-glib cleans out unknown attribute from the XML. I could
then simply parse the file with a generic XML parser, but I found
simpler to pre-parse it into a header built within GIMP. I still use
appstream-glib at runtime as it takes care of localization for us
(though in the same time, we also have the localization in the main po
files, so maybe we could just embed the release note strings as well).
See appstream-glib report: https://github.com/hughsie/appstream-glib/issues/431
2022-03-05 14:06:46 -08:00
|
|
|
#include "libgimpwidgets/gimpwidgets-private.h"
|
2020-01-29 11:52:17 -08:00
|
|
|
|
|
|
|
|
#include "widgets-types.h"
|
|
|
|
|
|
|
|
|
|
#include "core/gimp.h"
|
|
|
|
|
#include "core/gimp-gui.h"
|
|
|
|
|
#include "core/gimpcontainer.h"
|
|
|
|
|
#include "core/gimpcontext.h"
|
2021-07-05 03:33:35 -07:00
|
|
|
#include "core/gimpdisplay.h"
|
2020-01-29 11:52:17 -08:00
|
|
|
#include "core/gimptoolgroup.h"
|
|
|
|
|
#include "core/gimptoolinfo.h"
|
|
|
|
|
|
|
|
|
|
#include "actions/tools-commands.h"
|
|
|
|
|
|
2020-06-01 06:13:10 -07:00
|
|
|
#include "gimpaccellabel.h"
|
2020-01-29 11:52:17 -08:00
|
|
|
#include "gimpaction.h"
|
|
|
|
|
#include "gimpdock.h"
|
|
|
|
|
#include "gimptoolbox.h"
|
|
|
|
|
#include "gimptoolbutton.h"
|
|
|
|
|
#include "gimpwidgets-utils.h"
|
|
|
|
|
#include "gimpwindowstrategy.h"
|
|
|
|
|
|
2020-06-01 06:13:10 -07:00
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
|
2020-01-29 11:52:17 -08:00
|
|
|
|
|
|
|
|
#define ARROW_SIZE 0.125 /* * 100% */
|
|
|
|
|
#define ARROW_BORDER 3 /* px */
|
|
|
|
|
|
|
|
|
|
#define MENU_TIMEOUT 250 /* milliseconds */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
PROP_0,
|
|
|
|
|
PROP_TOOLBOX,
|
|
|
|
|
PROP_TOOL_ITEM
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct _GimpToolButtonPrivate
|
|
|
|
|
{
|
|
|
|
|
GimpToolbox *toolbox;
|
|
|
|
|
GimpToolItem *tool_item;
|
|
|
|
|
|
|
|
|
|
GtkWidget *palette;
|
|
|
|
|
|
2020-06-01 06:13:10 -07:00
|
|
|
GtkWidget *tooltip_widget;
|
|
|
|
|
|
2020-01-29 11:52:17 -08:00
|
|
|
GtkWidget *menu;
|
|
|
|
|
GHashTable *menu_items;
|
|
|
|
|
gint menu_timeout_id;
|
|
|
|
|
GdkEvent *menu_timeout_event;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* local function prototypes */
|
|
|
|
|
|
|
|
|
|
static void gimp_tool_button_constructed (GObject *object);
|
|
|
|
|
static void gimp_tool_button_dispose (GObject *object);
|
|
|
|
|
static void gimp_tool_button_set_property (GObject *object,
|
|
|
|
|
guint property_id,
|
|
|
|
|
const GValue *value,
|
|
|
|
|
GParamSpec *pspec);
|
|
|
|
|
static void gimp_tool_button_get_property (GObject *object,
|
|
|
|
|
guint property_id,
|
|
|
|
|
GValue *value,
|
|
|
|
|
GParamSpec *pspec);
|
|
|
|
|
|
|
|
|
|
static void gimp_tool_button_hierarchy_changed (GtkWidget *widget,
|
|
|
|
|
GtkWidget *previous_toplevel);
|
|
|
|
|
static gboolean gimp_tool_button_draw (GtkWidget *widget,
|
|
|
|
|
cairo_t *cr);
|
2020-06-01 06:13:10 -07:00
|
|
|
static gboolean gimp_tool_button_query_tooltip (GtkWidget *widget,
|
|
|
|
|
gint x,
|
|
|
|
|
gint y,
|
|
|
|
|
gboolean keyboard_mode,
|
|
|
|
|
GtkTooltip *tooltip);
|
2020-01-29 11:52:17 -08:00
|
|
|
|
|
|
|
|
static void gimp_tool_button_toggled (GtkToggleToolButton *toggle_tool_button);
|
|
|
|
|
|
|
|
|
|
static gboolean gimp_tool_button_button_press (GtkWidget *widget,
|
|
|
|
|
GdkEventButton *event,
|
|
|
|
|
GimpToolButton *tool_button);
|
|
|
|
|
static gboolean gimp_tool_button_button_release (GtkWidget *widget,
|
|
|
|
|
GdkEventButton *event,
|
|
|
|
|
GimpToolButton *tool_button);
|
|
|
|
|
static gboolean gimp_tool_button_scroll (GtkWidget *widget,
|
|
|
|
|
GdkEventScroll *event,
|
|
|
|
|
GimpToolButton *tool_button);
|
|
|
|
|
|
|
|
|
|
static void gimp_tool_button_tool_changed (GimpContext *context,
|
|
|
|
|
GimpToolInfo *tool_info,
|
|
|
|
|
GimpToolButton *tool_button);
|
|
|
|
|
|
|
|
|
|
static void gimp_tool_button_active_tool_changed (GimpToolGroup *tool_group,
|
|
|
|
|
GimpToolButton *tool_button);
|
|
|
|
|
|
|
|
|
|
static void gimp_tool_button_tool_add (GimpContainer *container,
|
|
|
|
|
GimpToolInfo *tool_info,
|
|
|
|
|
GimpToolButton *tool_button);
|
|
|
|
|
static void gimp_tool_button_tool_remove (GimpContainer *container,
|
|
|
|
|
GimpToolInfo *tool_info,
|
|
|
|
|
GimpToolButton *tool_button);
|
|
|
|
|
static void gimp_tool_button_tool_reorder (GimpContainer *container,
|
|
|
|
|
GimpToolInfo *tool_info,
|
|
|
|
|
gint new_index,
|
|
|
|
|
GimpToolButton *tool_button);
|
|
|
|
|
|
|
|
|
|
static void gimp_tool_button_icon_size_notify (GtkToolPalette *palette,
|
|
|
|
|
const GParamSpec *pspec,
|
|
|
|
|
GimpToolButton *tool_button);
|
|
|
|
|
|
2023-01-31 11:02:29 -08:00
|
|
|
static void gimp_tool_button_menu_item_activate (GtkMenuItem *menu_item,
|
|
|
|
|
GimpAction *action);
|
|
|
|
|
|
2020-03-25 11:05:47 -07:00
|
|
|
static gboolean gimp_tool_button_menu_leave_notify (GtkMenu *menu,
|
|
|
|
|
GdkEventCrossing *event,
|
|
|
|
|
GimpToolButton *tool_button);
|
2020-01-29 11:52:17 -08:00
|
|
|
|
|
|
|
|
static gboolean gimp_tool_button_menu_timeout (GimpToolButton *tool_button);
|
|
|
|
|
|
|
|
|
|
static void gimp_tool_button_update (GimpToolButton *tool_button);
|
|
|
|
|
static void gimp_tool_button_update_toggled (GimpToolButton *tool_button);
|
2020-03-25 11:05:47 -07:00
|
|
|
static void gimp_tool_button_update_menu (GimpToolButton *tool_button);
|
2020-01-29 11:52:17 -08:00
|
|
|
|
|
|
|
|
static void gimp_tool_button_add_menu_item (GimpToolButton *tool_button,
|
|
|
|
|
GimpToolInfo *tool_info,
|
|
|
|
|
gint index);
|
|
|
|
|
static void gimp_tool_button_remove_menu_item (GimpToolButton *tool_button,
|
|
|
|
|
GimpToolInfo *tool_info);
|
|
|
|
|
|
|
|
|
|
static void gimp_tool_button_reconstruct_menu (GimpToolButton *tool_button);
|
|
|
|
|
static void gimp_tool_button_destroy_menu (GimpToolButton *tool_button);
|
|
|
|
|
static gboolean gimp_tool_button_show_menu (GimpToolButton *tool_button,
|
|
|
|
|
const GdkEvent *trigger_event);
|
|
|
|
|
|
|
|
|
|
static GimpAction * gimp_tool_button_get_action (GimpToolButton *tool_button,
|
|
|
|
|
GimpToolInfo *tool_info);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (GimpToolButton, gimp_tool_button,
|
|
|
|
|
GTK_TYPE_TOGGLE_TOOL_BUTTON)
|
|
|
|
|
|
|
|
|
|
#define parent_class gimp_tool_button_parent_class
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* private functions */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_class_init (GimpToolButtonClass *klass)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
|
GtkToggleToolButtonClass *toggle_tool_button_class = GTK_TOGGLE_TOOL_BUTTON_CLASS (klass);
|
|
|
|
|
|
|
|
|
|
object_class->constructed = gimp_tool_button_constructed;
|
|
|
|
|
object_class->dispose = gimp_tool_button_dispose;
|
|
|
|
|
object_class->get_property = gimp_tool_button_get_property;
|
|
|
|
|
object_class->set_property = gimp_tool_button_set_property;
|
|
|
|
|
|
|
|
|
|
widget_class->hierarchy_changed = gimp_tool_button_hierarchy_changed;
|
|
|
|
|
widget_class->draw = gimp_tool_button_draw;
|
2020-06-01 06:13:10 -07:00
|
|
|
widget_class->query_tooltip = gimp_tool_button_query_tooltip;
|
2020-01-29 11:52:17 -08:00
|
|
|
|
|
|
|
|
toggle_tool_button_class->toggled = gimp_tool_button_toggled;
|
|
|
|
|
|
|
|
|
|
g_object_class_install_property (object_class, PROP_TOOLBOX,
|
|
|
|
|
g_param_spec_object ("toolbox",
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
GIMP_TYPE_TOOLBOX,
|
|
|
|
|
GIMP_PARAM_READWRITE |
|
|
|
|
|
G_PARAM_CONSTRUCT_ONLY));
|
|
|
|
|
|
|
|
|
|
g_object_class_install_property (object_class, PROP_TOOL_ITEM,
|
|
|
|
|
g_param_spec_object ("tool-item",
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
GIMP_TYPE_TOOL_ITEM,
|
2020-01-30 00:45:41 -08:00
|
|
|
GIMP_PARAM_READWRITE));
|
2020-01-29 11:52:17 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_init (GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
tool_button->priv = gimp_tool_button_get_instance_private (tool_button);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_constructed (GObject *object)
|
|
|
|
|
{
|
|
|
|
|
GimpToolButton *tool_button = GIMP_TOOL_BUTTON (object);
|
|
|
|
|
GimpContext *context;
|
|
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (parent_class)->constructed (object);
|
|
|
|
|
|
|
|
|
|
context = gimp_toolbox_get_context (tool_button->priv->toolbox);
|
|
|
|
|
|
|
|
|
|
/* Make sure the toolbox buttons won't grab focus, which has
|
|
|
|
|
* nearly no practical use, and prevents various actions until
|
|
|
|
|
* you click back in canvas.
|
|
|
|
|
*/
|
|
|
|
|
gtk_widget_set_can_focus (gtk_bin_get_child (GTK_BIN (tool_button)), FALSE);
|
|
|
|
|
|
|
|
|
|
gtk_widget_add_events (gtk_bin_get_child (GTK_BIN (tool_button)),
|
|
|
|
|
GDK_SCROLL_MASK);
|
|
|
|
|
|
|
|
|
|
g_signal_connect (gtk_bin_get_child (GTK_BIN (tool_button)),
|
|
|
|
|
"button-press-event",
|
|
|
|
|
G_CALLBACK (gimp_tool_button_button_press),
|
|
|
|
|
tool_button);
|
|
|
|
|
g_signal_connect (gtk_bin_get_child (GTK_BIN (tool_button)),
|
|
|
|
|
"button-release-event",
|
|
|
|
|
G_CALLBACK (gimp_tool_button_button_release),
|
|
|
|
|
tool_button);
|
|
|
|
|
g_signal_connect (gtk_bin_get_child (GTK_BIN (tool_button)),
|
|
|
|
|
"scroll-event",
|
|
|
|
|
G_CALLBACK (gimp_tool_button_scroll),
|
|
|
|
|
tool_button);
|
|
|
|
|
|
|
|
|
|
g_signal_connect_object (context, "tool-changed",
|
|
|
|
|
G_CALLBACK (gimp_tool_button_tool_changed),
|
|
|
|
|
tool_button,
|
|
|
|
|
0);
|
|
|
|
|
|
|
|
|
|
gimp_tool_button_update (tool_button);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_dispose (GObject *object)
|
|
|
|
|
{
|
|
|
|
|
GimpToolButton *tool_button = GIMP_TOOL_BUTTON (object);
|
|
|
|
|
|
|
|
|
|
gimp_tool_button_set_tool_item (tool_button, NULL);
|
|
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_set_property (GObject *object,
|
|
|
|
|
guint property_id,
|
|
|
|
|
const GValue *value,
|
|
|
|
|
GParamSpec *pspec)
|
|
|
|
|
{
|
|
|
|
|
GimpToolButton *tool_button = GIMP_TOOL_BUTTON (object);
|
|
|
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
|
{
|
|
|
|
|
case PROP_TOOLBOX:
|
|
|
|
|
tool_button->priv->toolbox = g_value_get_object (value);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PROP_TOOL_ITEM:
|
|
|
|
|
gimp_tool_button_set_tool_item (tool_button, g_value_get_object (value));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_get_property (GObject *object,
|
|
|
|
|
guint property_id,
|
|
|
|
|
GValue *value,
|
|
|
|
|
GParamSpec *pspec)
|
|
|
|
|
{
|
|
|
|
|
GimpToolButton *tool_button = GIMP_TOOL_BUTTON (object);
|
|
|
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
|
{
|
|
|
|
|
case PROP_TOOLBOX:
|
|
|
|
|
g_value_set_object (value, tool_button->priv->toolbox);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PROP_TOOL_ITEM:
|
|
|
|
|
g_value_set_object (value, tool_button->priv->tool_item);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_hierarchy_changed (GtkWidget *widget,
|
|
|
|
|
GtkWidget *previous_toplevel)
|
|
|
|
|
{
|
|
|
|
|
GimpToolButton *tool_button = GIMP_TOOL_BUTTON (widget);
|
|
|
|
|
GtkWidget *palette;
|
|
|
|
|
|
|
|
|
|
if (GTK_WIDGET_CLASS (parent_class)->hierarchy_changed)
|
|
|
|
|
{
|
|
|
|
|
GTK_WIDGET_CLASS (parent_class)->hierarchy_changed (widget,
|
|
|
|
|
previous_toplevel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
palette = gtk_widget_get_ancestor (GTK_WIDGET (tool_button),
|
|
|
|
|
GTK_TYPE_TOOL_PALETTE);
|
|
|
|
|
|
|
|
|
|
if (palette != tool_button->priv->palette)
|
|
|
|
|
{
|
|
|
|
|
if (tool_button->priv->palette)
|
|
|
|
|
{
|
|
|
|
|
g_signal_handlers_disconnect_by_func (
|
|
|
|
|
tool_button->priv->palette,
|
|
|
|
|
gimp_tool_button_icon_size_notify,
|
|
|
|
|
tool_button);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tool_button->priv->palette = palette;
|
|
|
|
|
|
|
|
|
|
if (tool_button->priv->palette)
|
|
|
|
|
{
|
|
|
|
|
g_signal_connect (
|
|
|
|
|
tool_button->priv->palette, "notify::icon-size",
|
|
|
|
|
G_CALLBACK (gimp_tool_button_icon_size_notify),
|
|
|
|
|
tool_button);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gimp_tool_button_update (tool_button);
|
|
|
|
|
|
|
|
|
|
gimp_tool_button_reconstruct_menu (tool_button);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
gimp_tool_button_draw (GtkWidget *widget,
|
|
|
|
|
cairo_t *cr)
|
|
|
|
|
{
|
|
|
|
|
GimpToolButton *tool_button = GIMP_TOOL_BUTTON (widget);
|
|
|
|
|
|
|
|
|
|
if (GTK_WIDGET_CLASS (parent_class)->draw)
|
|
|
|
|
GTK_WIDGET_CLASS (parent_class)->draw (widget, cr);
|
|
|
|
|
|
|
|
|
|
if (GIMP_IS_TOOL_GROUP (tool_button->priv->tool_item))
|
|
|
|
|
{
|
|
|
|
|
GtkStyleContext *style = gtk_widget_get_style_context (widget);
|
|
|
|
|
GtkStateFlags state = gtk_widget_get_state_flags (widget);
|
|
|
|
|
GdkRGBA fg;
|
|
|
|
|
GtkAllocation allocation;
|
|
|
|
|
gint size;
|
|
|
|
|
gint x1, y1;
|
|
|
|
|
gint x2, y2;
|
|
|
|
|
|
|
|
|
|
gtk_style_context_get_color (style, state, &fg);
|
|
|
|
|
|
|
|
|
|
gtk_widget_get_allocation (widget, &allocation);
|
|
|
|
|
|
|
|
|
|
size = MIN (allocation.width, allocation.height);
|
|
|
|
|
|
|
|
|
|
x1 = SIGNED_ROUND (allocation.width -
|
|
|
|
|
(ARROW_BORDER + size * ARROW_SIZE));
|
|
|
|
|
y1 = SIGNED_ROUND (allocation.height -
|
|
|
|
|
(ARROW_BORDER + size * ARROW_SIZE));
|
|
|
|
|
|
|
|
|
|
x2 = SIGNED_ROUND (allocation.width - ARROW_BORDER);
|
|
|
|
|
y2 = SIGNED_ROUND (allocation.height - ARROW_BORDER);
|
|
|
|
|
|
|
|
|
|
cairo_save (cr);
|
|
|
|
|
|
|
|
|
|
cairo_move_to (cr, x2, y1);
|
|
|
|
|
cairo_line_to (cr, x2, y2);
|
|
|
|
|
cairo_line_to (cr, x1, y2);
|
|
|
|
|
cairo_close_path (cr);
|
|
|
|
|
|
|
|
|
|
gdk_cairo_set_source_rgba (cr, &fg);
|
|
|
|
|
cairo_fill (cr);
|
|
|
|
|
|
|
|
|
|
cairo_restore (cr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-01 06:13:10 -07:00
|
|
|
static GtkWidget *
|
|
|
|
|
gimp_tool_button_query_tooltip_add_tool (GimpToolButton *tool_button,
|
|
|
|
|
GtkGrid *grid,
|
|
|
|
|
gint row,
|
|
|
|
|
GimpToolInfo *tool_info,
|
|
|
|
|
const gchar *label_str,
|
|
|
|
|
GtkIconSize icon_size)
|
|
|
|
|
{
|
2023-01-31 11:02:29 -08:00
|
|
|
Gimp *gimp;
|
|
|
|
|
GimpAction *action = NULL;
|
|
|
|
|
GtkWidget *label;
|
|
|
|
|
GtkWidget *image;
|
|
|
|
|
gchar *name;
|
2020-06-01 06:13:10 -07:00
|
|
|
|
2023-01-31 11:02:29 -08:00
|
|
|
gimp = gimp_toolbox_get_context (tool_button->priv->toolbox)->gimp;
|
|
|
|
|
name = gimp_tool_info_get_action_name (tool_info);
|
2020-06-01 06:13:10 -07:00
|
|
|
|
2023-01-31 11:02:29 -08:00
|
|
|
action = GIMP_ACTION (g_action_map_lookup_action (G_ACTION_MAP (gimp->app), name));
|
|
|
|
|
g_free (name);
|
2020-06-01 06:13:10 -07:00
|
|
|
|
|
|
|
|
image = gtk_image_new_from_icon_name (
|
|
|
|
|
gimp_viewable_get_icon_name (GIMP_VIEWABLE (tool_info)),
|
|
|
|
|
icon_size);
|
|
|
|
|
gtk_grid_attach (grid,
|
|
|
|
|
image,
|
|
|
|
|
0, row,
|
|
|
|
|
1, 1);
|
|
|
|
|
gtk_widget_show (image);
|
|
|
|
|
|
|
|
|
|
label = gtk_label_new (label_str);
|
|
|
|
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
|
|
|
|
gtk_grid_attach (grid,
|
|
|
|
|
label,
|
|
|
|
|
1, row,
|
|
|
|
|
1, 1);
|
|
|
|
|
gtk_widget_show (label);
|
|
|
|
|
|
|
|
|
|
if (action)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *accel_label;
|
|
|
|
|
|
|
|
|
|
accel_label = gimp_accel_label_new (action);
|
|
|
|
|
gtk_widget_set_margin_start (accel_label, 16);
|
|
|
|
|
gtk_label_set_xalign (GTK_LABEL (accel_label), 1.0);
|
|
|
|
|
gtk_grid_attach (grid,
|
|
|
|
|
accel_label,
|
|
|
|
|
2, row,
|
|
|
|
|
1, 1);
|
|
|
|
|
gtk_widget_show (accel_label);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return label;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
gimp_tool_button_query_tooltip (GtkWidget *widget,
|
|
|
|
|
gint x,
|
|
|
|
|
gint y,
|
|
|
|
|
gboolean keyboard_mode,
|
|
|
|
|
GtkTooltip *tooltip)
|
|
|
|
|
{
|
|
|
|
|
GimpToolButton *tool_button = GIMP_TOOL_BUTTON (widget);
|
|
|
|
|
|
|
|
|
|
if (! tool_button->priv->tooltip_widget)
|
|
|
|
|
{
|
|
|
|
|
GimpToolInfo *tool_info;
|
|
|
|
|
GtkWidget *grid;
|
|
|
|
|
GtkWidget *label;
|
|
|
|
|
gchar **tooltip_labels;
|
|
|
|
|
GtkIconSize icon_size = GTK_ICON_SIZE_MENU;
|
|
|
|
|
gint row = 0;
|
|
|
|
|
|
|
|
|
|
tool_info = gimp_tool_button_get_tool_info (tool_button);
|
|
|
|
|
|
|
|
|
|
if (! tool_info)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (tool_button->priv->palette)
|
|
|
|
|
{
|
|
|
|
|
icon_size = gtk_tool_palette_get_icon_size (
|
|
|
|
|
GTK_TOOL_PALETTE (tool_button->priv->palette));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
grid = gtk_grid_new ();
|
|
|
|
|
gtk_grid_set_column_spacing (GTK_GRID (grid), 4);
|
|
|
|
|
gtk_widget_show (grid);
|
|
|
|
|
|
|
|
|
|
tool_button->priv->tooltip_widget = g_object_ref_sink (grid);
|
|
|
|
|
|
|
|
|
|
tooltip_labels = g_strsplit (tool_info->tooltip, ": ", 2);
|
|
|
|
|
|
|
|
|
|
label = gimp_tool_button_query_tooltip_add_tool (tool_button,
|
|
|
|
|
GTK_GRID (grid),
|
|
|
|
|
row++,
|
|
|
|
|
tool_info,
|
|
|
|
|
tooltip_labels[0],
|
|
|
|
|
icon_size);
|
|
|
|
|
gimp_label_set_attributes (GTK_LABEL (label),
|
|
|
|
|
PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
|
|
|
|
|
-1);
|
|
|
|
|
|
|
|
|
|
if (tooltip_labels[0])
|
|
|
|
|
{
|
|
|
|
|
//gtk_table_set_row_spacing (GTK_TABLE (table), 0, 0);
|
|
|
|
|
|
|
|
|
|
label = gtk_label_new (tooltip_labels[1]);
|
|
|
|
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
|
|
|
|
gtk_grid_attach (GTK_GRID (grid),
|
|
|
|
|
label,
|
|
|
|
|
1, row++,
|
|
|
|
|
1, 1);
|
|
|
|
|
gtk_widget_show (label);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_strfreev (tooltip_labels);
|
|
|
|
|
|
|
|
|
|
if (GIMP_IS_TOOL_GROUP (tool_button->priv->tool_item))
|
|
|
|
|
{
|
|
|
|
|
GimpContainer *children;
|
|
|
|
|
gint n_children;
|
|
|
|
|
|
|
|
|
|
children = gimp_viewable_get_children (
|
|
|
|
|
GIMP_VIEWABLE (tool_button->priv->tool_item));
|
|
|
|
|
|
|
|
|
|
n_children = gimp_container_get_n_children (children);
|
|
|
|
|
|
|
|
|
|
if (n_children > 1)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *label;
|
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
|
|
label = gtk_label_new (_("Also in group:"));
|
|
|
|
|
gtk_widget_set_margin_top (label, 4);
|
|
|
|
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
|
|
|
|
gimp_label_set_attributes (GTK_LABEL (label),
|
|
|
|
|
PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
|
|
|
|
|
-1);
|
|
|
|
|
gtk_grid_attach (GTK_GRID (grid),
|
|
|
|
|
label,
|
|
|
|
|
0, row++,
|
|
|
|
|
3, 1);
|
|
|
|
|
gtk_widget_show (label);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < n_children; i++)
|
|
|
|
|
{
|
|
|
|
|
GimpToolInfo *other_tool_info;
|
|
|
|
|
|
|
|
|
|
other_tool_info = GIMP_TOOL_INFO (
|
|
|
|
|
gimp_container_get_child_by_index (children, i));
|
|
|
|
|
|
|
|
|
|
if (other_tool_info != tool_info)
|
|
|
|
|
{
|
|
|
|
|
gimp_tool_button_query_tooltip_add_tool (
|
|
|
|
|
tool_button,
|
|
|
|
|
GTK_GRID (grid),
|
|
|
|
|
row++,
|
|
|
|
|
other_tool_info,
|
|
|
|
|
other_tool_info->label,
|
|
|
|
|
icon_size);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gtk_tooltip_set_custom (tooltip, tool_button->priv->tooltip_widget);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-29 11:52:17 -08:00
|
|
|
static void
|
|
|
|
|
gimp_tool_button_toggled (GtkToggleToolButton *toggle_tool_button)
|
|
|
|
|
{
|
|
|
|
|
GimpToolButton *tool_button = GIMP_TOOL_BUTTON (toggle_tool_button);
|
|
|
|
|
GimpContext *context;
|
|
|
|
|
GimpToolInfo *tool_info;
|
|
|
|
|
|
|
|
|
|
if (GTK_TOGGLE_TOOL_BUTTON_CLASS (parent_class)->toggled)
|
|
|
|
|
GTK_TOGGLE_TOOL_BUTTON_CLASS (parent_class)->toggled (toggle_tool_button);
|
|
|
|
|
|
|
|
|
|
context = gimp_toolbox_get_context (tool_button->priv->toolbox);
|
|
|
|
|
tool_info = gimp_tool_button_get_tool_info (tool_button);
|
|
|
|
|
|
|
|
|
|
if (tool_info)
|
|
|
|
|
{
|
2021-07-05 03:33:35 -07:00
|
|
|
GimpDisplay *display;
|
|
|
|
|
|
2020-01-29 11:52:17 -08:00
|
|
|
if (gtk_toggle_tool_button_get_active (toggle_tool_button))
|
|
|
|
|
gimp_context_set_tool (context, tool_info);
|
|
|
|
|
else if (tool_info == gimp_context_get_tool (context))
|
|
|
|
|
gtk_toggle_tool_button_set_active (toggle_tool_button, TRUE);
|
2021-07-05 03:33:35 -07:00
|
|
|
|
|
|
|
|
/* Give focus to the main image. */
|
|
|
|
|
if ((display = gimp_context_get_display (context)) &&
|
|
|
|
|
gimp_context_get_image (context))
|
|
|
|
|
{
|
2021-07-05 06:24:12 -07:00
|
|
|
gimp_display_grab_focus (display);
|
2021-07-05 03:33:35 -07:00
|
|
|
}
|
2020-01-29 11:52:17 -08:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gtk_toggle_tool_button_set_active (toggle_tool_button, FALSE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
gimp_tool_button_button_press (GtkWidget *widget,
|
|
|
|
|
GdkEventButton *event,
|
|
|
|
|
GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
if (GIMP_IS_TOOL_GROUP (tool_button->priv->tool_item))
|
|
|
|
|
{
|
|
|
|
|
if (gdk_event_triggers_context_menu ((GdkEvent *) event) &&
|
|
|
|
|
gimp_tool_button_show_menu (tool_button, (GdkEvent *) event))
|
|
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
else if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
|
|
|
|
|
! tool_button->priv->menu_timeout_id)
|
|
|
|
|
{
|
|
|
|
|
GdkEventButton *timeout_event;
|
|
|
|
|
|
|
|
|
|
timeout_event = (GdkEventButton *) gdk_event_copy (
|
|
|
|
|
(GdkEvent *) event);
|
|
|
|
|
timeout_event->time += MENU_TIMEOUT;
|
|
|
|
|
|
|
|
|
|
tool_button->priv->menu_timeout_event = (GdkEvent *) timeout_event;
|
|
|
|
|
|
|
|
|
|
tool_button->priv->menu_timeout_id = g_timeout_add (
|
|
|
|
|
MENU_TIMEOUT,
|
|
|
|
|
(GSourceFunc) gimp_tool_button_menu_timeout,
|
|
|
|
|
tool_button);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (event->type == GDK_2BUTTON_PRESS && event->button == 1)
|
|
|
|
|
{
|
|
|
|
|
GimpContext *context;
|
|
|
|
|
GimpDock *dock;
|
|
|
|
|
|
|
|
|
|
context = gimp_toolbox_get_context (tool_button->priv->toolbox);
|
|
|
|
|
dock = GIMP_DOCK (tool_button->priv->toolbox);
|
|
|
|
|
|
|
|
|
|
gimp_window_strategy_show_dockable_dialog (
|
|
|
|
|
GIMP_WINDOW_STRATEGY (gimp_get_window_strategy (context->gimp)),
|
|
|
|
|
context->gimp,
|
|
|
|
|
gimp_dock_get_dialog_factory (dock),
|
|
|
|
|
gimp_widget_get_monitor (widget),
|
|
|
|
|
"gimp-tool-options");
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
gimp_tool_button_button_release (GtkWidget *widget,
|
|
|
|
|
GdkEventButton *event,
|
|
|
|
|
GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
if (event->button == 1 && tool_button->priv->menu_timeout_id)
|
|
|
|
|
{
|
|
|
|
|
g_source_remove (tool_button->priv->menu_timeout_id);
|
|
|
|
|
|
|
|
|
|
tool_button->priv->menu_timeout_id = 0;
|
|
|
|
|
|
|
|
|
|
g_clear_pointer (&tool_button->priv->menu_timeout_event, gdk_event_free);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
gimp_tool_button_scroll (GtkWidget *widget,
|
|
|
|
|
GdkEventScroll *event,
|
|
|
|
|
GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
GimpToolInfo *tool_info;
|
|
|
|
|
gint delta;
|
|
|
|
|
|
|
|
|
|
tool_info = gimp_tool_button_get_tool_info (tool_button);
|
|
|
|
|
|
|
|
|
|
switch (event->direction)
|
|
|
|
|
{
|
|
|
|
|
case GDK_SCROLL_UP:
|
|
|
|
|
delta = -1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GDK_SCROLL_DOWN:
|
|
|
|
|
delta = +1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tool_info && GIMP_IS_TOOL_GROUP (tool_button->priv->tool_item))
|
|
|
|
|
{
|
|
|
|
|
GimpContainer *children;
|
|
|
|
|
gint n_children;
|
|
|
|
|
gint index;
|
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
|
|
children = gimp_viewable_get_children (
|
|
|
|
|
GIMP_VIEWABLE (tool_button->priv->tool_item));
|
|
|
|
|
|
|
|
|
|
n_children = gimp_container_get_n_children (children);
|
|
|
|
|
|
|
|
|
|
index = gimp_container_get_child_index (children,
|
|
|
|
|
GIMP_OBJECT (tool_info));
|
|
|
|
|
|
|
|
|
|
for (i = 1; i < n_children; i++)
|
|
|
|
|
{
|
|
|
|
|
GimpToolInfo *new_tool_info;
|
|
|
|
|
gint new_index;
|
|
|
|
|
|
|
|
|
|
new_index = (index + i * delta) % n_children;
|
|
|
|
|
if (new_index < 0) new_index += n_children;
|
|
|
|
|
|
|
|
|
|
new_tool_info = GIMP_TOOL_INFO (
|
|
|
|
|
gimp_container_get_child_by_index (children, new_index));
|
|
|
|
|
|
|
|
|
|
if (gimp_tool_item_get_visible (GIMP_TOOL_ITEM (new_tool_info)))
|
|
|
|
|
{
|
|
|
|
|
gimp_tool_group_set_active_tool_info (
|
|
|
|
|
GIMP_TOOL_GROUP (tool_button->priv->tool_item), new_tool_info);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_tool_changed (GimpContext *context,
|
|
|
|
|
GimpToolInfo *tool_info,
|
|
|
|
|
GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
gimp_tool_button_update_toggled (tool_button);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_active_tool_changed (GimpToolGroup *tool_group,
|
|
|
|
|
GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
gimp_tool_button_update (tool_button);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_tool_add (GimpContainer *container,
|
|
|
|
|
GimpToolInfo *tool_info,
|
|
|
|
|
GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
gint index;
|
|
|
|
|
|
|
|
|
|
index = gimp_container_get_child_index (container, GIMP_OBJECT (tool_info));
|
|
|
|
|
|
|
|
|
|
gimp_tool_button_add_menu_item (tool_button, tool_info, index);
|
2020-06-01 06:13:10 -07:00
|
|
|
|
|
|
|
|
gimp_tool_button_update (tool_button);
|
2020-01-29 11:52:17 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_tool_remove (GimpContainer *container,
|
|
|
|
|
GimpToolInfo *tool_info,
|
|
|
|
|
GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
gimp_tool_button_remove_menu_item (tool_button, tool_info);
|
2020-06-01 06:13:10 -07:00
|
|
|
|
|
|
|
|
gimp_tool_button_update (tool_button);
|
2020-01-29 11:52:17 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_tool_reorder (GimpContainer *container,
|
|
|
|
|
GimpToolInfo *tool_info,
|
|
|
|
|
gint new_index,
|
|
|
|
|
GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
gimp_tool_button_remove_menu_item (tool_button, tool_info);
|
|
|
|
|
gimp_tool_button_add_menu_item (tool_button, tool_info, new_index);
|
2020-06-01 06:13:10 -07:00
|
|
|
|
|
|
|
|
gimp_tool_button_update (tool_button);
|
2020-01-29 11:52:17 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_icon_size_notify (GtkToolPalette *palette,
|
|
|
|
|
const GParamSpec *pspec,
|
|
|
|
|
GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
gimp_tool_button_reconstruct_menu (tool_button);
|
2020-06-01 06:13:10 -07:00
|
|
|
|
|
|
|
|
gimp_tool_button_update (tool_button);
|
2020-01-29 11:52:17 -08:00
|
|
|
}
|
|
|
|
|
|
2023-01-31 11:02:29 -08:00
|
|
|
static void
|
|
|
|
|
gimp_tool_button_menu_item_activate (GtkMenuItem *menu_item,
|
|
|
|
|
GimpAction *action)
|
|
|
|
|
{
|
|
|
|
|
gimp_action_activate (action);
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 11:05:47 -07:00
|
|
|
static gboolean
|
|
|
|
|
gimp_tool_button_menu_leave_notify (GtkMenu *menu,
|
|
|
|
|
GdkEventCrossing *event,
|
|
|
|
|
GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
if (event->mode == GDK_CROSSING_NORMAL &&
|
|
|
|
|
gtk_widget_get_visible (tool_button->priv->menu))
|
|
|
|
|
{
|
|
|
|
|
gimp_tool_button_update_menu (tool_button);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-29 11:52:17 -08:00
|
|
|
static gboolean
|
|
|
|
|
gimp_tool_button_menu_timeout (GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
GdkEvent *event = tool_button->priv->menu_timeout_event;
|
|
|
|
|
|
|
|
|
|
tool_button->priv->menu_timeout_id = 0;
|
|
|
|
|
tool_button->priv->menu_timeout_event = NULL;
|
|
|
|
|
|
|
|
|
|
gimp_tool_button_show_menu (tool_button, event);
|
|
|
|
|
|
|
|
|
|
gdk_event_free (event);
|
|
|
|
|
|
|
|
|
|
/* work around gtk not properly redrawing the button in the toggled state */
|
|
|
|
|
if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (tool_button)))
|
|
|
|
|
{
|
|
|
|
|
gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (tool_button),
|
|
|
|
|
FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_update (GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
GimpToolInfo *tool_info;
|
|
|
|
|
|
|
|
|
|
tool_info = gimp_tool_button_get_tool_info (tool_button);
|
|
|
|
|
|
|
|
|
|
gtk_tool_button_set_icon_name (
|
|
|
|
|
GTK_TOOL_BUTTON (tool_button),
|
|
|
|
|
tool_info ? gimp_viewable_get_icon_name (GIMP_VIEWABLE (tool_info)) :
|
|
|
|
|
NULL);
|
|
|
|
|
|
2020-06-01 06:13:10 -07:00
|
|
|
g_clear_object (&tool_button->priv->tooltip_widget);
|
|
|
|
|
|
|
|
|
|
if (tool_info)
|
2020-01-29 11:52:17 -08:00
|
|
|
{
|
|
|
|
|
gimp_help_set_help_data (GTK_WIDGET (tool_button),
|
|
|
|
|
tool_info->tooltip, tool_info->help_id);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gimp_help_set_help_data (GTK_WIDGET (tool_button), NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
app, tools: allow creating demo "scenarios" from the AppStream metadata.
The idea is to add some "demo" attribute to a list item inside the
<release> tag, since we already decided that (for now at least) we'd
keep a strict "intro + list" logics, as we did until now.
This demo attribute uses an internal format to specify successive
widgets to blink (like a demo path towards a feature). For now, what it
allows is:
* raise the toolbox, select a tool and blink the tool button.
* raise a dockable, blink any widgets in there.
Now it is still limited and needs to evolve. In particular:
* What happens if the blinked tool button was explicitly removed from
Preferences? Should we re-add it for the demo? And once done, should
we remove it again? Then should we select back the tool previously
selected?
* What happens if the dockable widget is not visible? Should we allow
changing the settings to be able to demo correctly the new/changed
settings? Should it be temporary? If temporary, it can be annoying as
you'd still have to look attentively the demo to find back the path to
the new settings. If not temporary, some people may dislike we touch
their settings.
* What if docks are hidden? Should we unhide them, then hide them back
after demo time?
Also regarding the implementation: originally I wanted to just grab the
demo attribute directly from the AppStream metadata file, but I realized
that appstream-glib cleans out unknown attribute from the XML. I could
then simply parse the file with a generic XML parser, but I found
simpler to pre-parse it into a header built within GIMP. I still use
appstream-glib at runtime as it takes care of localization for us
(though in the same time, we also have the localization in the main po
files, so maybe we could just embed the release note strings as well).
See appstream-glib report: https://github.com/hughsie/appstream-glib/issues/431
2022-03-05 14:06:46 -08:00
|
|
|
if (tool_info)
|
|
|
|
|
{
|
2022-03-29 08:04:32 -07:00
|
|
|
const gchar *tool_name = gimp_object_get_name (tool_info);
|
|
|
|
|
gchar *identifier;
|
app, tools: allow creating demo "scenarios" from the AppStream metadata.
The idea is to add some "demo" attribute to a list item inside the
<release> tag, since we already decided that (for now at least) we'd
keep a strict "intro + list" logics, as we did until now.
This demo attribute uses an internal format to specify successive
widgets to blink (like a demo path towards a feature). For now, what it
allows is:
* raise the toolbox, select a tool and blink the tool button.
* raise a dockable, blink any widgets in there.
Now it is still limited and needs to evolve. In particular:
* What happens if the blinked tool button was explicitly removed from
Preferences? Should we re-add it for the demo? And once done, should
we remove it again? Then should we select back the tool previously
selected?
* What happens if the dockable widget is not visible? Should we allow
changing the settings to be able to demo correctly the new/changed
settings? Should it be temporary? If temporary, it can be annoying as
you'd still have to look attentively the demo to find back the path to
the new settings. If not temporary, some people may dislike we touch
their settings.
* What if docks are hidden? Should we unhide them, then hide them back
after demo time?
Also regarding the implementation: originally I wanted to just grab the
demo attribute directly from the AppStream metadata file, but I realized
that appstream-glib cleans out unknown attribute from the XML. I could
then simply parse the file with a generic XML parser, but I found
simpler to pre-parse it into a header built within GIMP. I still use
appstream-glib at runtime as it takes care of localization for us
(though in the same time, we also have the localization in the main po
files, so maybe we could just embed the release note strings as well).
See appstream-glib report: https://github.com/hughsie/appstream-glib/issues/431
2022-03-05 14:06:46 -08:00
|
|
|
|
2022-03-29 08:04:32 -07:00
|
|
|
if (g_str_has_prefix (tool_name, "gimp-") &&
|
|
|
|
|
g_str_has_suffix (tool_name, "-tool"))
|
app, tools: allow creating demo "scenarios" from the AppStream metadata.
The idea is to add some "demo" attribute to a list item inside the
<release> tag, since we already decided that (for now at least) we'd
keep a strict "intro + list" logics, as we did until now.
This demo attribute uses an internal format to specify successive
widgets to blink (like a demo path towards a feature). For now, what it
allows is:
* raise the toolbox, select a tool and blink the tool button.
* raise a dockable, blink any widgets in there.
Now it is still limited and needs to evolve. In particular:
* What happens if the blinked tool button was explicitly removed from
Preferences? Should we re-add it for the demo? And once done, should
we remove it again? Then should we select back the tool previously
selected?
* What happens if the dockable widget is not visible? Should we allow
changing the settings to be able to demo correctly the new/changed
settings? Should it be temporary? If temporary, it can be annoying as
you'd still have to look attentively the demo to find back the path to
the new settings. If not temporary, some people may dislike we touch
their settings.
* What if docks are hidden? Should we unhide them, then hide them back
after demo time?
Also regarding the implementation: originally I wanted to just grab the
demo attribute directly from the AppStream metadata file, but I realized
that appstream-glib cleans out unknown attribute from the XML. I could
then simply parse the file with a generic XML parser, but I found
simpler to pre-parse it into a header built within GIMP. I still use
appstream-glib at runtime as it takes care of localization for us
(though in the same time, we also have the localization in the main po
files, so maybe we could just embed the release note strings as well).
See appstream-glib report: https://github.com/hughsie/appstream-glib/issues/431
2022-03-05 14:06:46 -08:00
|
|
|
{
|
|
|
|
|
/* The GimpToolInfo names are of the form "gimp-pencil-tool",
|
|
|
|
|
* and action names are of the form "tools-pencil".
|
|
|
|
|
* To simplify things, I make the tool button identifiers the
|
|
|
|
|
* same as the actions, which make them easier to find.
|
|
|
|
|
*/
|
|
|
|
|
gchar *suffix;
|
|
|
|
|
|
2022-03-29 08:04:32 -07:00
|
|
|
identifier = g_strdup_printf ("tools-%s", tool_name + 5);
|
|
|
|
|
suffix = g_strrstr (identifier, "-tool");
|
app, tools: allow creating demo "scenarios" from the AppStream metadata.
The idea is to add some "demo" attribute to a list item inside the
<release> tag, since we already decided that (for now at least) we'd
keep a strict "intro + list" logics, as we did until now.
This demo attribute uses an internal format to specify successive
widgets to blink (like a demo path towards a feature). For now, what it
allows is:
* raise the toolbox, select a tool and blink the tool button.
* raise a dockable, blink any widgets in there.
Now it is still limited and needs to evolve. In particular:
* What happens if the blinked tool button was explicitly removed from
Preferences? Should we re-add it for the demo? And once done, should
we remove it again? Then should we select back the tool previously
selected?
* What happens if the dockable widget is not visible? Should we allow
changing the settings to be able to demo correctly the new/changed
settings? Should it be temporary? If temporary, it can be annoying as
you'd still have to look attentively the demo to find back the path to
the new settings. If not temporary, some people may dislike we touch
their settings.
* What if docks are hidden? Should we unhide them, then hide them back
after demo time?
Also regarding the implementation: originally I wanted to just grab the
demo attribute directly from the AppStream metadata file, but I realized
that appstream-glib cleans out unknown attribute from the XML. I could
then simply parse the file with a generic XML parser, but I found
simpler to pre-parse it into a header built within GIMP. I still use
appstream-glib at runtime as it takes care of localization for us
(though in the same time, we also have the localization in the main po
files, so maybe we could just embed the release note strings as well).
See appstream-glib report: https://github.com/hughsie/appstream-glib/issues/431
2022-03-05 14:06:46 -08:00
|
|
|
suffix[0] = '\0';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-03-29 08:04:32 -07:00
|
|
|
identifier = g_strdup (tool_name);
|
app, tools: allow creating demo "scenarios" from the AppStream metadata.
The idea is to add some "demo" attribute to a list item inside the
<release> tag, since we already decided that (for now at least) we'd
keep a strict "intro + list" logics, as we did until now.
This demo attribute uses an internal format to specify successive
widgets to blink (like a demo path towards a feature). For now, what it
allows is:
* raise the toolbox, select a tool and blink the tool button.
* raise a dockable, blink any widgets in there.
Now it is still limited and needs to evolve. In particular:
* What happens if the blinked tool button was explicitly removed from
Preferences? Should we re-add it for the demo? And once done, should
we remove it again? Then should we select back the tool previously
selected?
* What happens if the dockable widget is not visible? Should we allow
changing the settings to be able to demo correctly the new/changed
settings? Should it be temporary? If temporary, it can be annoying as
you'd still have to look attentively the demo to find back the path to
the new settings. If not temporary, some people may dislike we touch
their settings.
* What if docks are hidden? Should we unhide them, then hide them back
after demo time?
Also regarding the implementation: originally I wanted to just grab the
demo attribute directly from the AppStream metadata file, but I realized
that appstream-glib cleans out unknown attribute from the XML. I could
then simply parse the file with a generic XML parser, but I found
simpler to pre-parse it into a header built within GIMP. I still use
appstream-glib at runtime as it takes care of localization for us
(though in the same time, we also have the localization in the main po
files, so maybe we could just embed the release note strings as well).
See appstream-glib report: https://github.com/hughsie/appstream-glib/issues/431
2022-03-05 14:06:46 -08:00
|
|
|
}
|
|
|
|
|
|
2022-03-29 08:04:32 -07:00
|
|
|
gimp_widget_set_identifier (GTK_WIDGET (tool_button), identifier);
|
|
|
|
|
g_free (identifier);
|
app, tools: allow creating demo "scenarios" from the AppStream metadata.
The idea is to add some "demo" attribute to a list item inside the
<release> tag, since we already decided that (for now at least) we'd
keep a strict "intro + list" logics, as we did until now.
This demo attribute uses an internal format to specify successive
widgets to blink (like a demo path towards a feature). For now, what it
allows is:
* raise the toolbox, select a tool and blink the tool button.
* raise a dockable, blink any widgets in there.
Now it is still limited and needs to evolve. In particular:
* What happens if the blinked tool button was explicitly removed from
Preferences? Should we re-add it for the demo? And once done, should
we remove it again? Then should we select back the tool previously
selected?
* What happens if the dockable widget is not visible? Should we allow
changing the settings to be able to demo correctly the new/changed
settings? Should it be temporary? If temporary, it can be annoying as
you'd still have to look attentively the demo to find back the path to
the new settings. If not temporary, some people may dislike we touch
their settings.
* What if docks are hidden? Should we unhide them, then hide them back
after demo time?
Also regarding the implementation: originally I wanted to just grab the
demo attribute directly from the AppStream metadata file, but I realized
that appstream-glib cleans out unknown attribute from the XML. I could
then simply parse the file with a generic XML parser, but I found
simpler to pre-parse it into a header built within GIMP. I still use
appstream-glib at runtime as it takes care of localization for us
(though in the same time, we also have the localization in the main po
files, so maybe we could just embed the release note strings as well).
See appstream-glib report: https://github.com/hughsie/appstream-glib/issues/431
2022-03-05 14:06:46 -08:00
|
|
|
}
|
|
|
|
|
|
2020-01-29 11:52:17 -08:00
|
|
|
gimp_tool_button_update_toggled (tool_button);
|
2020-03-25 11:05:47 -07:00
|
|
|
gimp_tool_button_update_menu (tool_button);
|
2020-01-29 11:52:17 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_update_toggled (GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
GimpContext *context;
|
|
|
|
|
GimpToolInfo *tool_info;
|
|
|
|
|
|
|
|
|
|
context = gimp_toolbox_get_context (tool_button->priv->toolbox);
|
|
|
|
|
|
|
|
|
|
tool_info = gimp_tool_button_get_tool_info (tool_button);
|
|
|
|
|
|
|
|
|
|
gtk_toggle_tool_button_set_active (
|
|
|
|
|
GTK_TOGGLE_TOOL_BUTTON (tool_button),
|
|
|
|
|
tool_info && tool_info == gimp_context_get_tool (context));
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 11:05:47 -07:00
|
|
|
static void
|
|
|
|
|
gimp_tool_button_update_menu (GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
if (tool_button->priv->menu &&
|
|
|
|
|
gtk_widget_get_visible (tool_button->priv->menu))
|
|
|
|
|
{
|
|
|
|
|
GimpToolInfo *tool_info = gimp_tool_button_get_tool_info (tool_button);
|
|
|
|
|
|
|
|
|
|
if (tool_info)
|
|
|
|
|
{
|
|
|
|
|
gtk_menu_shell_select_item (
|
|
|
|
|
GTK_MENU_SHELL (tool_button->priv->menu),
|
|
|
|
|
g_hash_table_lookup (tool_button->priv->menu_items, tool_info));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-29 11:52:17 -08:00
|
|
|
static void
|
|
|
|
|
gimp_tool_button_add_menu_item (GimpToolButton *tool_button,
|
|
|
|
|
GimpToolInfo *tool_info,
|
|
|
|
|
gint index)
|
|
|
|
|
{
|
2023-01-31 11:02:29 -08:00
|
|
|
GimpAction *action;
|
|
|
|
|
GtkWidget *item;
|
|
|
|
|
GtkWidget *hbox;
|
|
|
|
|
GtkWidget *image;
|
|
|
|
|
GtkWidget *label;
|
|
|
|
|
GtkIconSize icon_size = GTK_ICON_SIZE_MENU;
|
2020-01-29 11:52:17 -08:00
|
|
|
|
|
|
|
|
action = gimp_tool_button_get_action (tool_button, tool_info);
|
|
|
|
|
|
|
|
|
|
if (tool_button->priv->palette)
|
|
|
|
|
{
|
|
|
|
|
icon_size = gtk_tool_palette_get_icon_size (
|
|
|
|
|
GTK_TOOL_PALETTE (tool_button->priv->palette));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
item = gtk_menu_item_new ();
|
|
|
|
|
gtk_menu_shell_insert (GTK_MENU_SHELL (tool_button->priv->menu), item, index);
|
2023-01-31 11:02:29 -08:00
|
|
|
g_signal_connect (item, "activate",
|
|
|
|
|
G_CALLBACK (gimp_tool_button_menu_item_activate),
|
|
|
|
|
action);
|
2020-01-29 11:52:17 -08:00
|
|
|
gimp_help_set_help_data (item, tool_info->tooltip, tool_info->help_id);
|
|
|
|
|
|
|
|
|
|
g_object_bind_property (tool_info, "visible",
|
|
|
|
|
item, "visible",
|
|
|
|
|
G_BINDING_SYNC_CREATE);
|
|
|
|
|
|
|
|
|
|
g_object_set_data (G_OBJECT (item), "gimp-tool-info", tool_info);
|
|
|
|
|
|
|
|
|
|
gimp_gtk_container_clear (GTK_CONTAINER (item));
|
|
|
|
|
|
|
|
|
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (item), hbox);
|
|
|
|
|
gtk_widget_show (hbox);
|
|
|
|
|
|
|
|
|
|
image = gtk_image_new_from_icon_name (
|
|
|
|
|
gimp_viewable_get_icon_name (GIMP_VIEWABLE (tool_info)),
|
|
|
|
|
icon_size);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (image);
|
|
|
|
|
|
|
|
|
|
label = gtk_accel_label_new (tool_info->label);
|
|
|
|
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (label);
|
|
|
|
|
|
|
|
|
|
if (action)
|
|
|
|
|
{
|
2023-01-31 11:02:29 -08:00
|
|
|
label = gimp_accel_label_new (action);
|
|
|
|
|
gtk_label_set_xalign (GTK_LABEL (label), 1.0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (label);
|
|
|
|
|
|
|
|
|
|
/* TODO: while porting to GAction, this part seems useless, as the toolbox
|
|
|
|
|
* is perfectly working. But maybe I'm missing something. So leaving this
|
|
|
|
|
* here for further investigation.
|
|
|
|
|
* We probably want to check what gimp_ui_manager_connect_proxy() does
|
|
|
|
|
* exactly.
|
|
|
|
|
*/
|
|
|
|
|
#if 0
|
2020-01-29 11:52:17 -08:00
|
|
|
if (ui_manager)
|
|
|
|
|
{
|
|
|
|
|
g_signal_emit_by_name (ui_manager, "connect-proxy",
|
|
|
|
|
action, item);
|
|
|
|
|
}
|
2023-01-31 11:02:29 -08:00
|
|
|
#endif
|
2020-01-29 11:52:17 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_hash_table_insert (tool_button->priv->menu_items, tool_info, item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_remove_menu_item (GimpToolButton *tool_button,
|
|
|
|
|
GimpToolInfo *tool_info)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *item;
|
|
|
|
|
|
|
|
|
|
item = g_hash_table_lookup (tool_button->priv->menu_items, tool_info);
|
|
|
|
|
|
|
|
|
|
gtk_container_remove (GTK_CONTAINER (tool_button->priv->menu), item);
|
|
|
|
|
|
|
|
|
|
g_hash_table_remove (tool_button->priv->menu_items, tool_info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_reconstruct_menu_add_menu_item (GimpToolInfo *tool_info,
|
|
|
|
|
GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
gimp_tool_button_add_menu_item (tool_button, tool_info, -1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_reconstruct_menu (GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
gimp_tool_button_destroy_menu (tool_button);
|
|
|
|
|
|
|
|
|
|
if (GIMP_IS_TOOL_GROUP (tool_button->priv->tool_item))
|
|
|
|
|
{
|
|
|
|
|
GimpContainer *children;
|
|
|
|
|
|
|
|
|
|
children = gimp_viewable_get_children (
|
|
|
|
|
GIMP_VIEWABLE (tool_button->priv->tool_item));
|
|
|
|
|
|
|
|
|
|
tool_button->priv->menu = gtk_menu_new ();
|
|
|
|
|
gtk_menu_attach_to_widget (GTK_MENU (tool_button->priv->menu),
|
|
|
|
|
GTK_WIDGET (tool_button), NULL);
|
|
|
|
|
|
2020-03-25 11:05:47 -07:00
|
|
|
g_signal_connect (tool_button->priv->menu, "leave-notify-event",
|
|
|
|
|
G_CALLBACK (gimp_tool_button_menu_leave_notify),
|
|
|
|
|
tool_button);
|
2020-01-29 11:52:17 -08:00
|
|
|
|
|
|
|
|
tool_button->priv->menu_items = g_hash_table_new (g_direct_hash,
|
|
|
|
|
g_direct_equal);
|
|
|
|
|
|
|
|
|
|
gimp_container_foreach (
|
|
|
|
|
children,
|
|
|
|
|
(GFunc) gimp_tool_button_reconstruct_menu_add_menu_item,
|
|
|
|
|
tool_button);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gimp_tool_button_destroy_menu (GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
if (tool_button->priv->menu)
|
|
|
|
|
{
|
|
|
|
|
gtk_menu_detach (GTK_MENU (tool_button->priv->menu));
|
|
|
|
|
tool_button->priv->menu = NULL;
|
|
|
|
|
|
|
|
|
|
g_clear_pointer (&tool_button->priv->menu_items, g_hash_table_unref);
|
|
|
|
|
|
|
|
|
|
if (tool_button->priv->menu_timeout_id)
|
|
|
|
|
{
|
|
|
|
|
g_source_remove (tool_button->priv->menu_timeout_id);
|
|
|
|
|
|
|
|
|
|
tool_button->priv->menu_timeout_id = 0;
|
|
|
|
|
|
|
|
|
|
g_clear_pointer (&tool_button->priv->menu_timeout_event,
|
|
|
|
|
gdk_event_free);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
gimp_tool_button_show_menu (GimpToolButton *tool_button,
|
|
|
|
|
const GdkEvent *trigger_event)
|
|
|
|
|
{
|
|
|
|
|
if (! tool_button->priv->menu)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
gtk_menu_popup_at_widget (
|
|
|
|
|
GTK_MENU (tool_button->priv->menu),
|
|
|
|
|
GTK_WIDGET (tool_button),
|
|
|
|
|
GDK_GRAVITY_NORTH_EAST,
|
|
|
|
|
GDK_GRAVITY_NORTH_WEST,
|
|
|
|
|
trigger_event);
|
|
|
|
|
|
2020-03-25 11:05:47 -07:00
|
|
|
gimp_tool_button_update_menu (tool_button);
|
|
|
|
|
|
2020-01-29 11:52:17 -08:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GimpAction *
|
|
|
|
|
gimp_tool_button_get_action (GimpToolButton *tool_button,
|
|
|
|
|
GimpToolInfo *tool_info)
|
|
|
|
|
{
|
2023-01-31 11:02:29 -08:00
|
|
|
GimpAction *action = NULL;
|
2020-01-29 11:52:17 -08:00
|
|
|
|
2023-01-31 11:02:29 -08:00
|
|
|
if (tool_info)
|
2020-01-29 11:52:17 -08:00
|
|
|
{
|
2023-01-31 11:02:29 -08:00
|
|
|
GimpContext *context;
|
|
|
|
|
Gimp *gimp;
|
|
|
|
|
gchar *name;
|
2020-01-29 11:52:17 -08:00
|
|
|
|
2023-01-31 11:02:29 -08:00
|
|
|
context = gimp_toolbox_get_context (tool_button->priv->toolbox);
|
|
|
|
|
gimp = context->gimp;
|
|
|
|
|
name = gimp_tool_info_get_action_name (tool_info);
|
2020-01-29 11:52:17 -08:00
|
|
|
|
2023-01-31 11:02:29 -08:00
|
|
|
action = GIMP_ACTION (g_action_map_lookup_action (G_ACTION_MAP (gimp->app), name));
|
2020-01-29 11:52:17 -08:00
|
|
|
|
|
|
|
|
g_free (name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return action;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* public functions */
|
|
|
|
|
|
|
|
|
|
GtkToolItem *
|
|
|
|
|
gimp_tool_button_new (GimpToolbox *toolbox,
|
|
|
|
|
GimpToolItem *tool_item)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_TOOLBOX (toolbox), NULL);
|
|
|
|
|
g_return_val_if_fail (tool_item == NULL ||
|
|
|
|
|
GIMP_IS_TOOL_ITEM (tool_item), NULL);
|
|
|
|
|
|
|
|
|
|
return g_object_new (GIMP_TYPE_TOOL_BUTTON,
|
|
|
|
|
"toolbox", toolbox,
|
|
|
|
|
"tool-item", tool_item,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GimpToolbox *
|
|
|
|
|
gimp_tool_button_get_toolbox (GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_TOOL_BUTTON (tool_button), NULL);
|
|
|
|
|
|
|
|
|
|
return tool_button->priv->toolbox;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gimp_tool_button_set_tool_item (GimpToolButton *tool_button,
|
|
|
|
|
GimpToolItem *tool_item)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (GIMP_IS_TOOL_BUTTON (tool_button));
|
|
|
|
|
g_return_if_fail (tool_item == NULL || GIMP_IS_TOOL_ITEM (tool_item));
|
|
|
|
|
|
|
|
|
|
if (tool_item != tool_button->priv->tool_item)
|
|
|
|
|
{
|
|
|
|
|
if (GIMP_IS_TOOL_GROUP (tool_button->priv->tool_item))
|
|
|
|
|
{
|
|
|
|
|
GimpContainer *children;
|
|
|
|
|
|
|
|
|
|
children = gimp_viewable_get_children (
|
|
|
|
|
GIMP_VIEWABLE (tool_button->priv->tool_item));
|
|
|
|
|
|
|
|
|
|
g_signal_handlers_disconnect_by_func (
|
|
|
|
|
tool_button->priv->tool_item,
|
|
|
|
|
gimp_tool_button_active_tool_changed,
|
|
|
|
|
tool_button);
|
|
|
|
|
|
|
|
|
|
g_signal_handlers_disconnect_by_func (
|
|
|
|
|
children,
|
|
|
|
|
gimp_tool_button_tool_add,
|
|
|
|
|
tool_button);
|
|
|
|
|
g_signal_handlers_disconnect_by_func (
|
|
|
|
|
children,
|
|
|
|
|
gimp_tool_button_tool_remove,
|
|
|
|
|
tool_button);
|
|
|
|
|
g_signal_handlers_disconnect_by_func (
|
|
|
|
|
children,
|
|
|
|
|
gimp_tool_button_tool_reorder,
|
|
|
|
|
tool_button);
|
|
|
|
|
|
|
|
|
|
gimp_tool_button_destroy_menu (tool_button);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_set_object (&tool_button->priv->tool_item, tool_item);
|
|
|
|
|
|
|
|
|
|
if (GIMP_IS_TOOL_GROUP (tool_button->priv->tool_item))
|
|
|
|
|
{
|
|
|
|
|
GimpContainer *children;
|
|
|
|
|
|
|
|
|
|
children = gimp_viewable_get_children (
|
|
|
|
|
GIMP_VIEWABLE (tool_button->priv->tool_item));
|
|
|
|
|
|
|
|
|
|
g_signal_connect (
|
|
|
|
|
tool_button->priv->tool_item, "active-tool-changed",
|
|
|
|
|
G_CALLBACK (gimp_tool_button_active_tool_changed),
|
|
|
|
|
tool_button);
|
|
|
|
|
|
|
|
|
|
g_signal_connect (
|
|
|
|
|
children, "add",
|
|
|
|
|
G_CALLBACK (gimp_tool_button_tool_add),
|
|
|
|
|
tool_button);
|
|
|
|
|
g_signal_connect (
|
|
|
|
|
children, "remove",
|
|
|
|
|
G_CALLBACK (gimp_tool_button_tool_remove),
|
|
|
|
|
tool_button);
|
|
|
|
|
g_signal_connect (
|
|
|
|
|
children, "reorder",
|
|
|
|
|
G_CALLBACK (gimp_tool_button_tool_reorder),
|
|
|
|
|
tool_button);
|
|
|
|
|
|
|
|
|
|
gimp_tool_button_reconstruct_menu (tool_button);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gimp_tool_button_update (tool_button);
|
|
|
|
|
|
|
|
|
|
g_object_notify (G_OBJECT (tool_button), "tool-item");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GimpToolItem *
|
|
|
|
|
gimp_tool_button_get_tool_item (GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_TOOL_BUTTON (tool_button), NULL);
|
|
|
|
|
|
|
|
|
|
return tool_button->priv->tool_item;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GimpToolInfo *
|
|
|
|
|
gimp_tool_button_get_tool_info (GimpToolButton *tool_button)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_TOOL_BUTTON (tool_button), NULL);
|
|
|
|
|
|
|
|
|
|
if (tool_button->priv->tool_item)
|
|
|
|
|
{
|
|
|
|
|
if (GIMP_IS_TOOL_INFO (tool_button->priv->tool_item))
|
|
|
|
|
{
|
|
|
|
|
return GIMP_TOOL_INFO (tool_button->priv->tool_item);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return gimp_tool_group_get_active_tool_info (
|
|
|
|
|
GIMP_TOOL_GROUP (tool_button->priv->tool_item));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|