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)