Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gimp/app/widgets/   (Gimp Bildeditor Version 3.2.0©)  Datei vom 14.2.2026 mit Größe 18 kB image not shown  

Quelle  gimpradioaction.c   Sprache: C

 

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * gimpradioaction.c
 * Copyright (C) 2004 Michael Natterer <mitch@gimp.org>
 * Copyright (C) 2008 Sven Neumann <sven@gimp.org>
 * Copyright (C) 2023 Jehan
 *
 * 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 <gegl.h>
#include <gtk/gtk.h>

#include "libgimpbase/gimpbase.h"
#include "libgimpwidgets/gimpwidgets.h"

#include "widgets-types.h"

#include "gimpaction.h"
#include "gimpaction-history.h"
#include "gimpradioaction.h"

/**
 * GimpRadioAction:
 *
 * An action which is part of a group of radio actions. It is guaranteed that at
 * most one action is active in the group.
 *
 * The "state" in any of the actions of the group is the @value associated to
 * the active action of the group.
 */


enum
{
  PROP_0,
  PROP_VALUE,
  PROP_GROUP,
  PROP_GROUP_LABEL,
  PROP_CURRENT_VALUE
};

struct _GimpRadioActionPrivate
{
  GSList *group;
  gchar  *group_label;

  gint    value;
};

static void      gimp_radio_action_g_action_iface_init (GActionInterface *iface);

static void      gimp_radio_action_dispose             (GObject          *object);
static void      gimp_radio_action_finalize            (GObject          *object);
static void      gimp_radio_action_get_property        (GObject          *object,
                                                        guint             prop_id,
                                                        GValue           *value,
                                                        GParamSpec       *pspec);
static void      gimp_radio_action_set_property        (GObject          *object,
                                                        guint             prop_id,
                                                        const GValue     *value,
                                                        GParamSpec       *pspec);

static gboolean  gimp_radio_action_get_enabled         (GAction          *action);
static void      gimp_radio_action_change_state        (GAction          *action,
                                                        GVariant         *value);
static const GVariantType *
                 gimp_radio_action_get_state_type      (GAction          *action);
static GVariant *
                 gimp_radio_action_get_state           (GAction          *action);
static const GVariantType *
                 gimp_radio_action_get_parameter_type  (GAction          *action);

static void      gimp_radio_action_activate            (GAction          *action,
                                                        GVariant         *parameter);

static gboolean  gimp_radio_action_toggle              (GimpToggleAction *action);


G_DEFINE_TYPE_WITH_CODE (GimpRadioAction, gimp_radio_action, GIMP_TYPE_TOGGLE_ACTION,
                         G_ADD_PRIVATE (GimpRadioAction)
                         G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, gimp_radio_action_g_action_iface_init))

#define parent_class gimp_radio_action_parent_class


static void
gimp_radio_action_class_init (GimpRadioActionClass *klass)
{
  GObjectClass          *object_class = G_OBJECT_CLASS (klass);
  GimpToggleActionClass *toggle_class = GIMP_TOGGLE_ACTION_CLASS (klass);

  object_class->dispose      = gimp_radio_action_dispose;
  object_class->finalize     = gimp_radio_action_finalize;
  object_class->get_property = gimp_radio_action_get_property;
  object_class->set_property = gimp_radio_action_set_property;

  toggle_class->toggle       = gimp_radio_action_toggle;

  /**
   * GimpRadioAction:value:
   *
   * The value is an arbitrary integer which can be used as a convenient way to
   * determine which action in the group is currently active in an ::activate
   * signal handler.
   * See gimp_radio_action_get_current_value() for convenient ways to get and
   * set this property.
   **/

  g_object_class_install_property (object_class, PROP_VALUE,
                                   g_param_spec_int ("value",
                                                     "Value",
                                                     "The value returned by gimp_radio_action_get_current_value() when this action is the current action of its group.",
                                                     G_MININT,
                                                     G_MAXINT,
                                                     0,
                                                     GIMP_PARAM_READWRITE));

  /**
   * GimpRadioAction:group:
   *
   * Sets a new group for a radio action.
   */

  g_object_class_install_property (object_class, PROP_GROUP,
                                   g_param_spec_object ("group",
                                                        "Group",
                                                        "The radio action whose group this action belongs to.",
                                                        GIMP_TYPE_RADIO_ACTION,
                                                        GIMP_PARAM_WRITABLE));

  /**
   * GimpRadioAction:group-label:
   *
   * Sets the group label. It will be common to all actions in a same group.
   */

  g_object_class_install_property (object_class, PROP_GROUP_LABEL,
                                   g_param_spec_string ("group-label",
                                                        "Group string",
                                                        "The label for all the radio action in the group this action belongs to.",
                                                        NULL,
                                                        GIMP_PARAM_WRITABLE |
                                                        G_PARAM_EXPLICIT_NOTIFY));
  /**
   * GimpRadioAction:value:
   *
   * The value property of the currently active member of the group to which
   * this action belongs.
   **/

  g_object_class_install_property (object_class, PROP_CURRENT_VALUE,
                                   g_param_spec_int ("current-value",
                                                     "Current value",
                                                     "The value property of the currently active member of the group to which this action belongs.",
                                                     G_MININT,
                                                     G_MAXINT,
                                                     0,
                                                     GIMP_PARAM_READWRITE));
}

