<commit_before>/* GTK - The GIMP Toolkit
 *
 * Copyright (C) 2010  Intel Corporation
 * Copyright (C) 2010  RedHat, Inc.
 *
 * 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 2 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 <http://www.gnu.org/licenses/>.
 *
 * Author:
 *      <NAME> <<EMAIL>>
 *      <NAME> <<EMAIL>>
 *
 * Based on similar code from Mx.
 */

/**
 * SECTION:gtkswitch
 * @Short_Description: A “light switch” style toggle
 * @Title: GtkSwitch
 * @See_Also: #GtkToggleButton
 *
 * #GtkSwitch is a widget that has two states: on or off. The user can control
 * which state should be active by clicking the empty area, or by dragging the
 * handle.
 *
 * GtkSwitch can also handle situations where the underlying state changes with
 * a delay. See #GtkSwitch::state-set for details.
 */

#include "config.h"

#include "gtkswitch.h"

#include "deprecated/gtkactivatable.h"
#include "gtkintl.h"
#include "gtkprivate.h"
#include "deprecated/gtktoggleaction.h"
#include "gtkwidget.h"
#include "gtkmarshalers.h"
#include "gtkapplicationprivate.h"
#include "gtkactionable.h"
#include "a11y/gtkswitchaccessible.h"
#include "gtkactionhelper.h"
#include "gtkwidgetprivate.h"

#include <math.h>

#define DEFAULT_SLIDER_WIDTH    (36)

struct _GtkSwitchPrivate
{
  GdkWindow *event_window;
  GtkAction *action;
  GtkActionHelper *action_helper;

  GtkGesture *pan_gesture;
  GtkGesture *multipress_gesture;

  gint handle_x;
  gint offset;
  gint drag_start;
  gint drag_threshold;
  gint64 start_time;
  gint64 end_time;
  guint tick_id;

  guint state                 : 1;
  guint is_active             : 1;
  guint in_switch             : 1;
  guint use_action_appearance : 1;
};

enum
{
  PROP_0,
  PROP_ACTIVE,
  PROP_STATE,
  PROP_RELATED_ACTION,
  PROP_USE_ACTION_APPEARANCE,
  LAST_PROP,
  PROP_ACTION_NAME,
  PROP_ACTION_TARGET
};

enum
{
  ACTIVATE,
  STATE_SET,
  LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

static GParamSpec *switch_props[LAST_PROP] = { NULL, };

static void gtk_switch_actionable_iface_init (GtkActionableInterface *iface);
static void gtk_switch_activatable_interface_init (GtkActivatableIface *iface);

G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
G_DEFINE_TYPE_WITH_CODE (GtkSwitch, gtk_switch, GTK_TYPE_WIDGET,
                         G_ADD_PRIVATE (GtkSwitch)
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE,
                                                gtk_switch_actionable_iface_init)
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
                                                gtk_switch_activatable_interface_init));
G_GNUC_END_IGNORE_DEPRECATIONS;

/* From clutter-easing.c, based on <NAME>'s
 * infamous easing equations, MIT license.
 */
static gdouble
ease_out_cubic (gdouble t)
{
  gdouble p = t - 1;

  return p * p * p + 1;
}

static void
gtk_switch_end_toggle_animation (GtkSwitch *sw)
{
  GtkSwitchPrivate *priv = sw->priv;

  if (priv->tick_id != 0)
    {
      GdkFrameClock *clock = gtk_widget_get_frame_clock (GTK_WIDGET (sw));
      g_signal_handler_disconnect (clock, priv->tick_id);
      priv->tick_id = 0;
      gdk_frame_clock_end_updating (clock);
    }
}

static void
gtk_switch_on_frame_clock_update (GdkFrameClock *clock,
                                  GtkSwitch     *sw)
{
  GtkSwitchPrivate *priv = sw->priv;
  gint64 now;

  now = gdk_frame_clock_get_frame_time (clock);

  if (now < priv->end_time)
    {
      gdouble t;
      gint dest_offset;

      if (priv->is_active)
        dest_offset = 0;
      else
        dest_offset = gtk_widget_get_allocated_width (GTK_WIDGET (sw)) / 2;

      t = (now - priv->start_time) / (gdouble) (priv->end_time - priv->start_time);
      t = ease_out_cubic (t);
      priv->handle_x = priv->offset + t * (dest_offset - priv->offset);
    }
  else
    {
      gtk_switch_set_active (sw, !priv->is_active);
    }

  gtk_widget_queue_draw (GTK_WIDGET (sw));
}

#define ANIMATION_DURATION 100

