[layout] Add layers to BinLayout
authorEmmanuele Bassi <ebassi@linux.intel.com>
Mon, 14 Sep 2009 20:51:49 +0000 (21:51 +0100)
committerEmmanuele Bassi <ebassi@linux.intel.com>
Wed, 14 Oct 2009 10:27:29 +0000 (11:27 +0100)
Each actor managed by a BinLayout policy should reside inside its
own "layer", with horizontal and vertical alignment. The :x-align
and :y-align properties of the BinLayout are the default alignment
policies, which are copied to each new "layer" when it is created.

The set_alignment() and get_alignment() methods of BinLayout can
be changed to operate on a specific "layer".

The whole machinery uses the new ChildMeta support inside the
LayoutManager base abstract class.

clutter/clutter-bin-layout.c
clutter/clutter-bin-layout.h
tests/interactive/test-box.c

index c922319..8b92db6 100644 (file)
 #include "clutter-actor.h"
 #include "clutter-animatable.h"
 #include "clutter-bin-layout.h"
+#include "clutter-child-meta.h"
 #include "clutter-debug.h"
 #include "clutter-enum-types.h"
 #include "clutter-private.h"
 
+#define CLUTTER_TYPE_BIN_LAYER          (clutter_bin_layer_get_type ())
+#define CLUTTER_BIN_LAYER(obj)          (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BIN_LAYER, ClutterBinLayer))
+#define CLUTTER_IS_BIN_LAYER(obj)       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BIN_LAYER))
+
 #define CLUTTER_BIN_LAYOUT_GET_PRIVATE(obj)     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_BIN_LAYOUT, ClutterBinLayoutPrivate))
 
+typedef struct _ClutterBinLayer         ClutterBinLayer;
+typedef struct _ClutterChildMetaClass   ClutterBinLayerClass;
+
 struct _ClutterBinLayoutPrivate
 {
   ClutterBinAlignment x_align;
@@ -55,6 +63,24 @@ struct _ClutterBinLayoutPrivate
   gdouble y_factor;
 };
 
+struct _ClutterBinLayer
+{
+  ClutterChildMeta parent_instance;
+
+  ClutterBinLayout *layout;
+
+  ClutterBinAlignment x_align;
+  ClutterBinAlignment y_align;
+};
+
+enum
+{
+  PROP_LAYER_0,
+
+  PROP_LAYER_X_ALIGN,
+  PROP_LAYER_Y_ALIGN
+};
+
 enum
 {
   PROP_0,
@@ -63,11 +89,146 @@ enum
   PROP_Y_ALIGN
 };
 
+G_DEFINE_TYPE (ClutterBinLayer,
+               clutter_bin_layer,
+               CLUTTER_TYPE_CHILD_META);
+
 G_DEFINE_TYPE (ClutterBinLayout,
                clutter_bin_layout,
                CLUTTER_TYPE_LAYOUT_MANAGER);
 
 
