示例#1
0
class MTFlippableWidget(MTWidget):
    '''This is wrapper widget using which you can make a
    widget have two sides and you can flip between the sides ::

        from pymt import *

        widget = MTFlippableWidget()
        widget.add_widget(MTLabel(label='Front'), side='front')
        widget.add_widget(MTLabel(label='Back'), side='back')

        @widget.event
        def on_touch_down(touch):
            widget.flip()

        runTouchApp(widget)

    :Parameters:
        `flipangle` : float, default to 90.
            Angle to flip back/front

    '''
    def __init__(self, **kwargs):
        kwargs.setdefault('flipangle', 90.)
        super(MTFlippableWidget, self).__init__(**kwargs)
        self.flipangle      = kwargs.get('flipangle')

        # For flipping animations
        self.zangle         = 0
        self.side           = 'front'

        # Holds children for both sides
        self.children_front = SafeList()
        self.children_back  = SafeList()

        self._anim_current  = None
        self._anim_back     = Animation(zangle=180)
        self._anim_front    = Animation(zangle=0)

    def add_widget(self, w, side='front', front=True):
        '''Add a widget on a side.

        :Parameters:
            `front` : boolean, default is True
                Indicate if the widget must be top added or bottom added in the list.
            `side` : string, default is 'front'
                Specify which side you want to add widget.
                (can be one of 'front', 'back' or '', defaults to add to both sides)
        '''
        assert(side in ('front', 'back', ''))
        if side == 'front':
            if front:
                self.children_front.append(w)
            else:
                self.children_front.insert(0, w)
        elif side == 'back':
            if front:
                self.children_back.append(w)
            else:
                self.children_back.insert(0, w)
        else:
            self.add_widget(w, side='front', front=front)
            self.add_widget(w, side='back', front=front)

        if self.side == side:
            super(MTFlippableWidget, self).add_widget(w, front)

        try:
            w.parent = self
        except Exception:
            pass

    def draw(self):
        set_color(*self.style.get('bg-color'))
        drawCSSRectangle(pos=(0, 0), size=self.size, style=self.style)

    def flip_children(self):
        # This has to be called exactly half way through the animation
        # so it looks like there are actually two sides'''
        if self.side == 'front':
            self.side = 'back'
            self.children.clear()
            for x in self.children_back[:]:
                super(MTFlippableWidget, self).add_widget(x)
        else:
            self.side = 'front'
            self.children.clear()
            for x in self.children_front[:]:
                super(MTFlippableWidget, self).add_widget(x)

    def flip_to(self, to):
        '''Flip to the requested side ('front' or 'back')'''
        assert(to in ('back', 'front'))
        if to == 'back' and self.side == 'front':
            self.flip_children()
        elif to == 'front' and self.side == 'back':
            self.flip_children()

    def flip(self):
        '''Triggers a flipping animation'''
        if self._anim_current:
            self._anim_current.stop()
        if self.side == 'front':
            self._anim_current = self.do(self._anim_back)
        else:
            self._anim_current = self.do(self._anim_front)

    def on_update(self):
        if self.zangle < self.flipangle:
            self.flip_to('front')
        else:
            self.flip_to('back')
        return super(MTFlippableWidget, self).on_update()

    def on_draw(self):
        with gx_matrix:
            glTranslatef(self.x, self.y, 0)
            glTranslatef(self.width / 2, 0, 0)
            if self.side == 'front':
                glRotatef(self.zangle, 0, 1, 0)
            else:
                glRotatef(self.zangle + 180, 0, 1, 0)
            glTranslatef(-self.width / 2, 0, 0)
            super(MTFlippableWidget, self).on_draw()