static void
gtk_switch_begin_toggle_animation (GtkSwitch *sw)
{
  GtkSwitchPrivate *priv = sw->priv;
  gboolean animate;

  g_object_get (gtk_widget_get_settings (GTK_WIDGET (sw)),
                "gtk-enable-animations", &animate,
                NULL);

  if (animate)
    {
      GdkFrameClock *clock = gtk_widget_get_frame_clock (GTK_WIDGET (sw));
      priv->start_time = gdk_frame_clock_get_frame_time (clock);
      priv->end_time = priv->start_time + 1000 * ANIMATION_DURATION;
      priv->offset = priv->handle_x;
      if (priv->tick_id == 0)
        {
          priv->tick_id = g_signal_connect (clock, "update",
                                            G_CALLBACK (gtk_switch_on_frame_clock_update), sw);
          gdk_frame_clock_begin_updating (clock);
        }
    }
  else
    {
      gtk_switch_set_active (sw, !priv->is_active);<commit_msg>GtkSwitch: Use gtk_widget_add_tick_callback<commit_after>/* GTK - The GIMP Toolkit
 *
 * Copyright (C) 2010  Intel Corporation
 * Copyright (C) 2010  RedHat, Inc.
 *
 * 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 2 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 <http://www.gnu.org/licenses/>.
 *
 * Author:
 *      <NAME> <<EMAIL>>
 *      <NAME> <<EMAIL>>
 *
 * Based on similar code from Mx.
 */

/**
 * SECTION:gtkswitch
 * @Short_Description: A “light switch” style toggle
 * @Title: GtkSwitch
 * @See_Also: #GtkToggleButton
 *
 * #GtkSwitch is a widget that has two states: on or off. The user can control
 * which state should be active by clicking the empty area, or by dragging the
 * handle.
 *
 * GtkSwitch can also handle situations where the underlying state changes with
 * a delay. See #GtkSwitch::state-set for details.
 */

#include "config.h"

#include "gtkswitch.h"

#include "deprecated/gtkactivatable.h"
#include "gtkintl.h"
#include "gtkprivate.h"
#include "deprecated/gtktoggleaction.h"
#include "gtkwidget.h"
#include "gtkmarshalers.h"
#include "gtkapplicationprivate.h"
#include "gtkactionable.h"
#include "a11y/gtkswitchaccessible.h"
#include "gtkactionhelper.h"
#include "gtkwidgetprivate.h"

#include <math.h>

#define DEFAULT_SLIDER_WIDTH    (36)

struct _GtkSwitchPrivate
{
  GdkWindow *event_window;
  GtkAction *action;
  GtkActionHelper *action_helper;

  GtkGesture *pan_gesture;
  GtkGesture *multipress_gesture;

  gint handle_x;
  gint offset;
  gint drag_start;
  gint drag_threshold;
  gint64 start_time;
  gint64 end_time;
  guint tick_id;

  guint state                 : 1;
  guint is_active             : 1;
  guint in_switch             : 1;
  guint use_action_appearance : 1;
};

enum
{
  PROP_0,
  PROP_ACTIVE,
  PROP_STATE,
  PROP_RELATED_ACTION,
  PROP_USE_ACTION_APPEARANCE,
  LAST_PROP,
  PROP_ACTION_NAME,
  PROP_ACTION_TARGET
};

enum
{
  ACTIVATE,
  STATE_SET,
  LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

static GParamSpec *switch_props[LAST_PROP] = { NULL, };

static void gtk_switch_actionable_iface_init (GtkActionableInterface *iface);
static void gtk_switch_activatable_interface_init (GtkActivatableIface *iface);

G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
G_DEFINE_TYPE_WITH_CODE (GtkSwitch, gtk_switch, GTK_TYPE_WIDGET,
                         G_ADD_PRIVATE (GtkSwitch)
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE,
                                                gtk_switch_actionable_iface_init)
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
                                                gtk_switch_activatable_interface_init));
G_GNUC_END_IGNORE_DEPRECATIONS;

/* From clutter-easing.c, based on <NAME>'s
 * infamous easing equations, MIT license.
 */
static gdouble
ease_out_cubic (gdouble t)
{
  gdouble p = t - 1;

  return p * p * p + 1;
}

static void
gtk_switch_end_toggle_animation (GtkSwitch *sw)
{
  GtkSwitchPrivate *priv = sw->priv;

  if (priv->tick_id != 0)
    {
      gtk_widget_remove_tick_callback (GTK_WIDGET (sw), priv->tick_id);
      priv->tick_id = 0;
    }
}

static gboolean
gtk_switch_on_frame_clock_update (GtkWidget     *widget,
                                  GdkFrameClock *clock,
                                  gpointer       user_data)
{
  GtkSwitch *sw = GTK_SWITCH (widget);
  GtkSwitchPrivate *priv = sw->priv;
  gint64 now;

  now = gdk_frame_clock_get_frame_time (clock);

  if (now < priv->end_time)
    {
      gdouble t;
      gint dest_offset;

      if (priv->is_active)
        dest_offset = 0;
      else
        dest_offset = gtk_widget_get_allocated_width (GTK_WIDGET (sw)) / 2;

      t = (now - priv->start_time) / (gdouble) (priv->end_time - priv->start_time);
      t = ease_out_cubic (t);
      priv->handle_x = priv->offset + t * (dest_offset - priv->offset);
    }
  else
    {
      gtk_switch_set_active (sw, !priv->is_active);
    }

  gtk_widget_queue_draw (GTK_WIDGET (sw));

  return G_SOURCE_CONTINUE;
}

#define ANIMATION_DURATION 100

static void
gtk_switch_begin_toggle_animation (GtkSwitch *sw)
{
  GtkSwitchPrivate *priv = sw->priv;
  gboolean animate;

  g_object_get (gtk_widget_get_settings (GTK_WIDGET (sw)),
                "gtk-enable-animations", &animate,
                NULL);

  if (animate)
    {
      GdkFrameClock *clock = gtk_widget_get_frame_clock (GTK_WIDGET (sw));
      priv->start_time = gdk_frame_clock_get_frame_time (clock);
      priv->end_time = priv->start_time + 1000 * ANIMATION_DURATION;
      priv->offset = priv->handle_x;
      if (priv->tick_id == 0)
        priv->tick_id = gtk_widget_add_tick_callback (GTK_WIDGET (sw),
                                                      gtk_switch_on_frame_clock_update,
                                                      NULL, NULL);
    }
  else
    {
      gtk_switch_set_active (sw, !priv->is_active);
{'fraction_non_alphanumeric': 0.09057971014492754, 'fraction_numerical': 0.007246376811594203, 'mean_word_length': 2.9635493372606776, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 17, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2829870', 'n_tokens_mistral': 3746, 'n_tokens_neox': 3587, 'n_words': 905}