/* GIMP - The GNU Image Manipulation Program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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 /* memcmp */ #include #include "libgimpbase/gimpbase.h" #include "libgimpmath/gimpmath.h" #include "libgimpconfig/gimpconfig.h" #include "core-types.h" #include "gimppadactions.h" #include "gimpparamspecs.h" #include "gimp-intl.h" typedef struct _GimpPadAction GimpPadAction; struct _GimpPadAction { GimpPadActionType type; gint number; gint mode; gchar *action_name; }; struct _GimpPadActionsPrivate { GArray *actions; }; /* local function prototypes */ static void gimp_pad_actions_config_iface_init (GimpConfigInterface *iface); static void gimp_pad_actions_finalize (GObject *object); static gboolean gimp_pad_actions_serialize (GimpConfig *config, GimpConfigWriter *writer, gpointer data); static gboolean gimp_pad_actions_deserialize (GimpConfig *config, GScanner *scanner, gint nest_level, gpointer data); static gboolean gimp_pad_actions_equal (GimpConfig *a, GimpConfig *b); static void gimp_pad_actions_reset (GimpConfig *config); static gboolean gimp_pad_actions_config_copy (GimpConfig *src, GimpConfig *dest, GParamFlags flags); G_DEFINE_TYPE_WITH_CODE (GimpPadActions, gimp_pad_actions, G_TYPE_OBJECT, G_ADD_PRIVATE (GimpPadActions) G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, gimp_pad_actions_config_iface_init)) #define parent_class gimp_pad_actions_parent_class static void gimp_pad_actions_class_init (GimpPadActionsClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gimp_pad_actions_finalize; } static void gimp_pad_actions_config_iface_init (GimpConfigInterface *iface) { iface->serialize = gimp_pad_actions_serialize; iface->deserialize = gimp_pad_actions_deserialize; iface->equal = gimp_pad_actions_equal; iface->reset = gimp_pad_actions_reset; iface->copy = gimp_pad_actions_config_copy; } static void clear_action (gpointer user_data) { GimpPadAction *pad_action = user_data; g_free (pad_action->action_name); } static void gimp_pad_actions_init (GimpPadActions *pad_actions) { pad_actions->priv = gimp_pad_actions_get_instance_private (pad_actions); pad_actions->priv->actions = g_array_new (FALSE, FALSE, sizeof (GimpPadAction)); g_array_set_clear_func (pad_actions->priv->actions, clear_action); } static void gimp_pad_actions_finalize (GObject *object) { GimpPadActions *pad_actions = GIMP_PAD_ACTIONS (object); g_clear_pointer (&pad_actions->priv->actions, g_array_unref); G_OBJECT_CLASS (parent_class)->finalize (object); } static gboolean gimp_pad_actions_serialize (GimpConfig *config, GimpConfigWriter *writer, gpointer data) { GimpPadActions *pad_actions = GIMP_PAD_ACTIONS (config); guint i; for (i = 0; i < pad_actions->priv->actions->len; i++) { GimpPadAction *pad_action; const gchar *name = NULL; pad_action = &g_array_index (pad_actions->priv->actions, GimpPadAction, i); switch (pad_action->type) { case GIMP_PAD_ACTION_BUTTON: name = "button"; break; case GIMP_PAD_ACTION_RING: name = "ring"; break; case GIMP_PAD_ACTION_STRIP: name = "strip"; break; } gimp_config_writer_open (writer, name); gimp_config_writer_printf (writer, "%d", pad_action->number); gimp_config_writer_printf (writer, "%d", pad_action->mode); gimp_config_writer_string (writer, pad_action->action_name); gimp_config_writer_close (writer); } return TRUE; } static gboolean gimp_pad_actions_deserialize (GimpConfig *config, GScanner *scanner, gint nest_level, gpointer data) { GimpPadActions *pad_actions = GIMP_PAD_ACTIONS (config); GTokenType token; guint scope_id; guint old_scope_id; scope_id = g_type_qname (G_TYPE_FROM_INSTANCE (config)); old_scope_id = g_scanner_set_scope (scanner, scope_id); g_scanner_scope_add_symbol (scanner, scope_id, "button", GINT_TO_POINTER (GIMP_PAD_ACTION_BUTTON)); g_scanner_scope_add_symbol (scanner, scope_id, "ring", GINT_TO_POINTER (GIMP_PAD_ACTION_RING)); g_scanner_scope_add_symbol (scanner, scope_id, "strip", GINT_TO_POINTER (GIMP_PAD_ACTION_STRIP)); token = G_TOKEN_LEFT_PAREN; while (g_scanner_peek_next_token (scanner) == token) { GimpPadActionType type; gint number; gint mode; gchar *action_name = NULL; token = g_scanner_get_next_token (scanner); switch (token) { case G_TOKEN_LEFT_PAREN: token = G_TOKEN_SYMBOL; break; case G_TOKEN_SYMBOL: if (scanner->value.v_symbol == GUINT_TO_POINTER (GIMP_PAD_ACTION_BUTTON) || scanner->value.v_symbol == GUINT_TO_POINTER (GIMP_PAD_ACTION_RING) || scanner->value.v_symbol == GUINT_TO_POINTER (GIMP_PAD_ACTION_STRIP)) type = GPOINTER_TO_UINT (scanner->value.v_symbol); else goto error; if (! gimp_scanner_parse_int (scanner, &number)) goto error; if (! gimp_scanner_parse_int (scanner, &mode)) goto error; if (! gimp_scanner_parse_string (scanner, &action_name)) goto error; gimp_pad_actions_set_action (pad_actions, type, number, mode, action_name); g_clear_pointer (&action_name, g_free); token = G_TOKEN_RIGHT_PAREN; break; case G_TOKEN_RIGHT_PAREN: token = G_TOKEN_LEFT_PAREN; break; default: break; } } error: g_scanner_scope_remove_symbol (scanner, scope_id, "button"); g_scanner_scope_remove_symbol (scanner, scope_id, "ring"); g_scanner_scope_remove_symbol (scanner, scope_id, "strip"); g_scanner_set_scope (scanner, old_scope_id); return G_TOKEN_LEFT_PAREN; } static gboolean gimp_pad_actions_equal (GimpConfig *a, GimpConfig *b) { GimpPadActions *a_pad_actions = GIMP_PAD_ACTIONS (a); GimpPadActions *b_pad_actions = GIMP_PAD_ACTIONS (b); if (a_pad_actions->priv->actions->len != b_pad_actions->priv->actions->len || memcmp (a_pad_actions->priv->actions->data, b_pad_actions->priv->actions->data, sizeof (GimpPadAction) * a_pad_actions->priv->actions->len)) { return FALSE; } return TRUE; } static void gimp_pad_actions_reset (GimpConfig *config) { GimpPadActions *pad_actions = GIMP_PAD_ACTIONS (config); g_array_set_size (pad_actions->priv->actions, 0); } static gboolean gimp_pad_actions_config_copy (GimpConfig *src, GimpConfig *dest, GParamFlags flags) { gimp_config_sync (G_OBJECT (src), G_OBJECT (dest), flags); gimp_data_dirty (GIMP_DATA (dest)); return TRUE; } static gint gimp_pad_actions_find_action (GArray *array, GimpPadActionType type, guint number, guint mode) { GimpPadAction *pad_action; guint i; for (i = 0; i < array->len; i++) { pad_action = &g_array_index (array, GimpPadAction, i); if (pad_action->type == type && pad_action->number == number && pad_action->mode == mode) return i; } return -1; } /* public functions */ GimpPadActions * gimp_pad_actions_new (void) { return g_object_new (GIMP_TYPE_PAD_ACTIONS, NULL); } void gimp_pad_actions_foreach (GimpPadActions *pad_actions, GimpPadActionForeach func, gpointer data) { GimpPadActionsPrivate *private; GimpPadAction *pad_action; guint i; private = pad_actions->priv; for (i = 0; i < private->actions->len; i++) { pad_action = &g_array_index (private->actions, GimpPadAction, i); func (pad_actions, pad_action->type, pad_action->number, pad_action->mode, pad_action->action_name, data); } } gint gimp_pad_actions_set_action (GimpPadActions *pad_actions, GimpPadActionType type, guint number, guint mode, const gchar *action_name) { GimpPadActionsPrivate *private; GimpPadAction new_action = { 0, }; guint i; g_return_val_if_fail (GIMP_IS_PAD_ACTIONS (pad_actions), -1); g_return_val_if_fail (type <= GIMP_PAD_ACTION_STRIP, -1); g_return_val_if_fail (action_name, -1); g_return_val_if_fail (*action_name, -1); new_action.type = type; new_action.number = number; new_action.mode = mode; new_action.action_name = g_strdup (action_name); private = pad_actions->priv; /* Find insertion point */ for (i = 0; i < private->actions->len; i++) { GimpPadAction *pad_action; pad_action = &g_array_index (private->actions, GimpPadAction, i); /* If the number/mode is already there, this is an existing item */ if (pad_action->type == type && pad_action->number == number && pad_action->mode == mode) { g_array_remove_index (private->actions, i); break; } if (pad_action->type > type || (pad_action->type == type && pad_action->mode > mode) || (pad_action->type == type && pad_action->mode == mode && pad_action->number > number)) break; } if (i == pad_actions->priv->actions->len) g_array_append_val (private->actions, new_action); else g_array_insert_val (private->actions, i, new_action); return i; } void gimp_pad_actions_clear_action (GimpPadActions *pad_actions, GimpPadActionType type, guint number, guint mode) { GimpPadActionsPrivate *private; gint pos; g_return_if_fail (GIMP_IS_PAD_ACTIONS (pad_actions)); g_return_if_fail (type <= GIMP_PAD_ACTION_STRIP); private = pad_actions->priv; pos = gimp_pad_actions_find_action (private->actions, type, number, mode); if (pos >= 0) g_array_remove_index (private->actions, pos); } gint gimp_pad_actions_get_n_actions (GimpPadActions *pad_actions) { GimpPadActionsPrivate *private; g_return_val_if_fail (GIMP_IS_PAD_ACTIONS (pad_actions), -1); private = pad_actions->priv; return private->actions->len; } const gchar * gimp_pad_actions_get_action (GimpPadActions *pad_actions, GimpPadActionType type, guint number, guint mode) { GimpPadActionsPrivate *private; GimpPadAction *pad_action; gint pos; g_return_val_if_fail (GIMP_IS_PAD_ACTIONS (pad_actions), NULL); g_return_val_if_fail (type <= GIMP_PAD_ACTION_STRIP, NULL); private = pad_actions->priv; pos = gimp_pad_actions_find_action (private->actions, type, number, mode); if (pos >= 0) { pad_action = &g_array_index (private->actions, GimpPadAction, pos); return pad_action->action_name; } else { return NULL; } }