The following example demonstrates the implementation of a box container that lays its child actors out horizontally. A real container should probably allow optional padding around the container and spacing between the child actors. You might also want to allow some child actors to expand to fill the available space, or align differently inside the container.
File: main.py
import sys import clutter from examplebox import ExampleBox def main(): stage_color = clutter.Color(0, 0, 0, 255) actor_color = clutter.Color(255, 255, 255, 153) actor_color2 = clutter.Color(16, 64, 144, 255) # Get the stage and set its size and color stage = clutter.Stage() stage.set_size(200, 200) stage.set_color(stage_color) # Add our custom container to the stage box = ExampleBox() # Set the size to the preferred size of the container box.set_size(-1, -1) box.set_position(20, 20) stage.add(box) box.show() # Add some actors to our container actor = clutter.Rectangle(color=actor_color) actor.set_size(75, 75) box.add(actor) actor.show() actor2 = clutter.Rectangle(color=actor_color2) actor2.set_size(75, 75) box.add(actor2) actor2.show() # Show the stage stage.show() stage.connect('destroy', clutter.main_quit) box.do_remove_all() # Start the main loop, so we can respond to events clutter.main() return 0 if __name__ == '__main__': sys.exit(main())
File: examplebox.py
import gobject import clutter from clutter import cogl class ExampleBox(clutter.Actor, clutter.Container): """ Simple example of a container actor ExampleBox imposes a specific layout on its children, unlike clutter.Group which is a free-form container. """ __gtype_name__ = 'ExampleBox' def __init__(self): super(ExampleBox, self).__init__() self._children = [] def do_add(self, *children): for child in children: if child in self._children: raise ValueError("Actor %s is already a children of %s" % ( child, self)) self._children.append(child) child.set_parent(self) self.queue_relayout() def do_remove(self, *children): for child in children: if child in self._children: self._children.remove(child) child.unparent() self.queue_relayout() else: raise ValueError("Actor %s is not a child of %s" % ( child, self)) def do_remove_all(self): """Removes all child actors from the ExampleBox""" self.do_remove(*self._children) def do_show_all(self): for child in self._children: child.show() def do_hide_all(self): for child in self._children: child.hide() def do_foreach(self, func, data): for child in self._children: func(child, data) def do_paint(self): cogl.push_matrix() for child in self._children: if child.props.mapped: child.paint() cogl.pop_matrix() def do_pick(self, color): for child in self._children: if child.props.mapped: child.do_pick(child, color) def do_allocate(self, box, flags): child_x = child_y = 0 for child in self._children: # Discover what size the child wants child_width, child_height = child.get_preferred_size()[2:] # Calculate the position and size that the child may actually have # Position the child just after the previous child, horizontally child_box = clutter.ActorBox() child_box.x1 = child_x child_box.x2 = child_x + child_width child_x = child_box.x2 # Position the child at the top of the container child_box.y1 = 0 child_box.y2 = child_box.y1 + child_height # Tell the child what position and size it may actually have child.allocate(child_box, flags) clutter.Actor.do_allocate(self, box, flags) def get_preferred_height(self): min_height = natural_height = 0 # For this container, the preferred height is the maximum height # of the children. The preferred height is independent of the given width. # Calculate the preferred height for this container, # based on the preferred height requested by the children for child in self._children: if not child.props.visible: child_min_height, child_natural_height = child.get_preferred_height(-1) min_height = max(min_height, child_min_height) natural_height = max(natural_height, child_natural_height) return min_height, natural_height def get_preferred_width(self): min_width = natural_width = 0 # For this container, the preferred width is the sum of the widths # of the children. The preferred width depends on the height provided # by for_height. # Calculate the preferred width for this container, # based on the preferred width requested by the children for child in self._children: if child.props.visible: child_min_width, child_natural_width = child.get_preferred_width(for_height) min_width += child_min_width natural_width += child_natural_width return min_width, natural_width gobject.type_register(ExampleBox)