Ejemplo n.º 1
0
    def __init__(self):

        self._loading_image = None
        self._error_image = None

        self._q_load  = collections.deque()
        self._q_done  = collections.deque()
        self._client  = SafeList()
        self._running = False
        self._start_wanted = False

        getClock().schedule_interval(self._update, 1 / 25.)
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    def __init__(self, **kwargs):
        kwargs.setdefault('show_tabs', False)
        kwargs.setdefault('duration', 1.)
        super(MTScreenLayout, self).__init__(**kwargs)
        self.screens = SafeList()
        self.screen = None
        self.previous_screen = None
        self._switch_t = 1.1
        self.duration = kwargs.get('duration')

        self.container = MTBoxLayout(orientation='vertical')
        super(MTScreenLayout, self).add_widget(self.container)

        self.tabs = self.new_tab_layout()
        self._show_tabs = False
        self.show_tabs = kwargs.get('show_tabs', False)
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    def __init__(self, **kwargs):
        kwargs.setdefault('group', None)
        super(MTToggleButton, self).__init__(**kwargs)

        # add the widget to the group if exist.
        self._group = kwargs.get('group')
        if self._group is not None:
            if not self._group in self._groups:
                MTToggleButton._groups[self._group] = SafeList()
            ref = weakref.ref(self)
            MTToggleButton._groups[self._group].append(ref)
Ejemplo n.º 6
0
    def __init__(self, device, id, args):
        if self.__class__ == Touch:
            raise NotImplementedError, 'class Touch is abstract'

        # Uniq ID
        Touch.__uniq_id += 1
        self.uid = Touch.__uniq_id
        self.device = device

        # For push/pop
        self.attr = []
        self.default_attrs = (
            'x', 'y', 'z',
            'dxpos', 'dypos', 'dzpos',
            'oxpos', 'oypos', 'ozpos')

        # For grab
        self.grab_list = SafeList()
        self.grab_exclusive_class = None
        self.grab_state = False
        self.grab_current = None

        # TUIO definition
        self.id = id
        self.sx = 0.0
        self.sy = 0.0
        self.sz = 0.0
        self.profile = ('pos', )

        # new parameters
        self.x = 0.0
        self.y = 0.0
        self.z = 0.0
        self.shape = None
        self.dxpos = None
        self.dypos = None
        self.dzpos = None
        self.oxpos = None
        self.oypos = None
        self.ozpos = None
        self.dsxpos = None
        self.dsypos = None
        self.dszpos = None
        self.osxpos = None
        self.osypos = None
        self.oszpos = None
        self.time_start = getClock().get_time()
        self.is_double_tap = False
        self.double_tap_time = 0
        self.userdata = {}

        self.depack(args)
Ejemplo n.º 7
0
Archivo: loader.py Proyecto: bernt/pymt
    def __init__(self):
        loading_png_fn = os.path.join(pymt_data_dir, 'loader.png')
        error_png_fn = os.path.join(pymt_data_dir, 'error.png')

        self.loading_image = ImageLoader.load(loading_png_fn)
        self.error_image = ImageLoader.load(error_png_fn)

        self._q_load  = collections.deque()
        self._q_done  = collections.deque()
        self._client  = SafeList()
        self._running = False
        self._start_wanted = False

        getClock().schedule_interval(self._update, 1 / 25.)
Ejemplo n.º 8
0
    def __init__(self, **kwargs):
        kwargs.setdefault('show_tabs', False)
        kwargs.setdefault('duration', 1.)
        super(MTScreenLayout, self).__init__(**kwargs)
        self.screens = SafeList()
        self.screen = None
        self.previous_screen = None
        self._switch_t = 1.1
        self.duration = kwargs.get('duration')

        self.container = MTBoxLayout(orientation='vertical')
        super(MTScreenLayout, self).add_widget(self.container)

        self.tabs = self.new_tab_layout()
        self._show_tabs  = False
        self.show_tabs = kwargs.get('show_tabs', False)
Ejemplo n.º 9
0
    def fullscreen(self, *largs, **kwargs):
        root_win = self.parent.get_parent_window()

        # save state for restore
        self.old_children = root_win.children
        self.old_size = self.size

        # set new children
        root_win.children = SafeList()
        root_win.add_widget(self.container)

        btn_unfullscreen = MTButton(pos=(root_win.width - 50,
                                         root_win.height - 50),
                                    size=(50, 50),
                                    label='Back')
        btn_unfullscreen.push_handlers(on_release=self.unfullscreen)
        root_win.add_widget(btn_unfullscreen)
        self.size = root_win.size
        self.container.size = self.size
Ejemplo n.º 10
0
class MTKineticList(MTStencilContainer):
    '''This is a kinetic container widget, that allows you to make
    a kinetic list scrolling in either direction.

    :Parameters:
        `align` : string, default to 'center'
            Alignement of widget inside the row (or col). Can be
            one of 'center', 'left', 'right'
        `friction` : float, defaults to 10
            The Pseudo-friction of the pseudo-kinetic scrolling.
            Formula for friction is ::

                acceleration = 1 + friction * frame_delta_time

        `padding_x` : int, defaults to 4
            The spacing between scrolling items on the x axis
        `padding_y` : int, defaults to 4
            The spacing between scrolling items on the y axis
        `w_limit` : int, defaults to 1
            The limit of items that will appear horizontally.
            When this is set to a non-zero value the width(in
            terms of items in the kinetic list) will be w_limit,
            and the height will continually expand.
        `h_limit` : int, defaults to 0
            Exect opposite of w_limit.  If I didn't make either
            this or w_limit clear go bug xelapond
        `do_x` : bool, defaults to False
            Enable scrolling on the X axis
        `do_y` : bool, defaults to True
            Enable scrolling on the Y axis
        `title` : string, defaults to <Title Goes Here>
            Sets the title of the widget, which appears in 20
            point font at the top
        `deletable` : bool, defaults to True
            When enabled it allows you to delete children by
            entering delete mode(red button in upper left)
        `searchable` : bool, defaults to True
            When enabled it allows you to enter search mode
            and filter items
        `trigger_distance` : int, default to 3
            Maximum trigger distance to dispatch event on children
            (this mean if you move too much, trigger will not happen.)

    :Styles:
        `bg-color` : color
             Background color of the widget
        `scrollbar-size` : int
            Size of scrollbar in pixel (use 0 to disable it.)
        `scrollbar-color` : color
            Color of scrollbar
        `scrollbar-margin` : int int int int
            Margin top/right/bottom/left of scrollbar (left are not used.)

    :Events:
        `on_delete` (child)
            Fired when an item gets deleted.
    '''
    def __init__(self, **kwargs):
        kwargs.setdefault('friction', 10)
        kwargs.setdefault('padding_x', 4)
        kwargs.setdefault('padding_y', 4)
        kwargs.setdefault('w_limit', 1)
        kwargs.setdefault('h_limit', 0)
        kwargs.setdefault('do_x', False)
        kwargs.setdefault('do_y', True)
        kwargs.setdefault('title', 'No title')
        kwargs.setdefault('deletable', True)
        kwargs.setdefault('searchable', True)
        kwargs.setdefault('trigger_distance', 3)
        kwargs.setdefault('align', 'center')

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

        self.register_event_type('on_delete')

        self._a_sinput_out  = None
        self._a_sinput_in   = None
        self.title          = Label('')
        self.sb             = None
        self.sinput         = None

        self.do_x       = kwargs.get('do_x')
        self.do_y       = kwargs.get('do_y')
        self.titletext  = kwargs.get('title')
        self.deletable  = kwargs.get('deletable')
        self.searchable = kwargs.get('searchable')
        self.friction   = kwargs.get('friction')
        self.padding_x  = kwargs.get('padding_x')
        self.padding_y  = kwargs.get('padding_y')
        self.w_limit    = kwargs.get('w_limit')
        self.h_limit    = kwargs.get('h_limit')
        self.align      = kwargs.get('align')
        self.trigger_distance = kwargs.get('trigger_distance')

        if self.w_limit and self.h_limit:
            raise Exception('You cannot limit both axes')
        elif not(self.w_limit or self.h_limit):
            raise Exception('You must limit at least one axis')

        # How far to offset tself.deletable and he axes(used for scrolling/panning)
        self.xoffset = 0
        self.yoffset = 0
        # X and Y translation vectors for the kinetic movement
        self.vx = 0
        self.vy = 0
        # List of all children, whatever will be the search
        self.pchildren = []
        # For extra blob stats
        self.touch = {}
        # Holds widgets not a part of the scrolling(search button, etc)
        self.widgets = []
        self._last_content_size = 0
        self._scrollbar_index = 0
        self._scrollbar_size = 0

        # create the UI part.
        self._create_ui()

    def _create_ui(self):
        # Title Text
        if self.titletext is not None:
            self.title = Label(
                font_size=18,
                bold=True,
                anchor_x='center',
                anchor_y='center',
                label=self.titletext)
            self.title.x = self.width/2 + self.x
            self.title.y = self.height - 20 + self.y

        # Delete Button
        if self.deletable:
            self.db = MTToggleButton(
                label='X',
                pos=(self.x + self.width - 80, self.y + self.height - 40),
                size=(80, 40),
                cls='kineticlist-delete')
            self.db.push_handlers(on_press=self.toggle_delete)
            self.widgets.append(self.db)

        # Search Button and Input Text Area
        if self.searchable:
            self.sb = MTToggleButton(
                label='S',  #Button
                pos=(self.x, self.y + self.width - 40),
                size=(80, 40),
                cls='kineticlist-search')

            self.sb.push_handlers(on_press=self.toggle_search)
            self.sb.parent = self
            self.widgets.append(self.sb)

            self.sinput = pymt.MTTextInput(pos=
                (self.x, self.y + self.height - 40), size=(80, 40),
                style={'font-size': 20})
            self.sinput.parent = self
            self.sinput.push_handlers(on_text_change=self.apply_filter)
            self.widgets.insert(0, self.sinput)

            # Animations to hide and show the search text input box
            self._a_sinput_in = Animation(y=self.y + self.height - 40 -
                                         self.sinput.size[1], duration=0.5,
                                         f='ease_out_cubic')
            self._a_sinput_out = Animation(y=self.y + self.height -
                                          self.sinput.size[1], duration=0.5,
                                         f='ease_out_cubic')

    def on_delete(self, child):
        pass

    def clear(self):
        self.children = SafeList()
        self.pchildren = SafeList()
        self.xoffset = self.yoffset = 0

    def add_widget(self, widget, **kwargs):
        super(MTKineticList, self).add_widget(widget, **kwargs)
        self.pchildren.append(widget)

    def remove_widget(self, widget):
        super(MTKineticList, self).remove_widget(widget)
        if widget in self.pchildren:
            self.pchildren.remove(widget)
        self.dispatch_event('on_delete', widget)

    def toggle_delete(self, touch):
        '''Toggles the delete buttons on items
        Attached to the on_press handler of the delete button(self.db)
        '''
        if self.db.state == 'down':
            for child in self.children[:]:
                child.show_delete()
        else:
            for child in self.children[:]:
                child.hide_delete()

    def toggle_search(self, touch):
        '''Toggles the search area
        Attached to the on_press handler of self.sb(the green search button)
        '''
        if self.sb.state == 'down':
            self._a_sinput_in.animate(self.sinput)
        else:
            try:
                self.sinput.hide_keyboard()
            except:
                # There isn't a keyboard, so it throws a ValueError
                pass
            self.sinput.label = ''
            self._a_sinput_out.animate(self.sinput)

    def apply_filter(self, text):
        '''Applies the filter to the current children set'''
        self.search(text, 'label')
        #Move them so you don't have to scroll up to see them
        self.yoffset = self.padding_y
        self.xoffset = self.padding_x

    def filter(self, pattern, attr):
        '''Given an attribute of the children, and a pattern, return
        a list of the children with which pattern is in attr
        '''
        return filter(lambda c: pattern in str(getattr(c, attr)), self.pchildren)

    def search(self, pattern, attr):
        '''Apply a search pattern to the current set of children'''
        result = self.filter(pattern, attr)
        self.children.clear()
        for item in result:
            self.children.append(item)

    def endsearch(self):
        '''Resets the children set to the full set'''
        self.children.clear()
        for item in self.pchildren:
            self.children.append(item)

    def _get_total_width(self, items, axis):
        '''Given a list of items and an axis, return the space
        they take up(in pixels)
        '''
        total = 0
        if axis == 'width':
            for item in items:
                total += (item.width + self.padding_x)
        elif axis == 'height':
            for item in items:
                total += (item.height + self.padding_y)

        return total

    def goto_head(self):
        if not self.h_limit:
            self.yoffset = -self._get_total_width(self.children, 'height')/self.w_limit + self.size[1] - 100
        else:
            self.xoffset = self._get_total_width(self.children, 'width')/self.h_limit + self.size[0] - 100

    def do_layout(self):
        '''Apply layout to all the items'''

        t = index = 0

        # adapt value for direction
        w2          = self.width / 2.
        h2          = self.height / 2.
        inverse     = 0
        limit       = self.w_limit
        width_attr  = 'width'
        height_attr = 'height'
        xoffset     = self.xoffset
        sx          = self.x
        y           = self.y + self.yoffset
        padding_x   = self.padding_x
        padding_y   = self.padding_y

        # inverse
        if not self.w_limit:
            inverse     = 1
            limit       = self.h_limit
            width_attr  = 'height'
            height_attr = 'width'
            xoffset     = self.yoffset
            y           = self.x + self.xoffset
            padding_x   = self.padding_y
            padding_y   = self.padding_x
            w2, h2      = h2, w2
            sx          = self.y

        # calculate size of actual content
        size = 0
        for i in xrange(len(self.children)):
            if i % limit == 0:
                maxrange = min(i + limit, len(self.children))
                childrens = [self.children[z] for z in range(i, maxrange)]
                h = max((c.__getattribute__(height_attr) for c in childrens))
                size += h + padding_y
        self._last_content_size = size

        # add little padding for good looking.
        y += padding_y
        ny = y

        # recalculate position for each children
        for child in self.children[:]:

            # each row, calculate the height, advance y and reset x
            if index % limit == 0:

                # set y axis to the previous calculated position
                y = ny

                # get children in the row
                maxrange = min(t + limit, len(self.children))
                childrens = [self.children[z] for z in range(t, maxrange)]

                # take the largest height in the current row
                if len(childrens):
                    h = max((c.__getattribute__(height_attr) for c in childrens))
                else:
                    h = 0

                # prepare the y axis for next loop
                ny = y + h + padding_y

                # reset x for this row.
                if self.align == 'center':
                    x = sx + w2 + xoffset - \
                        (self._get_total_width(childrens, width_attr) / 2.)
                elif self.align == 'left':
                    x = 0
                elif self.align == 'right':
                    x = getattr(self, width_attr) - getattr(child, width_attr) - xoffset
                t += limit

            # reposition x
            if not inverse:
                child.kx = x + padding_x
                child.ky = y
            else:
                child.ky = x + padding_x
                child.kx = y
            x += child.__getattribute__(width_attr) + padding_x

            # Increment index
            index += 1

    def on_touch_down(self, touch):
        if not self.collide_point(touch.x, touch.y):
            return

        # ok, it's a touch for us. grab it !
        touch.grab(self)

        # first, check if own widget take the touch
        for w in reversed(self.widgets[:]):
            if w.on_touch_down(touch):
                return True

        # initiate kinetic movement.
        self.vx = self.vy = 0
        self.touch[touch.id] = {
            'ox': touch.x,
            'oy': touch.y,
            'xmot': 0,
            'ymot': 0,
            'travelx' : 0, #How far the blob has traveled total in the x axis
            'travely' : 0, #^
        }
        return True

    def on_touch_move(self, touch):
        # accept only grabbed touch by us
        if touch.grab_current != self:
            return

        # ok, if it's not a kinetic movement,
        # dispatch to children
        if touch.id not in self.touch:
            for w in reversed(self.widgets[:]):
                if w.on_touch_move(touch):
                    return True
            return

        # it's a kinetic movement, process it.
        t = self.touch[touch.id]
        t['xmot'] = touch.x - t['ox']
        t['ymot'] = touch.y - t['oy']
        t['ox'] = touch.x
        t['oy'] = touch.y
        t['travelx'] += abs(t['xmot'])
        t['travely'] += abs(t['ymot'])
        self.xoffset += t['xmot'] * self.do_x
        self.yoffset += t['ymot'] * self.do_y
        self.ensure_bounding()

    def on_touch_up(self, touch):
        # accept only grabbed touch by us
        if touch.grab_current != self:
            return

        # it's an up, ungrab us !
        touch.ungrab(self)

        if touch.id not in self.touch:
            for w in reversed(self.widgets[:]):
                if w.on_touch_up(touch):
                    return True
            return

        t = self.touch[touch.id]
        self.vx = t['xmot']
        self.vy = t['ymot']

        # check if we can transmit event to children
        if (self.do_x and t['travelx'] > self.trigger_distance) or \
           (self.do_y and t['travely'] > self.trigger_distance):
            return True

        # ok, the trigger distance is enough, we can dispatch event.
        # will not work if children grab the touch in down state :/
        for child in reversed(self.children[:]):
            must_break = child.dispatch_event('on_touch_down', touch)
            old_grab_current = touch.grab_current
            touch.grab_current = child
            child.dispatch_event('on_touch_up', touch)
            touch.grab_current = old_grab_current
            if must_break:
                break
        return True

    def ensure_bounding(self):
        size = float(self._last_content_size)
        if size <= 0:
            return

        self._scrollbar_size = 1
        self._scrollbar_index = 0

        if self.do_y:
            if size < self.height:
                self.yoffset = 0
            else:
                self.yoffset = boundary(self.yoffset, -size + self.height, 0)
                self._scrollbar_size = self.height / size
                self._scrollbar_index = -self.yoffset / size
        if self.do_x:
            if size < self.width:
                self.xoffset = 0
            else:
                self.xoffset = boundary(self.xoffset, -size + self.width, 0)
                self._scrollbar_size = self.width / size
                self._scrollbar_index = -self.xoffset / size

    def process_kinetic(self):
        '''Apply kinetic movement to all the items'''
        dt = getFrameDt()
        self.vx /= 1 + (self.friction * dt)
        self.vy /= 1 + (self.friction * dt)

        self.xoffset += self.vx * self.do_x
        self.yoffset += self.vy * self.do_y

        self.ensure_bounding()

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

        # draw children
        self.stencil_push()
        for w in self.children[:]:
            # internal update of children
            w.update()
            # optimization to draw only viewed children
            if self.do_y and (w.y + w.height < self.y or w.y > self.y + self.height):
                continue
            if self.do_x and (w.x + w.width < self.x or w.x > self.x + self.width):
                continue
            w.on_draw()
        self.stencil_pop()

        # draw widgets
        for w in self.widgets:
            w.dispatch_event('on_draw')
        # title bar
        if self.titletext is not None:
            set_color(*self.style.get('title-color'))
            w = 0
            if self.searchable:
                x = 80
                w += 80
            else:
                x = 0
            if self.deletable:
                w += 80
            drawCSSRectangle(pos=(self.x + x, self.height + self.y - 40),
                             size=(self.width - w, 40), prefix='title',
                             style=self.style)
            self.title.x = self.width/2 + self.x
            self.title.y = self.height - 20 + self.y
            self.title.draw()


        # scrollbar
        sb_size = self.style.get('scrollbar-size')
        if sb_size > 0:
            mtop, mright, mbottom, mleft = self.style.get('scrollbar-margin')
            if self.do_y:
                pos = [self.x + self.width - mright - sb_size, self.y + mbottom]
                size = [sb_size, self.height - mbottom - mtop]
                pos[1] += size[1] * self._scrollbar_index
                size[1] = size[1] * self._scrollbar_size
            if self.do_x:
                pos = [self.x + mleft, self.y + self.height - mtop - sb_size]
                size = [self.width - mleft - mright, sb_size]
                pos[0] += size[0] * self._scrollbar_index
                size[0] = size[0] * self._scrollbar_size
            set_color(*self.style.get('scrollbar-color'))
            drawRectangle(pos=pos, size=size)

    def on_draw(self):
        if not self.visible:
            return
        self.do_layout()
        self.process_kinetic()
        self.draw()