示例#2
0
class MTWidget(EventDispatcher):
    """Global base for any multitouch widget.
    Implement event for mouse, object, touch and animation.

    Event are dispatched through widget only if it's visible.

    :Parameters:
        `pos` : list, default is (0, 0)
            Position of widget, in (x, y) format
        `x` : int, default is None
            X position of widget
        `y` : int, default is None
            Y position of widget
        `size` : list, default is (100, 100)
            Size of widget, in (width, height) format
        `width` : int, default is None
            width position of widget
        `height` : int, default is None
            height position of widget
        `visible` : bool, default is True
            Visibility of widget
        `draw_children` : bool, default is True
            Indicate if children will be draw, or not
        `style` : dict, default to {}
            Add inline CSS
        `cls` : str, default is ''
            CSS class of this widget

    :Events:
        `on_update` ()
            Used to update the widget and his children.
        `on_draw` ()
            Used to draw the widget and his children.
        `on_touch_down` (Touch touch)
            Fired when a blob appear
        `on_touch_move` (Touch touch)
            Fired when a blob is moving
        `on_touch_up` (Touch touch)
            Fired when a blob disappear
        `on_resize` (float width, float height)
            Fired when widget is resized
        `on_parent_resize` (float width, float height)
            Fired when parent widget is resized
    """

    __metaclass__ = MTWidgetMetaclass

    __slots__ = (
        "children",
        "style",
        "draw_children",
        "_cls",
        "_root_window_source",
        "_root_window",
        "_parent_window_source",
        "_parent_window",
        "_parent_layout_source",
        "_parent_layout",
        "_size_hint",
        "_id",
        "_parent",
        "_visible",
        "_inline_style",
        "__animationcache__",
        "__weakref__",
    )

    visible_events = ["on_draw", "on_touch_up", "on_touch_move", "on_touch_down"]

    def __init__(self, **kwargs):
        kwargs.setdefault("pos", (0, 0))
        kwargs.setdefault("x", None)
        kwargs.setdefault("y", None)
        kwargs.setdefault("size", (100, 100))
        kwargs.setdefault("size_hint", (None, None))
        kwargs.setdefault("width", None)
        kwargs.setdefault("height", None)
        kwargs.setdefault("visible", True)
        kwargs.setdefault("draw_children", True)
        kwargs.setdefault("cls", "")
        kwargs.setdefault("style", {})

        self._id = None
        if "id" in kwargs:
            self.id = kwargs.get("id")

        super(MTWidget, self).__init__(**kwargs)

        # Registers events
        for ev in MTWidget.visible_events:
            self.register_event_type(ev)

        self.__animationcache__ = set()
        self._parent = None
        self.children = SafeList()
        self._visible = None
        self._size_hint = kwargs.get("size_hint")
        self.visible = kwargs.get("visible")
        self.draw_children = kwargs.get("draw_children")

        # cache for get_parent_window()
        self._parent_layout = None
        self._parent_layout_source = None
        self._parent_window = None
        self._parent_window_source = None
        self._root_window = None
        self._root_window_source = None

        self.register_event_type("on_update")
        self.register_event_type("on_animation_complete")
        self.register_event_type("on_resize")
        self.register_event_type("on_parent_resize")
        self.register_event_type("on_move")
        self.register_event_type("on_parent")

        if kwargs.get("x"):
            self._pos = (kwargs.get("x"), self.y)
        if kwargs.get("y"):
            self._pos = (self.x, kwargs.get("y"))
        if kwargs.get("width"):
            self._size = (kwargs.get("width"), self.height)
        if kwargs.get("height"):
            self._size = (self.width, kwargs.get("height"))

        # apply css
        self.style = {}
        self._cls = ""
        self._inline_style = kwargs.get("style")
        # loading is done here automaticly
        self.cls = kwargs.get("cls")

        self.init()

    def _set_cls(self, cls):
        self._cls = cls
        self.reload_css()

    def _get_cls(self):
        return self._cls

    cls = property(_get_cls, _set_cls, doc="Get/Set the class of the widget (used for CSS)")

    def _set_parent(self, parent):
        self._parent = parent
        self.dispatch_event("on_parent")

    def _get_parent(self):
        return self._parent

    parent = property(_get_parent, _set_parent, doc="MTWidget: parent of widget. Fired on_parent event when set")

    def _set_id(self, id):
        ref = weakref.ref(self)
        if ref in _id_2_widget:
            del _id_2_widget[self._id]
        self._id = id
        if self._id:
            if ref in _id_2_widget:
                pymt_logger.warning("Widget: ID <%s> is already used ! Replacing with new one." % id)
            _id_2_widget[self._id] = ref

    def _get_id(self):
        return self._id

    id = property(_get_id, _set_id, doc="str: id of widget")

    def _set_visible(self, visible):
        if self._visible == visible:
            return
        self._visible = visible
        # register or unregister event if the widget is visible or not
        if visible:
            for ev in MTWidget.visible_events:
                self.register_event_type(ev)
        else:
            for ev in MTWidget.visible_events:
                self.unregister_event_type(ev)

    def _get_visible(self):
        return self._visible

    visible = property(_get_visible, _set_visible, doc="bool: visibility of widget")

    def _set_size_hint(self, size_hint):
        if self._size_hint == size_hint:
            return False
        self._size_hint = size_hint

    def _get_size_hint(self):
        return self._size_hint

    size_hint = property(
        _get_size_hint, _set_size_hint, doc="size_hint is used by layouts to determine size behaviour during layout"
    )

    def apply_css(self, styles):
        """Called at __init__ time to applied css attribute in current class.
        """
        self.style.update(styles)

    def reload_css(self):
        """Called when css want to be reloaded from scratch"""
        self.style = {}
        style = css_get_style(widget=self)
        self.apply_css(style)
        if len(self._inline_style):
            self.apply_css(self._inline_style)

    def to_widget(self, x, y, relative=False):
        """Return the coordinate from window to local widget"""
        if self.parent:
            x, y = self.parent.to_widget(x, y)
        return self.to_local(x, y, relative=relative)

    def to_window(self, x, y, initial=True, relative=False):
        """Transform local coordinate to window coordinate"""
        if not initial:
            x, y = self.to_parent(x, y, relative=relative)
        if self.parent:
            return self.parent.to_window(x, y, initial=False, relative=relative)
        return (x, y)

    def to_parent(self, x, y, relative=False):
        """Transform local coordinate to parent coordinate

        :Parameters:
            `relative`: bool, default to False
                Change to True is you want to translate relative position from
                widget to his parent.
        """
        if relative:
            return (x + self.x, y + self.y)
        return (x, y)

    def to_local(self, x, y, relative=False):
        """Transform parent coordinate to local coordinate

        :Parameters:
            `relative`: bool, default to False
                Change to True is you want to translate a coordinate to a
                relative coordinate from widget.
        """
        if relative:
            return (x - self.x, y - self.y)
        return (x, y)

    def collide_point(self, x, y):
        """Test if the (x,y) is in widget bounding box"""
        if not self.visible:
            return False
        if x > self.x and x < self.x + self.width and y > self.y and y < self.y + self.height:
            return True

    def init(self):
        pass

    def get_root_window(self):
        """Return the root window of widget"""
        if not self.parent:
            return None

        # cache value
        if self._root_window_source != self.parent or self._root_window is None:
            self._root_window = self.parent.get_root_window()
            if not self._root_window:
                return None
            self._root_window_source = self.parent

        return self._root_window

    def get_parent_layout(self):
        """Return the parent layout of widget"""
        if not self.parent:
            return None

        # cache value
        if self._parent_layout_source != self.parent or self._parent_layout is None:
            self._parent_layout = self.parent.get_parent_layout()
            if not self._parent_layout:
                return None
            self._parent_layout_source = self.parent

        return self._parent_layout

    def get_parent_window(self):
        """Return the parent window of widget"""
        if not self.parent:
            return None

        # cache value
        if self._parent_window_source != self.parent or self._parent_window is None:
            self._parent_window = self.parent.get_parent_window()
            if not self._parent_window:
                return None
            self._parent_window_source = self.parent

        return self._parent_window

    def bring_to_front(self):
        """Remove it from wherever it is and add it back at the top"""
        if self.parent:
            parent = self.parent
            parent.remove_widget(self)
            parent.add_widget(self)

    def hide(self):
        """Hide the widget"""
        self.visible = False

    def show(self):
        """Show the widget"""
        self.visible = True

    def on_update(self):
        for w in self.children[:]:
            w.dispatch_event("on_update")

    def on_draw(self):
        self.draw()
        if self.draw_children:
            for w in self.children[:]:
                w.dispatch_event("on_draw")

    def draw(self):
        """Handle the draw of widget.
        Derivate this method to draw your widget."""
        set_color(*self.style.get("bg-color"))
        drawCSSRectangle(pos=self.pos, size=self.size, style=self.style)

    def add_widget(self, w, front=True):
        """Add a widget in the children list."""
        if front:
            self.children.append(w)
        else:
            self.children.insert(0, w)
        try:
            w.parent = self
        except Exception:
            pass

    def add_widgets(self, *widgets):
        for w in widgets:
            self.add_widget(w)

    def remove_widget(self, w):
        """Remove a widget from the children list"""
        if w in self.children:
            self.children.remove(w)

    def on_animation_complete(self, *largs):
        pass

    def on_parent(self):
        pass

    def on_parent_resize(self, w, h):
        pass

    def on_resize(self, w, h):
        for c in self.children[:]:
            c.dispatch_event("on_parent_resize", w, h)

    def on_move(self, x, y):
        for c in self.children[:]:
            c.dispatch_event("on_move", x, y)

    def on_touch_down(self, touch):
        for w in reversed(self.children[:]):
            if w.dispatch_event("on_touch_down", touch):
                return True

    def on_touch_move(self, touch):
        for w in reversed(self.children[:]):
            if w.dispatch_event("on_touch_move", touch):
                return True

    def on_touch_up(self, touch):
        for w in reversed(self.children[:]):
            if w.dispatch_event("on_touch_up", touch):
                return True

    def do(self, animation):
        """Apply/Start animations on the widgets.

        :Parameters:
            `animation` : Animation Object
                Animation object with properties to be animateds ","
        """
        if not animation.set_widget(self):
            return
        # XXX bug from Animation framework
        # we need to store a reference of our animation class
        # otherwise, if the animation is called with self.do(),
        # gc can suppress reference, and it's gone !
        animobj = animation.start(self)
        self.__animationcache__.add(animobj)

        def animobject_on_complete(widget, *l):
            if widget != self:
                return
            if animobj in self.__animationcache__:
                self.__animationcache__.remove(animobj)

        animation.connect("on_complete", animobject_on_complete)
        return animobj

    # generate event for all baseobject methods

    def _set_pos(self, x):
        if super(MTWidget, self)._set_pos(x):
            self.dispatch_event("on_move", *self._pos)
            return True

    pos = property(EventDispatcher._get_pos, _set_pos)

    def _set_x(self, x):
        if super(MTWidget, self)._set_x(x):
            self.dispatch_event("on_move", *self._pos)
            return True

    x = property(EventDispatcher._get_x, _set_x)

    def _set_y(self, x):
        if super(MTWidget, self)._set_y(x):
            self.dispatch_event("on_move", *self._pos)
            return True

    y = property(EventDispatcher._get_y, _set_y)

    def _set_size(self, x):
        if super(MTWidget, self)._set_size(x):
            self.dispatch_event("on_resize", *self._size)
            return True

    size = property(EventDispatcher._get_size, _set_size)

    def _set_width(self, x):
        if super(MTWidget, self)._set_width(x):
            self.dispatch_event("on_resize", *self._size)
            return True

    width = property(EventDispatcher._get_width, _set_width)

    def _set_height(self, x):
        if super(MTWidget, self)._set_height(x):
            self.dispatch_event("on_resize", *self._size)
            return True

    height = property(EventDispatcher._get_height, _set_height)
