<commit_before>/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
 * mx-notebook: notebook actor
 *
 * Copyright 2009, 2010 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Written by: <NAME> <<EMAIL>>
 *
 */

#include <config.h>
#include "mx-notebook.h"
#include "mx-private.h"
#ifdef HAVE_CLUTTER_GESTURE
#include <clutter-gesture/clutter-gesture.h>
#endif

static void clutter_container_iface_init (ClutterContainerIface *iface);

G_DEFINE_TYPE_WITH_CODE (MxNotebook, mx_notebook, MX_TYPE_WIDGET,
                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
                                                clutter_container_iface_init))

#define NOTEBOOK_PRIVATE(o) \
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), MX_TYPE_NOTEBOOK, MxNotebookPrivate))

struct _MxNotebookPrivate
{
  ClutterActor *current_page;

  GList *children;

  gboolean enable_gestures;

#if HAVE_CLUTTER_GESTURE
  ClutterGesture *gesture;
#endif
};

enum
{
  PROP_CURRENT_PAGE = 1,
  PROP_ENABLE_GESTURES
};

static void
mx_notebook_show_complete_cb (MxNotebook *book)
{
  MxNotebookPrivate *priv = book->priv;
  GList *l;

  for (l = priv->children; l; l = l->next)
    {
      ClutterActor *child = CLUTTER_ACTOR (l->data);
      if (child != priv->current_page)
        {
          clutter_actor_hide (child);
          clutter_actor_set_opacity (child, 0x00);
        }
    }
}

static void
mx_notebook_update_children (MxNotebook *book)
{
  MxNotebookPrivate *priv = book->priv;
  GList *l;

  for (l = priv->children; l; l = l->next)
    {
      ClutterActor *child = CLUTTER_ACTOR (l->data);
      ClutterAnimation *anim = clutter_actor_get_animation (child);

      if (anim)
        {
          /* A bit of a hack - we want to just abort the animation,
           * but there's no way of aborting an animation that was
           * started with clutter_actor_animate().
           */
          guint8 opacity = clutter_actor_get_opacity (child);
          g_signal_handlers_disconnect_by_func (anim,
                                                mx_notebook_show_complete_cb,
                                                book);
          clutter_animation_completed (anim);
          clutter_actor_set_opacity (child, opacity);
        }

      if (child == priv->current_page)
        {
          clutter_actor_show (child);
          clutter_actor_animate (child, CLUTTER_LINEAR, 250,
                                 "opacity", 255,
                                 "signal-swapped::completed",
                                   mx_notebook_show_complete_cb,
                                   book,
                                 NULL);
        }
    }
}

static void
mx_notebook_add (ClutterContainer *container,
                 ClutterActor     *actor)
{
  MxNotebookPrivate *priv = MX_NOTEBOOK (container)->priv;

  clutter_actor_set_parent (actor, CLUTTER_ACTOR (container));
  priv->children = g_list_append (priv->children, actor);

  if (!priv->current_page)
    {
      priv->current_page = actor;
      clutter_actor_set_opacity (actor, 0xff);
      g_object_notify (G_OBJECT (container), "current-page");
    }
  else
    clutter_actor_hide (actor);

  g_signal_emit_by_name (container, "actor-added", actor);
}

static void
mx_notebook_remove (ClutterContainer *container,
                    ClutterActor     *actor)
{
  MxNotebookPrivate *priv = MX_NOTEBOOK (container)->priv;

  GList *item = NULL;

  item = g_list_find (priv->children, actor);

  if (item == NULL)
    {
      g_warning ("Actor of type '%s' is not a child of container of type '%s'",
                 g_type_name (G_OBJECT_TYPE (actor)),
                 g_type_name (G_OBJECT_TYPE (container)));
      return;
    }

  /* If it was the current page, select either the previous or
   * the next, whichever exists first.
   */
  if (actor == priv->current_page)
    {
      priv->current_page = item->prev ? item->prev->data :
        (item->next ? item->next->data : NULL);
      g_object_notify (G_OBJECT (container), "current-page");
    }

  g_object_ref (actor);

  priv->children = g_list_delete_link (priv->children, item);
  clutter_actor_unparent (actor);

  g_signal_emit_by_name (container, "actor-removed", actor);

  g_object_unref (actor);

  mx_notebook_update_children (MX_NOTEBOOK (container));
}