Ejemplo n.º 11
0
 def clear(self):
     self.children = SafeList()
     self.pchildren = SafeList()
     self.xoffset = self.yoffset = 0
Ejemplo n.º 12
0
    def __init__(self, **kwargs):

        kwargs.setdefault('force', False)
        kwargs.setdefault('config', None)
        kwargs.setdefault('show_fps', False)
        kwargs.setdefault('style', {})

        # don't init window 2 times,
        # except if force is specified
        if self.__initialized and not kwargs.get('force'):
            return

        super(BaseWindow, self).__init__()

        # init privates
        self._modifiers = []
        self._size = (0, 0)
        self._rotation = 0

        # event subsystem
        self.register_event_type('on_flip')
        self.register_event_type('on_rotate')
        self.register_event_type('on_draw')
        self.register_event_type('on_update')
        self.register_event_type('on_resize')
        self.register_event_type('on_close')
        self.register_event_type('on_touch_down')
        self.register_event_type('on_touch_move')
        self.register_event_type('on_touch_up')
        self.register_event_type('on_mouse_down')
        self.register_event_type('on_mouse_move')
        self.register_event_type('on_mouse_up')
        self.register_event_type('on_keyboard')
        self.register_event_type('on_key_down')
        self.register_event_type('on_key_up')

        # set out window as the main pymt window
        setWindow(self)

        # apply styles for window
        self.style = {}
        style = css_get_style(widget=self)
        self.apply_css(style)

        # apply inline css
        self._inline_style = kwargs.get('style')
        if len(kwargs.get('style')):
            self.apply_css(kwargs.get('style'))

        self.children = SafeList()
        self.parent = self
        self.visible = True

        # add view
        if 'view' in kwargs:
            self.add_widget(kwargs.get('view'))

        # get window params, user options before config option
        params = {}

        if 'fullscreen' in kwargs:
            params['fullscreen'] = kwargs.get('fullscreen')
        else:
            params['fullscreen'] = pymt.pymt_config.get(
                'graphics', 'fullscreen')
            if params['fullscreen'] not in ('auto', 'fake'):
                params['fullscreen'] = params['fullscreen'].lower() in \
                    ('true', '1', 'yes', 'yup')

        if 'width' in kwargs:
            params['width'] = kwargs.get('width')
        else:
            params['width'] = pymt.pymt_config.getint('graphics', 'width')

        if 'height' in kwargs:
            params['height'] = kwargs.get('height')
        else:
            params['height'] = pymt.pymt_config.getint('graphics', 'height')

        if 'vsync' in kwargs:
            params['vsync'] = kwargs.get('vsync')
        else:
            params['vsync'] = pymt.pymt_config.getint('graphics', 'vsync')

        if 'fps' in kwargs:
            params['fps'] = kwargs.get('fps')
        else:
            params['fps'] = pymt.pymt_config.getint('graphics', 'fps')

        if 'rotation' in kwargs:
            params['rotation'] = kwargs.get('rotation')
        else:
            params['rotation'] = pymt.pymt_config.getint(
                'graphics', 'rotation')

        params['position'] = pymt.pymt_config.get('graphics', 'position',
                                                  'auto')
        if 'top' in kwargs:
            params['position'] = 'custom'
            params['top'] = kwargs.get('top')
        else:
            params['top'] = pymt.pymt_config.getint('graphics', 'top')

        if 'left' in kwargs:
            params['position'] = 'custom'
            params['left'] = kwargs.get('left')
        else:
            params['left'] = pymt.pymt_config.getint('graphics', 'left')

        # show fps if asked
        self.show_fps = kwargs.get('show_fps')
        if pymt.pymt_config.getboolean('pymt', 'show_fps'):
            self.show_fps = True

        # configure the window
        self.create_window(params)

        # init some gl
        self.init_gl()

        # attach modules + listener event
        pymt_modules.register_window(self)
        touch_event_listeners.append(self)

        # mark as initialized
        self.__initialized = True
Ejemplo n.º 13
0
class Touch(object):
    '''Abstract class to represent a touch, and support TUIO 1.0 definition.

    :Parameters:
        `id` : str
            uniq ID of the touch
        `args` : list
            list of parameters, passed to depack() function
    '''

    __metaclass__ = TouchMetaclass
    __uniq_id = 0
    __attrs__ = \
        ('device', 'attr',
         'id', 'sx', 'sy', 'sz', 'profile',
         'x', 'y', 'z', 'shape',
         'dxpos', 'dypos', 'dzpos',
         'oxpos', 'oypos', 'ozpos',
         'dsxpos', 'dsypos', 'dszpos',
         'osxpos', 'osypos', 'oszpos',
         'time_start', 'is_double_tap',
         'double_tap_time', 'userdata')

    def __init__(self, device, id, args):
        if self.__class__ == Touch:
            raise NotImplementedError, 'class Touch is abstract'

        # Uniq ID
        Touch.__uniq_id += 1
        self.uid = Touch.__uniq_id
        self.device = device

        # For push/pop
        self.attr = []
        self.default_attrs = (
            'x', 'y', 'z',
            'dxpos', 'dypos', 'dzpos',
            'oxpos', 'oypos', 'ozpos')

        # For grab
        self.grab_list = SafeList()
        self.grab_exclusive_class = None
        self.grab_state = False
        self.grab_current = None

        # TUIO definition
        self.id = id
        self.sx = 0.0
        self.sy = 0.0
        self.sz = 0.0
        self.profile = ('pos', )

        # new parameters
        self.x = 0.0
        self.y = 0.0
        self.z = 0.0
        self.shape = None
        self.dxpos = None
        self.dypos = None
        self.dzpos = None
        self.oxpos = None
        self.oypos = None
        self.ozpos = None
        self.dsxpos = None
        self.dsypos = None
        self.dszpos = None
        self.osxpos = None
        self.osypos = None
        self.oszpos = None
        self.time_start = getClock().get_time()
        self.is_double_tap = False
        self.double_tap_time = 0
        self.userdata = {}

        self.depack(args)

    def depack(self, args):
        '''Depack `args` into attributes in class'''
        if self.dsxpos is None:
            self.dsxpos = self.osxpos = self.sx
            self.dsypos = self.osypos = self.sy
            self.dszpos = self.oszpos = self.sz

    def grab(self, class_instance, exclusive=False):
        '''Grab a touch. You can grab a touch if you absolutly want to receive
        on_touch_move() and on_touch_up(), even if the touch is not dispatched
        by your parent ::

            def on_touch_down(self, touch):
                touch.grab(self)

            def on_touch_move(self, touch):
                if touch.grab_current == self:
                    # i receive my grabbed touch
                else:
                    # it's a normal touch

            def on_touch_up(self, touch):
                if touch.grab_current == self:
                    # i receive my grabbed touch, i must ungrab it !
                    touch.ungrab(self)
                else:
                    # it's a normal touch

        '''
        if self.grab_exclusive_class is not None:
            raise Exception('Cannot grab the touch, touch are exclusive')
        class_instance = weakref.ref(class_instance)
        if exclusive:
            self.grab_exclusive_class = class_instance
        self.grab_list.append(class_instance)

    def ungrab(self, class_instance):
        '''Ungrab a previous grabbed touch'''
        class_instance = weakref.ref(class_instance)
        if self.grab_exclusive_class == class_instance:
            self.grab_exclusive_class = None
        if class_instance in self.grab_list:
            self.grab_list.remove(class_instance)

    def move(self, args):
        '''Move the touch to another position.'''
        self.dxpos = self.x
        self.dypos = self.y
        self.dzpos = self.z
        self.dsxpos = self.sx
        self.dsypos = self.sy
        self.dszpos = self.sz
        self.depack(args)

    def scale_for_screen(self, w, h, p=None):
        '''Scale position for the screen'''
        self.x = self.sx * float(w)
        self.y = self.sy * float(h)
        if p:
            self.z = self.sz * float(p)
        if self.oxpos is None:
            self.dxpos = self.oxpos = self.x
            self.dypos = self.oypos = self.y
            self.dzpos = self.ozpos = self.z

    def push(self, attrs=None):
        '''Push attributes values in `attrs` in the stack'''
        if attrs is None:
            attrs = self.default_attrs
        values = [getattr(self, x) for x in attrs]
        self.attr.append((attrs, values))

    def pop(self):
        '''Pop attributes values from the stack'''
        attrs, values = self.attr.pop()
        for i in xrange(len(attrs)):
            setattr(self, attrs[i], values[i])

    def apply_transform_2d(self, transform):
        '''Apply a transformation on x, y, dxpos, dypos, oxpos, oypos'''
        self.x, self.y = transform(self.x, self.y)
        self.dxpos, self.dypos = transform(self.dxpos, self.dypos)
        self.oxpos, self.oypos = transform(self.oxpos, self.oypos)

    def copy_to(self, to):
        '''Copy some attribute to another touch object.'''
        for attr in self.__attrs__:
            to.__setattr__(attr, copy(self.__getattribute__(attr)))

    def __str__(self):
        classname = str(self.__class__).split('.')[-1].replace('>', '').replace('\'', '')
        return '<%s spos=%s pos=%s>' % (classname, str(self.spos), str(self.pos))

    def distance(self, other_touch):
        return Vector(self.pos).distance(other_touch.pos)

    def __repr__(self):
        out = []
        for x in dir(self):
            v = getattr(self, x)
            if x[0] == '_':
                continue
            if isroutine(v):
                continue
            out.append('%s="%s"' % (x, v))
        return '<%s %s>' % (
            self.__class__.__name__,
            ' '.join(out)
        )

    # facility
    @property
    def pos(self):
        '''Return position of the touch in the screen coordinate
        system (self.x, self.y)'''
        return self.x, self.y

    @property
    def dpos(self):
        '''Return previous position of the touch in the
        screen coordinate system (self.dxpos, self.dypos)'''
        return self.dxpos, self.dypos

    @property
    def opos(self):
        '''Return the initial position of the touch in the screen
        coordinate system (self.oxpos, self.oypos)'''
        return self.oxpos, self.oypos

    @property
    def spos(self):
        '''Return the position in the 0-1 coordinate system
        (self.sx, self.sy)'''
        return self.sx, self.sy

    # compatibility bridge
    xpos = property(lambda self: self.x)
    ypos = property(lambda self: self.y)
    blobID = property(lambda self: self.id)
    xmot = property(lambda self: self.X)
    ymot = property(lambda self: self.Y)
    zmot = property(lambda self: self.Z)
    mot_accel = property(lambda self: self.m)
    rot_accel = property(lambda self: self.r)
    angle = property(lambda self: self.a)
