def append(category, key, obj, timeout=None): '''Add a new object in the cache. :Parameters: `category` : str Identifier of the category `key` : str Uniq identifier of the object to store `obj` : object Object to store in cache `timeout` : double (optionnal) Custom time to delete the object if it's not used. ''' try: cat = Cache._categories[category] except KeyError: pymt_logger.warning('Cache: category <%s> not exist' % category) return timeout = timeout or cat['timeout'] # FIXME: activate purge when limit is hit #limit = cat['limit'] #if limit is not None and len(Cache._objects[category]) >= limit: # Cache._purge_oldest(category) Cache._objects[category][key] = { 'object': obj, 'timeout': timeout, 'lastaccess': getClock().get_time(), 'timestamp': getClock().get_time() }
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 __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 process(self, events): #print "InputPostprocTouchAndHold::process" if len(self.queue): events = self.queue + events self.queue = [] schedule = getClock().schedule_once unschedule = getClock().unschedule for type, touch in events: if type == 'down': touch.userdata['touchandhold.func'] = curry(self._timeout, touch) schedule(touch.userdata['touchandhold.func'], self.hold_time) elif type == 'up': unschedule(touch.userdata['touchandhold.func']) return events
def idle(self): '''This function is called every frames. By default : * it "tick" the clock to the next frame * read all input and dispatch event * dispatch on_update + on_draw + on_flip on window ''' # update dt global frame_dt frame_dt = getClock().tick() # read and dispatch input from providers self.dispatch_input() if pymt_window: pymt_window.dispatch_events() pymt_window.dispatch_event('on_update') pymt_window.dispatch_event('on_draw') pymt_window.dispatch_event('on_flip') # don't loop if we don't have listeners ! if len(pymt_event_listeners) == 0: self.exit() return False return self.quit
def _purge_by_timeout(dt): curtime = getClock().get_time() for category in Cache._objects: timeout = Cache._categories[category]['timeout'] if timeout is not None and dt > timeout: # XXX got a lag ! that may be because the frame take lot of # time to draw. and the timeout is not adapted to the current # framerate. So, increase the timeout by two. # ie: if the timeout is 1 sec, and framerate go to 0.7, newly # object added will be automaticly trashed. timeout *= 2 Cache._categories[category]['timeout'] = timeout continue for key in Cache._objects[category].keys()[:]: lastaccess = Cache._objects[category][key]['lastaccess'] objtimeout = Cache._objects[category][key]['timeout'] # take the object timeout if available if objtimeout is not None: timeout = objtimeout # no timeout, cancel if timeout is None: continue if curtime - lastaccess > timeout: del Cache._objects[category][key]
def _update(self): dt = getClock().get_time() - self._last_update if self._need_update is None: return if self._need_update == "now" or (self._need_update == "lazy" and dt > self.time_lazy_update): # create layout mode if not in cache layoutmode = "%s:%s" % (self.layout.ID, self.mode) if not layoutmode in self._cache: self._cache[layoutmode] = {"background": GlDisplayList(), "keys": GlDisplayList(), "usedlabel": []} self._current_cache = self._cache[layoutmode] # do real update self._do_update(mode="background") self._do_update(mode="keys") # don't update too fast next time (if it's lazy) self._last_update = getClock().get_time() self._last_update_scale = self.scale self._need_update = None
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 install_gobject_iteration(): '''Import and install gobject context iteration inside our event loop. This is used as soon as gobject is used (like gstreamer) ''' from pymt.clock import getClock import gobject if hasattr(gobject, '_gobject_already_installed'): # already installed, don't do it twice. return gobject._gobject_already_installed = True # get gobject mainloop / context loop = gobject.MainLoop() gobject.threads_init() context = loop.get_context() # schedule the iteration each frame def _gobject_iteration(*largs): context.iteration(False) getClock().schedule_interval(_gobject_iteration, 0)
def flip(self): pygame.display.flip() super(MTWindowPygame, self).flip() # do software vsync if asked # FIXME: vsync is surely not 60 for everyone # this is not a real vsync. this must be done by driver... # but pygame can't do vsync on X11, and some people # use hack to make it work under darwin... fps = self._fps if fps > 0: s = 1 / fps - (time() - getClock().get_time()) if s > 0: sleep(s)
def _update(self): dt = getClock().get_time() - self._last_update if self._need_update is None: return if self._need_update == 'now' or (self._need_update == 'lazy' and dt > self.time_lazy_update): # create layout mode if not in cache layoutmode = '%s:%s' % (self.layout.ID, self.mode) if not layoutmode in self._cache: self._cache[layoutmode] = {'background': GlDisplayList(), 'keys': GlDisplayList(), 'usedlabel': []} self._current_cache = self._cache[layoutmode] # do real update self._do_update(mode='background') self._do_update(mode='keys') # don't update too fast next time (if it's lazy) self._last_update = getClock().get_time() self._last_update_scale = self.scale self._need_update = None
def append(category, key, obj, timeout=None): '''Add a new object in the cache. :Parameters: `category` : str Identifier of the category `key` : str Uniq identifier of the object to store `obj` : object Object to store in cache `timeout` : double (optionnal) Custom time to delete the object if it's not used. ''' if not category in Cache._categories: pymt.pymt_logger.warning('Cache: category <%s> not exist' % category) return if timeout is None: timeout = Cache._categories[category]['timeout'] Cache._objects[category][key] = { 'object': obj, 'timeout': timeout, 'lastaccess': getClock().get_time(), 'timestamp': getClock().get_time() }
def get(category, key, default=None): '''Get a object in cache. :Parameters: `category` : str Identifier of the category `key` : str Uniq identifier of the object to store `default` : anything, default to None Default value to be returned if key is not found ''' try: Cache._objects[category][key]['lastaccess'] = getClock().get_time() return Cache._objects[category][key]['object'] except: return default
def get(category, key, default=None): '''Get a object in cache. :Parameters: `category` : str Identifier of the category `key` : str Uniq identifier of the object to store `default` : anything, default to None Default value to be returned if key is not found ''' try: Cache._objects[category][key]['lastaccess'] = getClock().get_time() return Cache._objects[category][key]['object'] except Exception: return default
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 _purge_oldest(category, maxpurge=1): print 'PURGE', category import heapq heap_list = [] for key in Cache._objects[category]: obj = Cache._objects[category][key] if obj['lastaccess'] == obj['timestamp']: continue heapq.heappush(heap_list, (obj['lastaccess'], key)) print '<<<', obj['lastaccess'] n = 0 while n < maxpurge: try: lastaccess, key = heapq.heappop(heap_list) print '=>', key, lastaccess, getClock().get_time() except Exception: return del Cache._objects[category][key]
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 _purge_by_timeout(*largs): curtime = getClock().get_time() for category in Cache._objects: timeout = Cache._categories[category]['timeout'] for key in Cache._objects[category].keys(): lastaccess = Cache._objects[category][key]['lastaccess'] objtimeout = Cache._objects[category][key]['timeout'] # take the object timeout if available if objtimeout is not None: timeout = objtimeout # no timeout, cancel if timeout is None: continue if curtime - lastaccess > timeout: del Cache._objects[category][key]
def process(self, events): # first, check if a touch down have a double tap for type, touch in events: if type == 'down': touch_double_tap = self.find_double_tap(touch) if touch_double_tap: touch.is_double_tap = True touch.double_tap_time = touch.time_start - touch_double_tap.time_start touch.double_tap_distance = touch_double_tap.double_tap_distance # add the touch internaly self.touches[touch.uid] = (type, touch) # second, check if up-touch is timeout for double tap time_current = getClock().get_time() for touchid in self.touches.keys()[:]: type, touch = self.touches[touchid] if type != 'up': continue if time_current - touch.time_start < self.double_tap_time: continue del self.touches[touchid] return events
def _lazy_update(self): self.container_width = int(self.width * self.scale) self.container_height = int(self.height * self.scale) self._need_update = 'lazy' self._last_update = getClock().get_time()
def __del__(self): try: getClock().unschedule(self._update) except Exception: pass
def start(self): '''Starts animating the AnimationBase Object''' if not self._running: self._running = True getClock().schedule_interval(self._next_frame, 0)
def __init__(self, x, y, width, height, origin): super(TextureRegion, self).__init__( width, height, origin.target, origin.id) self.x = x self.y = y self.owner = origin # recalculate texture coordinate origin_u1 = origin.tex_coords[0] origin_v1 = origin.tex_coords[1] origin_u2 = origin.tex_coords[2] origin_v2 = origin.tex_coords[5] scale_u = origin_u2 - origin_u1 scale_v = origin_v2 - origin_v1 u1 = x / float(origin.width) * scale_u + origin_u1 v1 = y / float(origin.height) * scale_v + origin_v1 u2 = (x + width) / float(origin.width) * scale_u + origin_u1 v2 = (y + height) / float(origin.height) * scale_v + origin_v1 self.tex_coords = (u1, v1, u2, v1, u2, v2, u1, v2) def __del__(self): # don't use self of owner ! pass if 'PYMT_DOC' not in os.environ: from pymt.clock import getClock # install tick to release texture every 200ms getClock().schedule_interval(_texture_release, 0.2)
def _on_draw(): global _toggle_state if _toggle_state == '': return win = getWindow() # # Show HELP screen # if _toggle_state == 'help': # draw the usual window win.on_draw() # make background more black set_color(0, 0, 0, .8) drawRectangle(size=win.size) # prepare calculation w2 = win.width / 2. h2 = win.height / 2. y = 0 k = {'font_size': 20} ydiff = 25 # draw help drawLabel('PyMT Keybinding', pos=(w2, win.height - 100), font_size=40) drawLabel('Press F1 to leave help', pos=(w2, win.height - 160), font_size=12) drawLabel('FPS is %.3f' % getClock().get_fps(), pos=(w2, win.height - 180), font_size=12) drawLabel('F1 - Show Help', pos=(w2, h2), **k) y += ydiff drawLabel('F2 - Show FPS (%s)' % str(win.show_fps), pos=(w2, h2 - y), **k) y += ydiff drawLabel('F3 - Show Cache state', pos=(w2, h2 - y), **k) y += ydiff drawLabel('F4 - Show Calibration screen', pos=(w2, h2 - y), **k) if _can_fullscreen(): y += ydiff drawLabel('F5 - Toggle fullscreen', pos=(w2, h2 - y), **k) y += ydiff drawLabel('F6 - Show log', pos=(w2, h2 - y), **k) y += ydiff drawLabel('F7 - Reload CSS', pos=(w2, h2 - y), **k) y += ydiff drawLabel('F8 - Show widget tree', pos=(w2, h2 - y), **k) y += ydiff drawLabel('F9 - Rotate the screen (%d)' % win.rotation, pos=(w2, h2 - y), **k) y += ydiff drawLabel('F12 - Screenshot', pos=(w2, h2 - y), **k) return True # # Draw cache state # elif _toggle_state == 'cachestat': # draw the usual window win.on_draw() # make background more black set_color(0, 0, 0, .8) drawRectangle(size=win.size) y = 0 for x in Cache._categories: y += 25 cat = Cache._categories[x] count = 0 usage = '-' limit = cat['limit'] timeout = cat['timeout'] try: count = len(Cache._objects[x]) except: pass try: usage = 100 * count / limit except: pass args = (x, usage, count, limit, timeout) drawLabel('%s: usage=%s%% count=%d limit=%s timeout=%s' % args, pos=(20, 20 + y), font_size=20, center=False, nocache=True) return True # # Draw calibration screen # elif _toggle_state == 'calibration': step = 8 ratio = win.height / float(win.width) stepx = win.width / step stepy = win.height / int(step * ratio) # draw black background set_color(0, 0, 0) drawRectangle(size=win.size) # draw lines set_color(1, 1, 1) for x in xrange(0, win.width, stepx): drawLine((x, 0, x, win.height)) for y in xrange(0, win.height, stepy): drawLine((0, y, win.width, y)) # draw circles drawCircle(pos=(win.width / 2., win.height / 2.), radius=win.width / step, linewidth = 2.) drawCircle(pos=(win.width / 2., win.height / 2.), radius=(win.width / step) * 2, linewidth = 2.) drawCircle(pos=(win.width / 2., win.height / 2.), radius=(win.width / step) * 3, linewidth = 2.) return True # # Draw calibration screen 2 (colors) # elif _toggle_state == 'calibration2': # draw black background set_color(0, 0, 0) drawRectangle(size=win.size) # gray step = 25 stepx = (win.width - 100) / step stepy = stepx * 2 sizew = stepx * step sizeh = stepy * step w2 = win.width / 2. h2 = win.height / 2. for _x in xrange(step): x = w2 - sizew / 2. + _x * stepx drawLabel(chr(65+_x), pos=(x + stepx / 2., h2 + 190)) c = _x / float(step) # grey set_color(c, c, c) drawRectangle(pos=(x, h2 + 100), size=(stepx, stepy)) # red set_color(c, 0, 0) drawRectangle(pos=(x, h2 + 80 - stepy), size=(stepx, stepy)) # green set_color(0, c, 0) drawRectangle(pos=(x, h2 + 60 - stepy * 2), size=(stepx, stepy)) # blue set_color(0, 0, c) drawRectangle(pos=(x, h2 + 40 - stepy * 3), size=(stepx, stepy)) return True # # Draw log screen # elif _toggle_state == 'log': # draw the usual window win.on_draw() # make background more black set_color(0, 0, 0, .8) drawRectangle(size=win.size) # calculation w2 = win.width / 2. h2 = win.height / 2. k = {'font_size': 11, 'center': False} y = win.height - 20 y = h2 max = int((h2 / 20)) levels = { logging.DEBUG: ('DEBUG', (.4,.4,1)), logging.INFO: ('INFO', (.4,1,.4)), logging.WARNING: ('WARNING', (1,1,.4)), logging.ERROR: ('ERROR', (1,.4,.4)), logging.CRITICAL: ('CRITICAL', (1,.4,.4)), } # draw title drawLabel('PyMT logger', pos=(w2, win.height - 100), font_size=40) # draw logs for log in reversed(pymt_logger_history.history[:max]): levelname, color = levels[log.levelno] msg = log.message.split('\n')[0] x = 10 s = drawLabel('[', pos=(x, y), **k) x += s[0] s = drawLabel(levelname, pos=(x, y), color=color, **k) x += s[0] s = drawLabel(']', pos=(x, y), **k) x += s[0] drawLabel(msg, pos=(100, y), **k) y -= 20 return True
def __del__(self): try: getClock().unschedule_intervale(self._update) except: pass
def stop(self): super(LoaderClock, self).stop() getClock().unschedule_interval(self.run)
def _on_draw(): global _toggle_state if _toggle_state == '': return win = getWindow() # # Show HELP screen # if _toggle_state == 'help': # draw the usual window win.on_draw() # make background more black set_color(0, 0, 0, .8) drawRectangle(size=win.size) # prepare calculation w2 = win.width / 2. h2 = win.height / 2. y = 0 k = {'font_size': 20} ydiff = 25 # draw help drawLabel('PyMT Keybinding', pos=(w2, win.height - 100), font_size=40) drawLabel('Press F1 to leave help', pos=(w2, win.height - 160), font_size=12) drawLabel('FPS is %.3f' % getClock().get_fps(), pos=(w2, win.height - 180), font_size=12) drawLabel('F1 - Show Help', pos=(w2, h2), **k) y += ydiff drawLabel('F2 - Show FPS (%s)' % str(win.show_fps), pos=(w2, h2 - y), **k) y += ydiff drawLabel('F3 - Show Cache state', pos=(w2, h2 - y), **k) y += ydiff drawLabel('F4 - Show Calibration screen', pos=(w2, h2 - y), **k) if _can_fullscreen(): y += ydiff drawLabel('F5 - Toggle fullscreen', pos=(w2, h2 - y), **k) y += ydiff drawLabel('F6 - Show log', pos=(w2, h2 - y), **k) y += ydiff drawLabel('F7 - Reload CSS', pos=(w2, h2 - y), **k) y += ydiff drawLabel('F8 - Show widget tree', pos=(w2, h2 - y), **k) y += ydiff drawLabel('F9 - Rotate the screen (%d)' % win.rotation, pos=(w2, h2 - y), **k) y += ydiff drawLabel('F12 - Screenshot', pos=(w2, h2 - y), **k) return True # # Draw cache state # elif _toggle_state == 'cachestat': # draw the usual window win.on_draw() # make background more black set_color(0, 0, 0, .8) drawRectangle(size=win.size) y = 0 for x in Cache._categories: y += 25 cat = Cache._categories[x] count = 0 usage = '-' limit = cat['limit'] timeout = cat['timeout'] try: count = len(Cache._objects[x]) except: pass try: usage = 100 * count / limit except: pass args = (x, usage, count, limit, timeout) drawLabel('%s: usage=%s%% count=%d limit=%s timeout=%s' % args, pos=(20, 20 + y), font_size=20, center=False, nocache=True) return True # # Draw calibration screen # elif _toggle_state == 'calibration': step = 8 ratio = win.height / float(win.width) stepx = win.width / step stepy = win.height / int(step * ratio) # draw black background set_color(0, 0, 0) drawRectangle(size=win.size) # draw lines set_color(1, 1, 1) for x in xrange(0, win.width, stepx): drawLine((x, 0, x, win.height)) for y in xrange(0, win.height, stepy): drawLine((0, y, win.width, y)) # draw circles drawCircle(pos=(win.width / 2., win.height / 2.), radius=win.width / step, linewidth=2.) drawCircle(pos=(win.width / 2., win.height / 2.), radius=(win.width / step) * 2, linewidth=2.) drawCircle(pos=(win.width / 2., win.height / 2.), radius=(win.width / step) * 3, linewidth=2.) return True # # Draw calibration screen 2 (colors) # elif _toggle_state == 'calibration2': # draw black background set_color(0, 0, 0) drawRectangle(size=win.size) # gray step = 25 stepx = (win.width - 100) / step stepy = stepx * 2 sizew = stepx * step sizeh = stepy * step w2 = win.width / 2. h2 = win.height / 2. for _x in xrange(step): x = w2 - sizew / 2. + _x * stepx drawLabel(chr(65 + _x), pos=(x + stepx / 2., h2 + 190)) c = _x / float(step) # grey set_color(c, c, c) drawRectangle(pos=(x, h2 + 100), size=(stepx, stepy)) # red set_color(c, 0, 0) drawRectangle(pos=(x, h2 + 80 - stepy), size=(stepx, stepy)) # green set_color(0, c, 0) drawRectangle(pos=(x, h2 + 60 - stepy * 2), size=(stepx, stepy)) # blue set_color(0, 0, c) drawRectangle(pos=(x, h2 + 40 - stepy * 3), size=(stepx, stepy)) return True # # Draw log screen # elif _toggle_state == 'log': # draw the usual window win.on_draw() # make background more black set_color(0, 0, 0, .8) drawRectangle(size=win.size) # calculation w2 = win.width / 2. h2 = win.height / 2. k = {'font_size': 11, 'center': False} y = win.height - 20 y = h2 max = int((h2 / 20)) levels = { logging.DEBUG: ('DEBUG', (.4, .4, 1)), logging.INFO: ('INFO', (.4, 1, .4)), logging.WARNING: ('WARNING', (1, 1, .4)), logging.ERROR: ('ERROR', (1, .4, .4)), logging.CRITICAL: ('CRITICAL', (1, .4, .4)), } # draw title drawLabel('PyMT logger', pos=(w2, win.height - 100), font_size=40) # draw logs for log in reversed(pymt_logger_history.history[:max]): levelname, color = levels[log.levelno] msg = log.message.split('\n')[0] x = 10 s = drawLabel('[', pos=(x, y), **k) x += s[0] s = drawLabel(levelname, pos=(x, y), color=color, **k) x += s[0] s = drawLabel(']', pos=(x, y), **k) x += s[0] drawLabel(msg, pos=(100, y), **k) y -= 20 return True
def __init__(self, x, y, width, height, origin): super(TextureRegion, self).__init__(width, height, origin.target, origin.id) self.x = x self.y = y self.owner = origin # recalculate texture coordinate origin_u1 = origin.tex_coords[0] origin_v1 = origin.tex_coords[1] origin_u2 = origin.tex_coords[2] origin_v2 = origin.tex_coords[5] scale_u = origin_u2 - origin_u1 scale_v = origin_v2 - origin_v1 u1 = x / float(origin.width) * scale_u + origin_u1 v1 = y / float(origin.height) * scale_v + origin_v1 u2 = (x + width) / float(origin.width) * scale_u + origin_u1 v2 = (y + height) / float(origin.height) * scale_v + origin_v1 self.tex_coords = (u1, v1, u2, v1, u2, v2, u1, v2) def __del__(self): # don't use self of owner ! pass if 'PYMT_DOC' not in os.environ: from pymt.clock import getClock # install tick to release texture every 200ms getClock().schedule_interval(_texture_release, 0.2)
for key in Cache._objects[category].keys(): lastaccess = Cache._objects[category][key]['lastaccess'] objtimeout = Cache._objects[category][key]['timeout'] # take the object timeout if available if objtimeout is not None: timeout = objtimeout # no timeout, cancel if timeout is None: continue if curtime - lastaccess > timeout: del Cache._objects[category][key] @staticmethod def print_usage(): print 'Cache usage :' for category in Cache._categories: print ' * %s : %d / %s, timeout=%s' % ( category.capitalize(), len(Cache._objects[category]), str(Cache._categories[category]['limit']), str(Cache._categories[category]['timeout']) ) # install the schedule clock for purging getClock().schedule_interval(Cache._purge_by_timeout, 1)
def stop(self): super(LoaderClock, self).stop() getClock().unschedule(self.run)
def start(self): super(LoaderClock, self).start() getClock().schedule_interval(self.run, 0.0001)
for key in Cache._objects[category].keys()[:]: lastaccess = Cache._objects[category][key]['lastaccess'] objtimeout = Cache._objects[category][key]['timeout'] # take the object timeout if available if objtimeout is not None: timeout = objtimeout # no timeout, cancel if timeout is None: continue if curtime - lastaccess > timeout: del Cache._objects[category][key] @staticmethod def print_usage(): '''Print the cache usage on the console''' print 'Cache usage :' for category in Cache._categories: print ' * %s : %d / %s, timeout=%s' % ( category.capitalize(), len(Cache._objects[category]), str(Cache._categories[category]['limit']), str(Cache._categories[category]['timeout']) ) # install the schedule clock for purging getClock().schedule_interval(Cache._purge_by_timeout, 1)
def on_touch_down(self, touch): if self.collide_point(touch.x, touch.y): self.show_controls() self._count += 1 getClock().schedule_once(self._try_hide_controls, 5) return super(MTVideo, self).on_touch_down(touch)