static void
mx_notebook_foreach (ClutterContainer *container,
                     ClutterCallback   callback,
                     gpointer          callback_data)
{
  MxNotebookPrivate *priv = MX_NOTEBOOK (container)->priv;

  g_list_foreach (priv->children, (GFunc) callback, callback_data);
}

static void
clutter_container_iface_init (ClutterContainerIface *iface)
{
  iface->add = mx_notebook_add;
  iface->remove = mx_notebook_remove;
  iface->foreach = mx_notebook_foreach;
}


static void
mx_notebook_get_property (GObject    *object,
                          guint       property_id,
                          GValue     *value,
                          GParamSpec *pspec)
{
  MxNotebookPrivate *priv = MX_NOTEBOOK (object)->priv;

  switch (property_id)
    {
    case PROP_CURRENT_PAGE:
      g_value_set_object (value, priv->current_page);
      break;

    case PROP_ENABLE_GESTURES:
      g_value_set_boolean (value, priv->enable_gestures);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);<commit_msg>notebook: Implement MxFocusable<commit_after>/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
 * mx-notebook: notebook actor
 *
 * Copyright 2009, 2010 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Written by: <NAME> <<EMAIL>>
 *
 */

#include <config.h>
#include "mx-notebook.h"
#include "mx-private.h"
#include "mx-focusable.h"
#ifdef HAVE_CLUTTER_GESTURE
#include <clutter-gesture/clutter-gesture.h>
#endif

static void clutter_container_iface_init (ClutterContainerIface *iface);
static void mx_focusable_iface_init (MxFocusableIface *iface);

G_DEFINE_TYPE_WITH_CODE (MxNotebook, mx_notebook, MX_TYPE_WIDGET,
                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
                                                clutter_container_iface_init)
                         G_IMPLEMENT_INTERFACE (MX_TYPE_FOCUSABLE,
                                                mx_focusable_iface_init))

#define NOTEBOOK_PRIVATE(o) \
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), MX_TYPE_NOTEBOOK, MxNotebookPrivate))

struct _MxNotebookPrivate
{
  ClutterActor *current_page;

  GList *children;

  gboolean enable_gestures;

#if HAVE_CLUTTER_GESTURE
  ClutterGesture *gesture;
#endif
};

enum
{
  PROP_CURRENT_PAGE = 1,
  PROP_ENABLE_GESTURES
};

static void
mx_notebook_show_complete_cb (MxNotebook *book)
{
  MxNotebookPrivate *priv = book->priv;
  GList *l;

  for (l = priv->children; l; l = l->next)
    {
      ClutterActor *child = CLUTTER_ACTOR (l->data);
      if (child != priv->current_page)
        {
          clutter_actor_hide (child);
          clutter_actor_set_opacity (child, 0x00);
        }
    }
}

static void
mx_notebook_update_children (MxNotebook *book)
{
  MxNotebookPrivate *priv = book->priv;
  GList *l;

  for (l = priv->children; l; l = l->next)
    {
      ClutterActor *child = CLUTTER_ACTOR (l->data);
      ClutterAnimation *anim = clutter_actor_get_animation (child);

      if (anim)
        {
          /* A bit of a hack - we want to just abort the animation,
           * but there's no way of aborting an animation that was
           * started with clutter_actor_animate().
           */
          guint8 opacity = clutter_actor_get_opacity (child);
          g_signal_handlers_disconnect_by_func (anim,
                                                mx_notebook_show_complete_cb,
                                                book);
          clutter_animation_completed (anim);
          clutter_actor_set_opacity (child, opacity);
        }

      if (child == priv->current_page)
        {
          clutter_actor_show (child);
          clutter_actor_animate (child, CLUTTER_LINEAR, 250,
                                 "opacity", 255,
                                 "signal-swapped::completed",
                                   mx_notebook_show_complete_cb,
                                   book,
                                 NULL);
        }
    }
}