Ejemplo n.º 14
0
    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')
Ejemplo n.º 15
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()
Ejemplo n.º 16
0
class BaseWindow(EventDispatcher):
    """BaseWindow is a abstract window widget, for any window implementation.

    .. warning::

        The parameters are not working in normal case. Because at import, PyMT
        create a default OpenGL window, to add the ability to use OpenGL
        directives, texture creation.. before creating MTWindow.
        If you don't like this behavior, you can include before the very first
        import of PyMT ::

            import os
            os.environ['PYMT_SHADOW'] = '0'
            from pymt import *

        This will forbid PyMT to create the default window !


    :Parameters:
        `fps`: int, default to 0
            Maximum FPS allowed. If 0, fps will be not limited
        `fullscreen`: bool
            Make window as fullscreen
        `width`: int
            Width of window
        `height`: int
            Height of window
        `vsync`: bool
            Vsync window

    :Styles:
        `bg-color`: color
            Background color of window
    """

    __instance = None
    __initialized = False
    _wallpaper = None
    _wallpaper_position = "norepeat"

    def __new__(cls, **kwargs):
        if cls.__instance is None:
            cls.__instance = EventDispatcher.__new__(cls)
        return cls.__instance

    def __init__(self, **kwargs):

        kwargs.setdefault("force", False)
        kwargs.setdefault("config", None)
        kwargs.setdefault("show_fps", False)
        kwargs.setdefault("style", {})

        # don't init window 2 times,
        # except if force is specified
        if self.__initialized and not kwargs.get("force"):
            return

        super(BaseWindow, self).__init__()

        # init privates
        self._modifiers = []
        self._size = (0, 0)
        self._rotation = 0

        # event subsystem
        self.register_event_type("on_flip")
        self.register_event_type("on_rotate")
        self.register_event_type("on_draw")
        self.register_event_type("on_update")
        self.register_event_type("on_resize")
        self.register_event_type("on_close")
        self.register_event_type("on_touch_down")
        self.register_event_type("on_touch_move")
        self.register_event_type("on_touch_up")
        self.register_event_type("on_mouse_down")
        self.register_event_type("on_mouse_move")
        self.register_event_type("on_mouse_up")
        self.register_event_type("on_keyboard")
        self.register_event_type("on_key_down")
        self.register_event_type("on_key_up")

        # set out window as the main pymt window
        setWindow(self)

        # apply styles for window
        self.style = {}
        style = css_get_style(widget=self)
        self.apply_css(style)

        # apply inline css
        self._inline_style = kwargs.get("style")
        if len(kwargs.get("style")):
            self.apply_css(kwargs.get("style"))

        self.children = SafeList()
        self.parent = self
        self.visible = True

        # add view
        if "view" in kwargs:
            self.add_widget(kwargs.get("view"))

        # get window params, user options before config option
        params = {}

        if "fullscreen" in kwargs:
            params["fullscreen"] = kwargs.get("fullscreen")
        else:
            params["fullscreen"] = pymt.pymt_config.get("graphics", "fullscreen")
            if params["fullscreen"] not in ("auto", "fake"):
                params["fullscreen"] = params["fullscreen"].lower() in ("true", "1", "yes", "yup")

        if "width" in kwargs:
            params["width"] = kwargs.get("width")
        else:
            params["width"] = pymt.pymt_config.getint("graphics", "width")

        if "height" in kwargs:
            params["height"] = kwargs.get("height")
        else:
            params["height"] = pymt.pymt_config.getint("graphics", "height")

        if "vsync" in kwargs:
            params["vsync"] = kwargs.get("vsync")
        else:
            params["vsync"] = pymt.pymt_config.getint("graphics", "vsync")

        if "fps" in kwargs:
            params["fps"] = kwargs.get("fps")
        else:
            params["fps"] = pymt.pymt_config.getint("graphics", "fps")

        if "rotation" in kwargs:
            params["rotation"] = kwargs.get("rotation")
        else:
            params["rotation"] = pymt.pymt_config.getint("graphics", "rotation")

        params["position"] = pymt.pymt_config.get("graphics", "position", "auto")
        if "top" in kwargs:
            params["position"] = "custom"
            params["top"] = kwargs.get("top")
        else:
            params["top"] = pymt.pymt_config.getint("graphics", "top")

        if "left" in kwargs:
            params["position"] = "custom"
            params["left"] = kwargs.get("left")
        else:
            params["left"] = pymt.pymt_config.getint("graphics", "left")

        # show fps if asked
        self.show_fps = kwargs.get("show_fps")
        if pymt.pymt_config.getboolean("pymt", "show_fps"):
            self.show_fps = True

        # configure the window
        self.create_window(params)

        # init some gl
        self.init_gl()

        # attach modules + listener event
        pymt_modules.register_window(self)
        touch_event_listeners.append(self)

        # mark as initialized
        self.__initialized = True

    def toggle_fullscreen(self):
        """Toggle fullscreen on window"""
        pass

    def close(self):
        """Close the window"""
        pass

    def create_window(self, params):
        """Will create the main window and configure it"""
        pass

    def on_flip(self):
        """Flip between buffers (event)"""
        self.flip()

    def flip(self):
        """Flip between buffers"""
        pass

    def dispatch_events(self):
        """Dispatch all events from windows"""
        pass

    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 _get_modifiers(self):
        return self._modifiers

    modifiers = property(_get_modifiers)

    def _get_size(self):
        r = self._rotation
        w, h = self._size
        if r == 0 or r == 180:
            return w, h
        return h, w

    def _set_size(self, size):
        if super(BaseWindow, self)._set_size(size):
            pymt_logger.debug("Window: Resize window to %s" % str(self.size))
            self.dispatch_event("on_resize", *size)
            return True
        return False

    size = property(_get_size, _set_size, doc="""Rotated size of the window""")

    # make some property read-only
    @property
    def width(self):
        """Rotated window width"""
        r = self._rotation
        if r == 0 or r == 180:
            return self._size[0]
        return self._size[1]

    @property
    def height(self):
        """Rotated window height"""
        r = self._rotation
        if r == 0 or r == 180:
            return self._size[1]
        return self._size[0]

    @property
    def center(self):
        """Rotated window center"""
        return self.width / 2.0, self.height / 2.0

    def _get_wallpaper(self):
        return self._wallpaper

    def _set_wallpaper(self, filename):
        self._wallpaper = pymt.Image(filename)

    wallpaper = property(_get_wallpaper, _set_wallpaper, doc="Get/set the wallpaper (must be a valid filename)")

    def _get_wallpaper_position(self):
        return self._wallpaper_position

    def _set_wallpaper_position(self, position):
        self._wallpaper_position = position

    wallpaper_position = property(
        _get_wallpaper_position,
        _set_wallpaper_position,
        doc="Get/set the wallpaper position (can be one of" + '"norepeat", "center", "repeat", "scale", "strech")',
    )

    def init_gl(self):
        version = glGetString(GL_VERSION)
        pymt_logger.info("Window: OpenGL version <%s>" % str(version))

        line_smooth = pymt.pymt_config.getint("graphics", "line_smooth")
        if line_smooth:
            if line_smooth == 1:
                hint = GL_FASTEST
            else:
                hint = GL_NICEST
            glHint(GL_LINE_SMOOTH_HINT, hint)
            glEnable(GL_LINE_SMOOTH)

    def add_widget(self, w):
        """Add a widget on window"""
        self.children.append(w)
        w.parent = self

    def remove_widget(self, w):
        """Remove a widget from window"""
        if not w in self.children:
            return
        self.children.remove(w)
        w.parent = None

    def clear(self):
        """Clear the window with background color"""
        glClearColor(*self.style.get("bg-color"))
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    def draw(self):
        """Draw the window background"""
        self.clear()
        if self.wallpaper is not None:
            self.draw_wallpaper()

    def draw_wallpaper(self):
        wallpaper = self.wallpaper
        if self.wallpaper_position == "center":
            wallpaper.x = (self.width - wallpaper.width) / 2
            wallpaper.y = (self.height - wallpaper.height) / 2
            wallpaper.draw()
        elif self.wallpaper_position == "repeat":
            r_x = float(self.width) / wallpaper.width
            r_y = float(self.height) / wallpaper.height
            if int(r_x) != r_x:
                r_x = int(r_x) + 1
            if int(r_y) != r_y:
                r_y = int(r_y) + 1
            for x in xrange(int(r_x)):
                for y in xrange(int(r_y)):
                    wallpaper.x = x * wallpaper.width
                    wallpaper.y = y * wallpaper.height
                    wallpaper.draw()
        elif self.wallpaper_position == "scale":
            wallpaper.size = self.size
            wallpaper.draw()

        elif self.wallpaper_position == "strech":
            w = self.width
            h = (self.width * wallpaper.height) / wallpaper.width
            if h < self.height:
                h = self.height
                w = (self.height * wallpaper.width) / wallpaper.height
            wallpaper.size = w, h
            wallpaper.pos = -(w - self.width) / 2, -(h - self.height) / 2
            wallpaper.draw()
        else:
            # no-repeat or any other options
            wallpaper.draw()

    def draw_mouse_touch(self):
        """Compatibility for MouseTouch, drawing a little red circle around
        under each mouse touches."""
        set_color(0.8, 0.2, 0.2, 0.7)
        for t in [x for x in getCurrentTouches() if x.device == "mouse"]:
            drawCircle(pos=(t.x, t.y), radius=10)

    def to_widget(self, x, y, initial=True, relative=False):
        return (x, y)

    def to_window(self, x, y, initial=True, relative=False):
        return (x, y)

    def get_root_window(self):
        return self

    def get_parent_window(self):
        return self

    def get_parent_layout(self):
        return None

    def on_update(self):
        """Event called when window are update the widget tree.
        (Usually before on_draw call.)
        """
        for w in self.children[:]:
            w.dispatch_event("on_update")

    def on_draw(self):
        """Event called when window we are drawing window.
        This function are cleaning the buffer with bg-color css,
        and call children drawing + show fps timer on demand"""

        # draw our window
        self.draw()

        # then, draw childrens
        for w in self.children[:]:
            w.dispatch_event("on_draw")

        if self.show_fps:
            fps = getClock().get_fps()
            drawLabel(label="FPS: %.2f" % float(fps), center=False, pos=(0, 0), font_size=10, bold=False)

        self.draw_mouse_touch()

    def on_touch_down(self, touch):
        """Event called when a touch is down"""
        w, h = self.system_size
        touch.scale_for_screen(w, h, rotation=self._rotation)
        for w in reversed(self.children[:]):
            if w.dispatch_event("on_touch_down", touch):
                return True

    def on_touch_move(self, touch):
        """Event called when a touch move"""
        w, h = self.system_size
        touch.scale_for_screen(w, h, rotation=self._rotation)
        for w in reversed(self.children[:]):
            if w.dispatch_event("on_touch_move", touch):
                return True

    def on_touch_up(self, touch):
        """Event called when a touch up"""
        w, h = self.system_size
        touch.scale_for_screen(w, h, rotation=self._rotation)
        for w in reversed(self.children[:]):
            if w.dispatch_event("on_touch_up", touch):
                return True

    def on_resize(self, width, height):
        """Event called when the window is resized"""
        self.update_viewport()

    def update_viewport(self):
        width, height = self.system_size
        w2 = width / 2.0
        h2 = height / 2.0

        # prepare the viewport
        glViewport(0, 0, width, height)

        # set the projection
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        glFrustum(-w2, w2, -h2, h2, 0.1, 1000)
        glScalef(5000, 5000, 1)

        # use the rotated size.
        width, height = self.size
        w2 = width / 2.0
        h2 = height / 2.0
        glTranslatef(-w2, -h2, -500)

        # set the model view
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        glTranslatef(w2, h2, 0)
        glRotatef(self._rotation, 0, 0, 1)
        glTranslatef(-w2, -h2, 0)

        # update window size
        for w in self.children:
            shw, shh = w.size_hint
            if shw and shh:
                w.size = shw * width, shh * height
            elif shw:
                w.width = shw * width
            elif shh:
                w.height = shh * height

    def _get_rotation(self):
        return self._rotation

    def _set_rotation(self, x):
        x = int(x % 360)
        if x == self._rotation:
            return
        if x not in (0, 90, 180, 270):
            raise ValueError("can rotate only 0,90,180,270 degrees")
        self._rotation = x
        self.dispatch_event("on_resize", *self.size)
        self.dispatch_event("on_rotate", x)

    rotation = property(
        _get_rotation, _set_rotation, "Get/set the window content rotation. Can be one of " "0, 90, 180, 270 degrees."
    )

    @property
    def system_size(self):
        """Real size of the window, without taking care of the rotation
        """
        return self._size

    def on_rotate(self, rotation):
        """Event called when the screen have been rotated
        """
        pass

    def on_close(self, *largs):
        """Event called when the window is closed"""
        pymt_modules.unregister_window(self)
        if self in touch_event_listeners[:]:
            touch_event_listeners.remove(self)

    def on_mouse_down(self, x, y, button, modifiers):
        """Event called when mouse is in action (press/release)"""
        pass

    def on_mouse_move(self, x, y, modifiers):
        """Event called when mouse is moving, with buttons pressed"""
        pass

    def on_mouse_up(self, x, y, button, modifiers):
        """Event called when mouse is moving, with buttons pressed"""
        pass

    def on_keyboard(self, key, scancode=None, unicode=None):
        """Event called when keyboard is in action

        .. warning::
            Some providers can skip `scancode` or `unicode` !!
        """
        pass

    def on_key_down(self, key, scancode=None, unicode=None):
        """Event called when a key is down (same arguments as on_keyboard)"""
        pass

    def on_key_up(self, key, scancode=None, unicode=None):
        """Event called when a key is up (same arguments as on_keyboard)"""
        pass