+/*
+ * ClutterBinLayer
+ */
+
+static void
+set_layer_x_align (ClutterBinLayer     *self,
+                   ClutterBinAlignment  alignment)
+{
+  ClutterLayoutManager *manager;
+
+  if (self->x_align == alignment)
+    return;
+
+  self->x_align = alignment;
+
+  g_assert (self->layout != NULL);
+  manager = CLUTTER_LAYOUT_MANAGER (self->layout);
+  clutter_layout_manager_layout_changed (manager);
+
+  g_object_notify (G_OBJECT (self), "x-align");
+}
+
+static void
+set_layer_y_align (ClutterBinLayer     *self,
+                   ClutterBinAlignment  alignment)
+{
+  ClutterLayoutManager *manager;
+
+  if (self->y_align == alignment)
+    return;
+
+  self->y_align = alignment;
+
+  g_assert (self->layout != NULL);
+  manager = CLUTTER_LAYOUT_MANAGER (self->layout);
+  clutter_layout_manager_layout_changed (manager);
+
+  g_object_notify (G_OBJECT (self), "y-align");
+}
+
+static void
+clutter_bin_layer_set_property (GObject      *gobject,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  ClutterBinLayer *layer = CLUTTER_BIN_LAYER (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_LAYER_X_ALIGN:
+      set_layer_x_align (layer, g_value_get_enum (value));
+      break;
+
+    case PROP_LAYER_Y_ALIGN:
+      set_layer_y_align (layer, g_value_get_enum (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_bin_layer_get_property (GObject    *gobject,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+  ClutterBinLayer *layer = CLUTTER_BIN_LAYER (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_LAYER_X_ALIGN:
+      g_value_set_enum (value, layer->x_align);
+      break;
+
+    case PROP_LAYER_Y_ALIGN:
+      g_value_set_enum (value, layer->y_align);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_bin_layer_class_init (ClutterBinLayerClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GParamSpec *pspec;
+
+  gobject_class->set_property = clutter_bin_layer_set_property;
+  gobject_class->get_property = clutter_bin_layer_get_property;
+
+  pspec = g_param_spec_enum ("x-align",
+                             "X Align",
+                             "Horizontal alignment for the actor "
+                             "inside the layer",
+                             CLUTTER_TYPE_BIN_ALIGNMENT,
+                             CLUTTER_BIN_ALIGNMENT_CENTER,
+                             CLUTTER_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class,
+                                   PROP_LAYER_X_ALIGN,
+                                   pspec);
+
+  pspec = g_param_spec_enum ("y-align",
+                             "Y Align",
+                             "Vertical alignment for the actor "
+                             "inside the layer manager",
+                             CLUTTER_TYPE_BIN_ALIGNMENT,
+                             CLUTTER_BIN_ALIGNMENT_CENTER,
+                             CLUTTER_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class,
+                                   PROP_LAYER_Y_ALIGN,
+                                   pspec);
+}
+
+static void
+clutter_bin_layer_init (ClutterBinLayer *layer)
+{
+  layer->x_align = CLUTTER_BIN_ALIGNMENT_CENTER;
+  layer->y_align = CLUTTER_BIN_ALIGNMENT_CENTER;
+}
+
+/*
+ * ClutterBinLayout
+ */
+
 static void
 set_x_align (ClutterBinLayout    *self,
              ClutterBinAlignment  alignment)
@@ -200,7 +361,6 @@ clutter_bin_layout_allocate (ClutterLayoutManager   *manager,
                              const ClutterActorBox  *allocation,
                              ClutterAllocationFlags  flags)
 {
-  ClutterBinLayoutPrivate *priv = CLUTTER_BIN_LAYOUT (manager)->priv;
   GList *children = clutter_container_get_children (container);
   GList *l;
   gfloat available_w, available_h;
@@ -211,17 +371,24 @@ clutter_bin_layout_allocate (ClutterLayoutManager   *manager,
   for (l = children; l != NULL; l = l->next)
     {
       ClutterActor *child = l->data;
+      ClutterChildMeta *meta;
+      ClutterBinLayer *layer;
       ClutterActorBox child_alloc = { 0, };
       gfloat child_width, child_height;
       ClutterRequestMode request;
 
-      if (priv->x_align == CLUTTER_BIN_ALIGNMENT_FILL)
+      meta = clutter_layout_manager_get_child_meta (manager,
+                                                    container,
+                                                    child);
+      layer = CLUTTER_BIN_LAYER (meta);
+
+      if (layer->x_align == CLUTTER_BIN_ALIGNMENT_FILL)
         {
           child_alloc.x1 = (int) 0;
           child_alloc.x2 = (int) available_w;
         }
 
-      if (priv->y_align == CLUTTER_BIN_ALIGNMENT_FILL)
+      if (layer->y_align == CLUTTER_BIN_ALIGNMENT_FILL)
         {
           child_alloc.y1 = (int) 0;
           child_alloc.y2 = (int) available_h;
@@ -230,11 +397,11 @@ clutter_bin_layout_allocate (ClutterLayoutManager   *manager,
       /* if we are filling horizontally and vertically then we
        * can break here because we already have a full allocation
        */
-      if (priv->x_align == CLUTTER_BIN_ALIGNMENT_FILL &&
-          priv->y_align == CLUTTER_BIN_ALIGNMENT_FILL)
+      if (layer->x_align == CLUTTER_BIN_ALIGNMENT_FILL &&
+          layer->y_align == CLUTTER_BIN_ALIGNMENT_FILL)
         {
           clutter_actor_allocate (child, &child_alloc, flags);
-          break;
+          continue;
         }
 
       request = CLUTTER_REQUEST_HEIGHT_FOR_WIDTH;
@@ -270,32 +437,32 @@ clutter_bin_layout_allocate (ClutterLayoutManager   *manager,
           child_width = CLAMP (nat_width, min_width, available_w);
         }
 
-      if (priv->x_align == CLUTTER_BIN_ALIGNMENT_FIXED)
+      if (layer->x_align == CLUTTER_BIN_ALIGNMENT_FIXED)
         {
           child_alloc.x1 = (int) clutter_actor_get_x (child);
           child_alloc.x2 = (int) child_alloc.x1 + child_width;
         }
       else
         {
-          gdouble x_align = get_bin_alignment_factor (priv->x_align);
+          gdouble x_align = get_bin_alignment_factor (layer->x_align);
 
-          if (priv->x_align != CLUTTER_BIN_ALIGNMENT_FILL)
+          if (layer->x_align != CLUTTER_BIN_ALIGNMENT_FILL)
             {
               child_alloc.x1 = (int) ((available_w - child_width) * x_align);
               child_alloc.x2 = (int) child_alloc.x1 + child_width;
             }
         }
 
-      if (priv->y_align == CLUTTER_BIN_ALIGNMENT_FIXED)
+      if (layer->y_align == CLUTTER_BIN_ALIGNMENT_FIXED)
         {
           child_alloc.y1 = (int) clutter_actor_get_y (child);
           child_alloc.y2 = (int) child_alloc.y1 + child_height;
         }
       else
         {
-          gdouble y_align = get_bin_alignment_factor (priv->y_align);
+          gdouble y_align = get_bin_alignment_factor (layer->y_align);
 
-          if (priv->y_align != CLUTTER_BIN_ALIGNMENT_FILL)
+          if (layer->y_align != CLUTTER_BIN_ALIGNMENT_FILL)
             {
               child_alloc.y1 = (int) ((available_h - child_height) * y_align);
               child_alloc.y2 = (int) child_alloc.y1 + child_height;
@@ -308,6 +475,28 @@ clutter_bin_layout_allocate (ClutterLayoutManager   *manager,
   g_list_free (children);
 }
 
+static ClutterChildMeta *
+clutter_bin_layout_create_child_meta (ClutterLayoutManager *manager,
+                                      ClutterContainer     *container,
+                                      ClutterActor         *actor)
+{
+  ClutterBinLayoutPrivate *priv;
+  ClutterChildMeta *meta;
+
+  priv = CLUTTER_BIN_LAYOUT (manager)->priv;
+
+  meta = g_object_new (CLUTTER_TYPE_BIN_LAYER,
+                       "container", container,
+                       "actor", actor,
+                       "x-align", priv->x_align,
+                       "y_align", priv->y_align,
+                       NULL);
+
+  CLUTTER_BIN_LAYER (meta)->layout = CLUTTER_BIN_LAYOUT (manager);
+
+  return meta;
+}
+
 static void
 clutter_bin_layout_set_property (GObject      *gobject,
                                  guint         prop_id,
@@ -411,6 +600,8 @@ clutter_bin_layout_class_init (ClutterBinLayoutClass *klass)
     clutter_bin_layout_get_preferred_height;
   layout_class->allocate =
     clutter_bin_layout_allocate;
+  layout_class->create_child_meta =
+    clutter_bin_layout_create_child_meta;
 }
 
 static void
@@ -424,9 +615,9 @@ clutter_bin_layout_init (ClutterBinLayout *self)
 
 /**
  * clutter_bin_layout_new:
- * @x_align: the #ClutterBinAlignment policy to be used on the
+ * @x_align: the default alignment policy to be used on the
  *   horizontal axis
- * @y_align: the #ClutterBinAlignment policy to be used on the
+ * @y_align: the default alignment policy to be used on the
  *   vertical axis
  *
  * Creates a new #ClutterBinLayout layout manager
@@ -448,29 +639,39 @@ clutter_bin_layout_new (ClutterBinAlignment x_align,
 /**
  * clutter_bin_layout_set_alignment:
  * @self: a #ClutterBinLayout
- * @x_align: the #ClutterBinAlignment policy to be used on the
- *   horizontal axis
- * @y_align: the #ClutterBinAlignment policy to be used on the
- *   vertical axis
+ * @container: a #ClutterContainer with a layout managed by @self
+ * @child: a #ClutterActor child of @container
+ * @x_align: the horizontal alignment policy to be used for the @child
+ *   inside @container
+ * @y_align: the vertical aligment policy to be used on the @child
+ *   inside @container
  *
- * Sets the alignment policies on the horizontal and vertical
- * axis for @self
+ * Sets the horizontal and vertical alignment policies to be applied
+ * to the @child of @container
  *
  * Since: 1.2
  */
 void
 clutter_bin_layout_set_alignment (ClutterBinLayout    *self,
+                                  ClutterContainer    *container,
+                                  ClutterActor        *child,
                                   ClutterBinAlignment  x_align,
                                   ClutterBinAlignment  y_align)
 {
+  ClutterLayoutManager *manager;
+  ClutterChildMeta *meta;
+  ClutterBinLayer *layer;
+
   g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
 
-  g_object_freeze_notify (G_OBJECT (self));
+  manager = CLUTTER_LAYOUT_MANAGER (self);
+  meta = clutter_layout_manager_get_child_meta (manager, container, child);
+  g_return_if_fail (CLUTTER_IS_BIN_LAYER (meta));
 
-  set_x_align (self, x_align);
-  set_y_align (self, y_align);
+  layer = CLUTTER_BIN_LAYER (meta);
 
-  g_object_thaw_notify (G_OBJECT (self));
+  set_layer_x_align (layer, x_align);
+  set_layer_y_align (layer, y_align);
 }
 
 /**
@@ -487,14 +688,26 @@ clutter_bin_layout_set_alignment (ClutterBinLayout    *self,
  */
 void
 clutter_bin_layout_get_alignment (ClutterBinLayout    *self,
+                                  ClutterContainer    *container,
+                                  ClutterActor        *child,
                                   ClutterBinAlignment *x_align,
                                   ClutterBinAlignment *y_align)
 {
+  ClutterLayoutManager *manager;
+  ClutterChildMeta *meta;
+  ClutterBinLayer *layer;
+
   g_return_if_fail (CLUTTER_IS_BIN_LAYOUT (self));
 
+  manager = CLUTTER_LAYOUT_MANAGER (self);
+  meta = clutter_layout_manager_get_child_meta (manager, container, child);
+  g_return_if_fail (CLUTTER_IS_BIN_LAYER (meta));
+
+  layer = CLUTTER_BIN_LAYER (meta);
+
   if (x_align)
-    *x_align = self->priv->x_align;
+    *x_align = layer->x_align;
 
   if (y_align)
-    *y_align = self->priv->y_align;
+    *y_align = layer->y_align;
 }
index 09449a1..5eb4617 100644 (file)
@@ -81,9 +81,13 @@ ClutterLayoutManager *clutter_bin_layout_new           (ClutterBinAlignment  ali
                                                         ClutterBinAlignment  align_y);
 
 void                  clutter_bin_layout_set_alignment (ClutterBinLayout    *self,
+                                                        ClutterContainer    *container,
+                                                        ClutterActor        *child,
                                                         ClutterBinAlignment  x_align,
                                                         ClutterBinAlignment  y_align);
 void                  clutter_bin_layout_get_alignment (ClutterBinLayout    *self,
+                                                        ClutterContainer    *container,
+                                                        ClutterActor        *child,
                                                         ClutterBinAlignment *x_align,
                                                         ClutterBinAlignment *y_align);
 
index ecfa07a..2c3d50e 100644 (file)
 #include <stdlib.h>
 #include <gmodule.h>
+#include <cairo/cairo.h>
 #include <clutter/clutter.h>
 
+static ClutterActor *
+make_background (const ClutterColor *color,
+                 gfloat              width,
+                 gfloat              height)
+{
+  ClutterActor *tex = clutter_cairo_texture_new (width, height);
+  cairo_t *cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (tex));
+  cairo_pattern_t *pat;
+  gfloat x, y;
+
+#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, 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);
+  cairo_destroy (cr);
+
+#undef BG_ROUND_RADIUS
+
+  return tex;
+}
+
+static gboolean
+on_box_enter (ClutterActor *box,
+              ClutterEvent *event,
+              ClutterActor *emblem)
+{
+  clutter_actor_animate (emblem, CLUTTER_LINEAR, 150,
+                         "opacity", 255,
+                         NULL);
+
+  return TRUE;
+}
+
+static gboolean
+on_box_leave (ClutterActor *box,
+              ClutterEvent *event,
+              ClutterActor *emblem)
+{
+  clutter_actor_animate (emblem, CLUTTER_LINEAR, 150,
+                         "opacity", 0,
+                         NULL);
+
+  return TRUE;
+}
+
 G_MODULE_EXPORT int
 test_box_main (int argc, char *argv[])
 {
   ClutterActor *stage, *box, *rect;
   ClutterLayoutManager *layout;
+  ClutterColor stage_color = { 0xe0, 0xf2, 0xfc, 0xff };
   ClutterColor bg_color = { 0xcc, 0xcc, 0xcc, 0x99 };
   ClutterColor *color;
 
@@ -14,7 +103,8 @@ test_box_main (int argc, char *argv[])
 
   stage = clutter_stage_get_default ();
   clutter_stage_set_title (CLUTTER_STAGE (stage), "Box test");
-  clutter_actor_set_size (stage, 320, 200);
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+  clutter_actor_set_size (stage, 640, 480);
 
   layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
                                    CLUTTER_BIN_ALIGNMENT_CENTER);
@@ -22,20 +112,67 @@ test_box_main (int argc, char *argv[])
   box = clutter_box_new (layout);
   clutter_container_add_actor (CLUTTER_CONTAINER (stage), box);
   clutter_actor_set_anchor_point_from_gravity (box, CLUTTER_GRAVITY_CENTER);
-  clutter_actor_set_position (box, 160, 100);
+  clutter_actor_set_position (box, 320, 240);
+  clutter_actor_set_reactive (box, TRUE);
+  clutter_actor_set_name (box, "box");
 
-  rect = clutter_rectangle_new_with_color (&bg_color);
+  rect = make_background (&bg_color, 200, 200);
   clutter_container_add_actor (CLUTTER_CONTAINER (box), rect);
-  clutter_actor_set_size (rect, 100, 100);
+  clutter_actor_lower_bottom (rect);
+  clutter_actor_set_name (rect, "background");
+
+  clutter_bin_layout_set_alignment (CLUTTER_BIN_LAYOUT (layout),
+                                    CLUTTER_CONTAINER (box),
+                                    rect,
+                                    CLUTTER_BIN_ALIGNMENT_FILL,
+                                    CLUTTER_BIN_ALIGNMENT_FILL);
+
+  {
+    ClutterActor *tex;
+    GError *error;
+
+    error = NULL;
+    tex = clutter_texture_new_from_file ("redhand.png", &error);
+    if (error)
+      g_error ("Unable to create texture: %s", error->message);
+
+    clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (tex), TRUE);
+    clutter_container_add_actor (CLUTTER_CONTAINER (box), tex);
+    clutter_actor_raise (tex, rect);
+    clutter_actor_set_width (tex, 175);
+    clutter_actor_set_name (tex, "texture");
+
+    clutter_bin_layout_set_alignment (CLUTTER_BIN_LAYOUT (layout),
+                                      CLUTTER_CONTAINER (box),
+                                      tex,
+                                      CLUTTER_BIN_ALIGNMENT_CENTER,
+                                      CLUTTER_BIN_ALIGNMENT_CENTER);
+  }
 
   color = clutter_color_new (g_random_int_range (0, 255),
                              g_random_int_range (0, 255),
                              g_random_int_range (0, 255),
-                             255);
+                             224);
 
   rect = clutter_rectangle_new_with_color (color);
   clutter_container_add_actor (CLUTTER_CONTAINER (box), rect);
   clutter_actor_set_size (rect, 50, 50);
+  clutter_actor_set_opacity (rect, 0);
+  clutter_actor_raise_top (rect);
+  clutter_actor_set_name (rect, "emblem");
+
+  clutter_bin_layout_set_alignment (CLUTTER_BIN_LAYOUT (layout),
+                                    CLUTTER_CONTAINER (box),
+                                    rect,
+                                    CLUTTER_BIN_ALIGNMENT_END,
+                                    CLUTTER_BIN_ALIGNMENT_END);
+
+  g_signal_connect (box,
+                    "enter-event", G_CALLBACK (on_box_enter),
+                    rect);
+  g_signal_connect (box,
+                    "leave-event", G_CALLBACK (on_box_leave),
+                    rect);
 
   clutter_actor_show_all (stage);