mutter/examples/bin-layout.c
Emmanuele Bassi 77ec8774a0 WARNING: Massive revert commit
Revert all the work that happened on the master branch.

Sadly, this is the only way to merge the current development branch back
into master.

It is now abundantly clear that I merged the 1.99 branch far too soon,
and that Clutter 2.0 won't happen any time soon, if at all.

Since having the development happen on a separate branch throws a lot of
people into confusion, let's undo the clutter-1.99 → master merge, and
move back the development of Clutter to the master branch.

In order to do so, we need to do some surgery to the Git repository.

First, we do a massive revert in a single commit of all that happened
since the switch to 1.99 and the API version bump done with the
89a2862b05 commit. The history is too long
to be reverted commit by commit without being extremely messy.
2015-01-03 20:34:20 +00:00

308 lines
10 KiB
C

#include <stdlib.h>
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <clutter/clutter.h>
static const ClutterColor bg_color = { 0xcc, 0xcc, 0xcc, 0x99 };
static gboolean is_expanded = FALSE;
static gboolean
on_canvas_draw (ClutterCanvas *canvas,
cairo_t *cr,
gint width,
gint height)
{
cairo_pattern_t *pat;
gfloat x, y;
g_print (G_STRLOC ": Painting at %d x %d\n", width, height);
cairo_save (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_restore (cr);
#define BG_ROUND_RADIUS 12
x = y = 0;
cairo_move_to (cr, BG_ROUND_RADIUS, y);
cairo_line_to (cr, width - BG_ROUND_RADIUS, y);
cairo_curve_to (cr, width, y, width, y, width, BG_ROUND_RADIUS);
cairo_line_to (cr, width, height - BG_ROUND_RADIUS);
cairo_curve_to (cr, width, height, width, height, width - BG_ROUND_RADIUS, height);
cairo_line_to (cr, BG_ROUND_RADIUS, height);
cairo_curve_to (cr, x, height, x, height, x, height - BG_ROUND_RADIUS);
cairo_line_to (cr, x, BG_ROUND_RADIUS);
cairo_curve_to (cr, x, y, x, y, BG_ROUND_RADIUS, y);
cairo_close_path (cr);
clutter_cairo_set_source_color (cr, &bg_color);
cairo_stroke (cr);
x += 4;
y += 4;
width -= 4;
height -= 4;
cairo_move_to (cr, BG_ROUND_RADIUS, y);
cairo_line_to (cr, width - BG_ROUND_RADIUS, y);
cairo_curve_to (cr, width, y, width, y, width, BG_ROUND_RADIUS);
cairo_line_to (cr, width, height - BG_ROUND_RADIUS);
cairo_curve_to (cr, width, height, width, height, width - BG_ROUND_RADIUS, height);
cairo_line_to (cr, BG_ROUND_RADIUS, height);
cairo_curve_to (cr, x, height, x, height, x, height - BG_ROUND_RADIUS);
cairo_line_to (cr, x, BG_ROUND_RADIUS);
cairo_curve_to (cr, x, y, x, y, BG_ROUND_RADIUS, y);
cairo_close_path (cr);
pat = cairo_pattern_create_linear (0, 0, 0, height);
cairo_pattern_add_color_stop_rgba (pat, 1, .85, .85, .85, 1);
cairo_pattern_add_color_stop_rgba (pat, .95, 1, 1, 1, 1);
cairo_pattern_add_color_stop_rgba (pat, .05, 1, 1, 1, 1);
cairo_pattern_add_color_stop_rgba (pat, 0, .85, .85, .85, 1);
cairo_set_source (cr, pat);
cairo_fill (cr);
cairo_pattern_destroy (pat);
#undef BG_ROUND_RADIUS
return TRUE;
}
static gboolean
on_box_enter (ClutterActor *box,
ClutterEvent *event,
ClutterActor *emblem)
{
/* we ease the opacity linearly */
clutter_actor_save_easing_state (emblem);
clutter_actor_set_easing_mode (emblem, CLUTTER_LINEAR);
clutter_actor_set_opacity (emblem, 255);
clutter_actor_restore_easing_state (emblem);
return CLUTTER_EVENT_STOP;
}
static gboolean
on_box_leave (ClutterActor *box,
ClutterEvent *event,
ClutterActor *emblem)
{
clutter_actor_save_easing_state (emblem);
clutter_actor_set_easing_mode (emblem, CLUTTER_LINEAR);
clutter_actor_set_opacity (emblem, 0);
clutter_actor_restore_easing_state (emblem);
return CLUTTER_EVENT_STOP;
}
static void
on_emblem_clicked (ClutterClickAction *action,
ClutterActor *emblem,
ClutterActor *box)
{
/* we add a little bounce to the resizing of the box */
clutter_actor_save_easing_state (box);
clutter_actor_set_easing_mode (box, CLUTTER_EASE_OUT_BOUNCE);
clutter_actor_set_easing_duration (box, 500);
if (!is_expanded)
clutter_actor_set_size (box, 400, 400);
else
clutter_actor_set_size (box, 200, 200);
clutter_actor_restore_easing_state (box);
is_expanded = !is_expanded;
}
static gboolean
on_emblem_long_press (ClutterClickAction *action,
ClutterActor *emblem,
ClutterLongPressState state,
ClutterActor *box)
{
switch (state)
{
case CLUTTER_LONG_PRESS_QUERY:
g_print ("*** long press: query ***\n");
return is_expanded;
case CLUTTER_LONG_PRESS_CANCEL:
g_print ("*** long press: cancel ***\n");
break;
case CLUTTER_LONG_PRESS_ACTIVATE:
g_print ("*** long press: activate ***\n");
break;
}
return TRUE;
}
static void
redraw_canvas (ClutterActor *actor,
ClutterCanvas *canvas)
{
/* we want to invalidate the canvas and redraw its contents
* only when the size changes at the end of the animation,
* to avoid drawing all the states inbetween
*/
clutter_canvas_set_size (canvas,
clutter_actor_get_width (actor),
clutter_actor_get_height (actor));
}
int
main (int argc, char *argv[])
{
ClutterActor *stage, *box, *bg, *icon, *emblem, *label;
ClutterLayoutManager *layout;
ClutterContent *canvas, *image;
ClutterColor *color;
ClutterAction *action;
GdkPixbuf *pixbuf;
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return 1;
/* prepare the stage */
stage = clutter_stage_new ();
clutter_stage_set_title (CLUTTER_STAGE (stage), "BinLayout");
clutter_actor_set_background_color (stage, CLUTTER_COLOR_Aluminium2);
clutter_actor_set_size (stage, 640, 480);
clutter_actor_show (stage);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
/* this is our BinLayout, with its default alignments */
layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_BIN_ALIGNMENT_CENTER);
/* the main container; this actor will use the BinLayout to lay
* out its children; we use the anchor point to keep it centered
* on the same position even when we change its size
*/
box = clutter_actor_new ();
clutter_actor_set_layout_manager (box, layout);
clutter_actor_add_constraint (box, clutter_align_constraint_new (stage, CLUTTER_ALIGN_BOTH, 0.5));
clutter_actor_set_position (box, 320, 240);
clutter_actor_set_reactive (box, TRUE);
clutter_actor_set_name (box, "box");
clutter_actor_add_child (stage, box);
/* the background is drawn using a canvas content */
canvas = clutter_canvas_new ();
g_signal_connect (canvas, "draw", G_CALLBACK (on_canvas_draw), NULL);
clutter_canvas_set_size (CLUTTER_CANVAS (canvas), 200, 200);
/* this is the background actor; we want it to fill the whole
* of the allocation given to it by its parent
*/
bg = clutter_actor_new ();
clutter_actor_set_name (bg, "background");
clutter_actor_set_size (bg, 200, 200);
clutter_actor_set_content (bg, canvas);
clutter_actor_set_x_expand (bg, TRUE);
clutter_actor_set_y_expand (bg, TRUE);
clutter_actor_set_x_align (bg, CLUTTER_ACTOR_ALIGN_FILL);
clutter_actor_set_y_align (bg, CLUTTER_ACTOR_ALIGN_FILL);
clutter_actor_add_child (box, bg);
/* we use the ::transitions-completed signal to get notification
* of the end of the sizing animation; this allows us to redraw
* the canvas only once the animation has stopped
*/
g_signal_connect (box, "transitions-completed",
G_CALLBACK (redraw_canvas),
canvas);
/* we use GdkPixbuf to load an image from our data directory */
pixbuf = gdk_pixbuf_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", NULL);
image = clutter_image_new ();
clutter_image_set_data (CLUTTER_IMAGE (image),
gdk_pixbuf_get_pixels (pixbuf),
gdk_pixbuf_get_has_alpha (pixbuf)
? COGL_PIXEL_FORMAT_RGBA_8888
: COGL_PIXEL_FORMAT_RGB_888,
gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
gdk_pixbuf_get_rowstride (pixbuf),
NULL);
g_object_unref (pixbuf);
/* this is the icon; it's going to be centered inside the box actor.
* we use the content gravity to keep the aspect ratio of the image,
* and the scaling filters to get a better result when scaling the
* image down.
*/
icon = clutter_actor_new ();
clutter_actor_set_name (icon, "icon");
clutter_actor_set_size (icon, 196, 196);
clutter_actor_set_x_expand (icon, TRUE);
clutter_actor_set_y_expand (icon, TRUE);
clutter_actor_set_x_align (icon, CLUTTER_ACTOR_ALIGN_CENTER);
clutter_actor_set_y_align (icon, CLUTTER_ACTOR_ALIGN_CENTER);
clutter_actor_set_content_gravity (icon, CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT);
clutter_actor_set_content_scaling_filters (icon,
CLUTTER_SCALING_FILTER_TRILINEAR,
CLUTTER_SCALING_FILTER_LINEAR);
clutter_actor_set_content (icon, image);
clutter_actor_add_child (box, icon);
color = clutter_color_new (g_random_int_range (0, 255),
g_random_int_range (0, 255),
g_random_int_range (0, 255),
224);
/* this is the emblem: a small rectangle with a random color, that we
* want to put in the bottom right corner
*/
emblem = clutter_actor_new ();
clutter_actor_set_name (emblem, "emblem");
clutter_actor_set_size (emblem, 48, 48);
clutter_actor_set_background_color (emblem, color);
clutter_actor_set_x_expand (emblem, TRUE);
clutter_actor_set_y_expand (emblem, TRUE);
clutter_actor_set_x_align (emblem, CLUTTER_ACTOR_ALIGN_END);
clutter_actor_set_y_align (emblem, CLUTTER_ACTOR_ALIGN_END);
clutter_actor_set_reactive (emblem, TRUE);
clutter_actor_set_opacity (emblem, 0);
clutter_actor_add_child (box, emblem);
clutter_color_free (color);
/* when clicking on the emblem, we want to perform an action */
action = clutter_click_action_new ();
clutter_actor_add_action (emblem, action);
g_signal_connect (action, "clicked", G_CALLBACK (on_emblem_clicked), box);
g_signal_connect (action, "long-press", G_CALLBACK (on_emblem_long_press), box);
/* whenever the pointer enters the box, we show the emblem; we hide
* the emblem when the pointer leaves the box
*/
g_signal_connect (box,
"enter-event", G_CALLBACK (on_box_enter),
emblem);
g_signal_connect (box,
"leave-event", G_CALLBACK (on_box_leave),
emblem);
/* a label, that we want to position at the top and center of the box */
label = clutter_text_new ();
clutter_actor_set_name (label, "text");
clutter_text_set_text (CLUTTER_TEXT (label), "A simple test");
clutter_actor_set_x_expand (label, TRUE);
clutter_actor_set_x_align (label, CLUTTER_ACTOR_ALIGN_CENTER);
clutter_actor_set_y_expand (label, TRUE);
clutter_actor_set_y_align (label, CLUTTER_ACTOR_ALIGN_START);
clutter_actor_add_child (box, label);
clutter_main ();
return EXIT_SUCCESS;
}