Ejemplo n.º 17
0
class MTScreenLayout(MTAbstractLayout):
    '''Base class to handle a list of screen (widgets).
    One child widget is shown at a time.

    :Parameters:
        `show_tabs`: bool, default to False
            If True, show tabs (useful for debugging)
        `duration`: float, default to 1.
            Duration to switch between screen

    '''
    def __init__(self, **kwargs):
        kwargs.setdefault('show_tabs', False)
        kwargs.setdefault('duration', 1.)
        super(MTScreenLayout, self).__init__(**kwargs)
        self.screens = SafeList()
        self.screen = None
        self.previous_screen = None
        self._switch_t = 1.1
        self.duration = kwargs.get('duration')

        self.container = MTBoxLayout(orientation='vertical')
        super(MTScreenLayout, self).add_widget(self.container)

        self.tabs = self.new_tab_layout()
        self._show_tabs = False
        self.show_tabs = kwargs.get('show_tabs', False)

    def _get_show_tabs(self):
        return self._show_tabs

    def _set_show_tabs(self, x):
        if self._show_tabs and x is False:
            self.container.remove_widget(self.tabs)
        if x and self._show_tabs is False:
            self.container.add_widget(self.tabs)
        self._show_tabs = x

    show_tabs = property(_get_show_tabs, _set_show_tabs)

    def new_tab_layout(self):
        '''called in init, to create teh layout in which all teh tabs are put.  overwrite to create custom tab layout
        (default is box layout, vertical, height=50, with horizontal stretch.)'''
        return MTBoxLayout(size_hint=(1.0, None), height=50)

    def new_tab(self, label):
        '''fucntion that returns a new tab.  return value must be of type MTButton or derive from it (must have on_press handler) if you overwrite the method.
        A Screenlayuot subclasses can overwrite this to create tabs based with own look and feel or do other custom things when a new tab is created'''
        return MTButton(label=label, size_hint=(1, 1), height=30)

    def add_widget(self, widget, tab_name=None):
        if tab_name:
            tab_btn = self.new_tab(tab_name)
            tab_btn.push_handlers(on_press=curry(self.select, widget))
            self.tabs.add_widget(tab_btn)
            if widget.id is None:
                widget.id = tab_name
        self.screens.append(widget)

    def remove_widget(self, widget):
        for btn in self.tabs.children[:]:
            if isinstance(widget, basestring):
                if btn.label == widget:
                    self.tabs.remove_widget(btn)
                    break
            elif btn.label == widget.id or (hasattr(widget, 'title')
                                            and btn.label == widget.title):
                self.tabs.remove_widget(btn)
                break
        if widget in self.screens:
            self.screens.remove(widget)

    def select(self, wid, *args):
        '''
        Select which screen is to be the current one.
        pass either a widget that has been added to this layout, or its id

        This function return True if the screen is selected, of False if we
        can't select the screen (non existant)
        '''
        if self.screen is not None:
            self.container.remove_widget(self.screen)
            self.previous_screen = self.screen
            self._switch_t = -1.0
        for screen in self.screens:
            if screen.id == wid or screen == wid:
                self.screen = screen
                self.container.add_widget(self.screen, do_layout=True)
                self.screen.parent = self
                return True
        return False

    def draw_transition(self, t):
        '''
        Function is called each frame while switching screens and
        responsible for drawing transition state.
        t will go from -1.0 (previous screen), to 0 (rigth in middle),
        until 1.0 (last time called before giving new screen full controll)
        '''
        set_color(*self.style['bg-color'])  #from 1 to zero
        drawRectangle(pos=self.container.pos, size=self.container.size)
        r, g, b = self.style['bg-color'][0:3]
        if t < 0:
            if self.previous_screen is not None:
                self.previous_screen.dispatch_event('on_draw')
            set_color(r, g, b, 1 + t)  #from 1 to zero
            drawRectangle(pos=self.container.pos, size=self.container.size)
        else:
            if self.previous_screen is not None:
                self.screen.dispatch_event('on_draw')
            set_color(r, g, b, 1 - t)  #from 0 to one
            drawRectangle(pos=self.container.pos, size=self.container.size)

    def on_update(self):
        if not self.screen and len(self.screens):
            self.select(self.screens[0])
        super(MTScreenLayout, self).on_update()

    def on_draw(self):
        super(MTScreenLayout, self).on_draw()
        if self._switch_t < 1.0:
            if self.duration == 0:
                self._switch_t = 1.
            else:
                self._switch_t += getFrameDt() / self.duration
            self.draw_transition(self._switch_t)
Ejemplo n.º 18
0
Archivo: loader.py Proyecto: bernt/pymt
class LoaderBase(object):
    '''Common base for Loader and specific implementation.
    By default, Loader will be the best available loader implementation.

    The _update() function is called every 1 / 25.s or each frame if we have
    less than 25 FPS.
    '''

    __metaclass__ = ABCMeta

    def __init__(self):
        loading_png_fn = os.path.join(pymt_data_dir, 'loader.png')
        error_png_fn = os.path.join(pymt_data_dir, 'error.png')

        self.loading_image = ImageLoader.load(loading_png_fn)
        self.error_image = ImageLoader.load(error_png_fn)

        self._q_load  = collections.deque()
        self._q_done  = collections.deque()
        self._client  = SafeList()
        self._running = False
        self._start_wanted = False

        getClock().schedule_interval(self._update, 1 / 25.)

    def __del__(self):
        try:
            getClock().unschedule_intervale(self._update)
        except:
            pass

    @abstractmethod
    def start(self):
        '''Start the loader thread/process'''
        self._running = True

    @abstractmethod
    def run(self, *largs):
        '''Main loop for the loader.'''
        pass

    @abstractmethod
    def stop(self):
        '''Stop the loader thread/process'''
        self._running = False

    def _load(self, parameters):
        '''(internal) Loading function, called by the thread.
        Will call _load_local() if the file is local,
        or _load_urllib() if the file is on Internet'''

        filename, load_callback, post_callback = parameters
        proto = filename.split(':', 1)[0]
        if load_callback is not None:
            data = load_callback(filename)
        elif proto in ('http', 'https', 'ftp'):
            data = self._load_urllib(filename)
        else:
            data = self._load_local(filename)

        if post_callback:
            data = post_callback(data)

        self._q_done.append((filename, data))

    def _load_local(self, filename):
        '''(internal) Loading a local file'''
        return ImageLoader.load(filename)

    def _load_urllib(self, filename):
        '''(internal) Loading a network file. First download it, save it to a
        temporary file, and pass it to _load_local()'''
        import urllib2, tempfile
        data = None
        try:
            suffix = '.%s'  % (filename.split('.')[-1])
            _out_osfd, _out_filename = tempfile.mkstemp(
                    prefix='pymtloader', suffix=suffix)

            # read from internet
            fd = urllib2.urlopen(filename)
            idata = fd.read()
            fd.close()

            # write to local filename
            os.write(_out_osfd, idata)
            os.close(_out_osfd)

            # load data
            data = self._load_local(_out_filename)
        except:
            pymt_logger.exception('Failed to load image <%s>' % filename)
            return self.error_image
        finally:
            os.unlink(_out_filename)

        return data

    def _update(self, *largs):
        '''(internal) Check if a data is loaded, and pass to the client'''
        # want to start it ?
        if self._start_wanted:
            if not self._running:
                self.start()
            self._start_wanted = False

        while True:
            try:
                filename, data = self._q_done.pop()
            except:
                return

            # create the image
            image = data#ProxyImage(data)
            Cache.append('pymt.loader', filename, image)

            # update client
            for c_filename, client in self._client[:]:
                if filename != c_filename:
                    continue
                # got one client to update
                client.image = image
                client.loaded = True
                client.dispatch_event('on_load')
                self._client.remove((c_filename, client))

    def image(self, filename, load_callback=None, post_callback=None):
        '''Load a image using loader. A Proxy image is returned
        with a loading image ::

            img = Loader.image(filename)
            # img will be a ProxyImage.
            # You'll use it the same as an Image class.
            # Later, when the image is really loaded,
            # the loader will change the img.image property
            # to the new loaded image

        '''
        data = Cache.get('pymt.loader', filename)
        if data not in (None, False):
            # found image
            return ProxyImage(data,
                    loading_image=self.loading_image,
                    loaded=True)

        client = ProxyImage(self.loading_image,
                    loading_image=self.loading_image)
        self._client.append((filename, client))

        if data is None:
            # if data is None, this is really the first time
            self._q_load.append((filename, load_callback, post_callback))
            Cache.append('pymt.loader', filename, False)
            self._start_wanted = True
        else:
            # already queued for loading
            pass

        return client
Ejemplo n.º 19
0
class LoaderBase(object):
    '''Common base for Loader and specific implementation.
    By default, Loader will be the best available loader implementation.

    The _update() function is called every 1 / 25.s or each frame if we have
    less than 25 FPS.
    '''

    __metaclass__ = ABCMeta

    def __init__(self):

        self._loading_image = None
        self._error_image = None

        self._q_load  = collections.deque()
        self._q_done  = collections.deque()
        self._client  = SafeList()
        self._running = False
        self._start_wanted = False

        getClock().schedule_interval(self._update, 1 / 25.)

    def __del__(self):
        try:
            getClock().unschedule(self._update)
        except Exception:
            pass

    @property
    def loading_image(self):
        '''Image used for loading (readonly)'''
        if not self._loading_image:
            loading_png_fn = os.path.join(pymt_data_dir, 'loader.png')
            self._loading_image = ImageLoader.load(filename=loading_png_fn)
        return self._loading_image

    @property
    def error_image(self):
        '''Image used for error (readonly)'''
        if not self._error_image:
            error_png_fn = os.path.join(pymt_data_dir, 'error.png')
            self._error_image = ImageLoader.load(filename=error_png_fn)
        return self._error_image

    @abstractmethod
    def start(self):
        '''Start the loader thread/process'''
        self._running = True

    @abstractmethod
    def run(self, *largs):
        '''Main loop for the loader.'''
        pass

    @abstractmethod
    def stop(self):
        '''Stop the loader thread/process'''
        self._running = False

    def _load(self, parameters):
        '''(internal) Loading function, called by the thread.
        Will call _load_local() if the file is local,
        or _load_urllib() if the file is on Internet'''

        filename, load_callback, post_callback = parameters
        proto = filename.split(':', 1)[0]
        if load_callback is not None:
            data = load_callback(filename)
        elif proto in ('http', 'https', 'ftp'):
            data = self._load_urllib(filename)
        else:
            data = self._load_local(filename)

        if post_callback:
            data = post_callback(data)

        self._q_done.append((filename, data))

    def _load_local(self, filename):
        '''(internal) Loading a local file'''
        return ImageLoader.load(filename)

    def _load_urllib(self, filename):
        '''(internal) Loading a network file. First download it, save it to a
        temporary file, and pass it to _load_local()'''
        import urllib2, tempfile
        data = None
        try:
            suffix = '.%s'  % (filename.split('.')[-1])
            _out_osfd, _out_filename = tempfile.mkstemp(
                    prefix='pymtloader', suffix=suffix)

            # read from internet
            fd = urllib2.urlopen(filename)
            idata = fd.read()
            fd.close()

            # write to local filename
            os.write(_out_osfd, idata)
            os.close(_out_osfd)

            # load data
            data = self._load_local(_out_filename)
        except Exception:
            pymt_logger.exception('Failed to load image <%s>' % filename)
            return self.error_image
        finally:
            os.unlink(_out_filename)

        return data

    def _update(self, *largs):
        '''(internal) Check if a data is loaded, and pass to the client'''
        # want to start it ?
        if self._start_wanted:
            if not self._running:
                self.start()
            self._start_wanted = False

        while True:
            try:
                filename, data = self._q_done.pop()
            except IndexError:
                return

            # create the image
            image = data#ProxyImage(data)
            Cache.append('pymt.loader', filename, image)

            # update client
            for c_filename, client in self._client[:]:
                if filename != c_filename:
                    continue
                # got one client to update
                client.image = image
                client.loaded = True
                client.dispatch_event('on_load')
                self._client.remove((c_filename, client))

    def image(self, filename, load_callback=None, post_callback=None):
        '''Load a image using loader. A Proxy image is returned
        with a loading image ::

            img = Loader.image(filename)
            # img will be a ProxyImage.
            # You'll use it the same as an Image class.
            # Later, when the image is really loaded,
            # the loader will change the img.image property
            # to the new loaded image

        '''
        data = Cache.get('pymt.loader', filename)
        if data not in (None, False):
            # found image
            return ProxyImage(data,
                    loading_image=self.loading_image,
                    loaded=True)

        client = ProxyImage(self.loading_image,
                    loading_image=self.loading_image)
        self._client.append((filename, client))

        if data is None:
            # if data is None, this is really the first time
            self._q_load.append((filename, load_callback, post_callback))
            Cache.append('pymt.loader', filename, False)
            self._start_wanted = True
        else:
            # already queued for loading
            pass

        return client
