You guys are awesome.
I'm attaching a corrected version of the sample you sent. I made minor
modification to prevent self recursion. I believe this could be added to the
pyclutter samples. Anyway, here it is.
Cheers,
Julien
2009/2/23 Damien Boucard - UbiCast <[email protected]>
> Hi Julien,
>
> I tried to translate examplebox.c into Python. See attached file, if it
> can help you...
>
> Damien.
>
>
> Le Mon, 23 Feb 2009 15:47:21 +0100,
> Julien Pauty <[email protected]> a écrit :
>
> > Hello,
> >
> > I'm trying to implement a container in python.
> >
> > I have something like this:
> >
> > class Cont(clutter.Actor, clutter.Container):
> >
> > __gtype_name__ = 'Cont'
> >
> > def __init__(self):
> > clutter.Actor.__init__(self)
> > clutter.Container.__init__(self)
> >
> >
> > def do_add(self, child):
> > clutter.Container.do_add(self, child)
> >
> > def do_remove(self, child):
> > clutter.Container.do_remove(child)
> >
> > If try to build such a class I get the following error:
> >
> > clutter.Container.__init__(self)
> > NotImplementedError: Cont can not be constructed
> >
> > I tried to provide some dummy method for the container, but this seems
> > useless, since Container provides default implementations.
> >
> > I also tried to not call the __init__ method of container, which seems
> > logical, since it's an interface. However, I get the following error
> > when I call do_add:.
> >
> > Warning: g_type_interface_peek: assertion `instance_class != NULL'
> > failed clutter.Container.do_add(self, child)
> >
> > This sounds like something is not initialized, but what ?
> >
> > So, what is the regular way to implement an interface ?
> >
> > Thanks,
> >
> > Julien
>
#!/usr/bin/env python
# -*- coding: utf-8 -*
import pygtk
pygtk.require('2.0')
import gobject
import clutter
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.
Specifically, ExampleBox lays out its children along an imaginary
horizontal line.
"""
def __init__(self):
clutter.Actor.__init__(self)
self.set_property('request-mode', clutter.REQUEST_WIDTH_FOR_HEIGHT)
self.children = list()
def do_add(self, actor):
self.pack(actor)
def do_remove(self, actor):
if actor in self.children:
actor.unparent()
self.children.remove(actor)
self.emit('actor-removed', actor)
self.queue_relayout()
def foreach(self, callback, user_data):
for child in self.children:
callback(child, user_data)
def show_all(self):
for child in self.children:
child.show()
self.show()
def hide_all(self):
self.hide()
for child in self.children:
child.hide()
def do_paint(self):
for child in self.children:
child.paint()
def do_pick(self, color):
for child in self.children:
child.pick(color)
def do_get_preferred_width(self, for_height):
"""
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.
"""
min_width = 0
natural_width = 0
# Calculate the preferred width for this container,
# based on the preferred width requested by the children:
for child in self.children:
if child.get_property('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
def do_get_preferred_height(self, for_width):
"""
For this container, the preferred height is the maximum height
of the children. The preferred height is independent of the given
width.
"""
min_height = 0
natural_height = 0
# Calculate the preferred height for this container,
# based on the preferred height requested by the children:
for child in self.children:
if child.get_property('visible'):
child_min_height, child_natural_height = \
child.get_preferred_height(for_width)
min_height += child_min_height
natural_height += child_natural_height
return min_height, natural_height
def do_allocate(self, box, absolute_origin_changed):
# Look at each child actor:
child_x = 0
for child in self.children:
# Discover what size the child wants:
min_width, min_height, natural_width, natural_height = \
child.get_preferred_size()
# 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 + natural_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 + natural_height
# Tell the child what position and size it may actually have:
child.allocate(child_box, absolute_origin_changed)
#print child_box.x1, child_box.x2, child_box.y1, child_box.y2
clutter.Actor.do_allocate(self, box, absolute_origin_changed)
def destroy(self):
# Destroy each child actor when this container is destroyed:
for child in self.children:
child.destroy()
del self.children
self.children = list()
clutter.Actor.destroy(self)
#
# # Public API
#
def pack(self, actor):
"""
Packs the given actor into ExampleBox instance.
:Parameters:
actor : clutter.Actor
An Actor object to pack into the box.
"""
self.children.append(actor)
actor.set_parent(self)
# queue a relayout of the container
self.queue_relayout()
def remove_all(self):
"""
Removes all child actors for the ExampleBox instance.
"""
for child in tuple(self.children):
self.remove(child)
gobject.type_register(ExampleBox)
if __name__ == '__main__':
import os
print os.getpid()
stage_color = clutter.Color(0x00, 0x00, 0x00, 0xff)
actor_color = clutter.Color(0xff, 0xff, 0xff, 0x99)
actor_color2 = clutter.Color(0x10, 0x40, 0x90, 0xff)
stage = clutter.Stage()
stage.set_size(200, 200)
stage.set_color(stage_color)
box = ExampleBox()
box.set_size(-1, -1)
box.set_position(20, 20)
stage.add(box)
box.show()
#
actor = clutter.Rectangle(actor_color)
actor.set_size(75, 75)
box.add(actor)
actor.show()
#
actor2 = clutter.Rectangle(actor_color2)
actor2.set_size(75, 75)
box.add(actor2)
actor2.show()
box.remove(actor2)
box.remove(actor)
box.add(actor2)
box.add(actor)
#
stage.show()
clutter.main()