class Scaled(Widget): def __init__(self, **kwargs): super(Scaled, self).__init__(**kwargs) self.elements = [] self.pointsize = 5 # this multiplies by two according to kivy docs with self.canvas: self._fbo = Fbo(size=self.size) self._rect = Rectangle(texture=self._fbo.texture) with self._fbo: Color(1, 1, 1) self._fborect = Rectangle(size=self._fbo.size) Color(0, 0, 1) self._points = Point(pointsize=self.pointsize) self._fbo.add_reload_observer(self._clear_fbo) self.bind(pos=self._update_rect, size=self._update_rect) def drawpoint(self, x, y): self.elements.append([x, y]) self._points.add_point(x, y) def draw(self, matrix): self._points.points = [] self._clear_fbo() for point in matrix: x = int(point[0] * (self.pointsize * 2) + self.pointsize) y = int(point[1] * (self.pointsize * 2) + self.pointsize) self.drawpoint(x, y) # RELOADING THE BUFFER AT ANY CHANGE def _clear_fbo(self, fbo=None): ''' This will reload the framebufferer either by the call of the observer or by the deletion of a point''' if fbo is None: fbo = self._fbo fbo.bind() fbo.clear_buffer() fbo.add(Color(1, 1, 1)) fbo.add(self._fborect) fbo.add(Color(0, 0, 1)) fbo.add(self._points) fbo.release() def _update_rect(self, instance, value): self._fbo.size = instance.size self._fborect.size = instance.size self._rect.size = instance.size self._rect.pos = instance.pos self._rect.texture = self._fbo.texture
class Scaled(Widget): def __init__(self, **kwargs): super(Scaled, self).__init__(**kwargs) self.elements = [] self.pointsize = 5 # this multiplies by two according to kivy docs with self.canvas: self._fbo = Fbo(size=self.size) self._rect = Rectangle(texture=self._fbo.texture) with self._fbo: Color(1, 1, 1) self._fborect = Rectangle(size=self._fbo.size) Color(0, 0, 1) self._points = Point(pointsize=self.pointsize) self._fbo.add_reload_observer(self._clear_fbo) self.bind(pos=self._update_rect, size=self._update_rect) def drawpoint(self, x, y): self.elements.append([x, y]) self._points.add_point(x, y) def draw(self, matrix): self._points.points = [] self._clear_fbo() for point in matrix: x = int(point[0] * (self.pointsize * 2) + self.pointsize) y = int(point[1] * (self.pointsize * 2) + self.pointsize) self.drawpoint(x, y) # RELOADING THE BUFFER AT ANY CHANGE def _clear_fbo(self, fbo=None): """ This will reload the framebufferer either by the call of the observer or by the deletion of a point""" if fbo is None: fbo = self._fbo fbo.bind() fbo.clear_buffer() fbo.add(Color(1, 1, 1)) fbo.add(self._fborect) fbo.add(Color(0, 0, 1)) fbo.add(self._points) fbo.release() def _update_rect(self, instance, value): self._fbo.size = instance.size self._fborect.size = instance.size self._rect.size = instance.size self._rect.pos = instance.pos self._rect.texture = self._fbo.texture
def on_touch_down(self, touch): if Widget.on_touch_down(self, touch) or not self.isInCanvas(touch): # ボタンなどのウィジット上でタッチした場合は処理をスルー return h, w = self.srcimg.shape[:2] m = self.margin ud = touch.ud x = touch.x if touch.x < w + 2 * m else touch.x - (w + 2 * m) if self.nowFraming(): # 枠設定中 g = str(self.fState) with self.canvas: # Color(ud['color'], 1, 1, mode='hsv', group=g) Color(0, 1, 0, mode='rgba', group=g) ud['cross'] = [ Rectangle(pos=(x, BUTTONH), size=(1, h), group=g), # クロスカーソル 縦 Rectangle(pos=(0, touch.y), size=(2 * (w + 2 * m), 1), group=g), # クロスカーソル 横 Rectangle(pos=(x + w + 2 * m, BUTTONH), size=(1, h), group=g) ] ud['label'] = Label(size_hint=(None, None)) self.update_touch_label(ud['label'], touch) self.add_widget(ud['label']) else: mark = self.nowMarking() if mark < 0: # not on marking return ud['group'] = g = str(touch.uid) ps = self.pointsize with self.canvas: exec(COLORS[mark]) # ud['drawings'] = Point(points=(touch.x, touch.y), source='res/picdicpics/particle.png', ud['drawings'] = [ Point(points=(x, touch.y), source='res/picdicpics/ic12_pennib.png', pointsize=ps, group=g), Point(points=(x + w + 2 * m, touch.y), source='res/picdicpics/ic15_pennib64.png', pointsize=ps, group=g) ] self.drawPoint(ud['drawings'][0].points, colorvalue=DRAW_COLORS[mark]) self.pushCV(g) touch.grab(self) # ドラッグの追跡を指定 return True
def init_board(self, points, voc_length, restored_labeled_list=None): """ params: points: list of trajectories' posistions, read from file params: voc_length: integer, length of target vocabulary params: restored_labeled_list: list of labeled indexes list, recording the index of selected points. """ self.isInit = True self.points = points self.voc_length = voc_length # re-draw basic trajectory on canvas self.canvas.clear() voc_points = Point(points=self.points, pointsize=5) self.canvas.add(Color(.6, .6, .6, 1)) self.canvas.add(voc_points) voc_lines = Line(points=self.points, width=4) self.canvas.add(Color(.6, .6, .6, .6)) self.canvas.add(voc_lines) # init cursors and selected points on canvas if restored_labeled_list is not None: self.init_restored(restored_labeled_list) else: self.init_default() # update all selected points index by cursors' positions self.update_selected_points()
def on_touch_down(self, touch): ud = touch.ud ud['group'] = g = str(touch.uid) if not self._ready: self._init_corner(touch) return if self.numCorners != 4 and self.isCorner(touch): self._init_corner(touch) return x, y = self.rectify(touch) print x, y ud = touch.ud ud['group'] = g = str(touch.uid) with self.canvas: ud['color'] = Color(random(), 1, 1, mode='hsv', group=g) ud['lines'] = Point(points=(x, y), source='particle.png', pointsize=5, group=g) self.send({'type': 'new', 'id': touch.uid, 'pos': (x, y)})
def on_touch_down(self, touch): message = {'event':'touchdown', 'uid':str(touch.uid), 'x':str(touch.x), 'y':str(touch.y), } sendmsg(message) win = self.get_parent_window() ud = touch.ud ud['group'] = g = str(touch.uid) pointsize = 5 ud['color'] = random() with self.canvas: Color(ud['color'], 1, 1, mode='hsv', group=g) ud['lines'] = [ Rectangle(pos=(touch.x, 0), size=(1, win.height), group=g), Rectangle(pos=(0, touch.y), size=(win.width, 1), group=g), Point(points=(touch.x, touch.y), source='particle.png', pointsize=pointsize, group=g)] ud['label'] = Label(size_hint=(None, None)) self.update_touch_label(ud['label'], touch) self.add_widget(ud['label']) touch.grab(self) return True
def on_touch_down(self, touch): win = self.get_parent_window() ud = touch.ud ud['group'] = g = str(touch.uid) pointsize = 5 if 'pressure' in touch.profile: ud['pressure'] = touch.pressure pointsize = (touch.pressure * 100000)**2 ud['color'] = random() with self.canvas: Color(ud['color'], 1, 1, mode='hsv', group=g) ud['lines'] = [ Rectangle(pos=(touch.x, 0), size=(1, win.height), group=g), Rectangle(pos=(0, touch.y), size=(win.width, 1), group=g), Point(points=(touch.x, touch.y), source='particle.png', pointsize=pointsize, group=g) ] ud['label'] = Label(size_hint=(None, None)) self.update_touch_label(ud['label'], touch) self.add_widget(ud['label']) touch.grab(self) return True
def __setitem__(self, point, value): R = value[0] / 255.0 G = value[1] / 255.0 B = value[2] / 255.0 with self.window.canvas: Color(R, G, B) Point(points=(point[0], self.height - point[1]))
def collision_circles(self, shape=None, distance=100, debug=False,color=None, *args): '''Simple circle <-> circle collision between the shapes i.e. there's a simple line between the centers of the two shapes and the collision is only about measuring distance -> 1+ radii intersections. ''' # get all combinations from all available shapes for com in self.otros: x = (self.player.center_x - com.center_x) ** 2 y = (self.player.center_y - com.center_y) ** 2 if sqrt(x + y) <= distance: # dispatch a custom event if the objects collide self.dispatch('on_collision', com) # draw collider only if debugging if not debug: return # add circle collider only if the shape doesn't have one d = distance / 2.0 cx, cy = shape.center points = [(cx + d * cos(i), cy + d * sin(i)) for i in range(44)] points = [p for ps in points for p in ps] with shape.canvas: Color(*color) shape.debug_collider = Point(points=points) shape.circulo = Ellipse(size=(distance+2,distance+2), pos=[shape.center_x - distance/2, shape.center_y - distance/2])
def collision_circles(self, shapes=None, distance=100, debug=False, *args): '''Simple circle <-> circle collision between the shapes i.e. there's a simple line between the centers of the two shapes and the collision is only about measuring distance -> 1+ radii intersections. ''' # get all combinations from all available shapes if not hasattr(self, 'combins'): self.combins = list(combinations(shapes, 2)) for com in self.combins: x = (com[0].center_x - com[1].center_x)**2 y = (com[0].center_y - com[1].center_y)**2 if sqrt(x + y) <= distance: # dispatch a custom event if the objects collide self.dispatch('on_collision', (com[0], com[1])) # draw collider only if debugging if not debug: return # add circle collider only if the shape doesn't have one for shape in shapes: if shape.debug_collider is not None: continue d = distance / 2.0 cx, cy = shape.center points = [(cx + d * cos(i), cy + d * sin(i)) for i in range(44)] points = [p for ps in points for p in ps] with shape.canvas: Color(rgba=(0, 1, 0, 1)) shape.debug_collider = Point(points=points)
def __init__(self, **kwargs): super(Scaled, self).__init__(**kwargs) self.elements = [] self.pointsize = 5 # this multiplies by two according to kivy docs with self.canvas: self._fbo = Fbo(size=self.size) self._rect = Rectangle(texture=self._fbo.texture) with self._fbo: Color(1, 1, 1) self._fborect = Rectangle(size=self._fbo.size) Color(0, 0, 1) self._points = Point(pointsize=self.pointsize) self._fbo.add_reload_observer(self._clear_fbo) self.bind(pos=self._update_rect, size=self._update_rect)
def test_point(self): from kivy.uix.widget import Widget from kivy.graphics import Point, Color r = self.render # 1 point wid = Widget() with wid.canvas: Color(1, 1, 1) Point(points=(10, 10)) r(wid) # 25 points wid = Widget() with wid.canvas: Color(1, 1, 1) Point(points=[x * 5 for x in range(50)]) r(wid)
def on_touch_down(self, touch, force=False): if force: self.touch_uid = touch.uid if self.touch_uid == touch.uid: #touch.grab(self) with self.canvas.before: PushMatrix() with self.canvas.after: PopMatrix() with self.canvas: # Create the ring of “satellite” points self.color_instruction = Color(1, 1, 0, 0) self.points = Point(points=self.pos, pointsize=5, source='particle.png') Translate(self.pos[0], self.pos[1], 0) self.scale_instruction = Scale(self.parent.cell_size * 10) self.rotate_instruction = Rotate(0, 0, 0, 1) self.rscale_instruction = Scale(1) num_satellites = 9 satellites = [] for i in range(num_satellites): angle = i / num_satellites * 2 * math.pi satellites.extend([ math.cos(angle) * 1.3, math.sin(angle) * 1.3, ]) Point(points=satellites, pointsize=0.2, source='particle2.png') # A scale-in animation animation = Animation(scale=self.parent.cell_size / 3 * 2, t='out_cubic', duration=0.2) animation.start(self.scale_instruction) # A fade-in animation animation = Animation(a=0.8, t='out_cubic', duration=0.2) animation.start(self.color_instruction) # A practically infinite spinning animation animation = Animation(angle=200000 * self.spin, duration=1000) animation.start(self.rotate_instruction) return True
def create_drawings(self): # from kivy.graphics import Line, RenderContext, Color, Point #from kivy.graphics import RenderContext, Color, Point self._grc = RenderContext(use_parent_modelview=True, use_parent_projection=True) with self._grc: self._gcolor = Color(*self.color) self._gline = Point(pointsize=self._pointsize) return [self._grc]
def on_touch_down(self, touch): ud = touch.ud ud['group'] = g = str(touch.uid) with self.canvas: ud['lines'] = [Point(points=(touch.x, touch.y), group=g)] print(touch) touch.grab(self) print(touch.grab_current) print(touch)
def on_touch_move(self, touch): if touch.grab_current is not self: return ud = touch.ud ud['lines'][0].pos = touch.x, 0 ud['lines'][1].pos = 0, touch.y index = -1 while True: try: points = ud['lines'][index].points oldx, oldy = points[-2], points[-1] break except: index -= 1 points = calculate_points(oldx, oldy, touch.x, touch.y, steps=5) # if pressure changed create a new point instruction if 'pressure' in ud: if not .95 < (touch.pressure / ud['pressure']) < 1.05: g = ud['group'] pointsize = (touch.pressure * 100000)**2 with self.canvas: Color(ud['color'], 1, 1, mode='hsv', group=g) ud['lines'].append( Point(points=(), source='particle.png', pointsize=pointsize, group=g)) if points: data = ",".join([str(i) for i in [touch.sx, touch.sy]]) self.pub.send_topic("touch", "move") self.pub.send_topic("data", data) print 'touch move ', data try: lp = ud['lines'][-1].add_point for idx in range(0, len(points), 2): lp(points[idx], points[idx + 1]) except GraphicException: pass ud['label'].pos = touch.pos import time t = int(time.time()) if t not in ud: ud[t] = 1 else: ud[t] += 1 self.update_touch_label(ud['label'], touch)
def on_touch_down(self, touch): win = self.get_parent_window() ud = touch.ud with self.canvas: Color(1, 0, 0, 1) ud['lines'] = Point(points=( touch.x, touch.y )) touch.grab(self) return True
def on_touch_down(self, touch): ud = touch.ud ud['group'] = g = str(touch.uid) with self.canvas: ud['color'] = Color(.31, .573, .816, mode='rgb', group=g) ud['lines'] = (Point(points=(touch.x, touch.y), source='particle.png', pointsize=5, group=g)) if (self.draw): for [x, y] in self.point_data: ud['lines'] = (Point(points=(x, y), source='particle.png', pointsize=5, group=g)) self.draw = False self.point_data.append([touch.x, touch.y]) touch.grab(self) ret = super(Painter, self).on_touch_down(touch) return False
def on_touch_move(self, touch): if touch.grab_current is not self: return # logging.info('on touch move') if not self.running_app.is_android: self.only_click = False else: self.only_click = 1 if self.only_click is True else False ud = touch.ud ud['lines'][0].pos = touch.x, 0 ud['lines'][1].pos = 0, touch.y index = -1 while True: try: points = ud['lines'][index].points oldx, oldy = points[-2], points[-1] break except: index -= 1 points = calculate_points(oldx, oldy, touch.x, touch.y) # if pressure changed create a new point instruction if 'pressure' in ud: if not .95 < (touch.pressure / ud['pressure']) < 1.05: g = ud['group'] pointsize = (touch.pressure * 100000) ** 2 with self.canvas: Color(ud['color'], 1, 1, mode='hsv', group=g) ud['lines'].append( Point(points=(), source='particle.png', pointsize=pointsize, group=g)) if points: try: lp = ud['lines'][-1].add_point for idx in range(0, len(points), 2): lp(points[idx], points[idx + 1]) except GraphicException: pass ud['label'].pos = touch.pos t = int(time.time()) if t not in ud: ud[t] = 1 else: ud[t] += 1 self.update_touch_label(ud['label'], touch, start_move=False)
def on_touch_move(self, touch): if touch.grab_current is not self: return ud = touch.ud ud['lines'][0].pos = touch.x, 0 ud['lines'][1].pos = 0, touch.y index = -1 while True: try: points = ud['lines'][index].points oldx, oldy = points[-2], points[-1] break except IndexError: index -= 1 points = calculate_points(oldx, oldy, touch.x, touch.y) # if pressure changed create a new point instruction if 'pressure' in ud: old_pressure = ud['pressure'] if (not old_pressure or not .99 < (touch.pressure / old_pressure) < 1.01): g = ud['group'] pointsize = self.normalize_pressure(touch.pressure) with self.canvas: Color(ud['color'], 1, 1, mode='hsv', group=g) ud['lines'].append( Point(points=(), source='particle.png', pointsize=pointsize, group=g)) if points: try: lp = ud['lines'][-1].add_point for idx in range(0, len(points), 2): lp(points[idx], points[idx + 1]) except GraphicException: pass ud['label'].pos = touch.pos import time t = int(time.time()) if t not in ud: ud[t] = 1 else: ud[t] += 1 self.update_touch_label(ud['label'], touch)
def on_touch_down(self, touch): _app = self._app if (_app.color_mode[0] == 'c' or not self.collide_point(*touch.pos)): return super(Picture, self).on_touch_down(touch) ud = touch.ud ud['group'] = g = str(touch.uid) _pos = list(self.ids.img.to_widget(*touch.pos)) _pos[0] += self.parent.x with self.ids.img.canvas.after: ud['color'] = Color(*_app.color_selector.color, group=g) ud['lines'] = Point(points=(_pos), source='../demo/touchtracer/particle.png', pointsize=5, group=g) touch.grab(self) return True
def test_point_add(self): from kivy.uix.widget import Widget from kivy.graphics import Point, Color r = self.render wid = Widget() with wid.canvas: Color(1, 1, 1) p = Point(pointsize=10) p.add_point(10, 10) p.add_point(90, 10) p.add_point(10, 90) p.add_point(50, 50) p.add_point(10, 50) p.add_point(50, 10) r(wid)
def on_touch_move(self, touch): if touch in self._corners: return x, y = self.rectify(touch) ud = touch.ud try: ud['lines'] = Point(points=(x, y), source='particle.png', pointsize=5, group=ud['group']) except GraphicException: pass self.send({'type': 'mov', 'id': touch.uid, 'pos': (x, y)})
def redraw(self, dt=None): """Redraw the whole line """ self.canvas.clear() if self.build: r, g = 0, 1 else: r, g = 1, 0 with self.canvas: for opacity, (x, y, active) in zip(range(self.max_points), reversed(self.points)): alpha = (1 - opacity / self.max_points) * self.opacity if active: Color(r, g, 0, alpha) else: Color(0.4 + r * 0.1, 0.4 + g * 0.1, 0.5, alpha) Point(points=(x, y), pointsize=5, source='particle.png')
def on_touch_move(self, touch): if touch.grab_current is not self: return ud = touch.ud index = -1 while True: try: points = ud['lines'][index].points oldx, oldy = points[-2], points[-1] break except: index -= 1 points = calculate_points(oldx, oldy, touch.x, touch.y) # if pressure changed create a new point instruction if 'pressure' in ud: if not .95 < (touch.pressure / ud['pressure']) < 1.05: g = ud['group'] pointsize = (touch.pressure * 100000)**2 with self.canvas: Color(ud['color'], 1, 1, mode='hsv', group=g) ud['lines'].append( Point(points=(), source='ui/particle.png', pointsize=pointsize, group=g)) if points: try: lp = ud['lines'][-1].add_point for idx in range(0, len(points), 2): lp(points[idx], points[idx + 1]) except GraphicException: pass import time t = int(time.time()) if t not in ud: ud[t] = 1 else: ud[t] += 1
def on_touch_down(self, touch, *args): ud = touch.ud ud['group'] = g = str(touch.uid) ud['color'] = random() pointsize = 5 with self.canvas: Color(ud['color'], 1, 1, mode='hsv', group=g) ud['line'] = [ Point(points=(touch.x, touch.y), pointsize=8, group=g) ] if self.collide_point(*touch.pos): self.ball.center = touch.pos if touch.is_double_tap: [ self.canvas.remove_group(str(i)) for i in range(int(self.lastErase), int(g)) ] # erases marks since last erase self.lastErase = g # saves current group to use as start point
def on_touch_down(self, touch): super().on_touch_down(touch) self.ud = touch.ud if (touch.pos[0] > self.pos[0] and touch.pos[0] < self.pos[0] + self.size[0] and touch.pos[1] > self.pos[1] and touch.pos[1] < self.pos[1] + self.size[1]): self.in_pad = True self.ud['group'] = g = str(touch.uid) pointsize = 3 self.ud['color'] = 0 with self.canvas.before: Color(.2, .1, .05, .08) self.ud['lines'] = [ Point(points=(touch.x, touch.y), pointsize=pointsize, group=g)] return True else: self.ud['lines'] = []
def on_touch_down(self, touch): win = self.get_parent_window() ud = touch.ud ud['group'] = g = str(touch.uid) with self.canvas: ud['color'] = Color(random(), 1, 1, mode='hsv', group=g) ud['lines'] = (Rectangle(pos=(touch.x, 0), size=(1, win.height), group=g), Rectangle(pos=(0, touch.y), size=(win.width, 1), group=g), Point(points=(touch.x, touch.y), source='particle.png', pointsize=5, group=g)) ud['label'] = Label(size_hint=(None, None)) self.update_touch_label(ud['label'], touch) self.add_widget(ud['label'])
def on_touch_down(self, touch): ud = touch.ud ud['group'] = g = str(touch.uid) pointsize = 5 if 'pressure' in touch.profile: ud['pressure'] = touch.pressure pointsize = (touch.pressure * 100000)**2 ud['color'] = random() with self.canvas: Color(ud['color'], 1, 1, mode='hsv', group=g) ud['lines'] = [ Point(points=(touch.x, touch.y), source='ui/particle.png', pointsize=pointsize, group=g) ] touch.grab(self) return True
def on_touch_down(self, touch, *args): #whiteline = InstructionGroup() ud = touch.ud ud['group'] = g = str(touch.uid) ud['color'] = random() pointsize = 5 print('You touched me!') print(' - location touched: ', touch.x, touch.y) with self.canvas: Color(ud['color'], 1, 1, mode='hsv', group=g) #Color(0,1.,0) # green #Color(1.,1.,0) # yellow #d = 30. #MyBall(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d)) ud['line'] = [Point(points=(touch.x, touch.y), pointsize=8, group=g)] #touch.ud['line'] = Line(points=(touch.x, touch.y), width=5) #noodle = touch.ud['line'] = Line(points=(touch.x, touch.y)) #self.whiteline.add(noodle) if self.collide_point(*touch.pos): #touch.grab(self) #self.remove_widget(self.ball) #self.app.add_widget(self.ball) self.ball.center = touch.pos #return True if touch.is_double_tap: print('Touch is a double tap!') print(' - interval is', touch.double_tap_time) print(' - distance between previous is', touch.double_tap_distance) #self.canvas.clear() # works but clears everything #self.whiteline.get_group('whiteline') #self.whiteline.remove_group('line') #self.canvas.remove_group(ud['group']) # above doesn't work because it would only remove # the group, which doesn't yet have any points in it #self.canvas.remove_group('1') # removes group 1 #print('last erase + g: ', self.lastErase, g) [self.canvas.remove_group(str(i)) for i in range(int(self.lastErase), int(g))] # erases marks since last erase self.lastErase = g # saves current group to use as start point
def on_touch_down(self, touch, after=False): if not self.can_draw: return touch_x, touch_y = self.to_widget(*touch.pos, relative=True) tex_width, tex_height = self.norm_image_size tex_y = (touch_y - (self.height - tex_height) / 2) / tex_height tex_x = (touch_x - (self.width - tex_width) / 2) / tex_width if tex_x < 0 or tex_x > 1 or \ tex_y < 0 or tex_y > 1: return with self.canvas: if len(self.graphics) < 4: Color(0, 1, 1) self.graphics.append(Point(points=touch.pos, pointsize=3)) self.dispatch("on_add_point", int(tex_y * self.texture_size[1]), int(tex_x * self.texture_size[0])) if len(self.graphics) == 4: self.draw_rect([p.points for p in self.graphics])
def __init__(self, **kwargs): super(Grid, self).__init__(**kwargs) # Which elements exist in the grid in the normalized coordinates self.elements = [] # If active, it can't be modified self.active = False # To the canvas, we add the FrameBufferObject and the rect to show it with self.canvas: self.fbo = Fbo(size=self.size) self.rect = Rectangle(texture=self.fbo.texture) # Color(1,0,0) # self.rect = Rectangle(size = self.size, pos = self.pos) # To the FrameBufferObject I set the color and add the point list with self.fbo: Color(1,1,1) self.points = Point( pointsize=self.point_size ) # add some observers to the fbo, changes for the point_size (grid # resizing) and widget resizing self.fbo.add_reload_observer(self._populate_fbo) self.bind( point_size = self._reshape ) self.bind( size = self._update_rect, pos = self._update_rect )
class Grid( Widget ): point_size = NumericProperty(10) def __init__(self, **kwargs): super(Grid, self).__init__(**kwargs) # Which elements exist in the grid in the normalized coordinates self.elements = [] # If active, it can't be modified self.active = False # To the canvas, we add the FrameBufferObject and the rect to show it with self.canvas: self.fbo = Fbo(size=self.size) self.rect = Rectangle(texture=self.fbo.texture) # Color(1,0,0) # self.rect = Rectangle(size = self.size, pos = self.pos) # To the FrameBufferObject I set the color and add the point list with self.fbo: Color(1,1,1) self.points = Point( pointsize=self.point_size ) # add some observers to the fbo, changes for the point_size (grid # resizing) and widget resizing self.fbo.add_reload_observer(self._populate_fbo) self.bind( point_size = self._reshape ) self.bind( size = self._update_rect, pos = self._update_rect ) def on_touch_down(self, touch): ''' Handle adding/removing points when the grid is not active''' if not self.active and self.collide_point(*touch.pos): # Move to a 0,0 from where the widget starts x = touch.x - self.x y = touch.y - self.y self.add_point( [x,y] ) return True return super(Grid, self).on_touch_down(touch) def normalize(self, coords): ''' normalization of coordinates, it will transform any given point in the widget to its corresponding normalized coords ''' # TODO: Create a picture to describe what are the normalized coordinates if type(coords) is tuple: coords = list(coords) if type(coords) is list: for ind in range(len(coords)): coords[ind] = int( coords[ind] // ( self.points.pointsize * 2 ) ) return coords else: return int( coords // ( self.points.pointsize * 2 ) ) def adjust(self, coords): ''' adjustment of a normalized coordinate to the real coordinate using the current point size as a guide ''' if type(coords) is tuple: coords = list(coords) if type(coords) is list: for ind in range(len(coords)): coords[ind] = int( coords[ind] * ( self.points.pointsize * 2 ) + self.points.pointsize ) return coords else: return int( coords * ( self.points.pointsize * 2 ) + self.points.pointsize ) def add_point(self, point, redraw=True): ''' method to add a point to the grid if it doesn't exist if it's there, remove it''' point = self.normalize(point) if point in self.elements: where = self.elements.index( point ) # Steal the reference to the vector of points points = self.points.points self.points.points = [] # Clean the desired point del(points[where*2]) del(points[where*2]) # Reassign the property for the context to know (kivy weird things) self.points.points = points # Remove from the historical del(self.elements[where]) # Redraw if asked for if redraw: self._populate_fbo(self.fbo) else: # add the normalized coords to the element list # it has to be copied because the adjust method will modify # the elements in points self.elements.append(point[:]) # add the point to the visible points using the adjusted coordinates # the * leading self.adjust is to unpack the resulting array self.points.add_point( *self.adjust(point) ) # print(self.elements) def next(self, instance): if len(self.elements) == 0: return # calculate the survivors nextgen = automaton.survivors(self.elements) # print(nextgen) # calculate any possible newborns nextgen += automaton.births(self.elements) # print(nextgen) # replace the current elements self.elements = nextgen # The vector comes with minivectors within, which is fine for the # list of elements but doesn't work for the adjustment of points in # the screen nextgen = [ i for cell in nextgen for i in cell ] # adjust the elements to the actual coordinates nextgen = self.adjust( nextgen ) # assign the vector back self.points.points = nextgen # redraw self._populate_fbo() def clear(self, instance): self.elements = [] self.points.points = [] self._populate_fbo() # RELOADING THE BUFFER AT ANY CHANGE def _populate_fbo(self, fbo = None): ''' This will reload the framebufferer either by the call of the observer or by the deletion of a point''' if fbo is None: fbo = self.fbo fbo.bind() fbo.clear_buffer() fbo.add(self.points) fbo.release() def _reshape(self, instance, value): # There are no elements if len(self.elements) == 0: # We just update the points to be drawn self.points.pointsize = self.point_size # If we do have elements else: # steal the reference to the vector points = self.points.points self.points.points = [] # normalize using current value points = self.normalize( points ) # reassing the value self.points.pointsize = self.point_size # adjust using new value points = self.adjust( points ) # assign the vector back self.points.points = points # redraw self._populate_fbo() # REDRAWING THE FBO AND THE def _update_rect( self, instance, value ): self.fbo.size = instance.size self.rect.size = instance.size self.rect.pos = instance.pos self.rect.texture = self.fbo.texture