Ejemplo n.º 20
0
class MTScreenLayout(MTAbstractLayout):
    '''Base class to handle a list of screen (widgets).
    One child widget is shown at a time.

    :Parameters:
        `show_tabs`: bool, default to False
            If True, show tabs (useful for debugging)
        `duration`: float, default to 1.
            Duration to switch between screen

    '''

    def __init__(self, **kwargs):
        kwargs.setdefault('show_tabs', False)
        kwargs.setdefault('duration', 1.)
        super(MTScreenLayout, self).__init__(**kwargs)
        self.screens = SafeList()
        self.screen = None
        self.previous_screen = None
        self._switch_t = 1.1
        self.duration = kwargs.get('duration')

        self.container = MTBoxLayout(orientation='vertical')
        super(MTScreenLayout, self).add_widget(self.container)

        self.tabs = self.new_tab_layout()
        self._show_tabs  = False
        self.show_tabs = kwargs.get('show_tabs', False)

    def _get_show_tabs(self):
        return self._show_tabs
    def _set_show_tabs(self, x):
        if self._show_tabs and x is False:
            self.container.remove_widget(self.tabs)
        if x and self._show_tabs is False:
            self.container.add_widget(self.tabs)
        self._show_tabs = x
    show_tabs = property(_get_show_tabs, _set_show_tabs)


    def new_tab_layout(self):
        '''called in init, to create teh layout in which all teh tabs are put.  overwrite to create custom tab layout
        (default is box layout, vertical, height=50, with horizontal stretch.)'''
        return MTBoxLayout(size_hint=(1.0, None), height=50)

    def new_tab(self, label):
        '''fucntion that returns a new tab.  return value must be of type MTButton or derive from it (must have on_press handler) if you overwrite the method.
        A Screenlayuot subclasses can overwrite this to create tabs based with own look and feel or do other custom things when a new tab is created'''
        return MTButton(label=label, size_hint=(1, 1), height=30)

    def add_widget(self, widget, tab_name=None):
        if tab_name:
            tab_btn = self.new_tab(tab_name)
            tab_btn.push_handlers(on_press=curry(self.select, widget))
            self.tabs.add_widget(tab_btn)
            if widget.id is None:
                widget.id = tab_name
        self.screens.append(widget)

    def remove_widget(self, widget):
        for btn in self.tabs.children[:]:
            if isinstance(widget, basestring):
                if btn.label == widget:
                    self.tabs.remove_widget(btn)
                    break
            elif btn.label == widget.id or (
                hasattr(widget, 'title') and btn.label == widget.title):
                self.tabs.remove_widget(btn)
                break
        if widget in self.screens:
            self.screens.remove(widget)

    def select(self, wid, *args):
        '''
        Select which screen is to be the current one.
        pass either a widget that has been added to this layout, or its id

        This function return True if the screen is selected, of False if we
        can't select the screen (non existant)
        '''
        if self.screen is not None:
            self.container.remove_widget(self.screen)
            self.previous_screen = self.screen
            self._switch_t = -1.0
        for screen in self.screens:
            if screen.id == wid or screen == wid:
                self.screen = screen
                self.container.add_widget(self.screen, do_layout=True)
                self.screen.parent = self
                return True
        return False


    def draw_transition(self, t):
        '''
        Function is called each frame while switching screens and
        responsible for drawing transition state.
        t will go from -1.0 (previous screen), to 0 (rigth in middle),
        until 1.0 (last time called before giving new screen full controll)
        '''
        set_color(*self.style['bg-color']) #from 1 to zero
        drawRectangle(pos=self.container.pos, size=self.container.size)
        r, g, b = self.style['bg-color'][0:3]
        if t < 0:
            if self.previous_screen is not None:
                self.previous_screen.dispatch_event('on_draw')
            set_color(r, g, b, 1+t) #from 1 to zero
            drawRectangle(pos=self.container.pos, size=self.container.size)
        else:
            if self.previous_screen is not None:
                self.screen.dispatch_event('on_draw')
            set_color(r, g, b, 1-t) #from 0 to one
            drawRectangle(pos=self.container.pos, size=self.container.size)

    def on_update(self):
        if not self.screen and len(self.screens):
            self.select(self.screens[0])
        super(MTScreenLayout, self).on_update()

    def on_draw(self):
        super(MTScreenLayout, self).on_draw()
        if self._switch_t < 1.0:
            if self.duration == 0:
                self._switch_t = 1.
            else:
                self._switch_t += getFrameDt() / self.duration
            self.draw_transition(self._switch_t)
Ejemplo n.º 21
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)
Ejemplo n.º 22
0
    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()
Ejemplo n.º 23
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()
Ejemplo n.º 24
0
class BaseWindow(EventDispatcher):
    '''BaseWindow is a abstract window widget, for any window implementation.

    .. warning::

        The parameters are not working in normal case. Because at import, PyMT
        create a default OpenGL window, to add the ability to use OpenGL
        directives, texture creation.. before creating MTWindow.
        If you don't like this behavior, you can include before the very first
        import of PyMT ::

            import os
            os.environ['PYMT_SHADOW'] = '0'
            from pymt import *

        This will forbid PyMT to create the default window !


    :Parameters:
        `fps`: int, default to 0
            Maximum FPS allowed. If 0, fps will be not limited
        `fullscreen`: bool
            Make window as fullscreen
        `width`: int
            Width of window
        `height`: int
            Height of window
        `vsync`: bool
            Vsync window

    :Styles:
        `bg-color`: color
            Background color of window
    '''

    __instance = None
    __initialized = False
    _wallpaper = None
    _wallpaper_position = 'norepeat'

    def __new__(cls, **kwargs):
        if cls.__instance is None:
            cls.__instance = EventDispatcher.__new__(cls)
        return cls.__instance

    def __init__(self, **kwargs):

        kwargs.setdefault('force', False)
        kwargs.setdefault('config', None)
        kwargs.setdefault('show_fps', False)
        kwargs.setdefault('style', {})

        # don't init window 2 times,
        # except if force is specified
        if self.__initialized and not kwargs.get('force'):
            return

        super(BaseWindow, self).__init__()

        # init privates
        self._modifiers = []
        self._size = (0, 0)
        self._rotation = 0

        # event subsystem
        self.register_event_type('on_flip')
        self.register_event_type('on_rotate')
        self.register_event_type('on_draw')
        self.register_event_type('on_update')
        self.register_event_type('on_resize')
        self.register_event_type('on_close')
        self.register_event_type('on_touch_down')
        self.register_event_type('on_touch_move')
        self.register_event_type('on_touch_up')
        self.register_event_type('on_mouse_down')
        self.register_event_type('on_mouse_move')
        self.register_event_type('on_mouse_up')
        self.register_event_type('on_keyboard')
        self.register_event_type('on_key_down')
        self.register_event_type('on_key_up')

        # set out window as the main pymt window
        setWindow(self)

        # apply styles for window
        self.style = {}
        style = css_get_style(widget=self)
        self.apply_css(style)

        # apply inline css
        self._inline_style = kwargs.get('style')
        if len(kwargs.get('style')):
            self.apply_css(kwargs.get('style'))

        self.children = SafeList()
        self.parent = self
        self.visible = True

        # add view
        if 'view' in kwargs:
            self.add_widget(kwargs.get('view'))

        # get window params, user options before config option
        params = {}

        if 'fullscreen' in kwargs:
            params['fullscreen'] = kwargs.get('fullscreen')
        else:
            params['fullscreen'] = pymt.pymt_config.get(
                'graphics', 'fullscreen')
            if params['fullscreen'] not in ('auto', 'fake'):
                params['fullscreen'] = params['fullscreen'].lower() in \
                    ('true', '1', 'yes', 'yup')

        if 'width' in kwargs:
            params['width'] = kwargs.get('width')
        else:
            params['width'] = pymt.pymt_config.getint('graphics', 'width')

        if 'height' in kwargs:
            params['height'] = kwargs.get('height')
        else:
            params['height'] = pymt.pymt_config.getint('graphics', 'height')

        if 'vsync' in kwargs:
            params['vsync'] = kwargs.get('vsync')
        else:
            params['vsync'] = pymt.pymt_config.getint('graphics', 'vsync')

        if 'fps' in kwargs:
            params['fps'] = kwargs.get('fps')
        else:
            params['fps'] = pymt.pymt_config.getint('graphics', 'fps')

        if 'rotation' in kwargs:
            params['rotation'] = kwargs.get('rotation')
        else:
            params['rotation'] = pymt.pymt_config.getint(
                'graphics', 'rotation')

        params['position'] = pymt.pymt_config.get('graphics', 'position',
                                                  'auto')
        if 'top' in kwargs:
            params['position'] = 'custom'
            params['top'] = kwargs.get('top')
        else:
            params['top'] = pymt.pymt_config.getint('graphics', 'top')

        if 'left' in kwargs:
            params['position'] = 'custom'
            params['left'] = kwargs.get('left')
        else:
            params['left'] = pymt.pymt_config.getint('graphics', 'left')

        # show fps if asked
        self.show_fps = kwargs.get('show_fps')
        if pymt.pymt_config.getboolean('pymt', 'show_fps'):
            self.show_fps = True

        # configure the window
        self.create_window(params)

        # init some gl
        self.init_gl()

        # attach modules + listener event
        pymt_modules.register_window(self)
        touch_event_listeners.append(self)

        # mark as initialized
        self.__initialized = True

    def toggle_fullscreen(self):
        '''Toggle fullscreen on window'''
        pass

    def close(self):
        '''Close the window'''
        pass

    def create_window(self, params):
        '''Will create the main window and configure it'''
        pass

    def on_flip(self):
        '''Flip between buffers (event)'''
        self.flip()

    def flip(self):
        '''Flip between buffers'''
        pass

    def dispatch_events(self):
        '''Dispatch all events from windows'''
        pass

    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 _get_modifiers(self):
        return self._modifiers

    modifiers = property(_get_modifiers)

    def _get_size(self):
        r = self._rotation
        w, h = self._size
        if r == 0 or r == 180:
            return w, h
        return h, w

    def _set_size(self, size):
        if super(BaseWindow, self)._set_size(size):
            pymt_logger.debug('Window: Resize window to %s' % str(self.size))
            self.dispatch_event('on_resize', *size)
            return True
        return False

    size = property(_get_size, _set_size, doc='''Rotated size of the window''')

    # make some property read-only
    @property
    def width(self):
        '''Rotated window width'''
        r = self._rotation
        if r == 0 or r == 180:
            return self._size[0]
        return self._size[1]

    @property
    def height(self):
        '''Rotated window height'''
        r = self._rotation
        if r == 0 or r == 180:
            return self._size[1]
        return self._size[0]

    @property
    def center(self):
        '''Rotated window center'''
        return self.width / 2., self.height / 2.

    def _get_wallpaper(self):
        return self._wallpaper

    def _set_wallpaper(self, filename):
        self._wallpaper = pymt.Image(filename)

    wallpaper = property(
        _get_wallpaper,
        _set_wallpaper,
        doc='Get/set the wallpaper (must be a valid filename)')

    def _get_wallpaper_position(self):
        return self._wallpaper_position

    def _set_wallpaper_position(self, position):
        self._wallpaper_position = position

    wallpaper_position = property(
        _get_wallpaper_position,
        _set_wallpaper_position,
        doc='Get/set the wallpaper position (can be one of' +
        '"norepeat", "center", "repeat", "scale", "strech")')

    def init_gl(self):
        version = glGetString(GL_VERSION)
        pymt_logger.info('Window: OpenGL version <%s>' % str(version))

        line_smooth = pymt.pymt_config.getint('graphics', 'line_smooth')
        if line_smooth:
            if line_smooth == 1:
                hint = GL_FASTEST
            else:
                hint = GL_NICEST
            glHint(GL_LINE_SMOOTH_HINT, hint)
            glEnable(GL_LINE_SMOOTH)

    def add_widget(self, w):
        '''Add a widget on window'''
        self.children.append(w)
        w.parent = self

    def remove_widget(self, w):
        '''Remove a widget from window'''
        if not w in self.children:
            return
        self.children.remove(w)
        w.parent = None

    def clear(self):
        '''Clear the window with background color'''
        glClearColor(*self.style.get('bg-color'))
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    def draw(self):
        '''Draw the window background'''
        self.clear()
        if self.wallpaper is not None:
            self.draw_wallpaper()

    def draw_wallpaper(self):
        wallpaper = self.wallpaper
        if self.wallpaper_position == 'center':
            wallpaper.x = (self.width - wallpaper.width) / 2
            wallpaper.y = (self.height - wallpaper.height) / 2
            wallpaper.draw()
        elif self.wallpaper_position == 'repeat':
            r_x = float(self.width) / wallpaper.width
            r_y = float(self.height) / wallpaper.height
            if int(r_x) != r_x:
                r_x = int(r_x) + 1
            if int(r_y) != r_y:
                r_y = int(r_y) + 1
            for x in xrange(int(r_x)):
                for y in xrange(int(r_y)):
                    wallpaper.x = x * wallpaper.width
                    wallpaper.y = y * wallpaper.height
                    wallpaper.draw()
        elif self.wallpaper_position == 'scale':
            wallpaper.size = self.size
            wallpaper.draw()

        elif self.wallpaper_position == 'strech':
            w = self.width
            h = (self.width * wallpaper.height) / wallpaper.width
            if h < self.height:
                h = self.height
                w = (self.height * wallpaper.width) / wallpaper.height
            wallpaper.size = w, h
            wallpaper.pos = -(w - self.width) / 2, -(h - self.height) / 2
            wallpaper.draw()
        else:
            # no-repeat or any other options
            wallpaper.draw()

    def draw_mouse_touch(self):
        '''Compatibility for MouseTouch, drawing a little red circle around
        under each mouse touches.'''
        set_color(0.8, 0.2, 0.2, 0.7)
        for t in [x for x in getCurrentTouches() if x.device == 'mouse']:
            drawCircle(pos=(t.x, t.y), radius=10)

    def to_widget(self, x, y, initial=True, relative=False):
        return (x, y)

    def to_window(self, x, y, initial=True, relative=False):
        return (x, y)

    def get_root_window(self):
        return self

    def get_parent_window(self):
        return self

    def get_parent_layout(self):
        return None

    def on_update(self):
        '''Event called when window are update the widget tree.
        (Usually before on_draw call.)
        '''
        for w in self.children[:]:
            w.dispatch_event('on_update')

    def on_draw(self):
        '''Event called when window we are drawing window.
        This function are cleaning the buffer with bg-color css,
        and call children drawing + show fps timer on demand'''

        # draw our window
        self.draw()

        # then, draw childrens
        for w in self.children[:]:
            w.dispatch_event('on_draw')

        if self.show_fps:
            fps = getClock().get_fps()
            drawLabel(label='FPS: %.2f' % float(fps),
                      center=False,
                      pos=(0, 0),
                      font_size=10,
                      bold=False)

        self.draw_mouse_touch()

    def on_touch_down(self, touch):
        '''Event called when a touch is down'''
        w, h = self.system_size
        touch.scale_for_screen(w, h, rotation=self._rotation)
        for w in reversed(self.children[:]):
            if w.dispatch_event('on_touch_down', touch):
                return True

    def on_touch_move(self, touch):
        '''Event called when a touch move'''
        w, h = self.system_size
        touch.scale_for_screen(w, h, rotation=self._rotation)
        for w in reversed(self.children[:]):
            if w.dispatch_event('on_touch_move', touch):
                return True

    def on_touch_up(self, touch):
        '''Event called when a touch up'''
        w, h = self.system_size
        touch.scale_for_screen(w, h, rotation=self._rotation)
        for w in reversed(self.children[:]):
            if w.dispatch_event('on_touch_up', touch):
                return True

    def on_resize(self, width, height):
        '''Event called when the window is resized'''
        self.update_viewport()

    def update_viewport(self):
        width, height = self.system_size
        w2 = width / 2.
        h2 = height / 2.

        # prepare the viewport
        glViewport(0, 0, width, height)

        # set the projection
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        glFrustum(-w2, w2, -h2, h2, .1, 1000)
        glScalef(5000, 5000, 1)

        # use the rotated size.
        width, height = self.size
        w2 = width / 2.
        h2 = height / 2.
        glTranslatef(-w2, -h2, -500)

        # set the model view
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        glTranslatef(w2, h2, 0)
        glRotatef(self._rotation, 0, 0, 1)
        glTranslatef(-w2, -h2, 0)

        # update window size
        for w in self.children:
            shw, shh = w.size_hint
            if shw and shh:
                w.size = shw * width, shh * height
            elif shw:
                w.width = shw * width
            elif shh:
                w.height = shh * height

    def _get_rotation(self):
        return self._rotation

    def _set_rotation(self, x):
        x = int(x % 360)
        if x == self._rotation:
            return
        if x not in (0, 90, 180, 270):
            raise ValueError('can rotate only 0,90,180,270 degrees')
        self._rotation = x
        self.dispatch_event('on_resize', *self.size)
        self.dispatch_event('on_rotate', x)

    rotation = property(
        _get_rotation, _set_rotation,
        'Get/set the window content rotation. Can be one of '
        '0, 90, 180, 270 degrees.')

    @property
    def system_size(self):
        '''Real size of the window, without taking care of the rotation
        '''
        return self._size

    def on_rotate(self, rotation):
        '''Event called when the screen have been rotated
        '''
        pass

    def on_close(self, *largs):
        '''Event called when the window is closed'''
        pymt_modules.unregister_window(self)
        if self in touch_event_listeners[:]:
            touch_event_listeners.remove(self)

    def on_mouse_down(self, x, y, button, modifiers):
        '''Event called when mouse is in action (press/release)'''
        pass

    def on_mouse_move(self, x, y, modifiers):
        '''Event called when mouse is moving, with buttons pressed'''
        pass

    def on_mouse_up(self, x, y, button, modifiers):
        '''Event called when mouse is moving, with buttons pressed'''
        pass

    def on_keyboard(self, key, scancode=None, unicode=None):
        '''Event called when keyboard is in action

        .. warning::
            Some providers can skip `scancode` or `unicode` !!
        '''
        pass

    def on_key_down(self, key, scancode=None, unicode=None):
        '''Event called when a key is down (same arguments as on_keyboard)'''
        pass

    def on_key_up(self, key, scancode=None, unicode=None):
        '''Event called when a key is up (same arguments as on_keyboard)'''
        pass
