diff options
Diffstat (limited to 'app/widgets/gimplayermodecombobox.c')
-rw-r--r-- | app/widgets/gimplayermodecombobox.c | 470 |
1 files changed, 470 insertions, 0 deletions
diff --git a/app/widgets/gimplayermodecombobox.c b/app/widgets/gimplayermodecombobox.c new file mode 100644 index 0000000..0483c4d --- /dev/null +++ b/app/widgets/gimplayermodecombobox.c @@ -0,0 +1,470 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1999 Peter Mattis and Spencer Kimball + * + * gimplayermodecombobox.c + * Copyright (C) 2017 Michael Natterer <mitch@gimp.org> + * + * 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 <gtk/gtk.h> +#include <gegl.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpwidgets/gimpwidgets.h" + +#include "widgets-types.h" + +#include "operations/layer-modes/gimp-layer-modes.h" + +#include "gimplayermodecombobox.h" + + +/** + * SECTION: gimplayermodecombobox + * @title: GimpLayerModeComboBox + * @short_description: A #GimpEnumComboBox subclass for selecting a layer mode. + * + * A #GtkComboBox subclass for selecting a layer mode + **/ + + +enum +{ + PROP_0, + PROP_CONTEXT, + PROP_LAYER_MODE, + PROP_GROUP +}; + + +struct _GimpLayerModeComboBoxPrivate +{ + GimpLayerModeContext context; + GimpLayerMode layer_mode; + GimpLayerModeGroup group; +}; + + +static void gimp_layer_mode_combo_box_constructed (GObject *object); +static void gimp_layer_mode_combo_box_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_layer_mode_combo_box_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static void gimp_layer_mode_combo_box_changed (GtkComboBox *gtk_combo); + +static void gimp_layer_mode_combo_box_update_model (GimpLayerModeComboBox *combo, + gboolean change_mode); +static gboolean gimp_layer_mode_combo_box_separator_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data); + + +G_DEFINE_TYPE_WITH_PRIVATE (GimpLayerModeComboBox, gimp_layer_mode_combo_box, + GIMP_TYPE_ENUM_COMBO_BOX) + +#define parent_class gimp_layer_mode_combo_box_parent_class + + +static void +gimp_layer_mode_combo_box_class_init (GimpLayerModeComboBoxClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkComboBoxClass *combo_class = GTK_COMBO_BOX_CLASS (klass); + + object_class->constructed = gimp_layer_mode_combo_box_constructed; + object_class->set_property = gimp_layer_mode_combo_box_set_property; + object_class->get_property = gimp_layer_mode_combo_box_get_property; + + combo_class->changed = gimp_layer_mode_combo_box_changed; + + g_object_class_install_property (object_class, PROP_CONTEXT, + g_param_spec_flags ("context", + NULL, NULL, + GIMP_TYPE_LAYER_MODE_CONTEXT, + GIMP_LAYER_MODE_CONTEXT_ALL, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_LAYER_MODE, + g_param_spec_enum ("layer-mode", + NULL, NULL, + GIMP_TYPE_LAYER_MODE, + GIMP_LAYER_MODE_NORMAL, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_GROUP, + g_param_spec_enum ("group", + NULL, NULL, + GIMP_TYPE_LAYER_MODE_GROUP, + GIMP_LAYER_MODE_GROUP_DEFAULT, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_layer_mode_combo_box_init (GimpLayerModeComboBox *combo) +{ + combo->priv = gimp_layer_mode_combo_box_get_instance_private (combo); + + gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo), + gimp_layer_mode_combo_box_separator_func, + GINT_TO_POINTER (GIMP_LAYER_MODE_SEPARATOR), + NULL); +} + +static void +gimp_layer_mode_combo_box_constructed (GObject *object) +{ + GimpLayerModeComboBox *combo = GIMP_LAYER_MODE_COMBO_BOX (object); + + G_OBJECT_CLASS (parent_class)->constructed (object); + + gimp_layer_mode_combo_box_update_model (combo, FALSE); + + gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), + combo->priv->layer_mode); +} + +static void +gimp_layer_mode_combo_box_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpLayerModeComboBox *combo = GIMP_LAYER_MODE_COMBO_BOX (object); + + switch (prop_id) + { + case PROP_CONTEXT: + gimp_layer_mode_combo_box_set_context (combo, g_value_get_flags (value)); + break; + + case PROP_LAYER_MODE: + gimp_layer_mode_combo_box_set_mode (combo, g_value_get_enum (value)); + break; + + case PROP_GROUP: + gimp_layer_mode_combo_box_set_group (combo, g_value_get_enum (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gimp_layer_mode_combo_box_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GimpLayerModeComboBox *combo = GIMP_LAYER_MODE_COMBO_BOX (object); + + switch (prop_id) + { + case PROP_CONTEXT: + g_value_set_flags (value, combo->priv->context); + break; + + case PROP_LAYER_MODE: + g_value_set_enum (value, combo->priv->layer_mode); + break; + + case PROP_GROUP: + g_value_set_enum (value, combo->priv->group); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gimp_layer_mode_combo_box_changed (GtkComboBox *gtk_combo) +{ + GimpLayerModeComboBox *combo = GIMP_LAYER_MODE_COMBO_BOX (gtk_combo); + GimpLayerMode mode; + + if (gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (combo), + (gint *) &mode)) + { + combo->priv->layer_mode = mode; + + g_object_notify (G_OBJECT (combo), "layer-mode"); + } +} + + +/** + * gimp_layer_mode_combo_box_new: + * Foo. + * + * Return value: a new #GimpLayerModeComboBox. + **/ +GtkWidget * +gimp_layer_mode_combo_box_new (GimpLayerModeContext context) +{ + return g_object_new (GIMP_TYPE_LAYER_MODE_COMBO_BOX, + "context", context, + NULL); +} + +void +gimp_layer_mode_combo_box_set_context (GimpLayerModeComboBox *combo, + GimpLayerModeContext context) +{ + g_return_if_fail (GIMP_IS_LAYER_MODE_COMBO_BOX (combo)); + + if (context != combo->priv->context) + { + g_object_freeze_notify (G_OBJECT (combo)); + + combo->priv->context = context; + g_object_notify (G_OBJECT (combo), "context"); + + gimp_layer_mode_combo_box_update_model (combo, TRUE); + + g_object_thaw_notify (G_OBJECT (combo)); + } +} + +GimpLayerModeContext +gimp_layer_mode_combo_box_get_context (GimpLayerModeComboBox *combo) +{ + g_return_val_if_fail (GIMP_IS_LAYER_MODE_COMBO_BOX (combo), + GIMP_LAYER_MODE_CONTEXT_ALL); + + return combo->priv->context; +} + +void +gimp_layer_mode_combo_box_set_mode (GimpLayerModeComboBox *combo, + GimpLayerMode mode) +{ + g_return_if_fail (GIMP_IS_LAYER_MODE_COMBO_BOX (combo)); + g_return_if_fail (gimp_layer_mode_get_context (mode) & combo->priv->context); + + if (mode != combo->priv->layer_mode) + { + GtkTreeModel *model; + GtkTreeIter dummy; + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo)); + + g_object_freeze_notify (G_OBJECT (combo)); + + if (! gimp_int_store_lookup_by_value (model, mode, &dummy)) + { + combo->priv->group = gimp_layer_mode_get_group (mode); + g_object_notify (G_OBJECT (combo), "group"); + + gimp_layer_mode_combo_box_update_model (combo, FALSE); + } + + gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), mode); + + g_object_thaw_notify (G_OBJECT (combo)); + } +} + +GimpLayerMode +gimp_layer_mode_combo_box_get_mode (GimpLayerModeComboBox *combo) +{ + g_return_val_if_fail (GIMP_IS_LAYER_MODE_COMBO_BOX (combo), + GIMP_LAYER_MODE_NORMAL); + + return combo->priv->layer_mode; +} + +void +gimp_layer_mode_combo_box_set_group (GimpLayerModeComboBox *combo, + GimpLayerModeGroup group) +{ + g_return_if_fail (GIMP_IS_LAYER_MODE_COMBO_BOX (combo)); + + if (group != combo->priv->group) + { + g_object_freeze_notify (G_OBJECT (combo)); + + combo->priv->group = group; + g_object_notify (G_OBJECT (combo), "group"); + + gimp_layer_mode_combo_box_update_model (combo, TRUE); + + g_object_thaw_notify (G_OBJECT (combo)); + } +} + +GimpLayerModeGroup +gimp_layer_mode_combo_box_get_group (GimpLayerModeComboBox *combo) +{ + g_return_val_if_fail (GIMP_IS_LAYER_MODE_COMBO_BOX (combo), + GIMP_LAYER_MODE_GROUP_DEFAULT); + + return combo->priv->group; +} + + +/* private functions */ + +static void +gimp_enum_store_add_value (GtkListStore *store, + GEnumValue *value) +{ + GtkTreeIter iter = { 0, }; + const gchar *desc; + const gchar *abbrev; + gchar *stripped; + + desc = gimp_enum_value_get_desc (GIMP_ENUM_STORE (store)->enum_class, value); + abbrev = gimp_enum_value_get_abbrev (GIMP_ENUM_STORE (store)->enum_class, value); + + /* no mnemonics in combo boxes */ + stripped = gimp_strip_uline (desc); + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + GIMP_INT_STORE_VALUE, value->value, + GIMP_INT_STORE_LABEL, stripped, + GIMP_INT_STORE_ABBREV, abbrev, + -1); + + g_free (stripped); +} + +static void +gimp_enum_store_add_separator (GtkListStore *store) +{ + GtkTreeIter iter = { 0, }; + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + GIMP_INT_STORE_VALUE, GIMP_LAYER_MODE_SEPARATOR, + -1); +} + +static GtkListStore * +gimp_enum_store_new_from_array (GType enum_type, + gint n_values, + const gint *values, + GimpLayerModeContext context) +{ + GtkListStore *store; + GEnumValue *value; + gboolean first_item = TRUE; + gboolean prepend_separator = FALSE; + gint i; + + g_return_val_if_fail (G_TYPE_IS_ENUM (enum_type), NULL); + g_return_val_if_fail (n_values > 1, NULL); + g_return_val_if_fail (values != NULL, NULL); + + store = g_object_new (GIMP_TYPE_ENUM_STORE, + "enum-type", enum_type, + NULL); + + for (i = 0; i < n_values; i++) + { + if (values[i] != GIMP_LAYER_MODE_SEPARATOR) + { + if (gimp_layer_mode_get_context (values[i]) & context) + { + value = g_enum_get_value (GIMP_ENUM_STORE (store)->enum_class, + values[i]); + + if (value) + { + if (prepend_separator) + { + gimp_enum_store_add_separator (store); + + prepend_separator = FALSE; + } + + gimp_enum_store_add_value (store, value); + + first_item = FALSE; + } + } + } + else + { + if (! first_item) + prepend_separator = TRUE; + } + } + + return store; +} + +static void +gimp_layer_mode_combo_box_update_model (GimpLayerModeComboBox *combo, + gboolean change_mode) +{ + GtkListStore *store; + const GimpLayerMode *modes; + gint n_modes; + + modes = gimp_layer_mode_get_group_array (combo->priv->group, &n_modes); + store = gimp_enum_store_new_from_array (GIMP_TYPE_LAYER_MODE, + n_modes, (gint *) modes, + combo->priv->context); + + gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (store)); + g_object_unref (store); + + if (change_mode) + { + GimpLayerMode new_mode; + + if (gimp_layer_mode_get_for_group (combo->priv->layer_mode, + combo->priv->group, + &new_mode) && + (gimp_layer_mode_get_context (new_mode) & combo->priv->context)) + { + gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo), new_mode); + } + else + { + GtkTreeIter iter; + + /* switch to the first mode, which will be one of the "normal" */ + gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter); + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter); + } + } +} + +static gboolean +gimp_layer_mode_combo_box_separator_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gint value; + + gtk_tree_model_get (model, iter, GIMP_INT_STORE_VALUE, &value, -1); + + return value == GPOINTER_TO_INT (data); +} |