static void
mx_notebook_add (ClutterContainer *container,
                 ClutterActor     *actor)
{
  MxNotebookPrivate *priv = MX_NOTEBOOK (container)->priv;

  clutter_actor_set_parent (actor, CLUTTER_ACTOR (container));
  priv->children = g_list_append (priv->children, actor);

  if (!priv->current_page)
    {
      priv->current_page = actor;
      clutter_actor_set_opacity (actor, 0xff);
      g_object_notify (G_OBJECT (container), "current-page");
    }
  else
    clutter_actor_hide (actor);

  g_signal_emit_by_name (container, "actor-added", actor);
}

static void
mx_notebook_remove (ClutterContainer *container,
                    ClutterActor     *actor)
{
  MxNotebookPrivate *priv = MX_NOTEBOOK (container)->priv;

  GList *item = NULL;

  item = g_list_find (priv->children, actor);

  if (item == NULL)
    {
      g_warning ("Actor of type '%s' is not a child of container of type '%s'",
                 g_type_name (G_OBJECT_TYPE (actor)),
                 g_type_name (G_OBJECT_TYPE (container)));
      return;
    }

  /* If it was the current page, select either the previous or
   * the next, whichever exists first.
   */
  if (actor == priv->current_page)
    {
      priv->current_page = item->prev ? item->prev->data :
        (item->next ? item->next->data : NULL);
      g_object_notify (G_OBJECT (container), "current-page");
    }

  g_object_ref (actor);

  priv->children = g_list_delete_link (priv->children, item);
  clutter_actor_unparent (actor);

  g_signal_emit_by_name (container, "actor-removed", actor);

  g_object_unref (actor);

  mx_notebook_update_children (MX_NOTEBOOK (container));
}

static void
mx_notebook_foreach (ClutterContainer *container,
                     ClutterCallback   callback,
                     gpointer          callback_data)
{
  MxNotebookPrivate *priv = MX_NOTEBOOK (container)->priv;

  g_list_foreach (priv->children, (GFunc) callback, callback_data);
}

static void
clutter_container_iface_init (ClutterContainerIface *iface)
{
  iface->add = mx_notebook_add;
  iface->remove = mx_notebook_remove;
  iface->foreach = mx_notebook_foreach;
}

static MxFocusable *
mx_notebook_accept_focus (MxFocusable *focusable,
                          MxFocusHint  hint)
{
  MxNotebookPrivate *priv = MX_NOTEBOOK (focusable)->priv;

  if (priv->current_page && MX_IS_FOCUSABLE (priv->current_page))
    return mx_focusable_accept_focus (MX_FOCUSABLE (priv->current_page), hint);
  else
    return NULL;
}

static MxFocusable *
mx_notebook_move_focus (MxFocusable      *focusable,
                        MxFocusDirection  direction,
                        MxFocusable      *from)
{
  return NULL;
}

static void
mx_focusable_iface_init (MxFocusableIface *iface)
{
  iface->accept_focus = mx_notebook_accept_focus;
  iface->move_focus = mx_notebook_move_focus;
}

static void
mx_notebook_get_property (GObject    *object,
                          guint       property_id,
                          GValue     *value,
                          GParamSpec *pspec)
{
  MxNotebookPrivate *priv = MX_NOTEBOOK (object)->priv;

  switch (property_id)
    {
    case PROP_CURRENT_PAGE:
      g_value_set_object (value, priv->current_page);
      break;

    case PROP_ENABLE_GESTURES:
      g_value_set_boolean (value, priv->enable_gestures);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
{'fraction_non_alphanumeric': 0.09128535295470223, 'fraction_numerical': 0.005058634168774431, 'mean_word_length': 2.5806805708013174, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 89, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4963193', 'n_tokens_mistral': 4146, 'n_tokens_neox': 4013, 'n_words': 986}