Ejemplo n.º 25
0
    def __init__(self, **kwargs):

        kwargs.setdefault('force', False)
        kwargs.setdefault('config', None)
        kwargs.setdefault('show_fps', False)
        kwargs.setdefault('style', {})

        # don't init window 2 times,
        # except if force is specified
        if self.__initialized and not kwargs.get('force'):
            return

        super(BaseWindow, self).__init__()

        # init privates
        self._modifiers = []
        self._size = (0, 0)

        # event subsystem
        self.register_event_type('on_flip')
        self.register_event_type('on_draw')
        self.register_event_type('on_update')
        self.register_event_type('on_resize')
        self.register_event_type('on_close')
        self.register_event_type('on_touch_down')
        self.register_event_type('on_touch_move')
        self.register_event_type('on_touch_up')
        self.register_event_type('on_mouse_down')
        self.register_event_type('on_mouse_move')
        self.register_event_type('on_mouse_up')
        self.register_event_type('on_keyboard')
        self.register_event_type('on_key_down')
        self.register_event_type('on_key_up')

        # set out window as the main pymt window
        setWindow(self)

        # apply styles for window
        self.style = {}
        style = css_get_style(widget=self)
        self.apply_css(style)

        # apply inline css
        self._inline_style = kwargs.get('style')
        if len(kwargs.get('style')):
            self.apply_css(kwargs.get('style'))

        self.children = SafeList()
        self.parent = self
        self.visible = True

        # add view
        if 'view' in kwargs:
            self.add_widget(kwargs.get('view'))

        # get window params, user options before config option
        params = {}

        if 'fullscreen' in kwargs:
            params['fullscreen'] = kwargs.get('fullscreen')
        else:
            params['fullscreen'] = pymt.pymt_config.get('graphics', 'fullscreen')
            if params['fullscreen'] not in ('auto', 'fake'):
                params['fullscreen'] = params['fullscreen'].lower() in \
                    ('true', '1', 'yes', 'yup')

        if 'width' in kwargs:
            params['width'] = kwargs.get('width')
        else:
            params['width'] = pymt.pymt_config.getint('graphics', 'width')

        if 'height' in kwargs:
            params['height'] = kwargs.get('height')
        else:
            params['height'] = pymt.pymt_config.getint('graphics', 'height')

        if 'vsync' in kwargs:
            params['vsync'] = kwargs.get('vsync')
        else:
            params['vsync'] = pymt.pymt_config.getint('graphics', 'vsync')


        params['position'] = pymt.pymt_config.get(
            'graphics', 'position', 'auto')
        if 'top' in kwargs:
            params['position'] = 'custom'
            params['top'] = kwargs.get('top')
        else:
            params['top'] = pymt.pymt_config.getint('graphics', 'top')

        if 'left' in kwargs:
            params['position'] = 'custom'
            params['left'] = kwargs.get('left')
        else:
            params['left'] = pymt.pymt_config.getint('graphics', 'left')

        # show fps if asked
        self.show_fps = kwargs.get('show_fps')
        if pymt.pymt_config.getboolean('pymt', 'show_fps'):
            self.show_fps = True

        # configure the window
        self.create_window(params)

        # init some gl
        self.init_gl()

        # attach modules + listener event
        pymt_modules.register_window(self)
        touch_event_listeners.append(self)

        # mark as initialized
        self.__initialized = True
Ejemplo n.º 26
0
    def __init__(self, **kwargs):

        kwargs.setdefault("force", False)
        kwargs.setdefault("config", None)
        kwargs.setdefault("show_fps", False)
        kwargs.setdefault("style", {})

        # don't init window 2 times,
        # except if force is specified
        if self.__initialized and not kwargs.get("force"):
            return

        super(BaseWindow, self).__init__()

        # init privates
        self._modifiers = []
        self._size = (0, 0)
        self._rotation = 0

        # event subsystem
        self.register_event_type("on_flip")
        self.register_event_type("on_rotate")
        self.register_event_type("on_draw")
        self.register_event_type("on_update")
        self.register_event_type("on_resize")
        self.register_event_type("on_close")
        self.register_event_type("on_touch_down")
        self.register_event_type("on_touch_move")
        self.register_event_type("on_touch_up")
        self.register_event_type("on_mouse_down")
        self.register_event_type("on_mouse_move")
        self.register_event_type("on_mouse_up")
        self.register_event_type("on_keyboard")
        self.register_event_type("on_key_down")
        self.register_event_type("on_key_up")

        # set out window as the main pymt window
        setWindow(self)

        # apply styles for window
        self.style = {}
        style = css_get_style(widget=self)
        self.apply_css(style)

        # apply inline css
        self._inline_style = kwargs.get("style")
        if len(kwargs.get("style")):
            self.apply_css(kwargs.get("style"))

        self.children = SafeList()
        self.parent = self
        self.visible = True

        # add view
        if "view" in kwargs:
            self.add_widget(kwargs.get("view"))

        # get window params, user options before config option
        params = {}

        if "fullscreen" in kwargs:
            params["fullscreen"] = kwargs.get("fullscreen")
        else:
            params["fullscreen"] = pymt.pymt_config.get("graphics", "fullscreen")
            if params["fullscreen"] not in ("auto", "fake"):
                params["fullscreen"] = params["fullscreen"].lower() in ("true", "1", "yes", "yup")

        if "width" in kwargs:
            params["width"] = kwargs.get("width")
        else:
            params["width"] = pymt.pymt_config.getint("graphics", "width")

        if "height" in kwargs:
            params["height"] = kwargs.get("height")
        else:
            params["height"] = pymt.pymt_config.getint("graphics", "height")

        if "vsync" in kwargs:
            params["vsync"] = kwargs.get("vsync")
        else:
            params["vsync"] = pymt.pymt_config.getint("graphics", "vsync")

        if "fps" in kwargs:
            params["fps"] = kwargs.get("fps")
        else:
            params["fps"] = pymt.pymt_config.getint("graphics", "fps")

        if "rotation" in kwargs:
            params["rotation"] = kwargs.get("rotation")
        else:
            params["rotation"] = pymt.pymt_config.getint("graphics", "rotation")

        params["position"] = pymt.pymt_config.get("graphics", "position", "auto")
        if "top" in kwargs:
            params["position"] = "custom"
            params["top"] = kwargs.get("top")
        else:
            params["top"] = pymt.pymt_config.getint("graphics", "top")

        if "left" in kwargs:
            params["position"] = "custom"
            params["left"] = kwargs.get("left")
        else:
            params["left"] = pymt.pymt_config.getint("graphics", "left")

        # show fps if asked
        self.show_fps = kwargs.get("show_fps")
        if pymt.pymt_config.getboolean("pymt", "show_fps"):
            self.show_fps = True

        # configure the window
        self.create_window(params)

        # init some gl
        self.init_gl()

        # attach modules + listener event
        pymt_modules.register_window(self)
        touch_event_listeners.append(self)

        # mark as initialized
        self.__initialized = True
Ejemplo n.º 27
0
 def clear(self):
     self.children = SafeList()
     self.pchildren = SafeList()
     self.xoffset = self.yoffset = 0
