From 160b17c8a8c29fcde27f713369e6c555275014ae Mon Sep 17 00:00:00 2001 From: Ell Date: Wed, 29 Jan 2020 19:55:49 +0200 Subject: [PATCH] app: add GimpToolGroup as a subclass of GimpToolItem Add GimpToolGroup as a new subclass of GimpToolItem, representing a collection of tools. The end goal is to display tool groups using a single button in the toolbox. Tool groups are not recursive: they can only contain individual tools, not other groups. Each group has a single "active tool", normally the most-recently-used tool of the group, which is activated when clicking on the tool's button. --- app/core/Makefile.am | 2 + app/core/core-types.h | 1 + app/core/gimptoolgroup.c | 385 +++++++++++++++++++++++++++++++++++++++ app/core/gimptoolgroup.h | 68 +++++++ po/POTFILES.in | 1 + 5 files changed, 457 insertions(+) create mode 100644 app/core/gimptoolgroup.c create mode 100644 app/core/gimptoolgroup.h diff --git a/app/core/Makefile.am b/app/core/Makefile.am index be8c571650..bda67d0837 100644 --- a/app/core/Makefile.am +++ b/app/core/Makefile.am @@ -457,6 +457,8 @@ libappcore_a_sources = \ gimptemplate.h \ gimptilehandlerprojectable.c \ gimptilehandlerprojectable.h \ + gimptoolgroup.c \ + gimptoolgroup.h \ gimptoolinfo.c \ gimptoolinfo.h \ gimptoolitem.c \ diff --git a/app/core/core-types.h b/app/core/core-types.h index c0de544643..40d4e3a560 100644 --- a/app/core/core-types.h +++ b/app/core/core-types.h @@ -119,6 +119,7 @@ typedef struct _GimpToolOptions GimpToolOptions; /* info objects */ typedef struct _GimpPaintInfo GimpPaintInfo; +typedef struct _GimpToolGroup GimpToolGroup; typedef struct _GimpToolInfo GimpToolInfo; typedef struct _GimpToolItem GimpToolItem; diff --git a/app/core/gimptoolgroup.c b/app/core/gimptoolgroup.c new file mode 100644 index 0000000000..b9a412ee68 --- /dev/null +++ b/app/core/gimptoolgroup.c @@ -0,0 +1,385 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimptoolgroup.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 . + */ + +#include "config.h" + +#include + +#include +#include + +#include "libgimpbase/gimpbase.h" +#include "libgimpconfig/gimpconfig.h" + +#include "core-types.h" + +#include "gimplist.h" +#include "gimpmarshal.h" +#include "gimptoolgroup.h" +#include "gimptoolinfo.h" + +#include "gimp-intl.h" + + +enum +{ + ACTIVE_TOOL_CHANGED, + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_ACTIVE_TOOL, + PROP_CHILDREN +}; + + +struct _GimpToolGroupPrivate +{ + gchar *active_tool; + GimpContainer *children; +}; + + +/* local function prototypes */ + + +static void gimp_tool_group_finalize (GObject *object); +static void gimp_tool_group_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_tool_group_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static gint64 gimp_tool_group_get_memsize (GimpObject *object, + gint64 *gui_size); + +static gchar * gimp_tool_group_get_description (GimpViewable *viewable, + gchar **tooltip); +static GimpContainer * gimp_tool_group_get_children (GimpViewable *viewable); +static void gimp_tool_group_set_expanded (GimpViewable *viewable, + gboolean expand); +static gboolean gimp_tool_group_get_expanded (GimpViewable *viewable); + +static void gimp_tool_group_child_add (GimpContainer *container, + GimpToolInfo *tool_info, + GimpToolGroup *tool_group); +static void gimp_tool_group_child_remove (GimpContainer *container, + GimpToolInfo *tool_info, + GimpToolGroup *tool_group); + + +G_DEFINE_TYPE_WITH_PRIVATE (GimpToolGroup, gimp_tool_group, GIMP_TYPE_TOOL_ITEM) + +#define parent_class gimp_tool_group_parent_class + +static guint gimp_tool_group_signals[LAST_SIGNAL] = { 0 }; + + +/* private functions */ + +static void +gimp_tool_group_class_init (GimpToolGroupClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass); + GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass); + + gimp_tool_group_signals[ACTIVE_TOOL_CHANGED] = + g_signal_new ("active-tool-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GimpToolGroupClass, active_tool_changed), + NULL, NULL, + gimp_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + object_class->finalize = gimp_tool_group_finalize; + object_class->get_property = gimp_tool_group_get_property; + object_class->set_property = gimp_tool_group_set_property; + + gimp_object_class->get_memsize = gimp_tool_group_get_memsize; + + viewable_class->default_icon_name = "folder"; + viewable_class->get_description = gimp_tool_group_get_description; + viewable_class->get_children = gimp_tool_group_get_children; + viewable_class->get_expanded = gimp_tool_group_get_expanded; + viewable_class->set_expanded = gimp_tool_group_set_expanded; + + GIMP_CONFIG_PROP_STRING (object_class, PROP_ACTIVE_TOOL, + "active-tool", NULL, NULL, + NULL, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_OBJECT (object_class, PROP_CHILDREN, + "children", NULL, NULL, + GIMP_TYPE_CONTAINER, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_AGGREGATE); +} + +static void +gimp_tool_group_init (GimpToolGroup *tool_group) +{ + tool_group->priv = gimp_tool_group_get_instance_private (tool_group); + + tool_group->priv->children = g_object_new ( + GIMP_TYPE_LIST, + "children-type", GIMP_TYPE_TOOL_INFO, + "append", TRUE, + NULL); + + g_signal_connect (tool_group->priv->children, "add", + G_CALLBACK (gimp_tool_group_child_add), + tool_group); + g_signal_connect (tool_group->priv->children, "remove", + G_CALLBACK (gimp_tool_group_child_remove), + tool_group); +} + +static void +gimp_tool_group_finalize (GObject *object) +{ + GimpToolGroup *tool_group = GIMP_TOOL_GROUP (object); + + g_clear_pointer (&tool_group->priv->active_tool, g_free); + + g_clear_object (&tool_group->priv->children); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_tool_group_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpToolGroup *tool_group = GIMP_TOOL_GROUP (object); + + switch (property_id) + { + case PROP_ACTIVE_TOOL: + g_value_set_string (value, tool_group->priv->active_tool); + break; + + case PROP_CHILDREN: + g_value_set_object (value, tool_group->priv->children); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_tool_group_set_property_add_tool (GimpToolInfo *tool_info, + GimpToolGroup *tool_group) +{ + gimp_container_add (tool_group->priv->children, GIMP_OBJECT (tool_info)); +} + +static void +gimp_tool_group_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpToolGroup *tool_group = GIMP_TOOL_GROUP (object); + + switch (property_id) + { + case PROP_ACTIVE_TOOL: + g_free (tool_group->priv->active_tool); + + tool_group->priv->active_tool = g_value_dup_string (value); + break; + + case PROP_CHILDREN: + { + GimpContainer *container = g_value_get_object (value); + + gimp_container_clear (tool_group->priv->children); + + if (! container) + break; + + gimp_container_foreach (container, + (GFunc) gimp_tool_group_set_property_add_tool, + tool_group); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gint64 +gimp_tool_group_get_memsize (GimpObject *object, + gint64 *gui_size) +{ + GimpToolGroup *tool_group = GIMP_TOOL_GROUP (object); + gint64 memsize = 0; + + memsize += gimp_object_get_memsize (GIMP_OBJECT (tool_group->priv->children), + gui_size); + + return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, + gui_size); +} + +static gchar * +gimp_tool_group_get_description (GimpViewable *viewable, + gchar **tooltip) +{ + /* Translators: this is a noun */ + return g_strdup (C_("tool-item", "Group")); +} + +static GimpContainer * +gimp_tool_group_get_children (GimpViewable *viewable) +{ + GimpToolGroup *tool_group = GIMP_TOOL_GROUP (viewable); + + return tool_group->priv->children; +} + +static void +gimp_tool_group_set_expanded (GimpViewable *viewable, + gboolean expand) +{ + if (! expand) + gimp_viewable_expanded_changed (viewable); +} + +static gboolean +gimp_tool_group_get_expanded (GimpViewable *viewable) +{ + return TRUE; +} + +static void +gimp_tool_group_child_add (GimpContainer *container, + GimpToolInfo *tool_info, + GimpToolGroup *tool_group) +{ + gimp_viewable_set_parent (GIMP_VIEWABLE (tool_info), + GIMP_VIEWABLE (tool_group)); + + if (! tool_group->priv->active_tool) + gimp_tool_group_set_active_tool_info (tool_group, tool_info); +} + +static void +gimp_tool_group_child_remove (GimpContainer *container, + GimpToolInfo *tool_info, + GimpToolGroup *tool_group) +{ + gimp_viewable_set_parent (GIMP_VIEWABLE (tool_info), NULL); + + if (! g_strcmp0 (tool_group->priv->active_tool, + gimp_object_get_name (GIMP_OBJECT (tool_info)))) + { + GimpToolInfo *active_tool_info = NULL; + + if (! gimp_container_is_empty (tool_group->priv->children)) + { + active_tool_info = GIMP_TOOL_INFO ( + gimp_container_get_first_child (tool_group->priv->children)); + } + + gimp_tool_group_set_active_tool_info (tool_group, active_tool_info); + } +} + + +/* public functions */ + +GimpToolGroup * +gimp_tool_group_new (void) +{ + GimpToolGroup *group; + + group = g_object_new (GIMP_TYPE_TOOL_GROUP, NULL); + + gimp_object_set_static_name (GIMP_OBJECT (group), "tool group"); + + return group; +} + +void +gimp_tool_group_set_active_tool (GimpToolGroup *tool_group, + const gchar *tool_name) +{ + g_return_if_fail (GIMP_IS_TOOL_GROUP (tool_group)); + + if (g_strcmp0 (tool_group->priv->active_tool, tool_name)) + { + g_return_if_fail (tool_name == NULL || + gimp_container_get_child_by_name ( + tool_group->priv->children, tool_name) != NULL); + + g_free (tool_group->priv->active_tool); + + tool_group->priv->active_tool = g_strdup (tool_name);; + + g_signal_emit (tool_group, + gimp_tool_group_signals[ACTIVE_TOOL_CHANGED], 0); + + g_object_notify (G_OBJECT (tool_group), "active-tool"); + } +} + +const gchar * +gimp_tool_group_get_active_tool (GimpToolGroup *tool_group) +{ + g_return_val_if_fail (GIMP_IS_TOOL_GROUP (tool_group), NULL); + + return tool_group->priv->active_tool; +} + +void +gimp_tool_group_set_active_tool_info (GimpToolGroup *tool_group, + GimpToolInfo *tool_info) +{ + g_return_if_fail (GIMP_IS_TOOL_GROUP (tool_group)); + g_return_if_fail (tool_info == NULL || GIMP_IS_TOOL_INFO (tool_info)); + + gimp_tool_group_set_active_tool ( + tool_group, + tool_info ? gimp_object_get_name (GIMP_OBJECT (tool_info)) : NULL); +} + +GimpToolInfo * +gimp_tool_group_get_active_tool_info (GimpToolGroup *tool_group) +{ + g_return_val_if_fail (GIMP_IS_TOOL_GROUP (tool_group), NULL); + + return GIMP_TOOL_INFO ( + gimp_container_get_child_by_name (tool_group->priv->children, + tool_group->priv->active_tool)); +} diff --git a/app/core/gimptoolgroup.h b/app/core/gimptoolgroup.h new file mode 100644 index 0000000000..ef4d979b5e --- /dev/null +++ b/app/core/gimptoolgroup.h @@ -0,0 +1,68 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimptoolgroup.h + * 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 . + */ + +#ifndef __GIMP_TOOL_GROUP_H__ +#define __GIMP_TOOL_GROUP_H__ + + +#include "gimptoolitem.h" + + +#define GIMP_TYPE_TOOL_GROUP (gimp_tool_group_get_type ()) +#define GIMP_TOOL_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TOOL_GROUP, GimpToolGroup)) +#define GIMP_TOOL_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_TOOL_GROUP, GimpToolGroupClass)) +#define GIMP_IS_TOOL_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TOOL_GROUP)) +#define GIMP_IS_TOOL_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_TOOL_GROUP)) +#define GIMP_TOOL_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_TOOL_GROUP, GimpToolGroupClass)) + + +typedef struct _GimpToolGroupPrivate GimpToolGroupPrivate; +typedef struct _GimpToolGroupClass GimpToolGroupClass; + +struct _GimpToolGroup +{ + GimpToolItem parent_instance; + + GimpToolGroupPrivate *priv; +}; + +struct _GimpToolGroupClass +{ + GimpToolItemClass parent_class; + + /* signals */ + void (* active_tool_changed) (GimpToolGroup *tool_group); +}; + + +GType gimp_tool_group_get_type (void) G_GNUC_CONST; + +GimpToolGroup * gimp_tool_group_new (void); + +void gimp_tool_group_set_active_tool (GimpToolGroup *tool_group, + const gchar *tool_name); +const gchar * gimp_tool_group_get_active_tool (GimpToolGroup *tool_group); + +void gimp_tool_group_set_active_tool_info (GimpToolGroup *tool_group, + GimpToolInfo *tool_info); +GimpToolInfo * gimp_tool_group_get_active_tool_info (GimpToolGroup *tool_group); + + +#endif /* __GIMP_TOOL_GROUP_H__ */ diff --git a/po/POTFILES.in b/po/POTFILES.in index f9c18aebf5..29ce971c33 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -194,6 +194,7 @@ app/core/gimpsymmetry-mirror.c app/core/gimpsymmetry-tiling.c app/core/gimptagcache.c app/core/gimptemplate.c +app/core/gimptoolgroup.c app/core/gimptooloptions.c app/core/gimptoolpreset.c app/core/gimptoolpreset-load.c