/* LIBPIKA - The PIKA Library * Copyright (C) 1995-2000 Peter Mattis and Spencer Kimball * * pikachoice.c * * This library is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . */ #include "config.h" #include #include "pikabasetypes.h" #include "pikachoice.h" #include "pikaparamspecs.h" typedef struct _PikaChoiceDesc { gchar *label; gchar *help; gint id; gboolean sensitive; } PikaChoiceDesc; enum { SENSITIVITY_CHANGED, LAST_SIGNAL }; struct _PikaChoice { GObject parent_instance; GHashTable *choices; GList *keys; }; static void pika_choice_finalize (GObject *object); static void pika_choice_desc_free (PikaChoiceDesc *desc); G_DEFINE_TYPE (PikaChoice, pika_choice, G_TYPE_OBJECT) #define parent_class pika_choice_parent_class static guint pika_choice_signals[LAST_SIGNAL] = { 0 }; static void pika_choice_class_init (PikaChoiceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); pika_choice_signals[SENSITIVITY_CHANGED] = g_signal_new ("sensitivity-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, 0, /*G_STRUCT_OFFSET (PikaChoiceClass, sensitivity_changed),*/ NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING); object_class->finalize = pika_choice_finalize; } static void pika_choice_init (PikaChoice *choice) { choice->choices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) pika_choice_desc_free); } static void pika_choice_finalize (GObject *object) { PikaChoice *choice = PIKA_CHOICE (object); g_hash_table_unref (choice->choices); g_list_free_full (choice->keys, (GDestroyNotify) g_free); } /* Public API */ /** * pika_choice_new: * * Returns: (transfer full): a #PikaChoice. * * Since: 3.0 **/ PikaChoice * pika_choice_new (void) { PikaChoice *choice; choice = g_object_new (PIKA_TYPE_CHOICE, NULL); return choice; } /** * pika_choice_new_with_values: * @nick: the first value. * @id: integer ID for @nick. * @label: the label of @nick. * @help: longer help text for @nick. * ...: more triplets of string to pre-fill the created %PikaChoice. * * Returns: (transfer full): a #PikaChoice. * * Since: 3.0 **/ PikaChoice * pika_choice_new_with_values (const gchar *nick, gint id, const gchar *label, const gchar *help, ...) { PikaChoice *choice; va_list va_args; g_return_val_if_fail (nick != NULL, NULL); g_return_val_if_fail (label != NULL, NULL); choice = pika_choice_new (); va_start (va_args, help); do { pika_choice_add (choice, nick, id, label, help); nick = va_arg (va_args, const gchar *); if (nick == NULL) break; id = va_arg (va_args, gint); label = va_arg (va_args, const gchar *); if (label == NULL) { g_critical ("%s: nick '%s' cannot have a NULL label.", G_STRFUNC, nick); break; } help = va_arg (va_args, const gchar *); } while (TRUE); va_end (va_args); return choice; } /** * pika_choice_add: * @choice: the %PikaChoice. * @nick: the nick of @choice. * @id: optional integer ID for @nick. * @label: the label of @choice. * @help: optional longer help text for @nick. * * This procedure adds a new possible value to @choice list of values. * The @id is an optional integer identifier. This can be useful for instance * when you want to work with different enum values mapped to each @nick. * * Since: 3.0 **/ void pika_choice_add (PikaChoice *choice, const gchar *nick, gint id, const gchar *label, const gchar *help) { PikaChoiceDesc *desc; GList *duplicate; g_return_if_fail (label != NULL); desc = g_new0 (PikaChoiceDesc, 1); desc->id = id; desc->label = g_strdup (label); desc->help = help != NULL ? g_strdup (help) : NULL; desc->sensitive = TRUE; g_hash_table_insert (choice->choices, g_strdup (nick), desc); duplicate = g_list_find_custom (choice->keys, nick, (GCompareFunc) g_strcmp0); if (duplicate != NULL) { choice->keys = g_list_remove_link (choice->keys, duplicate); pika_choice_desc_free (duplicate->data); g_list_free (duplicate); } choice->keys = g_list_append (choice->keys, g_strdup (nick)); } /** * pika_choice_is_valid: * @choice: a %PikaChoice. * @nick: the nick to check. * * This procedure checks if the given @nick is valid and refers to * an existing choice. * * Returns: Whether the choice is valid. * * Since: 3.0 **/ gboolean pika_choice_is_valid (PikaChoice *choice, const gchar *nick) { PikaChoiceDesc *desc; g_return_val_if_fail (PIKA_IS_CHOICE (choice), FALSE); g_return_val_if_fail (nick != NULL, FALSE); desc = g_hash_table_lookup (choice->choices, nick); return (desc != NULL && desc->sensitive); } /** * pika_choice_list_nicks: * @choice: a %PikaChoice. * @nick: the nick to check. * * This procedure returns the list of nicks allowed for @choice. * * Returns: (element-type gchar*) (transfer none): The list of @choice's nicks. * * Since: 3.0 **/ GList * pika_choice_list_nicks (PikaChoice *choice) { /* I don't use g_hash_table_get_keys() on purpose, because I want to retain * the adding-time order. */ return choice->keys; } /** * pika_choice_get_id: * @choice: a %PikaChoice. * @nick: the nick to lookup. * * Returns: the ID of @nick. * * Since: 3.0 **/ gint pika_choice_get_id (PikaChoice *choice, const gchar *nick) { PikaChoiceDesc *desc; desc = g_hash_table_lookup (choice->choices, nick); if (desc) return desc->id; else return 0; } /** * pika_choice_get_label: * @choice: a %PikaChoice. * @nick: the nick to lookup. * * Returns: (transfer none): the label of @nick. * * Since: 3.0 **/ const gchar * pika_choice_get_label (PikaChoice *choice, const gchar *nick) { PikaChoiceDesc *desc; desc = g_hash_table_lookup (choice->choices, nick); if (desc) return desc->label; else return NULL; } /** * pika_choice_get_help: * @choice: a %PikaChoice. * @nick: the nick to lookup. * * Returns the longer documentation for @nick. * * Returns: (transfer none): the help text of @nick. * * Since: 3.0 **/ const gchar * pika_choice_get_help (PikaChoice *choice, const gchar *nick) { PikaChoiceDesc *desc; desc = g_hash_table_lookup (choice->choices, nick); if (desc) return desc->help; else return NULL; } /** * pika_choice_get_documentation: * @choice: the %PikaChoice. * @nick: the possible value's nick you need documentation for. * @label: (transfer none): the label of @nick. * @help: (transfer none): the help text of @nick. * * Returns the documentation strings for @nick. * * Returns: %TRUE if @nick is found, %FALSE otherwise. * * Since: 3.0 **/ gboolean pika_choice_get_documentation (PikaChoice *choice, const gchar *nick, const gchar **label, const gchar **help) { PikaChoiceDesc *desc; desc = g_hash_table_lookup (choice->choices, nick); if (desc) { *label = desc->label; *help = desc->help; return TRUE; } return FALSE; } /** * pika_choice_set_sensitive: * @choice: the %PikaChoice. * @nick: the nick to lookup. * * Change the sensitivity of a possible @nick. Technically a non-sensitive @nick * means it cannot be chosen anymore (so [method@Gimp.Choice.is_valid] will * return %FALSE; nevertheless [method@Gimp.Choice.list_nicks] and other * functions to get information about a choice will still function). * * Returns: %TRUE if @nick is found, %FALSE otherwise. * * Since: 3.0 **/ void pika_choice_set_sensitive (PikaChoice *choice, const gchar *nick, gboolean sensitive) { PikaChoiceDesc *desc; g_return_if_fail (PIKA_IS_CHOICE (choice)); g_return_if_fail (nick != NULL); desc = g_hash_table_lookup (choice->choices, nick); g_return_if_fail (desc != NULL); if (desc->sensitive != sensitive) { desc->sensitive = sensitive; g_signal_emit (choice, pika_choice_signals[SENSITIVITY_CHANGED], 0, nick); } } /* Private functions */ static void pika_choice_desc_free (PikaChoiceDesc *desc) { g_free (desc->label); g_free (desc->help); g_free (desc); }