示例#3
0
class MTFlippableWidget(MTWidget):
    '''This is wrapper widget using which you can make a
    widget have two sides and you can flip between the sides ::

        from pymt import *

        widget = MTFlippableWidget()
        widget.add_widget(MTLabel(label='Front'), side='front')
        widget.add_widget(MTLabel(label='Back'), side='back')

        @widget.event
        def on_touch_down(touch):
            widget.flip()

        runTouchApp(widget)

    :Parameters:
        `flipangle` : float, default to 90.
            Angle to flip back/front

    '''
    def __init__(self, **kwargs):
        kwargs.setdefault('flipangle', 90.)
        super(MTFlippableWidget, self).__init__(**kwargs)
        self.flipangle = kwargs.get('flipangle')

        # For flipping animations
        self.zangle = 0
        self.side = 'front'

        # Holds children for both sides
        self.children_front = SafeList()
        self.children_back = SafeList()

        self._anim_current = None
        self._anim_back = Animation(zangle=180)
        self._anim_front = Animation(zangle=0)

    def add_widget(self, w, side='front', front=True):
        '''Add a widget on a side.

        :Parameters:
            `front` : boolean, default is True
                Indicate if the widget must be top added or bottom added in the list.
            `side` : string, default is 'front'
                Specify which side you want to add widget.
                (can be one of 'front', 'back' or '', defaults to add to both sides)
        '''
        assert (side in ('front', 'back', ''))
        if side == 'front':
            if front:
                self.children_front.append(w)
            else:
                self.children_front.insert(0, w)
        elif side == 'back':
            if front:
                self.children_back.append(w)
            else:
                self.children_back.insert(0, w)
        else:
            self.add_widget(w, side='front', front=front)
            self.add_widget(w, side='back', front=front)

        if self.side == side:
            super(MTFlippableWidget, self).add_widget(w, front)

        try:
            w.parent = self
        except Exception:
            pass

    def draw(self):
        set_color(*self.style.get('bg-color'))
        drawCSSRectangle(pos=(0, 0), size=self.size, style=self.style)

    def _flip_children(self):
        # This has to be called exactly half way through the animation
        # so it looks like there are actually two sides'''
        if self.side == 'front':
            self.side = 'back'
            self.children.clear()
            for x in self.children_back[:]:
                super(MTFlippableWidget, self).add_widget(x)
        else:
            self.side = 'front'
            self.children.clear()
            for x in self.children_front[:]:
                super(MTFlippableWidget, self).add_widget(x)

    def _set_side(self, to):
        assert (to in ('back', 'front'))
        if to == 'back' and self.side == 'front':
            self._flip_children()
        elif to == 'front' and self.side == 'back':
            self._flip_children()

    def flip_to(self, to):
        '''Flip to the requested side ('front' or 'back')'''
        assert (to in ('back', 'front'))
        if to == 'back' and self.side == 'front':
            self.flip()
        elif to == 'front' and self.side == 'back':
            self.flip()

    def flip(self):
        '''Triggers a flipping animation'''
        if self._anim_current:
            self._anim_current.stop()
        if self.side == 'front':
            self._anim_current = self.do(self._anim_back)
        else:
            self._anim_current = self.do(self._anim_front)

    def on_update(self):
        if self.zangle < self.flipangle:
            self._set_side('front')
        else:
            self._set_side('back')
        return super(MTFlippableWidget, self).on_update()

    def on_draw(self):
        with gx_matrix:
            glTranslatef(self.x, self.y, 0)
            glTranslatef(self.width / 2, 0, 0)
            if self.side == 'front':
                glRotatef(self.zangle, 0, 1, 0)
            else:
                glRotatef(self.zangle + 180, 0, 1, 0)
            glTranslatef(-self.width / 2, 0, 0)
            super(MTFlippableWidget, self).on_draw()
