class Timer(object): """ Simple profiling timer. Output log can be directed to 'console' or to 'textarea'. If output is to textarea, may specify log length. """ def __init__(self, log='console', log_length=5): self.time = Time() self.time_i = self.get_time() self.dtime = [] self.number = 0 self.log = None self.log_list = None self.log_num = 0 self.log_scroll = True self.set_log(log, log_length) def get_time(self): """ Get current time. """ return self.time.time() def set_time(self): """ Set current time. """ self.time_i = self.get_time() def lap_time(self, time_i=None, time_f=None, number=100, print_result=True): """ Time lapsed since previous set_time. Optional arguments time_i and time_f, number of calls to average, and print_results to output result. """ if time_i is None: time_i = self.time_i if time_f is None: time_f = self.get_time() self.dtime.append(time_f-time_i) self.number += 1 if self.number >= number: t_ave = ( sum(self.dtime)/number ) self.dtime = [] self.number = 0 if print_result: if self.log_type == 'console': self.log_num += 1 entry = "Time %d: %s" % (self.log_num, t_ave) print(entry) else: self.log_num += 1 entry = "Time %d: %s" % (self.log_num, t_ave) self.print_log(entry) return t_ave def set_log(self, log, log_length=5): """ Set log output. Argument log can be 'console' or 'textarea'. """ if log in ('console','textarea'): self.log_type = log if log == 'textarea': if not self.log: size = env.canvas.surface.width-5, 102 self.log = env.canvas.surface._display.Textarea(size) self.log.setReadonly(True) self.log.addMouseListener(self) self.onMouseUp = lambda sender,x,y: None self.onMouseMove = lambda sender,x,y: None self.onMouseEnter = lambda sender: None self.log_list = ['' for i in range(log_length)] self.log.toggle(True) else: if self.log: self.log.toggle(False) self.log_list = [] def onMouseDown(self, sender, x, y): self.log_scroll = False def onMouseLeave(self, sender): self.log_scroll = True def print_log(self, text): """ Print text to output. """ if self.log_type == 'console': print(text) else: self.log_list.pop(0) self.log_list.append(text+'\n') text = ''.join(self.log_list) self.log.setText(text) if self.log_scroll: self.log.setCursorPos(len(text))
class Canvas(Surface): def __init__(self, size, buffered): Surface.__init__(self, size) if isinstance(buffered, bool): self._bufferedimage = buffered else: self._bufferedimage = True try: if self.impl.canvasContext: self._isCanvas = True except: self._isCanvas = False self._bufferedimage = False if self._bufferedimage: self.surface = Surface(size) else: self.surface = self self.images = {} self.image_list = [] self.callback = None self.time = Time() self.event = env.event self.addMouseListener(self) self.addKeyEventListener(self) self.sinkEvents(Event.ONMOUSEDOWN | Event.ONMOUSEUP | Event.ONMOUSEMOVE | Event.ONMOUSEOUT | Event.ONMOUSEWHEEL | Event.ONKEYDOWN | Event.ONKEYPRESS | Event.ONKEYUP) self.onContextMenu = None self.preventContextMenu() self.evt = self.event.eventObj self.modKey = self.event.modKey self.specialKey = self.event.specialKey self.modKeyCode = self.event.modKeyCode self.specialKeyCode = self.event.specialKeyCode self.keyRepeat = self.event.keyRepeat self.keyHeld = self.event.keyHeld self.mouse_entered = True self.event._initiate_touch_listener(self) self._touch_callback = self.event.touchlistener.callback self._rect_list = [] self._rect_len = 0 self._rect_num = 0 self._framerate = 0 self._frametime = 0 self._rendertime = self.time.time() self._pause = False self._canvas_init() self.initialized = False def _canvas_init(self): global _canvas, _ctx, _img, _wnd _canvas = self _ctx = self.impl.canvasContext _img = self.surface.canvas _wnd = requestAnimationFrameInit() def onMouseMove(self, sender, x, y): event = DOM.eventGetCurrentEvent() if event.type in self.event.events: if not self.mouse_entered: self.event.mouseMovePre['x'] = self.event.mouseMove['x'] self.event.mouseMovePre['y'] = self.event.mouseMove['y'] else: self.event.mouseMovePre['x'] = x self.event.mouseMovePre['y'] = y self.mouse_entered = False self.event._updateQueue(self.evt[event.type](event, x, y)) self.event.mouseMove['x'] = x self.event.mouseMove['y'] = y def onMouseDown(self, sender, x, y): event = DOM.eventGetCurrentEvent() if event.type in self.event.events: self.event._updateQueue(self.evt[event.type](event, x, y)) self.event.mousePress[event.button] = True def onMouseUp(self, sender, x, y): event = DOM.eventGetCurrentEvent() if event.type in self.event.events: self.event._updateQueue(self.evt[event.type](event, x, y)) self.event.mousePress[event.button] = False def onMouseEnter(self, sender): self.mouse_entered = True def onMouseLeave(self, sender): self.event.mousePress[0] = False self.event.mousePress[1] = False self.event.mousePress[2] = False self.event.mouseMove['x'] = -1 self.event.mouseMove['y'] = -1 self.event.mouseMoveRel['x'] = None self.event.mouseMoveRel['y'] = None for keycode in self.modKeyCode: if self.event.keyPress[keycode]: self.event.keyPress[keycode] = False def onMouseWheel(self, event): if event.type in self.event.events: r = self.canvas.getBoundingClientRect() x = event.clientX - round(r.left) y = event.clientY - round(r.top) self.event._updateQueue(self.evt[event.type](event, x, y)) DOM.eventPreventDefault(event) def onKeyEvent(self, event): self.removeKeyEventListener(self) self.addKeyboardListener(self) DOM.currentEvent = event if hasattr(event, 'key') and hasattr(event, 'code'): self.onKeyDown(self, event.key, 0) else: self.event._set_key_event() self.onKeyDown = self._onKeyDown self.onKeyUp = self._onKeyUp self.onKeyPress = self._onKeyPress keycode = event.which or event.keyCode or 0 self._onKeyDown(self, keycode, 0) def onKeyDown(self, sender, keycode, mods): event = DOM.eventGetCurrentEvent() if event.key in self.modKey: self.event.keyPress[self.modKey[event.key]] = True if event.type in self.event.events: if not self._isPaused(event.key): self.event._updateQueue(self.evt[event.type](event)) DOM.eventPreventDefault(event) def onKeyUp(self, sender, keycode, mods): event = DOM.eventGetCurrentEvent() if event.key in self.modKey: self.event.keyPress[self.modKey[event.key]] = False if event.key in self.keyHeld: self.keyHeld[event.key]['pressed'] = False if event.type in self.event.events: self.event._updateQueue(self.evt[event.type](event)) def _onKeyDown(self, sender, keycode, mods): event = DOM.eventGetCurrentEvent() if keycode in self.modKeyCode: self.event.keyPress[keycode] = True if event.type in self.event.events: if not self._isPaused(keycode): self.event.keyCode = keycode if keycode in self.specialKeyCode: self.event._updateQueue(self.evt[event.type](event, keycode)) DOM.eventPreventDefault(event) else: DOM.eventPreventDefault(event) def _onKeyUp(self, sender, keycode, mods): event = DOM.eventGetCurrentEvent() if keycode in self.modKeyCode: self.event.keyPress[keycode] = False if keycode in self.keyHeld: self.keyHeld[keycode]['pressed'] = False if event.type in self.event.events: self.event._updateQueue(self.evt[event.type](event, keycode)) def _onKeyPress(self, sender, keycode, mods): event = DOM.eventGetCurrentEvent() if event.type in self.event.events: self.event.keyPressCode[self.event.keyCode] = keycode self.event._updateQueue(self.evt[event.type](event, keycode)) event.preventDefault() def _isPaused(self, keycode): if keycode not in self.keyHeld: self.keyHeld[keycode] = { 'pressed': False, 'delay': False, 'time': 0 } key = self.keyHeld[keycode] if not key['pressed']: key['pressed'] = True paused = False if self.keyRepeat[0]: key['delay'] = True key['time'] = self.time.time() else: paused = True if self.keyRepeat[0]: time = self.time.time() if key['delay']: if time - key['time'] > self.keyRepeat[0]: key['time'] = time key['delay'] = False paused = False elif time - key['time'] > self.keyRepeat[1]: key['time'] = time paused = False return paused def onTouchInitiate(self, event): self.event.touchlistener.activate() for callback in self._touch_callback: if hasattr(callback, 'onTouchInitiate'): callback.onTouchInitiate(event) self.onTouchStart(event) def onTouchStart(self, event): for callback in self._touch_callback: callback.onTouchStart(event) def onTouchEnd(self, event): for callback in self._touch_callback: callback.onTouchEnd(event) def onTouchMove(self, event): for callback in self._touch_callback: callback.onTouchMove(event) def onTouchCancel(self, event): for callback in self._touch_callback: callback.onTouchCancel(event) def preventContextMenu(self, setting=True): """ Control contextmenu event. Optional bool setting to prevent event, default to True. """ if setting: if self.onContextMenu: return element = self.getElement() self.onContextMenu = lambda event: event.preventDefault() element.addEventListener('contextmenu', self.onContextMenu) else: if not self.onContextMenu: return element = self.getElement() element.removeEventListener('contextmenu', self.onContextMenu) self.onContextMenu = None def resize(self, width, height): Surface.resize(self, width, height) if self._bufferedimage: self.surface.resize(width, height) self.surface._display._surface_rect = self.surface.get_rect() def set_callback(self, cb): if not hasattr(cb, 'run'): self.callback = Callback(cb) else: self.callback = cb def load_images(self, images): if images: image_list = [] for image in images: if isinstance(image, str): image_list.append(image) self.image_list.append(image) else: name = image[0] if isinstance(image[1], str): data = image[1] else: data = base64.b64encode(image[1].getvalue()) if not data.startswith('data:'): ext = name.strip().split('.')[-1] data = "data:%s;base64,%s" % (ext, data) #data:[<mediatype>][;base64],<data> image_list.append(data) self.image_list.append(name) loadImages(image_list, self) else: self.start() def onImagesLoaded(self, images): for i, image in enumerate(self.image_list): self.images[image] = images[i].getElement() self.start() def start(self): if not self.initialized: self.initialized = True _wnd.requestAnimationFrame(run) def stop(self): global run run = lambda ts: None self.run = lambda: None def _get_rect(self): if self._rect_num < self._rect_len: return self._rect_list[self._rect_num] else: self._rect_list.append(Rect(0, 0, 0, 0)) self._rect_len += 1 return self._rect_list[self._rect_num] def update(self, timestamp): if not self._framerate: self._frametime = timestamp - self._rendertime self.run() else: self._frametime += timestamp - self._rendertime if self._frametime > self._framerate: self.run() self._frametime = 0 self._rendertime = timestamp def render(self): while self._rect_num: rect = self._rect_list[self._rect_num - 1] x, y, width, height = rect.x, rect.y, rect.width, rect.height _ctx.drawImage(_img, x, y, width, height, x, y, width, height) self._rect_num -= 1 def run(self): self.callback.run()