static void
gimp_radio_action_g_action_iface_init (GActionInterface *iface)
{
  iface->get_name           = (const gchar* (*) (GAction*)) gimp_action_get_name;
  iface->activate           = gimp_radio_action_activate;
  iface->get_enabled        = gimp_radio_action_get_enabled;

  iface->change_state       = gimp_radio_action_change_state;
  iface->get_state_type     = gimp_radio_action_get_state_type;
  iface->get_state          = gimp_radio_action_get_state;
  iface->get_parameter_type = gimp_radio_action_get_parameter_type;
}

static void
gimp_radio_action_init (GimpRadioAction *action)
{
  action->priv = gimp_radio_action_get_instance_private (action);

  action->priv->group       = NULL;
  action->priv->group_label = NULL;
}

static void
gimp_radio_action_dispose (GObject *object)
{
  GimpRadioAction *action = GIMP_RADIO_ACTION (object);

  if (action->priv->group)
    {
      GSList *group;
      GSList *slist;

      group = g_slist_remove (action->priv->group, action);

      for (slist = group; slist; slist = slist->next)
        {
          GimpRadioAction *tmp_action = slist->data;

          tmp_action->priv->group = group;
        }

      action->priv->group = NULL;
    }

  G_OBJECT_CLASS (parent_class)->dispose (object);
}