Ejemplo n.º 28
0
class MTKineticList(MTStencilContainer):
    '''This is a kinetic container widget, that allows you to make
    a kinetic list scrolling in either direction.

    Some parameters are customizable in global configuration ::

        [widgets]
        list_friction = 10
        list_trigger_distance = 5

    :Parameters:
        `align` : string, default to 'center'
            Alignement of widget inside the row (or col). Can be
            one of 'center', 'left', 'right'
        `friction` : float, defaults to 10
            The Pseudo-friction of the pseudo-kinetic scrolling.
            Formula for friction is ::

                acceleration = 1 + friction * frame_delta_time

        `padding_x` : int, defaults to 4
            The spacing between scrolling items on the x axis
        `padding_y` : int, defaults to 4
            The spacing between scrolling items on the y axis
        `w_limit` : int, defaults to 1
            The limit of items that will appear horizontally.
            When this is set to a non-zero value the width(in
            terms of items in the kinetic list) will be w_limit,
            and the height will continually expand.
        `h_limit` : int, defaults to 0
            Exect opposite of w_limit.  If I didn't make either
            this or w_limit clear go bug xelapond
        `do_x` : bool, defaults to False
            Enable scrolling on the X axis
        `do_y` : bool, defaults to True
            Enable scrolling on the Y axis
        `title` : string, defaults to <Title Goes Here>
            Sets the title of the widget, which appears in 20
            point font at the top
        `deletable` : bool, defaults to True
            When enabled it allows you to delete children by
            entering delete mode(red button in upper left)
        `searchable` : bool, defaults to True
            When enabled it allows you to enter search mode
            and filter items
        `trigger_distance` : int, default to 3
            Maximum trigger distance to dispatch event on children
            (this mean if you move too much, trigger will not happen.)

    :Styles:
        `bg-color` : color
             Background color of the widget
        `scrollbar-size` : int
            Size of scrollbar in pixel (use 0 to disable it.)
        `scrollbar-color` : color
            Color of scrollbar
        `scrollbar-margin` : int int int int
            Margin top/right/bottom/left of scrollbar (left are not used.)

    :Events:
        `on_delete` (child)
            Fired when an item gets deleted.
    '''
    def __init__(self, **kwargs):
        kwargs.setdefault('padding_x', 4)
        kwargs.setdefault('padding_y', 4)
        kwargs.setdefault('w_limit', 1)
        kwargs.setdefault('h_limit', 0)
        kwargs.setdefault('do_x', False)
        kwargs.setdefault('do_y', True)
        kwargs.setdefault('title', 'No title')
        kwargs.setdefault('deletable', True)
        kwargs.setdefault('searchable', True)
        kwargs.setdefault('align', 'center')

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

        self.register_event_type('on_delete')

        self._a_sinput_out = None
        self._a_sinput_in = None
        self.title = Label('')
        self.sb = None
        self.sinput = None

        self.do_x = kwargs.get('do_x')
        self.do_y = kwargs.get('do_y')
        self.titletext = kwargs.get('title')
        self.deletable = kwargs.get('deletable')
        self.searchable = kwargs.get('searchable')
        self.padding_x = kwargs.get('padding_x')
        self.padding_y = kwargs.get('padding_y')
        self.w_limit = kwargs.get('w_limit')
        self.h_limit = kwargs.get('h_limit')
        self.align = kwargs.get('align')
        self.trigger_distance = kwargs.get(
            'trigger_distance',
            pymt_config.getint('widgets', 'list_trigger_distance'))
        self.friction = kwargs.get(
            'friction', pymt_config.getint('widgets', 'list_friction'))

        if self.w_limit and self.h_limit:
            raise Exception('You cannot limit both axes')
        elif not (self.w_limit or self.h_limit):
            raise Exception('You must limit at least one axis')

        # How far to offset tself.deletable and he axes(used for scrolling/panning)
        self.xoffset = 0
        self.yoffset = 0
        # X and Y translation vectors for the kinetic movement
        self.vx = 0
        self.vy = 0
        # List of all children, whatever will be the search
        self.pchildren = []
        # For extra blob stats
        self.touch = {}
        # Holds widgets not a part of the scrolling(search button, etc)
        self.widgets = []
        self._last_content_size = 0
        self._scrollbar_index = 0
        self._scrollbar_size = 0

        # create the UI part.
        self._create_ui()

    def _create_ui(self):
        # Title Text
        if self.titletext is not None:
            self.title = Label(font_size=18,
                               bold=True,
                               anchor_x='center',
                               anchor_y='center',
                               label=self.titletext)
            self.title.x = self.width / 2 + self.x
            self.title.y = self.height - 20 + self.y

        # Delete Button
        if self.deletable:
            self.db = MTToggleButton(label='X',
                                     pos=(self.x + self.width - 80,
                                          self.y + self.height - 40),
                                     size=(80, 40),
                                     cls='kineticlist-delete')
            self.db.push_handlers(on_press=self.toggle_delete)
            self.widgets.append(self.db)

        # Search Button and Input Text Area
        if self.searchable:
            self.sb = MTToggleButton(
                label='S',  #Button
                pos=(self.x, self.y + self.width - 40),
                size=(80, 40),
                cls='kineticlist-search')

            self.sb.push_handlers(on_press=self.toggle_search)
            self.sb.parent = self
            self.widgets.append(self.sb)

            self.sinput = pymt.MTTextInput(pos=(self.x,
                                                self.y + self.height - 40),
                                           size=(80, 40),
                                           style={'font-size': 20})
            self.sinput.parent = self
            self.sinput.push_handlers(on_text_change=self.apply_filter)
            self.widgets.insert(0, self.sinput)

            # Animations to hide and show the search text input box
            self._a_sinput_in = Animation(y=self.y + self.height - 40 -
                                          self.sinput.size[1],
                                          duration=0.5,
                                          f='ease_out_cubic')
            self._a_sinput_out = Animation(y=self.y + self.height -
                                           self.sinput.size[1],
                                           duration=0.5,
                                           f='ease_out_cubic')

    def on_delete(self, child):
        pass

    def clear(self):
        self.children = SafeList()
        self.pchildren = SafeList()
        self.xoffset = self.yoffset = 0

    def add_widget(self, widget, **kwargs):
        super(MTKineticList, self).add_widget(widget, **kwargs)
        self.pchildren.append(widget)

    def remove_widget(self, widget):
        super(MTKineticList, self).remove_widget(widget)
        if widget in self.pchildren:
            self.pchildren.remove(widget)
        self.dispatch_event('on_delete', widget)

    def toggle_delete(self, touch):
        '''Toggles the delete buttons on items
        Attached to the on_press handler of the delete button(self.db)
        '''
        if self.db.state == 'down':
            for child in self.children[:]:
                child.show_delete()
        else:
            for child in self.children[:]:
                child.hide_delete()

    def toggle_search(self, touch):
        '''Toggles the search area
        Attached to the on_press handler of self.sb(the green search button)
        '''
        if self.sb.state == 'down':
            self._a_sinput_in.animate(self.sinput)
        else:
            try:
                self.sinput.hide_keyboard()
            except:
                # There isn't a keyboard, so it throws a ValueError
                pass
            self.sinput.label = ''
            self._a_sinput_out.animate(self.sinput)

    def apply_filter(self, text):
        '''Applies the filter to the current children set'''
        self.search(text, 'label')
        #Move them so you don't have to scroll up to see them
        self.yoffset = self.padding_y
        self.xoffset = self.padding_x

    def filter(self, pattern, attr):
        '''Given an attribute of the children, and a pattern, return
        a list of the children with which pattern is in attr
        '''
        return filter(lambda c: pattern in str(getattr(c, attr)),
                      self.pchildren)

    def search(self, pattern, attr):
        '''Apply a search pattern to the current set of children'''
        result = self.filter(pattern, attr)
        self.children.clear()
        for item in result:
            self.children.append(item)

    def endsearch(self):
        '''Resets the children set to the full set'''
        self.children.clear()
        for item in self.pchildren:
            self.children.append(item)

    def _get_total_width(self, items, axis):
        '''Given a list of items and an axis, return the space
        they take up(in pixels)
        '''
        total = 0
        if axis == 'width':
            for item in items:
                total += (item.width + self.padding_x)
        elif axis == 'height':
            for item in items:
                total += (item.height + self.padding_y)

        return total

    def goto_head(self):
        if not self.h_limit:
            self.yoffset = -self._get_total_width(
                self.children, 'height') / self.w_limit + self.size[1] - 100
        else:
            self.xoffset = self._get_total_width(
                self.children, 'width') / self.h_limit + self.size[0] - 100

    def do_layout(self):
        '''Apply layout to all the items'''

        t = index = 0

        # adapt value for direction
        w2 = self.width / 2.
        h2 = self.height / 2.
        inverse = 0
        limit = self.w_limit
        width_attr = 'width'
        height_attr = 'height'
        xoffset = self.xoffset
        sx = self.x
        y = self.y + self.yoffset
        padding_x = self.padding_x
        padding_y = self.padding_y

        # inverse
        if not self.w_limit:
            inverse = 1
            limit = self.h_limit
            width_attr = 'height'
            height_attr = 'width'
            xoffset = self.yoffset
            y = self.x + self.xoffset
            padding_x = self.padding_y
            padding_y = self.padding_x
            w2, h2 = h2, w2
            sx = self.y

        # calculate size of actual content
        size = 0
        for i in xrange(len(self.children)):
            if i % limit == 0:
                maxrange = min(i + limit, len(self.children))
                childrens = [self.children[z] for z in range(i, maxrange)]
                h = max((c.__getattribute__(height_attr) for c in childrens))
                size += h + padding_y
        self._last_content_size = size

        # add little padding for good looking.
        y += padding_y
        ny = y

        # recalculate position for each children
        for child in self.children[:]:

            # each row, calculate the height, advance y and reset x
            if index % limit == 0:

                # set y axis to the previous calculated position
                y = ny

                # get children in the row
                maxrange = min(t + limit, len(self.children))
                childrens = [self.children[z] for z in range(t, maxrange)]

                # take the largest height in the current row
                if len(childrens):
                    h = max(
                        (c.__getattribute__(height_attr) for c in childrens))
                else:
                    h = 0

                # prepare the y axis for next loop
                ny = y + h + padding_y

                # reset x for this row.
                if self.align == 'center':
                    x = sx + w2 + xoffset - \
                        (self._get_total_width(childrens, width_attr) / 2.)
                elif self.align == 'left':
                    x = 0
                elif self.align == 'right':
                    x = getattr(self, width_attr) - getattr(
                        child, width_attr) - xoffset
                t += limit

            # reposition x
            if not inverse:
                child.kx = x + padding_x
                child.ky = y
            else:
                child.ky = x + padding_x
                child.kx = y
            x += child.__getattribute__(width_attr) + padding_x

            # Increment index
            index += 1

    def on_touch_down(self, touch):
        if not self.collide_point(touch.x, touch.y):
            return

        # ok, it's a touch for us. grab it !
        touch.grab(self)

        # first, check if own widget take the touch
        for w in reversed(self.widgets[:]):
            if w.on_touch_down(touch):
                return True

        # initiate kinetic movement.
        self.vx = self.vy = 0
        self.touch[touch.id] = {
            'ox': touch.x,
            'oy': touch.y,
            'xmot': 0,
            'ymot': 0,
            'travelx': 0,  #How far the blob has traveled total in the x axis
            'travely': 0,  #^
        }
        return True

    def on_touch_move(self, touch):
        # accept only grabbed touch by us
        if touch.grab_current != self:
            return

        # ok, if it's not a kinetic movement,
        # dispatch to children
        if touch.id not in self.touch:
            for w in reversed(self.widgets[:]):
                if w.on_touch_move(touch):
                    return True
            return

        # it's a kinetic movement, process it.
        t = self.touch[touch.id]
        t['xmot'] = touch.x - t['ox']
        t['ymot'] = touch.y - t['oy']
        t['ox'] = touch.x
        t['oy'] = touch.y
        t['travelx'] += abs(t['xmot'])
        t['travely'] += abs(t['ymot'])
        self.xoffset += t['xmot'] * self.do_x
        self.yoffset += t['ymot'] * self.do_y
        self.ensure_bounding()

    def on_touch_up(self, touch):
        # accept only grabbed touch by us
        if touch.grab_current != self:
            return

        # it's an up, ungrab us !
        touch.ungrab(self)

        if touch.id not in self.touch:
            for w in reversed(self.widgets[:]):
                if w.on_touch_up(touch):
                    return True
            return

        t = self.touch[touch.id]
        self.vx = t['xmot']
        self.vy = t['ymot']

        # check if we can transmit event to children
        if (self.do_x and t['travelx'] > self.trigger_distance) or \
           (self.do_y and t['travely'] > self.trigger_distance):
            return True

        # ok, the trigger distance is enough, we can dispatch event.
        # will not work if children grab the touch in down state :/
        for child in reversed(self.children[:]):
            must_break = child.dispatch_event('on_touch_down', touch)
            old_grab_current = touch.grab_current
            touch.grab_current = child
            child.dispatch_event('on_touch_up', touch)
            touch.grab_current = old_grab_current
            if must_break:
                break
        return True

    def ensure_bounding(self):
        size = float(self._last_content_size)
        if size <= 0:
            return

        self._scrollbar_size = 1
        self._scrollbar_index = 0

        if self.do_y:
            if size < self.height:
                self.yoffset = 0
            else:
                self.yoffset = boundary(self.yoffset, -size + self.height, 0)
                self._scrollbar_size = self.height / size
                self._scrollbar_index = -self.yoffset / size
        elif self.do_x:
            if size < self.width:
                self.xoffset = 0
            else:
                self.xoffset = boundary(self.xoffset, -size + self.width, 0)
                self._scrollbar_size = self.width / size
                self._scrollbar_index = -self.xoffset / size

    def process_kinetic(self):
        '''Apply kinetic movement to all the items'''
        dt = getFrameDt()
        self.vx /= 1 + (self.friction * dt)
        self.vy /= 1 + (self.friction * dt)

        self.xoffset += self.vx * self.do_x
        self.yoffset += self.vy * self.do_y

        self.ensure_bounding()

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

        # draw children
        self.stencil_push()
        for w in self.children[:]:
            # internal update of children
            w.update()
            # optimization to draw only viewed children
            if self.do_y and (w.y + w.height < self.y
                              or w.y > self.y + self.height):
                continue
            if self.do_x and (w.x + w.width < self.x
                              or w.x > self.x + self.width):
                continue
            w.on_draw()
        self.stencil_pop()

        # draw widgets
        for w in self.widgets:
            w.dispatch_event('on_draw')
        # title bar
        if self.titletext is not None:
            set_color(*self.style.get('title-color'))
            w = 0
            if self.searchable:
                x = 80
                w += 80
            else:
                x = 0
            if self.deletable:
                w += 80
            drawCSSRectangle(pos=(self.x + x, self.height + self.y - 40),
                             size=(self.width - w, 40),
                             prefix='title',
                             style=self.style)
            self.title.x = self.width / 2 + self.x
            self.title.y = self.height - 20 + self.y
            self.title.draw()

        # scrollbar
        sb_size = self.style.get('scrollbar-size')
        if sb_size > 0:
            mtop, mright, mbottom, mleft = self.style.get('scrollbar-margin')
            if self.do_y:
                pos = [
                    self.x + self.width - mright - sb_size, self.y + mbottom
                ]
                size = [sb_size, self.height - mbottom - mtop]
                pos[1] += size[1] * self._scrollbar_index
                size[1] = size[1] * self._scrollbar_size
            elif self.do_x:
                pos = [self.x + mleft, self.y + self.height - mtop - sb_size]
                size = [self.width - mleft - mright, sb_size]
                pos[0] += size[0] * self._scrollbar_index
                size[0] = size[0] * self._scrollbar_size
            set_color(*self.style.get('scrollbar-color'))
            drawRectangle(pos=pos, size=size)

    def on_draw(self):
        if not self.visible:
            return
        self.do_layout()
        self.process_kinetic()
        self.draw()
