mx/tests/test-draggable.c

406 lines
12 KiB
C

/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright 2009 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.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cogl/cogl.h>
#include <cogl-pango/cogl-pango.h>
#include <clutter/clutter.h>
#include <mx/mx.h>
#define DRAGGABLE_TYPE_RECTANGLE (draggable_rectangle_get_type ())
#define DRAGGABLE_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DRAGGABLE_TYPE_RECTANGLE, DraggableRectangle))
#define DRAGGABLE_IS_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DRAGGABLE_TYPE_RECTANGLE))
typedef struct _DraggableRectangle DraggableRectangle;
typedef struct _DraggableRectangleClass DraggableRectangleClass;
struct _DraggableRectangle
{
ClutterRectangle parent_instance;
/* Draggable properties */
guint threshold;
MxDragAxis axis;
#if 0
MxDragContainment containment;
#endif
ClutterActorBox area;
ClutterActor *actor;
guint is_enabled : 1;
gboolean drag_clone;
};
struct _DraggableRectangleClass
{
ClutterRectangleClass parent_class;
};
enum
{
PROP_0,
PROP_DRAG_THRESHOLD,
PROP_AXIS,
#if 0
PROP_CONTAINMENT_TYPE,
PROP_CONTAINMENT_AREA,
#endif
PROP_ENABLED,
PROP_ACTOR,
};
static void mx_draggable_iface_init (MxDraggableIface *iface);
static GType draggable_rectangle_get_type ();
G_DEFINE_TYPE_WITH_CODE (DraggableRectangle,
draggable_rectangle,
CLUTTER_TYPE_RECTANGLE,
G_IMPLEMENT_INTERFACE (MX_TYPE_DRAGGABLE,
mx_draggable_iface_init));
static void
draggable_rectangle_drag_begin (MxDraggable *draggable,
gfloat event_x,
gfloat event_y,
gint event_button,
ClutterModifierType modifiers)
{
gfloat x, y;
ClutterActor *self = CLUTTER_ACTOR (draggable);
ClutterActor *actor = mx_draggable_get_drag_actor (draggable);
ClutterActor *stage = clutter_actor_get_stage (self);
g_debug ("%s: drag of '%s' begin at %.2f, %.2f",
G_STRLOC,
clutter_actor_get_name (self),
event_x,
event_y);
if (actor)
{
clutter_actor_get_position (self, &x, &y);
clutter_actor_set_position (actor, x, y);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);
}
else
actor = self;
clutter_actor_set_opacity (actor, 224);
clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS,
30.0,
clutter_actor_get_width (actor) / 2.0,
0,
clutter_actor_get_height (actor) / 2.0);
}
static void
draggable_rectangle_drag_motion (MxDraggable *draggable,
gfloat delta_x,
gfloat delta_y)
{
ClutterActor *actor = mx_draggable_get_drag_actor (draggable);
g_debug ("%s: drag motion of '%s' (dx: %.2f, dy: %.2f)",
G_STRLOC,
clutter_actor_get_name (CLUTTER_ACTOR (draggable)),
delta_x,
delta_y);
if (!actor)
actor = CLUTTER_ACTOR (draggable);
clutter_actor_move_by (actor, delta_x, delta_y);
}
static void
draggable_rectangle_drag_end (MxDraggable *draggable,
gfloat event_x,
gfloat event_y)
{
gfloat x, y;
ClutterActor *self = CLUTTER_ACTOR (draggable);
ClutterActor *actor = mx_draggable_get_drag_actor (draggable);
ClutterActor *stage = clutter_actor_get_stage (self);
g_debug ("%s: drag of '%s' end at %.2f, %.2f",
G_STRLOC,
clutter_actor_get_name (CLUTTER_ACTOR (draggable)),
event_x,
event_y);
if (!actor)
{
clutter_actor_set_rotation (self, CLUTTER_Y_AXIS,
0.0, 0, 0, 0);
clutter_actor_set_opacity (self, 255);
return;
}
clutter_actor_get_position (actor, &x, &y);
clutter_actor_animate (self, CLUTTER_EASE_OUT_QUAD, 150,
"x", x,
"y", y,
NULL);
clutter_container_remove_actor (CLUTTER_CONTAINER (stage), actor);
}
static void
mx_draggable_iface_init (MxDraggableIface *iface)
{
iface->drag_begin = draggable_rectangle_drag_begin;
iface->drag_motion = draggable_rectangle_drag_motion;
iface->drag_end = draggable_rectangle_drag_end;
}
static void
draggable_rectangle_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
DraggableRectangle *rect = DRAGGABLE_RECTANGLE (gobject);
switch (prop_id)
{
case PROP_DRAG_THRESHOLD:
rect->threshold = g_value_get_uint (value);
break;
case PROP_AXIS:
rect->axis = g_value_get_enum (value);
break;
#if 0
case PROP_CONTAINMENT_TYPE:
rect->containment = g_value_get_enum (value);
break;
case PROP_CONTAINMENT_AREA:
{
ClutterActorBox *box = g_value_get_boxed (value);
if (box)
rect->area = *box;
else
memset (&rect->area, 0, sizeof (ClutterActorBox));
}
break;
#endif
case PROP_ENABLED:
rect->is_enabled = g_value_get_boolean (value);
if (rect->is_enabled)
mx_draggable_enable (MX_DRAGGABLE (gobject));
else
mx_draggable_disable (MX_DRAGGABLE (gobject));
break;
case PROP_ACTOR:
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
draggable_rectangle_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
DraggableRectangle *rect = DRAGGABLE_RECTANGLE (gobject);
switch (prop_id)
{
case PROP_DRAG_THRESHOLD:
g_value_set_uint (value, rect->threshold);
break;
case PROP_AXIS:
g_value_set_enum (value, rect->axis);
break;
#if 0
case PROP_CONTAINMENT_TYPE:
g_value_set_enum (value, rect->containment);
break;
case PROP_CONTAINMENT_AREA:
g_value_set_boxed (value, &rect->area);
break;
#endif
case PROP_ENABLED:
g_value_set_boolean (value, rect->is_enabled);
break;
case PROP_ACTOR:
if (rect->drag_clone)
g_value_set_object (value, rect->actor);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
draggable_rectangle_paint (ClutterActor *actor)
{
gfloat text_x, text_y;
ClutterActorBox box = { 0, };
gint layout_width, layout_height;
CoglColor color = { 0, };
PangoLayout *layout;
const gchar *name;
CLUTTER_ACTOR_CLASS (draggable_rectangle_parent_class)->paint (actor);
name = clutter_actor_get_name (actor);
clutter_actor_get_allocation_box (actor, &box);
layout = clutter_actor_create_pango_layout (actor, name);
pango_layout_get_size (layout, &layout_width, &layout_height);
text_x = ((box.x2 - box.x1) - (layout_width / 1024)) / 2;
text_y = ((box.y2 - box.y1) - (layout_height / 1024)) / 2;
cogl_color_set_from_4ub (&color, 0, 0, 0, 255);
cogl_pango_render_layout (layout,
(int) text_x,
(int) text_y,
&color, 0);
g_object_unref (layout);
}
static void
draggable_rectangle_dispose (GObject *object)
{
DraggableRectangle *rect = DRAGGABLE_RECTANGLE (object);
if (rect->actor)
{
g_object_unref (rect->actor);
rect->actor = NULL;
}
G_OBJECT_CLASS (draggable_rectangle_parent_class)->dispose (object);
}
static void
draggable_rectangle_class_init (DraggableRectangleClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->set_property = draggable_rectangle_set_property;
gobject_class->get_property = draggable_rectangle_get_property;
gobject_class->dispose = draggable_rectangle_dispose;
actor_class->paint = draggable_rectangle_paint;
g_object_class_override_property (gobject_class,
PROP_DRAG_THRESHOLD,
"drag-threshold");
g_object_class_override_property (gobject_class,
PROP_AXIS,
"axis");
#if 0
g_object_class_override_property (gobject_class,
PROP_CONTAINMENT_TYPE,
"containment-type");
g_object_class_override_property (gobject_class,
PROP_CONTAINMENT_AREA,
"containment-area");
#endif
g_object_class_override_property (gobject_class,
PROP_ENABLED,
"drag-enabled");
g_object_class_override_property (gobject_class,
PROP_ACTOR,
"drag-actor");
}
static void
draggable_rectangle_init (DraggableRectangle *self)
{
self->threshold = 0;
self->axis = 0;
#if 0
self->containment = MX_DISABLE_CONTAINMENT;
#endif
self->is_enabled = FALSE;
self->actor = g_object_ref_sink (clutter_clone_new (CLUTTER_ACTOR (self)));
}
int
main (int argc, char *argv[])
{
ClutterActor *stage;
ClutterActor *draggable;
ClutterColor rect_color = { 204, 204, 204, 255 };
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
stage = clutter_stage_get_default ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "Draggable Example");
clutter_actor_set_size (stage, 800, 600);
draggable = g_object_new (DRAGGABLE_TYPE_RECTANGLE, NULL);
((DraggableRectangle*)draggable)->drag_clone = TRUE;
clutter_container_add_actor (CLUTTER_CONTAINER (stage), draggable);
clutter_rectangle_set_color (CLUTTER_RECTANGLE (draggable), &rect_color);
clutter_actor_set_size (draggable, 100, 100);
clutter_actor_set_position (draggable, 350, 100);
clutter_actor_set_reactive (draggable, TRUE);
clutter_actor_set_name (draggable, "h-handle");
mx_draggable_set_axis (MX_DRAGGABLE (draggable), MX_DRAG_AXIS_X);
mx_draggable_enable (MX_DRAGGABLE (draggable));
draggable = g_object_new (DRAGGABLE_TYPE_RECTANGLE, NULL);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), draggable);
clutter_rectangle_set_color (CLUTTER_RECTANGLE (draggable), &rect_color);
clutter_actor_set_size (draggable, 100, 100);
clutter_actor_set_position (draggable, 350, 300);
clutter_actor_set_reactive (draggable, TRUE);
clutter_actor_set_name (draggable, "v-handle");
mx_draggable_set_axis (MX_DRAGGABLE (draggable), MX_DRAG_AXIS_Y);
mx_draggable_enable (MX_DRAGGABLE (draggable));
clutter_actor_show_all (stage);
clutter_main ();
return EXIT_SUCCESS;
}