From f6fce05ee94320db0ffbf4eab12e5fd86777ac92 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Mon, 24 May 2010 10:41:19 +0100 Subject: [PATCH] action: Add ClickAction ClickAction adds "clickable" semantics to an actor. It provides all the business logic to emit a high-level "clicked" signal from the various low-level signals inside ClutterActor. --- clutter/Makefile.am | 2 + clutter/clutter-click-action.c | 309 +++++++++++++++++++++++++++++++++++++++++ clutter/clutter-click-action.h | 97 +++++++++++++ clutter/clutter.h | 1 + 4 files changed, 409 insertions(+) create mode 100644 clutter/clutter-click-action.c create mode 100644 clutter/clutter-click-action.h diff --git a/clutter/Makefile.am b/clutter/Makefile.am index b71d1e6..e40d8c4 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -88,6 +88,7 @@ source_h = \ $(srcdir)/clutter-box-layout.h \ $(srcdir)/clutter-cairo-texture.h \ $(srcdir)/clutter-child-meta.h \ + $(srcdir)/clutter-click-action.h \ $(srcdir)/clutter-clone.h \ $(srcdir)/clutter-color.h \ $(srcdir)/clutter-constraint.h \ @@ -169,6 +170,7 @@ source_c = \ $(srcdir)/clutter-box-layout.c \ $(srcdir)/clutter-cairo-texture.c \ $(srcdir)/clutter-child-meta.c \ + $(srcdir)/clutter-click-action.c \ $(srcdir)/clutter-clone.c \ $(srcdir)/clutter-color.c \ $(srcdir)/clutter-constraint.c \ diff --git a/clutter/clutter-click-action.c b/clutter/clutter-click-action.c new file mode 100644 index 0000000..609b848 --- /dev/null +++ b/clutter/clutter-click-action.c @@ -0,0 +1,309 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corporation. + * + * 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 . + * + * Author: + * Emmanuele Bassi + */ + +/** + * SECTION:clutter-click-action + * @Title: ClutterClickAction + * @Short_Description: Action for clickable actors + * + * #ClutterClickAction is a sub-class of #ClutterAction that implements + * the logic for clickable actors, by using the low level events of + * #ClutterActor, such as #ClutterActor::button-press-event and + * #ClutterActor::button-release-event, to synthesize the high level + * #ClutterClickAction::clicked signal. + * + * To use #ClutterClickAction you just need to apply it to a #ClutterActor + * using clutter_actor_add_action() and connect to the + * #ClutterClickAction::clicked signal: + * + * |[ + * ClutterAction *action = clutter_click_action_new (); + * + * clutter_actor_add_action (actor, action); + * + * g_signal_connect (action, "clicked", G_CALLBACK (on_clicked), NULL); + * ]| + * + * #ClutterClickAction is available since Clutter 1.4 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clutter-click-action.h" + +#include "clutter-debug.h" +#include "clutter-enum-types.h" +#include "clutter-marshal.h" +#include "clutter-private.h" + +struct _ClutterClickActionPrivate +{ + guint event_id; + + guint press_button; + + guint is_held : 1; + guint is_pressed : 1; +}; + +enum +{ + PROP_0, + + PROP_HELD, + PROP_PRESSED +}; + +enum +{ + CLICKED, + + LAST_SIGNAL +}; + +static guint click_signals[LAST_SIGNAL] = { 0, }; + +G_DEFINE_TYPE (ClutterClickAction, clutter_click_action, CLUTTER_TYPE_ACTION); + +static inline void +click_action_set_pressed (ClutterClickAction *action, + gboolean is_pressed) +{ + ClutterClickActionPrivate *priv = action->priv; + + if (priv->is_pressed == is_pressed) + return; + + priv->is_pressed = is_pressed; + g_object_notify (G_OBJECT (action), "pressed"); +} + +static gboolean +actor_contains_source (ClutterActor *actor, + ClutterActor *event_source) +{ + while (event_source != NULL && event_source != actor) + event_source = clutter_actor_get_parent (event_source); + + return event_source != NULL; +} + +static gboolean +on_event (ClutterActor *actor, + ClutterEvent *event, + ClutterClickAction *action) +{ + ClutterClickActionPrivate *priv = action->priv; + gboolean res = FALSE; + + if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (action))) + return FALSE; + + switch (clutter_event_type (event)) + { + case CLUTTER_BUTTON_PRESS: + if (clutter_event_get_click_count (event) != 1) + return FALSE; + + if (priv->is_held) + return TRUE; + + if (!actor_contains_source (actor, clutter_event_get_source (event))) + return FALSE; + + priv->is_held = TRUE; + priv->press_button = clutter_event_get_button (event); + clutter_grab_pointer (actor); + + click_action_set_pressed (action, TRUE); + res = TRUE; + break; + + case CLUTTER_BUTTON_RELEASE: + if (clutter_event_get_button (event) != priv->press_button || + clutter_event_get_click_count (event) != 1) + return FALSE; + + if (!priv->is_held) + return TRUE; + + priv->is_held = FALSE; + clutter_ungrab_pointer (); + + if (!actor_contains_source (actor, clutter_event_get_source (event))) + return FALSE; + + click_action_set_pressed (action, FALSE); + g_signal_emit (action, click_signals[CLICKED], 0, actor); + res = TRUE; + break; + + case CLUTTER_ENTER: + click_action_set_pressed (action, priv->is_held); + break; + + case CLUTTER_LEAVE: + click_action_set_pressed (action, priv->is_held); + break; + + default: + break; + } + + return FALSE; +} + +static void +clutter_click_action_set_actor (ClutterActorMeta *meta, + ClutterActor *actor) +{ + ClutterClickActionPrivate *priv = CLUTTER_CLICK_ACTION (meta)->priv; + + if (priv->event_id != 0) + { + ClutterActor *old_actor = clutter_actor_meta_get_actor (meta); + + g_signal_handler_disconnect (old_actor, priv->event_id); + priv->event_id = 0; + } + + if (actor != NULL) + priv->event_id = g_signal_connect (actor, "event", + G_CALLBACK (on_event), + meta); + + CLUTTER_ACTOR_META_CLASS (clutter_click_action_parent_class)->set_actor (meta, actor); +} + +static void +clutter_click_action_get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ClutterClickActionPrivate *priv = CLUTTER_CLICK_ACTION (gobject)->priv; + + switch (prop_id) + { + case PROP_HELD: + g_value_set_boolean (value, priv->is_held); + break; + + case PROP_PRESSED: + g_value_set_boolean (value, priv->is_pressed); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } +} + +static void +clutter_click_action_class_init (ClutterClickActionClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); + GParamSpec *pspec; + + g_type_class_add_private (klass, sizeof (ClutterClickActionPrivate)); + + meta_class->set_actor = clutter_click_action_set_actor; + + gobject_class->get_property = clutter_click_action_get_property; + + /** + * ClutterClickAction:pressed: + * + * Whether the clickable actor should be in "pressed" state + * + * Since: 1.4 + */ + pspec = g_param_spec_boolean ("pressed", + "Pressed", + "Whether the clickable should " + "be in pressed state", + FALSE, + CLUTTER_PARAM_READABLE); + g_object_class_install_property (gobject_class, PROP_PRESSED, pspec); + + /** + * ClutterClickAction:held: + * + * Whether the clickable actor has the pointer grabbed + * + * Since: 1.4 + */ + pspec = g_param_spec_boolean ("held", + "Held", + "Whether the clickable has a grab", + FALSE, + CLUTTER_PARAM_READABLE); + g_object_class_install_property (gobject_class, PROP_HELD, pspec); + + /** + * ClutterClickAction::clicked: + * @action: the #ClutterClickAction that emitted the signal + * @actor: the #ClutterActor attached to the @action + * + * The ::clicked signal is emitted when the #ClutterActor to which + * a #ClutterClickAction has been applied should respond to a + * pointer button press and release events + * + * Since: 1.4 + */ + click_signals[CLICKED] = + g_signal_new (I_("clicked"), + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (ClutterClickActionClass, clicked), + NULL, NULL, + clutter_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + CLUTTER_TYPE_ACTOR); +} + +static void +clutter_click_action_init (ClutterClickAction *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, CLUTTER_TYPE_CLICK_ACTION, + ClutterClickActionPrivate); +} + +/** + * clutter_click_action_new: + * + * Creates a new #ClutterClickAction instance + * + * Return value: the newly created #ClutterClickAction + * + * Since: 1.4 + */ +ClutterAction * +clutter_click_action_new (void) +{ + return g_object_new (CLUTTER_TYPE_CLICK_ACTION, NULL); +} diff --git a/clutter/clutter-click-action.h b/clutter/clutter-click-action.h new file mode 100644 index 0000000..6be6386 --- /dev/null +++ b/clutter/clutter-click-action.h @@ -0,0 +1,97 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corporation. + * + * 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 . + * + * Author: + * Emmanuele Bassi + */ + +#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __CLUTTER_CLICK_ACTION_H__ +#define __CLUTTER_CLICK_ACTION_H__ + +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_CLICK_ACTION (clutter_click_action_get_type ()) +#define CLUTTER_CLICK_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CLICK_ACTION, ClutterClickAction)) +#define CLUTTER_IS_CLICK_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CLICK_ACTION)) +#define CLUTTER_CLICK_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_CLICK_ACTION, ClutterClickActionClass)) +#define CLUTTER_IS_CLICK_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_CLICK_ACTION)) +#define CLUTTER_CLICK_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_CLICK_ACTION, ClutterClickActionClass)) + +typedef struct _ClutterClickAction ClutterClickAction; +typedef struct _ClutterClickActionPrivate ClutterClickActionPrivate; +typedef struct _ClutterClickActionClass ClutterClickActionClass; + +/** + * ClutterClickAction: + * + * The ClutterClickAction structure contains + * only private data and should be accessed using the provided API + * + * Since: 1.4 + */ +struct _ClutterClickAction +{ + /*< private >*/ + ClutterAction parent_instance; + + ClutterClickActionPrivate *priv; +}; + +/** + * ClutterClickActionClass: + * @clicked: class handler for the #ClutterClickAction::clicked signal + * + * The ClutterClickActionClass structure + * contains only private data + * + * Since: 1.4 + */ +struct _ClutterClickActionClass +{ + /*< private >*/ + ClutterActionClass parent_class; + + /*< public >*/ + void (* clicked) (ClutterClickAction *action, + ClutterActor *actor); + + /*< private >*/ + void (* _clutter_click_action1) (void); + void (* _clutter_click_action2) (void); + void (* _clutter_click_action3) (void); + void (* _clutter_click_action4) (void); + void (* _clutter_click_action5) (void); + void (* _clutter_click_action6) (void); + void (* _clutter_click_action7) (void); +}; + +GType clutter_click_action_get_type (void) G_GNUC_CONST; + +ClutterAction *clutter_click_action_new (void); + +G_END_DECLS + +#endif /* __CLUTTER_CLICK_ACTION_H__ */ diff --git a/clutter/clutter.h b/clutter/clutter.h index 9779025..0e7c2d7 100644 --- a/clutter/clutter.h +++ b/clutter/clutter.h @@ -53,6 +53,7 @@ #include "clutter-box-layout.h" #include "clutter-cairo-texture.h" #include "clutter-child-meta.h" +#include "clutter-click-action.h" #include "clutter-clone.h" #include "clutter-color.h" #include "clutter-constraint.h" -- 2.7.4