示例#4
0
class MTWidget(EventDispatcher):
    '''Global base for any multitouch widget.
    Implement event for mouse, object, touch and animation.

    Event are dispatched through widget only if it's visible.

    :Parameters:
        `pos` : list, default is (0, 0)
            Position of widget, in (x, y) format
        `x` : int, default is None
            X position of widget
        `y` : int, default is None
            Y position of widget
        `size` : list, default is (100, 100)
            Size of widget, in (width, height) format
        `width` : int, default is None
            width position of widget
        `height` : int, default is None
            height position of widget
        `visible` : bool, default is True
            Visibility of widget
        `draw_children` : bool, default is True
            Indicate if children will be draw, or not
        `style` : dict, default to {}
            Add inline CSS
        `cls` : str, default is ''
            CSS class of this widget

    :Events:
        `on_update` ()
            Used to update the widget and his children.
        `on_draw` ()
            Used to draw the widget and his children.
        `on_touch_down` (Touch touch)
            Fired when a blob appear
        `on_touch_move` (Touch touch)
            Fired when a blob is moving
        `on_touch_up` (Touch touch)
            Fired when a blob disappear
        `on_resize` (float width, float height)
            Fired when widget is resized
        `on_parent_resize` (float width, float height)
            Fired when parent widget is resized
    '''

    __metaclass__ = MTWidgetMetaclass

    __slots__ = ('children', 'style', 'draw_children', '_cls',
                 '_root_window_source', '_root_window',
                 '_parent_window_source', '_parent_window',
                 '_parent_layout_source', '_parent_layout', '_size_hint',
                 '_id', '_parent', '_visible', '_inline_style',
                 '__animationcache__', '__weakref__')

    visible_events = [
        'on_draw', 'on_touch_up', 'on_touch_move', 'on_touch_down'
    ]

    def __init__(self, **kwargs):
        kwargs.setdefault('pos', (0, 0))
        kwargs.setdefault('x', None)
        kwargs.setdefault('y', None)
        kwargs.setdefault('size', (100, 100))
        kwargs.setdefault('size_hint', (None, None))
        kwargs.setdefault('width', None)
        kwargs.setdefault('height', None)
        kwargs.setdefault('visible', True)
        kwargs.setdefault('draw_children', True)
        kwargs.setdefault('cls', '')
        kwargs.setdefault('style', {})

        self._id = None
        if 'id' in kwargs:
            self.id = kwargs.get('id')

        super(MTWidget, self).__init__(**kwargs)

        # Registers events
        for ev in MTWidget.visible_events:
            self.register_event_type(ev)

        # privates
        self.__animationcache__ = set()
        self._parent = None
        self._visible = None
        self._size_hint = kwargs.get('size_hint')

        #: List of children (SafeList)
        self.children = SafeList()
        #: If False, childrens are not drawed. (deprecated)
        self.draw_children = kwargs.get('draw_children')
        #: Dictionnary that contains the widget style
        self.style = {}

        # apply visibility
        self.visible = kwargs.get('visible')

        # cache for get_parent_window()
        self._parent_layout = None
        self._parent_layout_source = None
        self._parent_window = None
        self._parent_window_source = None
        self._root_window = None
        self._root_window_source = None

        # register events
        register_event_type = self.register_event_type
        for event in ('on_update', 'on_animation_complete', 'on_resize',
                      'on_parent_resize', 'on_move', 'on_parent'):
            register_event_type(event)

        if kwargs.get('x'):
            self._pos = (kwargs.get('x'), self.y)
        if kwargs.get('y'):
            self._pos = (self.x, kwargs.get('y'))
        if kwargs.get('width'):
            self._size = (kwargs.get('width'), self.height)
        if kwargs.get('height'):
            self._size = (self.width, kwargs.get('height'))

        # apply style
        self._cls = ''
        self._inline_style = kwargs['style']

        # loading is done here automaticly
        self.cls = kwargs.get('cls')

    def _set_cls(self, cls):
        self._cls = cls
        self.reload_css()

    def _get_cls(self):
        return self._cls

    cls = property(
        _get_cls,
        _set_cls,
        doc='Get/Set the class of the widget (used for CSS, can be a string '
        'or a list of string')

    def _set_parent(self, parent):
        self._parent = parent
        self.dispatch_event('on_parent')

    def _get_parent(self):
        return self._parent

    parent = property(
        _get_parent,
        _set_parent,
        doc='MTWidget: parent of widget. Fired on_parent event when set')

    def _set_id(self, id):
        ref = weakref.ref(self)
        if ref in _id_2_widget:
            del _id_2_widget[self._id]
        self._id = id
        if self._id:
            if ref in _id_2_widget:
                pymt_logger.warning(
                    'Widget: ID <%s> is already used ! Replacing with new one.'
                    % id)
            _id_2_widget[self._id] = ref

    def _get_id(self):
        return self._id

    id = property(_get_id, _set_id, doc='str: id of widget')

    def _set_visible(self, visible):
        if self._visible == visible:
            return
        self._visible = visible
        # register or unregister event if the widget is visible or not
        if visible:
            for ev in MTWidget.visible_events:
                self.register_event_type(ev)
        else:
            for ev in MTWidget.visible_events:
                self.unregister_event_type(ev)

    def _get_visible(self):
        return self._visible

    visible = property(
        _get_visible,
        _set_visible,
        doc=''
        'True if the widget is visible. If False, the events on_draw,'
        'on_touch_down, on_touch_move, on_touch_up are not dispatched.')

    def _set_size_hint(self, size_hint):
        if self._size_hint == size_hint:
            return False
        self._size_hint = size_hint

    def _get_size_hint(self):
        return self._size_hint

    size_hint = property(
        _get_size_hint,
        _set_size_hint,
        doc=
        'size_hint is used by layouts to determine size behaviour during layout'
    )

    def apply_css(self, styles):
        '''Called at __init__ time to applied css attribute in current class.
        '''
        self.style.update(styles)

    def reload_css(self):
        '''Called when css want to be reloaded from scratch'''
        self.style = {}
        style = css_get_style(widget=self)
        self.apply_css(style)
        if len(self._inline_style):
            self.apply_css(self._inline_style)

    def to_widget(self, x, y, relative=False):
        '''Return the coordinate from window to local widget'''
        if self.parent:
            x, y = self.parent.to_widget(x, y)
        return self.to_local(x, y, relative=relative)

    def to_window(self, x, y, initial=True, relative=False):
        '''Transform local coordinate to window coordinate'''
        if not initial:
            x, y = self.to_parent(x, y, relative=relative)
        if self.parent:
            return self.parent.to_window(x,
                                         y,
                                         initial=False,
                                         relative=relative)
        return (x, y)

    def to_parent(self, x, y, relative=False):
        '''Transform local coordinate to parent coordinate

        :Parameters:
            `relative`: bool, default to False
                Change to True is you want to translate relative position from
                widget to his parent.
        '''
        if relative:
            return (x + self.x, y + self.y)
        return (x, y)

    def to_local(self, x, y, relative=False):
        '''Transform parent coordinate to local coordinate

        :Parameters:
            `relative`: bool, default to False
                Change to True is you want to translate a coordinate to a
                relative coordinate from widget.
        '''
        if relative:
            return (x - self.x, y - self.y)
        return (x, y)

    def collide_point(self, x, y):
        '''Test if the (x,y) is in widget bounding box'''
        if not self.visible:
            return False
        if x > self.x  and x < self.x + self.width and \
           y > self.y and y < self.y + self.height:
            return True

    def get_root_window(self):
        '''Return the root window of widget'''
        if not self.parent:
            return None

        # cache value
        if self._root_window_source != self.parent or self._root_window is None:
            self._root_window = self.parent.get_root_window()
            if not self._root_window:
                return None
            self._root_window_source = self.parent

        return self._root_window

    def get_parent_layout(self):
        '''Return the parent layout of widget'''
        if not self.parent:
            return None

        # cache value
        if self._parent_layout_source != self.parent or self._parent_layout is None:
            self._parent_layout = self.parent.get_parent_layout()
            if not self._parent_layout:
                return None
            self._parent_layout_source = self.parent

        return self._parent_layout

    def get_parent_window(self):
        '''Return the parent window of widget'''
        if not self.parent:
            return None

        # cache value
        if self._parent_window_source != self.parent or self._parent_window is None:
            self._parent_window = self.parent.get_parent_window()
            if not self._parent_window:
                return None
            self._parent_window_source = self.parent

        return self._parent_window

    def bring_to_front(self):
        '''Remove it from wherever it is and add it back at the top'''
        if self.parent:
            parent = self.parent
            parent.remove_widget(self)
            parent.add_widget(self)

    def hide(self):
        '''Hide the widget'''
        self.visible = False

    def show(self):
        '''Show the widget'''
        self.visible = True

    def on_update(self):
        for w in self.children[:]:
            w.dispatch_event('on_update')

    def on_draw(self):
        self.draw()
        if self.draw_children:
            for w in self.children[:]:
                w.dispatch_event('on_draw')

    def draw(self):
        '''Handle the draw of widget.
        Derivate this method to draw your widget.'''
        set_color(*self.style.get('bg-color'))
        drawCSSRectangle(pos=self.pos, size=self.size, style=self.style)

    def add_widget(self, w, front=True):
        '''Add a widget in the children list.'''
        if front:
            self.children.append(w)
        else:
            self.children.insert(0, w)
        try:
            w.parent = self
        except Exception:
            pass

    def add_widgets(self, *widgets):
        for w in widgets:
            self.add_widget(w)

    def remove_widget(self, w):
        '''Remove a widget from the children list'''
        if w in self.children:
            self.children.remove(w)

    def on_animation_complete(self, *largs):
        pass

    def on_parent(self):
        pass

    def on_parent_resize(self, w, h):
        pass

    def on_resize(self, w, h):
        for c in self.children[:]:
            c.dispatch_event('on_parent_resize', w, h)

    def on_move(self, x, y):
        for c in self.children[:]:
            c.dispatch_event('on_move', x, y)

    def on_touch_down(self, touch):
        for w in reversed(self.children[:]):
            if w.dispatch_event('on_touch_down', touch):
                return True

    def on_touch_move(self, touch):
        for w in reversed(self.children[:]):
            if w.dispatch_event('on_touch_move', touch):
                return True

    def on_touch_up(self, touch):
        for w in reversed(self.children[:]):
            if w.dispatch_event('on_touch_up', touch):
                return True

    def do(self, animation):
        '''Apply/Start animations on the widgets.

        :Parameters:
            `animation` : Animation Object
                Animation object with properties to be animateds ","
        '''
        if not animation.set_widget(self):
            return
        # XXX bug from Animation framework
        # we need to store a reference of our animation class
        # otherwise, if the animation is called with self.do(),
        # gc can suppress reference, and it's gone !
        animobj = animation.start(self)
        self.__animationcache__.add(animobj)

        def animobject_on_complete(widget, *l):
            if widget != self:
                return
            if animobj in self.__animationcache__:
                self.__animationcache__.remove(animobj)

        animation.connect('on_complete', animobject_on_complete)
        return animobj

    # generate event for all baseobject methods

    def _set_pos(self, x):
        if super(MTWidget, self)._set_pos(x):
            self.dispatch_event('on_move', *self._pos)
            return True

    pos = property(EventDispatcher._get_pos, _set_pos)

    def _set_x(self, x):
        if super(MTWidget, self)._set_x(x):
            self.dispatch_event('on_move', *self._pos)
            return True

    x = property(EventDispatcher._get_x, _set_x)

    def _set_y(self, x):
        if super(MTWidget, self)._set_y(x):
            self.dispatch_event('on_move', *self._pos)
            return True

    y = property(EventDispatcher._get_y, _set_y)

    def _set_size(self, x):
        if super(MTWidget, self)._set_size(x):
            self.dispatch_event('on_resize', *self._size)
            return True

    size = property(EventDispatcher._get_size, _set_size)

    def _set_width(self, x):
        if super(MTWidget, self)._set_width(x):
            self.dispatch_event('on_resize', *self._size)
            return True

    width = property(EventDispatcher._get_width, _set_width)

    def _set_height(self, x):
        if super(MTWidget, self)._set_height(x):
            self.dispatch_event('on_resize', *self._size)
            return True

    height = property(EventDispatcher._get_height, _set_height)