<commit_before>/*
 * Clutter-GStreamer.
 *
 * GStreamer integration library for Clutter.
 *
 * video-player.c - A simple video player with an OSD.
 *
 * Copyright (C) 2007,2008 OpenedHand
 *
 * 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, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <stdlib.h>

#include <clutter/clutter.h>
#include <clutter-gst/clutter-gst.h>

#define SEEK_H 14
#define SEEK_W 440

typedef struct _VideoApp
{
  ClutterActor *stage;

  ClutterActor *vtexture;

  ClutterActor *control;
  ClutterActor *control_bg;
  ClutterActor *control_label;

  ClutterActor *control_play, *control_pause;

  ClutterActor *control_seek1, *control_seek2, *control_seekbar;

  gboolean      controls_showing, paused;

  guint         controls_timeout;
} VideoApp;

static void show_controls (VideoApp *app, gboolean vis);

static gboolean opt_fullscreen = FALSE;
static gboolean opt_loop = FALSE;

static GOptionEntry options[] =
{
  { "fullscreen",
    'f', 0,
    G_OPTION_ARG_NONE,
    &opt_fullscreen,
    "Start the player in fullscreen",
    NULL },

  { "loop",
    'l', 0,
    G_OPTION_ARG_NONE,
    &opt_loop,
    "Start the video again once reached the EOS",
    NULL },

  { NULL }
};

static gboolean
controls_timeout_cb (gpointer data)
{
  VideoApp *app = data;

  app->controls_timeout = 0;
  show_controls (app, FALSE);

  return FALSE;
}

static void
show_controls (VideoApp *app, gboolean vis)
{
  if (app->control == NULL)
    return;

  if (vis == TRUE && app->controls_showing == TRUE)
    {
      if (app->controls_timeout == 0)
        {
          app->controls_timeout =
            g_timeout_add_seconds (5, controls_timeout_cb, app);
        }

      return;
    }

  if (vis == TRUE && app->controls_showing == FALSE)
    {
      app->controls_showing = TRUE;

      clutter_stage_show_cursor (CLUTTER_STAGE (app->stage));
      clutter_actor_animate (app->control, CLUTTER_EASE_OUT_QUINT, 250,
                             "opacity", 224,
                             NULL);

      return;
    }

  if (vis == FALSE && app->controls_showing == TRUE)
    {
      app->controls_showing = FALSE;

      clutter_stage_hide_cursor (CLUTTER_STAGE (app->stage));
      clutter_actor_animate (app->control, CLUTTER_EASE_OUT_QUINT, 250,
                             "opacity", 0,
                             NULL);
      return;
    }
}

void
toggle_pause_state (VideoApp *app)
{
  if (app->vtexture == NULL)
    return;

  if (app->paused)
    {
      clutter_media_set_playing (CLUTTER_MEDIA(app->vtexture),
                                 TRUE);
      app->paused = FALSE;
      clutter_actor_hide (app->control_play);
      clutter_actor_show (app->control_pause);
    }
  else
    {
      clutter_media_set_playing (CLUTTER_MEDIA(app->vtexture),
                                 FALSE);
      app->paused = TRUE;
      clutter_actor_hide (app->control_pause);
      clutter_actor_show (app->control_play);
    }
}

static void
reset_animation (ClutterAnimation *animation,
                 VideoApp         *app)
{
  if (app->vtexture)
    clutter_actor_set_rotation (app->vtexture, CLUTTER_Y_AXIS, 0.0, 0, 0, 0);
}

static gboolean
input_cb (ClutterStage *stage,
          ClutterEvent *event,
          gpointer      user_data)
{
  VideoApp *app = (VideoApp*)user_data;
  gboolean handled = FALSE;

  switch (event->type)
    {
    case CLUTTER_MOTION:
      show_controls (app, TRUE);
      handled = TRUE;
      break;

    case CLUTTER_BUTTON_PRESS:
      if (app->controls_showing)
        {
          ClutterActor       *actor;
          ClutterButtonEvent *bev = (ClutterButtonEvent *) event;

          actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL,
                                                  bev->x,
                                                  bev->y);

          if (actor == app->control_pause || actor == app->control_play)
            {
              toggle_pause_state (app);
            }
          else if (actor == app->control_seek1 ||
                   actor == app->control_seek2 ||
                   actor == app->control_seekbar)
            {
              gfloat x, y, dist;
              gdouble progress;

              clutter_actor_get_transformed_position (app->control_seekbar,
                                                      &x, &y);

              dist = bev->x - x;

              dist = CLAMP (dist, 0, SEEK_W);

              progress = (gdouble) dist / SEEK_W;

              clutter_media_set_progress (CLUTTER_MEDIA (app->vtexture),
                                          progress);
            }
        }
      handled = TRUE;
      break;

    case CLUTTER_KEY_PRESS:
      {
        ClutterVertex center = { 0, };
        ClutterAnimation *animation = NULL;

        switch (clutter_event_get_key_symbol (event))
          {
          case CLUTTER_d:
            if (app->vtexture)
              {
                clutter_container_remove_actor (CLUTTER_CONTAINER (app->stage),
                                                app->vtexture);
                app->vtexture = NULL;
              }
            if (app->control)
              {
                clutter_container_remove_actor (CLUTTER_CONTAINER (app->stage),
                                                app->control);
                app->control = NULL;
              }
            break;
          case CLUTTER_q:
          case CLUTTER_Escape:
            clutter_actor_destroy (app->stage);
            break;

          case CLUTTER_e:
            if (app->vtexture == NULL)
              break;

            center.x = clutter_actor_get_width (app->vtexture) / 2;

            animation =
              clutter_actor_animate (app->vtexture, CLUTTER_LINEAR, 500,
                                     "rotation-angle-y", 360.0,
                                     "fixed::rotation-center-y", &center,
                                     NULL);
            g_signal_connect (animation, "completed",
                              G_CALLBACK (reset_animation),
                              app);
            handled = TRUE;
            break;

          default:
            toggle_pause_state (app);
            handled = TRUE;<commit_msg>videoplayer: fix reset_animaton so it can be performed more than once<commit_after>/*
 * Clutter-GStreamer.
 *
 * GStreamer integration library for Clutter.
 *
 * video-player.c - A simple video player with an OSD.
 *
 * Copyright (C) 2007,2008 OpenedHand
 *
 * 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, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <stdlib.h>

#include <clutter/clutter.h>
#include <clutter-gst/clutter-gst.h>

#define SEEK_H 14
#define SEEK_W 440

typedef struct _VideoApp
{
  ClutterActor *stage;

  ClutterActor *vtexture;

  ClutterActor *control;
  ClutterActor *control_bg;
  ClutterActor *control_label;

  ClutterActor *control_play, *control_pause;

  ClutterActor *control_seek1, *control_seek2, *control_seekbar;

  gboolean      controls_showing, paused;

  guint         controls_timeout;
} VideoApp;

static void show_controls (VideoApp *app, gboolean vis);

static gboolean opt_fullscreen = FALSE;
static gboolean opt_loop = FALSE;

static GOptionEntry options[] =
{
  { "fullscreen",
    'f', 0,
    G_OPTION_ARG_NONE,
    &opt_fullscreen,
    "Start the player in fullscreen",
    NULL },

  { "loop",
    'l', 0,
    G_OPTION_ARG_NONE,
    &opt_loop,
    "Start the video again once reached the EOS",
    NULL },

  { NULL }
};

static gboolean
controls_timeout_cb (gpointer data)
{
  VideoApp *app = data;

  app->controls_timeout = 0;
  show_controls (app, FALSE);

  return FALSE;
}

static void
show_controls (VideoApp *app, gboolean vis)
{
  if (app->control == NULL)
    return;

  if (vis == TRUE && app->controls_showing == TRUE)
    {
      if (app->controls_timeout == 0)
        {
          app->controls_timeout =
            g_timeout_add_seconds (5, controls_timeout_cb, app);
        }

      return;
    }

  if (vis == TRUE && app->controls_showing == FALSE)
    {
      app->controls_showing = TRUE;

      clutter_stage_show_cursor (CLUTTER_STAGE (app->stage));
      clutter_actor_animate (app->control, CLUTTER_EASE_OUT_QUINT, 250,
                             "opacity", 224,
                             NULL);

      return;
    }

  if (vis == FALSE && app->controls_showing == TRUE)
    {
      app->controls_showing = FALSE;

      clutter_stage_hide_cursor (CLUTTER_STAGE (app->stage));
      clutter_actor_animate (app->control, CLUTTER_EASE_OUT_QUINT, 250,
                             "opacity", 0,
                             NULL);
      return;
    }
}

void
toggle_pause_state (VideoApp *app)
{
  if (app->vtexture == NULL)
    return;

  if (app->paused)
    {
      clutter_media_set_playing (CLUTTER_MEDIA(app->vtexture),
                                 TRUE);
      app->paused = FALSE;
      clutter_actor_hide (app->control_play);
      clutter_actor_show (app->control_pause);
    }
  else
    {
      clutter_media_set_playing (CLUTTER_MEDIA(app->vtexture),
                                 FALSE);
      app->paused = TRUE;
      clutter_actor_hide (app->control_pause);
      clutter_actor_show (app->control_play);
    }
}

static void
reset_animation (ClutterAnimation *animation,
                 VideoApp         *app)
{
  if (app->vtexture)
    clutter_actor_set_rotation (app->vtexture, CLUTTER_Y_AXIS, 0.0, 0, 0, 0);
}

static gboolean
input_cb (ClutterStage *stage,
          ClutterEvent *event,
          gpointer      user_data)
{
  VideoApp *app = (VideoApp*)user_data;
  gboolean handled = FALSE;

  switch (event->type)
    {
    case CLUTTER_MOTION:
      show_controls (app, TRUE);
      handled = TRUE;
      break;

    case CLUTTER_BUTTON_PRESS:
      if (app->controls_showing)
        {
          ClutterActor       *actor;
          ClutterButtonEvent *bev = (ClutterButtonEvent *) event;

          actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_ALL,
                                                  bev->x,
                                                  bev->y);

          if (actor == app->control_pause || actor == app->control_play)
            {
              toggle_pause_state (app);
            }
          else if (actor == app->control_seek1 ||
                   actor == app->control_seek2 ||
                   actor == app->control_seekbar)
            {
              gfloat x, y, dist;
              gdouble progress;

              clutter_actor_get_transformed_position (app->control_seekbar,
                                                      &x, &y);

              dist = bev->x - x;

              dist = CLAMP (dist, 0, SEEK_W);

              progress = (gdouble) dist / SEEK_W;

              clutter_media_set_progress (CLUTTER_MEDIA (app->vtexture),
                                          progress);
            }
        }
      handled = TRUE;
      break;

    case CLUTTER_KEY_PRESS:
      {
        ClutterVertex center = { 0, };
        ClutterAnimation *animation = NULL;

        switch (clutter_event_get_key_symbol (event))
          {
          case CLUTTER_d:
            if (app->vtexture)
              {
                clutter_container_remove_actor (CLUTTER_CONTAINER (app->stage),
                                                app->vtexture);
                app->vtexture = NULL;
              }
            if (app->control)
              {
                clutter_container_remove_actor (CLUTTER_CONTAINER (app->stage),
                                                app->control);
                app->control = NULL;
              }
            break;
          case CLUTTER_q:
          case CLUTTER_Escape:
            clutter_actor_destroy (app->stage);
            break;

          case CLUTTER_e:
            if (app->vtexture == NULL)
              break;

            center.x = clutter_actor_get_width (app->vtexture) / 2;

            animation =
              clutter_actor_animate (app->vtexture, CLUTTER_LINEAR, 500,
                                     "rotation-angle-y", 360.0,
                                     "fixed::rotation-center-y", &center,
                                     NULL);
            g_signal_connect_after (animation, "completed",
                              G_CALLBACK (reset_animation),
                              app);
            handled = TRUE;
            break;

          default:
            toggle_pause_state (app);
            handled = TRUE;
{'fraction_non_alphanumeric': 0.09062635614060466, 'fraction_numerical': 0.008968609865470852, 'mean_word_length': 1.777063667403093, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 107, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 34, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3913600', 'n_tokens_mistral': 4162, 'n_tokens_neox': 3946, 'n_words': 997}