Ejemplo n.º 29
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)
Ejemplo n.º 30
0
class BaseWindow(EventDispatcher):
    '''BaseWindow is a abstract window widget, for any window implementation.

    .. warning::

        The parameters are not working in normal case. Because at import, PyMT
        create a default OpenGL window, to add the ability to use OpenGL
        directives, texture creation.. before creating MTWindow.
        If you don't like this behavior, you can include before the very first
        import of PyMT ::

            import os
            os.environ['PYMT_SHADOW'] = '0'
            from pymt import *

        This will forbid PyMT to create the default window !


    :Parameters:
        `fullscreen`: bool
            Make window as fullscreen
        `width`: int
            Width of window
        `height`: int
            Height of window
        `vsync`: bool
            Vsync window

    :Styles:
        `bg-color`: color
            Background color of window
    '''

    __instance = None
    __initialized = False
    _wallpaper = None
    _wallpaper_position = 'norepeat'

    def __new__(cls, **kwargs):
        if cls.__instance is None:
            cls.__instance = EventDispatcher.__new__(cls)
        return cls.__instance

    def __init__(self, **kwargs):

        kwargs.setdefault('force', False)
        kwargs.setdefault('config', None)
        kwargs.setdefault('show_fps', False)
        kwargs.setdefault('style', {})

        # don't init window 2 times,
        # except if force is specified
        if self.__initialized and not kwargs.get('force'):
            return

        super(BaseWindow, self).__init__()

        # init privates
        self._modifiers = []
        self._size = (0, 0)

        # event subsystem
        self.register_event_type('on_flip')
        self.register_event_type('on_draw')
        self.register_event_type('on_update')
        self.register_event_type('on_resize')
        self.register_event_type('on_close')
        self.register_event_type('on_touch_down')
        self.register_event_type('on_touch_move')
        self.register_event_type('on_touch_up')
        self.register_event_type('on_mouse_down')
        self.register_event_type('on_mouse_move')
        self.register_event_type('on_mouse_up')
        self.register_event_type('on_keyboard')
        self.register_event_type('on_key_down')
        self.register_event_type('on_key_up')

        # set out window as the main pymt window
        setWindow(self)

        # apply styles for window
        self.style = {}
        style = css_get_style(widget=self)
        self.apply_css(style)

        # apply inline css
        self._inline_style = kwargs.get('style')
        if len(kwargs.get('style')):
            self.apply_css(kwargs.get('style'))

        self.children = SafeList()
        self.parent = self
        self.visible = True

        # add view
        if 'view' in kwargs:
            self.add_widget(kwargs.get('view'))

        # get window params, user options before config option
        params = {}

        if 'fullscreen' in kwargs:
            params['fullscreen'] = kwargs.get('fullscreen')
        else:
            params['fullscreen'] = pymt.pymt_config.get('graphics', 'fullscreen')
            if params['fullscreen'] not in ('auto', 'fake'):
                params['fullscreen'] = params['fullscreen'].lower() in \
                    ('true', '1', 'yes', 'yup')

        if 'width' in kwargs:
            params['width'] = kwargs.get('width')
        else:
            params['width'] = pymt.pymt_config.getint('graphics', 'width')

        if 'height' in kwargs:
            params['height'] = kwargs.get('height')
        else:
            params['height'] = pymt.pymt_config.getint('graphics', 'height')

        if 'vsync' in kwargs:
            params['vsync'] = kwargs.get('vsync')
        else:
            params['vsync'] = pymt.pymt_config.getint('graphics', 'vsync')


        params['position'] = pymt.pymt_config.get(
            'graphics', 'position', 'auto')
        if 'top' in kwargs:
            params['position'] = 'custom'
            params['top'] = kwargs.get('top')
        else:
            params['top'] = pymt.pymt_config.getint('graphics', 'top')

        if 'left' in kwargs:
            params['position'] = 'custom'
            params['left'] = kwargs.get('left')
        else:
            params['left'] = pymt.pymt_config.getint('graphics', 'left')

        # show fps if asked
        self.show_fps = kwargs.get('show_fps')
        if pymt.pymt_config.getboolean('pymt', 'show_fps'):
            self.show_fps = True

        # configure the window
        self.create_window(params)

        # init some gl
        self.init_gl()

        # attach modules + listener event
        pymt_modules.register_window(self)
        touch_event_listeners.append(self)

        # mark as initialized
        self.__initialized = True

    def toggle_fullscreen(self):
        '''Toggle fullscreen on window'''
        pass

    def close(self):
        '''Close the window'''
        pass

    def create_window(self, params):
        '''Will create the main window and configure it'''
        pass

    def on_flip(self):
        '''Flip between buffers (event)'''
        self.flip()

    def flip(self):
        '''Flip between buffers'''
        pass

    def dispatch_events(self):
        '''Dispatch all events from windows'''
        pass

    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 _get_modifiers(self):
        return self._modifiers
    modifiers = property(_get_modifiers)

    def _set_size(self, size):
        if super(BaseWindow, self)._set_size(size):
            pymt_logger.debug('Window: Resize window to %s' % str(self.size))
            self.dispatch_event('on_resize', *size)
            return True
        return False
    size = property(EventDispatcher._get_size, _set_size)

    # make some property read-only
    width = property(EventDispatcher._get_width)
    height = property(EventDispatcher._get_height)
    center = property(EventDispatcher._get_center)

    def _get_wallpaper(self):
        return self._wallpaper
    def _set_wallpaper(self, filename):
        self._wallpaper = pymt.Image(filename)
    wallpaper = property(_get_wallpaper, _set_wallpaper,
            doc='Get/set the wallpaper (must be a valid filename)')

    def _get_wallpaper_position(self):
        return self._wallpaper_position
    def _set_wallpaper_position(self, position):
        self._wallpaper_position = position
    wallpaper_position = property(
            _get_wallpaper_position, _set_wallpaper_position,
            doc='Get/set the wallpaper position (can be one of' +
                '"norepeat", "center", "repeat", "scale", "strech")')

    def init_gl(self):
        version = glGetString(GL_VERSION)
        pymt_logger.info('Window: OpenGL version <%s>' % str(version))

        line_smooth = pymt.pymt_config.getint('graphics', 'line_smooth')
        if line_smooth:
            if line_smooth == 1:
                hint = GL_FASTEST
            else:
                hint = GL_NICEST
            glHint(GL_LINE_SMOOTH_HINT, hint)
            glEnable(GL_LINE_SMOOTH)

    def add_widget(self, w):
        '''Add a widget on window'''
        self.children.append(w)
        w.parent = self

    def remove_widget(self, w):
        '''Remove a widget from window'''
        if not w in self.children:
            return
        self.children.remove(w)
        w.parent = None

    def clear(self):
        '''Clear the window with background color'''
        glClearColor(*self.style.get('bg-color'))
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    def draw(self):
        '''Draw the window background'''
        self.clear()
        if self.wallpaper is not None:
            self.draw_wallpaper()

    def draw_wallpaper(self):
        wallpaper = self.wallpaper
        if self.wallpaper_position == 'center':
            wallpaper.x = (self.width - wallpaper.width) / 2
            wallpaper.y = (self.height - wallpaper.height) / 2
            wallpaper.draw()
        elif self.wallpaper_position == 'repeat':
            r_x = float(self.width) / wallpaper.width
            r_y = float(self.height) / wallpaper.height
            if int(r_x) != r_x:
                r_x = int(r_x) + 1
            if int(r_y) != r_y:
                r_y = int(r_y) + 1
            for x in xrange(int(r_x)):
                for y in xrange(int(r_y)):
                    wallpaper.x = x * wallpaper.width
                    wallpaper.y = y * wallpaper.height
                    wallpaper.draw()
        elif self.wallpaper_position == 'scale':
            wallpaper.size = self.size
            wallpaper.draw()

        elif self.wallpaper_position == 'strech':
            w = self.width
            h = (self.width * wallpaper.height) / wallpaper.width
            if h < self.height:
                h = self.height
                w = (self.height * wallpaper.width) / wallpaper.height
            wallpaper.size = w, h
            wallpaper.pos = -(w - self.width) / 2, -(h - self.height) / 2
            wallpaper.draw()
        else:
            # no-repeat or any other options
            wallpaper.draw()


    def draw_mouse_touch(self):
        '''Compatibility for MouseTouch, drawing a little red circle around
        under each mouse touches.'''
        set_color(0.8, 0.2, 0.2, 0.7)
        for t in [x for x in getCurrentTouches() if x.device == 'mouse']:
            drawCircle(pos=(t.x, t.y), radius=10)

    def to_widget(self, x, y, initial=True, relative=False):
        return (x, y)

    def to_window(self, x, y, initial=True, relative=False):
        return (x, y)

    def get_root_window(self):
        return self

    def get_parent_window(self):
        return self

    def get_parent_layout(self):
        return None

    def on_update(self):
        '''Event called when window are update the widget tree.
        (Usually before on_draw call.)
        '''
        for w in self.children[:]:
            w.dispatch_event('on_update')

    def on_draw(self):
        '''Event called when window we are drawing window.
        This function are cleaning the buffer with bg-color css,
        and call children drawing + show fps timer on demand'''

        # draw our window
        self.draw()

        # then, draw childrens
        for w in self.children[:]:
            w.dispatch_event('on_draw')

        if self.show_fps:
            fps = getClock().get_fps()
            drawLabel(label='FPS: %.2f' % float(fps),
                center=False, pos=(0, 0),
                font_size=10, bold=False)

        self.draw_mouse_touch()

    def on_touch_down(self, touch):
        '''Event called when a touch is down'''
        touch.scale_for_screen(*self.size)
        for w in reversed(self.children[:]):
            if w.dispatch_event('on_touch_down', touch):
                return True

    def on_touch_move(self, touch):
        '''Event called when a touch move'''
        touch.scale_for_screen(*self.size)
        for w in reversed(self.children[:]):
            if w.dispatch_event('on_touch_move', touch):
                return True

    def on_touch_up(self, touch):
        '''Event called when a touch up'''
        touch.scale_for_screen(*self.size)
        for w in reversed(self.children[:]):
            if w.dispatch_event('on_touch_up', touch):
                return True

    def on_resize(self, width, height):
        '''Event called when the window is resized'''
        glViewport(0, 0, width, height)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        glFrustum(-width / 2, width / 2, -height / 2, height / 2, .1, 1000)
        glScalef(5000, 5000, 1)
        glTranslatef(-width / 2, -height / 2, -500)
        glMatrixMode(GL_MODELVIEW)

        for w in self.children:
            shw, shh = w.size_hint
            if shw and shh:
                w.size = shw * width, shh * height
            elif shw:
                w.width = shw * width
            elif shh:
                w.height = shh * height

    def on_close(self, *largs):
        '''Event called when the window is closed'''
        pymt_modules.unregister_window(self)
        if self in touch_event_listeners[:]:
            touch_event_listeners.remove(self)

    def on_mouse_down(self, x, y, button, modifiers):
        '''Event called when mouse is in action (press/release)'''
        pass

    def on_mouse_move(self, x, y, modifiers):
        '''Event called when mouse is moving, with buttons pressed'''
        pass

    def on_mouse_up(self, x, y, button, modifiers):
        '''Event called when mouse is moving, with buttons pressed'''
        pass

    def on_keyboard(self, key, scancode=None, unicode=None):
        '''Event called when keyboard is in action

        .. warning::
            Some providers can skip `scancode` or `unicode` !!
        '''
        pass

    def on_key_down(self, key, scancode=None, unicode=None):
        '''Event called when a key is down (same arguments as on_keyboard)'''
        pass

    def on_key_up(self, key, scancode=None, unicode=None):
        '''Event called when a key is up (same arguments as on_keyboard)'''
        pass
Ejemplo n.º 31
0
    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')