static void
gimp_radio_action_finalize (GObject *object)
{
  GimpRadioAction *action = GIMP_RADIO_ACTION (object);

  g_clear_pointer (&action->priv->group_label, g_free);

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
gimp_radio_action_get_property (GObject    *object,
                                guint       prop_id,
                                GValue     *value,
                                GParamSpec *pspec)
{
  GimpRadioAction *action = GIMP_RADIO_ACTION (object);

  switch (prop_id)
    {
    case PROP_VALUE:
      g_value_set_int (value, action->priv->value);
      break;
    case PROP_CURRENT_VALUE:
      g_value_set_int (value,
                       gimp_radio_action_get_current_value (action));
      break;
    case PROP_GROUP_LABEL:
      g_value_set_string (value,
                          gimp_radio_action_get_group_label (action));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gimp_radio_action_set_property (GObject      *object,
                                guint         prop_id,
                                const GValue *value,
                                GParamSpec   *pspec)
{
  GimpRadioAction *action = GIMP_RADIO_ACTION (object);

  switch (prop_id)
    {
    case PROP_VALUE:
      action->priv->value = g_value_get_int (value);
      break;
    case PROP_GROUP:
      {
        GimpRadioAction *arg;
        GSList          *slist = NULL;

        if (G_VALUE_HOLDS_OBJECT (value))
          {
            arg = GIMP_RADIO_ACTION (g_value_get_object (value));
            if (arg)
              slist = gimp_radio_action_get_group (arg);
            gimp_radio_action_set_group (action, slist);
          }
      }
    break;
    case PROP_GROUP_LABEL:
      gimp_radio_action_set_group_label (action, g_value_get_string (value));
      break;
    case PROP_CURRENT_VALUE:
      gimp_radio_action_set_current_value (action,
                                           g_value_get_int (value));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}


static gboolean
gimp_radio_action_get_enabled (GAction *action)
{
  GimpRadioAction *radio = GIMP_RADIO_ACTION (action);

  return gimp_radio_action_get_current_value (radio) != radio->priv->value &&
         gimp_action_is_sensitive (GIMP_ACTION (action), NULL);
}

static void
gimp_radio_action_change_state (GAction  *action,
                                GVariant *value)
{
  g_return_if_fail (GIMP_IS_ACTION (action));
  g_return_if_fail (value != NULL);
  g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_INT32));

  gimp_radio_action_set_current_value (GIMP_RADIO_ACTION (action),
                                       g_variant_get_int32 (value));
}

static const GVariantType *
gimp_radio_action_get_state_type (GAction *action)
{
  return G_VARIANT_TYPE_INT32;
}

static GVariant *
gimp_radio_action_get_state (GAction *action)
{
  GimpRadioAction *radio;
  GVariant        *state;

  g_return_val_if_fail (GIMP_IS_RADIO_ACTION (action), NULL);

  radio = GIMP_RADIO_ACTION (action);

  state = g_variant_new_int32 (gimp_radio_action_get_current_value (radio));

  return g_variant_ref_sink (state);
}

/* This is a bit on the ugly side. In order to be shown as a radio item when the
 * GUI is created by GTK (which happens either on macOS or with environment
 * variable GIMP_GTK_MENUBAR), the menu item requires a "target" attribute
 * (which is automatically added in GimpMenuModel) and the action needs to have
 * a parameter type of the right type.
 * In reality, how we use our radio actions is to have several tied actions
 * rather than a single action to which we pass a parameter (we ignore the
 * passed parameter anyway). This makes it a lot easier to have people assign
 * shortcuts to these.
 * So the ugly part is to add a parameter type here, even though the parameter
 * just won't be used.
 * See #9704.
 */

static const GVariantType *
gimp_radio_action_get_parameter_type (GAction *action)
{
  return G_VARIANT_TYPE_INT32;
}

static void
gimp_radio_action_activate (GAction  *action,
                            GVariant *parameter)
{
  GimpRadioAction *radio;

  g_return_if_fail (GIMP_IS_RADIO_ACTION (action));

  radio = GIMP_RADIO_ACTION (action);

  gimp_radio_action_set_current_value (radio, radio->priv->value);
  g_signal_emit_by_name (radio, "toggled");
}

static gboolean
gimp_radio_action_toggle (GimpToggleAction *action)
{
  gboolean active = gimp_toggle_action_get_active (action);

  if (! active)
    {
      GimpRadioAction *radio = GIMP_RADIO_ACTION (action);

      gimp_radio_action_set_current_value (radio, radio->priv->value);

      return gimp_toggle_action_get_active (action);
    }
  return FALSE;
}


/*  public functions  */

GimpAction *
gimp_radio_action_new (const gchar *name,
                       const gchar *label,
                       const gchar *short_label,
                       const gchar *tooltip,
                       const gchar *icon_name,
                       const gchar *help_id,
                       gint         value,
                       GimpContext *context)
{
  GimpAction *action;

  action = g_object_new (GIMP_TYPE_RADIO_ACTION,
                         "name",        name,
                         "label",       label,
                         "short-label", short_label,
                         "tooltip",     tooltip,
                         "icon-name",   icon_name,
                         "value",       value,
                         "context",     context,
                         NULL);

  gimp_action_set_help_id (action, help_id);

  return action;
}

GSList *
gimp_radio_action_get_group (GimpRadioAction *action)
{
  g_return_val_if_fail (GIMP_IS_RADIO_ACTION (action), NULL);

  return action->priv->group;
}

void
gimp_radio_action_set_group (GimpRadioAction *action,
                             GSList          *group)
{
  g_return_if_fail (GIMP_IS_RADIO_ACTION (action));
  g_return_if_fail (! g_slist_find (group, action));

  if (action->priv->group)
    {
      GSList *slist;

      action->priv->group = g_slist_remove (action->priv->group, action);

      for (slist = action->priv->group; slist; slist = slist->next)
        {
          GimpRadioAction *tmp_action = slist->data;

          tmp_action->priv->group = action->priv->group;
        }
    }

  action->priv->group = g_slist_prepend (group, action);
  g_clear_pointer (&action->priv->group_label, g_free);

  if (group)
    {
      GSList *slist;

      action->priv->group_label = g_strdup (GIMP_RADIO_ACTION (group->data)->priv->group_label);

      for (slist = action->priv->group; slist; slist = slist->next)
        {
          GimpRadioAction *tmp_action = slist->data;

          tmp_action->priv->group = action->priv->group;
        }
    }
  else
    {
      gimp_toggle_action_set_active (GIMP_TOGGLE_ACTION (action), TRUE);
    }

  g_object_notify (G_OBJECT (action), "group-label");
}

void
gimp_radio_action_set_group_label (GimpRadioAction *action,
                                   const gchar     *label)
{
  GSList *slist;

  g_return_if_fail (GIMP_IS_RADIO_ACTION (action));

  for (slist = action->priv->group; slist; slist = slist->next)
    {
      GimpRadioAction *tmp_action = slist->data;

      g_clear_pointer (&tmp_action->priv->group_label, g_free);

      if (label != NULL)
        tmp_action->priv->group_label = g_strdup (label);

      g_object_notify (G_OBJECT (tmp_action), "group-label");
    }
}

const gchar *
gimp_radio_action_get_group_label (GimpRadioAction *action)
{
  g_return_val_if_fail (GIMP_IS_RADIO_ACTION (action), NULL);

  return action->priv->group_label;
}

gint
gimp_radio_action_get_current_value (GimpRadioAction *action)
{
  GSList *slist;

  g_return_val_if_fail (GIMP_IS_RADIO_ACTION (action), 0);

  if (action->priv->group)
    {
      for (slist = action->priv->group; slist; slist = slist->next)
        {
          GimpToggleAction *toggle_action = slist->data;

          if (gimp_toggle_action_get_active (toggle_action))
            return GIMP_RADIO_ACTION (toggle_action)->priv->value;
        }
    }

  return action->priv->value;
}

void
gimp_radio_action_set_current_value (GimpRadioAction *action,
                                     gint             current_value)
{
  GSList           *slist;
  GimpToggleAction *changed1 = NULL;
  GimpToggleAction *changed2 = NULL;

  g_return_if_fail (GIMP_IS_RADIO_ACTION (action));

  if (action->priv->group)
    {
      for (slist = action->priv->group; slist; slist = slist->next)
        {
          GimpToggleAction *toggle = slist->data;
          GimpRadioAction  *radio  = slist->data;

          if (radio->priv->value == current_value &&
              gimp_toggle_action_get_active (toggle))
            {
              /* Value to set is already toggled. */
              return;
            }
          else if (radio->priv->value == current_value)
            {
              /* Change the "active" state but don't notify the property change
               * immediately. We want to notify both "active" properties
               * together so that we are always in consistent state.
               */

              _gimp_toggle_action_set_active (toggle, TRUE);
              changed1 = toggle;
            }
          else if (gimp_toggle_action_get_active (toggle))
            {
              changed2 = toggle;
            }
        }
    }

  if (! changed1)
    {
      g_warning ("Radio group does not contain an action with value '%d'",
                 current_value);
    }
  else
    {
      if (changed2)
        {
          _gimp_toggle_action_set_active (changed2, FALSE);
          g_object_notify (G_OBJECT (changed2), "active");
          g_signal_emit_by_name (changed2, "toggled");
          g_object_notify (G_OBJECT (changed2), "enabled");
          g_object_notify (G_OBJECT (changed2), "state");
        }
      g_object_notify (G_OBJECT (changed1), "active");

      for (slist = action->priv->group; slist; slist = slist->next)
        {
          g_object_notify (slist->data, "current-value");
          gimp_action_emit_change_state (GIMP_ACTION (slist->data),
                                         g_variant_new_int32 (current_value));
        }
      g_object_notify (G_OBJECT (changed1), "enabled");
      g_object_notify (G_OBJECT (changed1), "state");
    }
}

Messung
CHZG
81959690

¤ Dauer der Verarbeitung: 0.3 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.