class BillboardDisplay(InstructionGroup): def __init__(self, pos, texture, size_x=1.0, size_y=1.0, intensity=1.0, Tr=1.0): super(BillboardDisplay, self).__init__() self.intensity = intensity self.Tr = Tr self.translate = Translate() self.rotate_azi = Rotate(origin=(0,0,0), axis=(0,1,0)) self.rotate_ele = Rotate(origin=(0,0,0), axis=(1,0,0)) self.scale = Scale() self.color_instruction = InstructionGroup() self.mesh = Mesh( texture=texture, vertices=rectangle_nurb.vertices, indices=rectangle_nurb.indices, fmt=rectangle_nurb.vertex_format, mode='triangles' ) self.add(PushMatrix()) self.add(self.translate) self.add(self.rotate_azi) self.add(self.rotate_ele) self.add(self.scale) self.add(self.color_instruction) self.add(self.mesh) self.add(PopMatrix()) self.set_color(intensity=intensity, Tr=Tr) self.set_size(size_x, size_y) self.set_pos(pos) self.set_texture(texture) def set_texture(self, texture): self.texture = texture self.mesh.texture = texture def set_rotate(self, angles): self.rotate_azi.angle = angles[0] * 180/np.pi self.rotate_ele.angle = angles[1] * 180/np.pi def set_size(self, size_x, size_y): self.scale.xyz = (size_x, size_y, 1) def set_pos(self, pos): self.translate.xyz = pos def set_color(self, intensity=1.0, Tr=1.0): self.color_instruction.clear() self.color_instruction.add( ChangeState( Kd=(0.6, 0.6, 0.6), Ka=(0.8, 0.8, 0.8), Ks=(0.9, 0.9, 0.9), Tr=Tr, Ns=1.0, intensity=intensity ) )
def group(self, color): rgb = InstructionGroup() color = Color(1, 1, 0) xyz = color rgb.add(xyz) rgb.add(Rectangle(pos=self.pos, size=self.size) ) return rgb
def group(self, color): rgb = InstructionGroup() color = Color(1, 0, 0) xyz = color rgb.add(xyz) radius = sqrt(sqrt(sum([x*x for x in self.size]))) rgb.add(Line(circle=(self.pos[0], self.pos[1], radius ) ) ) return rgb
class NurbDisplay(InstructionGroup): def __init__(self, nurb, pos, size=1.0, color=(0.0,1.0,0.0), tr=1.0, intensity=1.0): super(NurbDisplay, self).__init__() self.color = color self.tr = tr self.intensity = intensity self.translate = Translate() self.scale = Scale() self.color_instruction = InstructionGroup() self.add(PushMatrix()) self.add(self.translate) self.add(self.scale) self.add(self.color_instruction) self.add(self.make_mesh(nurb)) self.add(PopMatrix()) self.set_color() self.set_size(size) self.set_pos(pos) def make_mesh(self, m): return Mesh( vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode='triangles' ) def set_size(self, size): self.scale.xyz = (size, size, size) def set_pos(self, pos): self.translate.xyz = pos def set_color(self, color=None, tr=None, intensity=None): if tr is not None: self.tr = tr if intensity is not None: self.intensity = intensity if color is not None: self.color = color self.color_instruction.clear() self.color_instruction.add( ChangeState( Kd=self.color, Ka=self.color, Ks=(0.3, 0.3, 0.3), Tr=self.tr, Ns=1.0, intensity=self.intensity ) )
def __get_dbg_aabb_gfx(self): if self.__dbg_aabb is None: c = Color(0.8, 0.8, 0.8, 0.3) r = Rectangle() group = InstructionGroup() for instruction in (c, r): group.add(instruction) def update_r(_, ((left, bottom), (right, top))): r.pos = (left, bottom) r.size = (right - left, top - bottom) self.bind(aabb=update_r) update_r(None, self.aabb) self.__dbg_aabb = group
def __get_dbg_viewport_gfx(self): if self.__dbg_viewport is None: c = Color(1, 1, 1, 0.5) r = Rectangle() group = InstructionGroup() for instruction in (c, r): group.add(instruction) def update_r(_, __): r.pos = self.viewport_pos r.size = self.viewport_size self.bind(viewport_pos=update_r, viewport_size=update_r) update_r(None, None) self.__dbg_viewport = group return self.__dbg_viewport
def __init__(self, pos, texture, size_x=1.0, size_y=1.0, intensity=1.0, Tr=1.0): super(BillboardDisplay, self).__init__() self.intensity = intensity self.Tr = Tr self.translate = Translate() self.rotate_azi = Rotate(origin=(0,0,0), axis=(0,1,0)) self.rotate_ele = Rotate(origin=(0,0,0), axis=(1,0,0)) self.scale = Scale() self.color_instruction = InstructionGroup() self.mesh = Mesh( texture=texture, vertices=rectangle_nurb.vertices, indices=rectangle_nurb.indices, fmt=rectangle_nurb.vertex_format, mode='triangles' ) self.add(PushMatrix()) self.add(self.translate) self.add(self.rotate_azi) self.add(self.rotate_ele) self.add(self.scale) self.add(self.color_instruction) self.add(self.mesh) self.add(PopMatrix()) self.set_color(intensity=intensity, Tr=Tr) self.set_size(size_x, size_y) self.set_pos(pos) self.set_texture(texture)
def __init__(self, **kwargs): super(CanvasWidget, self).__init__(**kwargs) self.size = (512, 512) self._keyboard = Window.request_keyboard(self._keyboard_closed, self) self._keyboard.bind(on_key_down=self._on_keyboard_down) self.img = Image.open('test.png') self.img = self.img = self.img.transpose(Image.FLIP_TOP_BOTTOM) self.texture = Texture.create(size=(512,512)) self.texture.mag_filter = 'nearest' size = 512*512*3 buf = [] for r,g,b,a in self.img.getdata(): buf.extend([r,g,b,a]) #buf = [int(x*255/size) for x in range(size)] #buf = self._flatten_list(self.pixels) self.arr = array('B', buf) self.texture.blit_buffer(self.arr, colorfmt='rgba', bufferfmt='ubyte') with self.canvas: self.test = InstructionGroup() #self.test.add(Color(1, 1, 0, mode='rgb')) self.test.add(Rectangle(texture=self.texture, pos=self.pos, size=self.size, group='heh')) #self.bind(texture=self.on_texture_update) self.bind(pos=self.on_texture_update) self.bind(size=self.on_texture_update)
def do_layout(self, *args): super(Piece, self).do_layout(*args) if hasattr(self, 'outline'): self.canvas.before.remove(self.outline) self.outline = InstructionGroup() for child in self.children: self.outline.add(Color(.5, .8, 1, .8)) self.outline.add(Line( points=[ child.x - 1, child.y - 1, child.right + 1, child.y - 1, child.right + 1, child.top + 1, child.x - 1, child.top + 1 ], close=True, width=1.5 )) if self.canvas.before: self.canvas.before.add(self.outline) if len(self.children) == 0: if hasattr(self, 'outline'): self.canvas.before.remove(self.outline)
def food(self,*args): self.foodblue = InstructionGroup() self.foodblue.add(Color(1, 0, 0, 1)) x = random.randint(int(self.rangeSnake[0]), int(self.rangeSnake[2]-10)) y = random.randint(int(self.rangeSnake[1]), int(self.rangeSnake[3]-10)) self.food = Rectangle(pos=(x,y), size=(10,10)) self.foodblue.add(self.food)
def __init__(self, **kwargs): """Make triggers and bind.""" kwargs['size_hint'] = (None, None) self.translate = Translate(0, 0) self.group = InstructionGroup() super().__init__(**kwargs) self.bind(offxs=self.on_pos, offys=self.on_pos)
def update(self, *args): if hasattr(self, 'outline'): self.canvas.before.remove(self.outline) self.outline = InstructionGroup() if self.highlight: for child in self.children[:]: self.outline.add(Color(1, .2, .2, .8)) self.outline.add(Line( points=[ child.x - 1, child.y - 1, child.right + 1, child.y - 1, child.right + 1, child.top + 1, child.x - 1, child.top + 1 ], close=True, width=1.5 )) if self.canvas.before: self.canvas.before.add(self.outline) self.highlight = False else: self.canvas.before.remove(self.outline) self.highlight = True
class ErrorPiece(Piece): def __init__(self, **kwargs): super(ErrorPiece, self).__init__(**kwargs) self.highlight = False def on_parent(self, *args): if self.parent: Clock.schedule_interval(self.update, .5) def on_keypress(self, keyboard, keycode, text, modifiers): return True def do_layout(self, *args): super(ErrorPiece, self).do_layout(*args) self.update() def update(self, *args): if hasattr(self, 'outline'): self.canvas.before.remove(self.outline) self.outline = InstructionGroup() if self.highlight: for child in self.children[:]: self.outline.add(Color(1, .2, .2, .8)) self.outline.add(Line( points=[ child.x - 1, child.y - 1, child.right + 1, child.y - 1, child.right + 1, child.top + 1, child.x - 1, child.top + 1 ], close=True, width=1.5 )) if self.canvas.before: self.canvas.before.add(self.outline) self.highlight = False else: self.canvas.before.remove(self.outline) self.highlight = True
def __init__(self, **kwargs): super(ResizableCursor, self).__init__(**kwargs) self.size_hint = (None, None) self.pos_hint = (None, None) self.source = '' self.rect = Rectangle(pos=(-9998,-9998), size=(1, 1)) self.size = (dp(22), dp(22)) self.pos = [-9998, -9998] # Makes an instruction group with a rectangle and # loads an image inside it # Binds its properties to mouse positional changes and events triggered instr = InstructionGroup() instr.add(self.rect) self.canvas.after.add(instr) self.bind(pos=lambda obj, val: setattr(self.rect, 'pos', val)) self.bind(source=lambda obj, val: setattr(self.rect, 'source', val)) self.bind(hidden=lambda obj, val: self.on_mouse_move(Window.mouse_pos)) Window.bind(mouse_pos=lambda obj, val: self.on_mouse_move(val))
def __get_dbg_origin_gfx(self): if self.__dbg_origin is None: c1 = Color(1, 0, 0, 0.5) r1 = Rectangle() c2 = Color(0, 1, 0, 0.5) r2 = Rectangle() c3 = Color(0, 0, 1, 0.5) e = Ellipse() group = InstructionGroup() for instruction in (c1, r1, c2, r2, c3, e): group.add(instruction) def update_geom(_, (w, h)): r1.size = (w, 0.1 * h) r2.size = (0.1 * w, h) e.size = (0.5 * w, 0.5 * h) e.pos = (0.25 * w, 0.25 * h) self.bind(viewport_size=update_geom) update_geom(None, self.size) self.__dbg_origin = group
def __init__(self, points, **kwargs): # calculate some basic information about the data self.points = points self.points_x = zip(*points)[0] self.points_y = zip(*points)[1] # if we could figure out how to draw an arbitrary number of ticks in kv, this would be cleaner self.ticks = InstructionGroup() self.tick_translate = Translate() super(LinePlot, self).__init__(**kwargs) self.canvas.insert(0, self.ticks) self.viewport = (min(self.points_x), min(self.points_y), max(self.points_x), max(self.points_y))
def __init__(self, nurb, pos, size=1.0, color=(0.0,1.0,0.0), tr=1.0, intensity=1.0): super(NurbDisplay, self).__init__() self.color = color self.tr = tr self.intensity = intensity self.translate = Translate() self.scale = Scale() self.color_instruction = InstructionGroup() self.add(PushMatrix()) self.add(self.translate) self.add(self.scale) self.add(self.color_instruction) self.add(self.make_mesh(nurb)) self.add(PopMatrix()) self.set_color() self.set_size(size) self.set_pos(pos)
def __init__(self, iface, amount, tag, func, serv_addr, bufsize=1024): """ iface: interface to sniff on amount: max amount of latest rssis to maintain tag: value for tag field, used as sign func: function to process rssi list, should takes list of rssis in and output another list of single output value serv_addr: server addr, format as (HOST, PORT) bufsize: max size of receive buf, should be big enough """ super(sniffWidget, self).__init__() self.iface = iface self.amount = amount self.tag = tag self.rssi_dict = {} self.rssi_dict["tag"] = tag self.prcs_dict = {} self.prcs_dict["tag"] = self.tag self.func = func # server addr self.serv_addr = serv_addr self.bufsize = bufsize # client socket # use ipv4 udp self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #self.sock.settimeout(3.0) # initial communication with server self.config() # visualize aps #self.visual_aps() # initial coords self.coords = (0, 0) # used to record all instructions that draw user-dots self.obj = InstructionGroup() self.objects = [] # used to indicate whether update should be down actually self.update_flag = 0 # children widget, 2 buttons # define event behavior for those two def _on_press1(instance): # change the text and flag if instance.flag == -1: instance.flag = 1 instance.text = "Pause" instance.parent.set_flag() elif instance.flag == 0: instance.flag = 1 instance.text = "Pause" instance.parent.set_flag() elif instance.flag == 1: instance.flag = 0 instance.text = "Resume" instance.parent.unset_flag() def _on_press2(instance): # clear the canvas and re-initial btn1 instance.parent.clear() instance.parent.btn1.reinit() instance.parent.unset_flag() self.btn1.bind(on_press=_on_press1) self.btn2.bind(on_press=_on_press2)
def charting(self, *args): """ 繪圖 """ self.canvas.clear() if self.dataList == None or len(self.dataList) == 0: self.drawNoDataGraph() return self.calcMaxTick() self.drawCordFrame() self.profitPerNumDict.clear() self.maxNum = 5 tmpProfitPer = None aNum = None for profitPer in self.dataList: if profitPer < 0: tmpProfitPer = math.floor(profitPer) if tmpProfitPer < self.min_tickNum: tmpProfitPer = self.min_tickNum else: tmpProfitPer = math.ceil(profitPer) if tmpProfitPer > self.max_tickNum: tmpProfitPer = self.max_tickNum tmpProfitPer = int(tmpProfitPer) aNum = self.profitPerNumDict.get(str(tmpProfitPer)) if aNum == None: aNum = 0 aNum += 1 self.profitPerNumDict[str(tmpProfitPer)] = aNum if aNum > self.maxNum: self.maxNum = aNum self.yscale = (self.height - self.shift_bottom - self.shift_top) / self.maxNum self.drawCordInfo() index = None shift_xpos = None center_pos = int(self.pillarPoint / 2) for i in range(self.min_tickNum, self.max_tickNum + 1): if i == 0: shift_xpos = self.ycordWidth elif i > 0: shift_xpos = self.ycordWidth * 2 else: shift_xpos = 0 index = i - self.min_tickNum aNum = self.profitPerNumDict.get(str(i)) if aNum != None: lineColor = Color() lineColor.rgba = self.GRID_COLOR instg = InstructionGroup(group="data") instg.add(lineColor) x1 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + shift_xpos) y1 = int(self.pos[1] + self.shift_bottom) x2 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + shift_xpos) y2 = int(self.pos[1] + self.shift_bottom + aNum * self.yscale) instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg) instg = InstructionGroup(group="data") instg.add(lineColor) x1 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + shift_xpos) y1 = int(self.pos[1] + self.shift_bottom + aNum * self.yscale) x2 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + self.pillarPoint - 1 + shift_xpos) y2 = int(self.pos[1] + self.shift_bottom + aNum * self.yscale) instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg) instg = InstructionGroup(group="data") instg.add(lineColor) x1 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + self.pillarPoint - 1 + shift_xpos) y1 = int(self.pos[1] + self.shift_bottom) x2 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + self.pillarPoint - 1 + shift_xpos) y2 = int(self.pos[1] + self.shift_bottom + aNum * self.yscale) instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg) x1 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + shift_xpos + center_pos) self.xcordDict[str(i)] = x1
def move(self,*dt): self.canvas.clear() self.canvas.add(self.foodblue) x,y = self.snake[-1] if abs(self.snake[-1][0] -self.food.pos[0])<10 and abs(self.snake[-1][1] -self.food.pos[1])<10:#吃到食物 x,y = self.snake[-1] if self.keyboard.direction == "left": for i in range(1,11): x1,y1 = x-i,y self.snake.append((x1,y1)) elif self.keyboard.direction == "right": for i in range(1,11): x1,y1 = x+i,y self.snake.append((x1,y1)) elif self.keyboard.direction == "up": for i in range(1,11): x1,y1 = x,y+i self.snake.append((x1,y1)) elif self.keyboard.direction == "down": for i in range(1,11): x1,y1 = x,y-i self.snake.append((x1,y1)) self.foods() else: if self.keyboard.direction == "left": x,y = x-1,y if x < self.rangeSnake[0] : self.gameover() for a,b in self.snake: if x >a and x-a<10 and abs(b-y)<10: self.gameover() break elif self.keyboard.direction == "right": x,y = x+1,y if x+10 > self.rangeSnake[2]: self.gameover() for a,b in self.snake: if a>x and a-x < 10 and abs(b-y)< 10: self.gameover() break elif self.keyboard.direction == "up": x,y = x,y+1 if y+10 >self.rangeSnake[3]: self.gameover() for a,b in self.snake: if b>y and b-y < 10 and abs(x-a)<10: self.gameover() break elif self.keyboard.direction == "down": x,y = x,y-1 if y < self.rangeSnake[1]: self.gameover() for a,b in self.snake: if y >b and y-b>10 and abs(x-a)<10: self.gameover() break self.snake.append((x,y)) del self.snake[0] for i in self.snake: snake = InstructionGroup() snake.add(Color(0, 0, 1, 1)) snake.add(Rectangle(pos=i, size=(10,10))) self.canvas.add(snake)
def drawCrossLine(self, aIndex): """ """ dataNum = len(self.dataDict) if dataNum == 0: return if aIndex >= self.dispMax: index = self.dispMax - 1 elif aIndex >= self.dispNum: index = self.dispNum - 1 elif aIndex < 0: index = 0 else: index = aIndex self.crossLineIndex = index if self.infoFunc == None: self._showInfo(index) else: aKey = self.keyList[self.scopeIdx[0] + index] aDict = self.dataDict.get(aKey) refDict = {} for aKey in aDict.keys(): refDict[aKey] = aDict.get(aKey) preIndex = self.scopeIdx[0] + index - 1 if preIndex < 0: refDict["UD"] = 0 else: aKey = self.keyList[preIndex] preDict = self.dataDict.get(aKey) refDict["UD"] = aDict.get("CP") - preDict.get("CP") self.infoFunc(refDict) if self.isDrawCrossLine == False: return groupStr = self.instGroup + "cross_line" self.canvas.remove_group(groupStr) color = Color() color.rgba = self.CROSS_LINE_COLOR instg = InstructionGroup(group=groupStr) instg.add(color) x1 = self.chartPos[0] + (index + 1) * (self.tickWide + self.tickGap) - self.backGap y1 = self.chartPos[1] x2 = x1 y2 = self.chartPos[1] + self.chartSize[1] instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg) aKey = self.keyList[self.scopeIdx[0] + index] aDict = self.dataDict.get(aKey) instg = InstructionGroup(group=groupStr) instg.add(color) x1 = self.chartPos[0] y1 = self.chartPos[1] + (aDict.get("CP") - self.lowestValue) * self.yscale x2 = self.chartPos[0] + self.chartSize[0] y2 = y1 instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg)
class DialGauge(Widget): dial_diameter = NumericProperty(180) dial_size = ReferenceListProperty(dial_diameter, dial_diameter) scale_max = NumericProperty(100.0) scale_min = NumericProperty(0.0) scale_increment = NumericProperty(10.0) angle_start = NumericProperty(0.0) angle_stop = NumericProperty(360.0) angle_offset = NumericProperty(0.0) tic_frequency = NumericProperty(2.0) tic_length = NumericProperty(8) tic_width = NumericProperty(2) tic_radius = NumericProperty(100) tic_color = ListProperty([0, 0, 1]) dial_color = ListProperty([1, 1, 1]) needle_color = ListProperty([1, 0, 0]) hub_color = ListProperty([1, 0, 0]) needle_length = NumericProperty(100) needle_width = NumericProperty(4) hub_radius = NumericProperty(20) semi_circle = BooleanProperty(False) value = NumericProperty(0.0) value_offset_pos = ListProperty([0, 0]) show_value = BooleanProperty(True) value_color = ListProperty([0, 0, 1, 1]) value_font_size = NumericProperty(20) scale_font_size = NumericProperty(10) annulars = ListProperty() annular_thickness = NumericProperty(8) setpoint_thickness = NumericProperty(2) setpoint_length = NumericProperty(None) setpoint_value = NumericProperty(float('nan')) setpoint_color = ListProperty([0, 0, 0, 1]) def __init__(self, **kwargs): super(DialGauge, self).__init__(**kwargs) self.annular_canvas = None self.setpoint_canvas = None self.draw_annulars() self.draw_ticks() self.draw_setpoint() self.bind(pos=self._redraw, size=self._redraw) self.bind(setpoint_value=self.draw_setpoint) def get_dial_center(self): x = self.pos[0] + self.dial_diameter / 2. y = self.pos[1] + self.dial_diameter / 2. if self.semi_circle: y += (-self.dial_diameter / 2 + self.hub_radius) return [x, y] def set_dial_center(self): pass dial_center = AliasProperty(get_dial_center, set_dial_center, bind=['size', 'pos']) def value_to_angle(self, v): ''' convert the given value to the angle required for the scale ''' return -180.0 + self.angle_start + self.angle_offset + ( (self.angle_stop - self.angle_start) * ((float(v) - self.scale_min) / (self.scale_max - self.scale_min))) def _redraw(self, instance, value): if self.annular_canvas: self.canvas.before.remove(self.annular_canvas) self.draw_annulars() self.canvas.remove(self.ticks) self.draw_ticks() self.draw_setpoint() def draw_annulars(self): # draw annulars that are in the annulars list: # requires properties annular_thickness, and a list of dicts {color: , start: , stop: }, ..., # where start and stop are the values of the scale to start and stop the annular if len(self.annulars) == 0: return awidth = self.annular_thickness self.annular_canvas = InstructionGroup() if self.semi_circle: self.annular_canvas.add(PushMatrix()) self.annular_canvas.add( Translate(0, -self.dial_diameter / 2 + self.hub_radius)) for a in self.annulars: self.annular_canvas.add(Color(*a.get('color', [0, 1, 0, 1]))) st = self.value_to_angle(a.get('start', self.scale_min)) en = self.value_to_angle(a.get('stop', self.scale_max)) self.annular_canvas.add( Line(ellipse=(self.pos[0] + awidth, self.pos[1] + awidth, self.dial_diameter - awidth * 2, self.dial_diameter - awidth * 2, st + awidth / 2.0 - self.tic_width, en + awidth / 2.0), width=awidth, cap='none', joint='round')) if self.semi_circle: self.annular_canvas.add(PopMatrix()) self.canvas.before.add(self.annular_canvas) def draw_ticks(self): scangle = self.angle_stop - self.angle_start inc = scangle / ( (self.scale_max - self.scale_min) / self.scale_increment) inc /= self.tic_frequency cnt = 0 # create an instruction group so we can remove it and recall draw_ticks to update when pos or size changes self.ticks = InstructionGroup() self.ticks.add(Color(*self.tic_color)) labi = self.scale_min x = -180.0 + self.angle_start + self.angle_offset # start while x <= self.angle_stop - 180 + self.angle_offset: a = x if (x < 0.0) else x + 360.0 need_label = True ticlen = self.tic_length if (cnt % self.tic_frequency != 0): ticlen = self.tic_length / 2 need_label = False cnt += 1 self.ticks.add(PushMatrix()) self.ticks.add( Rotate(angle=a, axis=(0, 0, -1), origin=(self.dial_center[0], self.dial_center[1]))) self.ticks.add(Translate(0, self.tic_radius - ticlen)) self.ticks.add( Line(points=[ self.dial_center[0], self.dial_center[1], self.dial_center[0], self.dial_center[1] + ticlen ], width=self.tic_width, cap='none', joint='none')) if need_label: #print("label: " + str(labi)) #kw['font_size'] = self.tic_length * 2 label = CoreLabel(text=str(int(round(labi))), font_size=self.scale_font_size) label.refresh() texture = label.texture self.ticks.add( Translate(-texture.size[0] / 2, -texture.size[1] - 2)) self.ticks.add( Rectangle(texture=texture, pos=self.dial_center, size=texture.size)) labi += self.scale_increment self.ticks.add(PopMatrix()) x += inc self.canvas.add(self.ticks) def draw_setpoint(self, *args): # draw a setpoint if self.setpoint_canvas: self.canvas.after.remove(self.setpoint_canvas) self.setpoint_canvas = None if math.isnan(self.setpoint_value): return v = self.value_to_angle(self.setpoint_value) length = self.dial_diameter / 2.0 - self.tic_length if not self.setpoint_length else self.setpoint_length self.setpoint_canvas = InstructionGroup() self.setpoint_canvas.add(PushMatrix()) self.setpoint_canvas.add(Color(*self.setpoint_color)) self.setpoint_canvas.add( Rotate(angle=v, axis=(0, 0, -1), origin=self.dial_center)) self.setpoint_canvas.add( Translate(self.dial_center[0], self.dial_center[1])) self.setpoint_canvas.add( Line(points=[0, 0, 0, length], width=self.setpoint_thickness, cap='none')) #self.setpoint_canvas.add(SmoothLine(points=[0, 0, 0, length], width=self.setpoint_thickness)) self.setpoint_canvas.add(PopMatrix()) self.canvas.after.add(self.setpoint_canvas)
class DisplayController(object): def __init__(self, width, height, canvas, ac, eye_pos, eye_angle): super(DisplayController, self).__init__() self.width = width self.height = height self.canvas = canvas self.eye_pos = eye_pos self.eye_angle = eye_angle self.ac = ac self.canvas.shader.source = resource_find('data/simple.glsl') self.all_notes = [] self.future_notes = {} self.past_notes = {} self.ticks = [] # self.planes = range(0, 10 * config['PLANE_SPACING'], config['PLANE_SPACING']) self.planes = [] self.lines = [] self.past_displays = InstructionGroup() self.future_displays = InstructionGroup() self.plane_displays = InstructionGroup() self.line_displays = InstructionGroup() self.fixed_x = Translate(0, 0, 0) self.fixed_y = Translate(0, 0, 0) self.fixed_z = Translate(0, 0, 0) self.fixed_azi = Rotate(origin=(0, 0, 0), axis=(0, 1, 0)) self.fixed_ele = Rotate(origin=(0, 0, 0), axis=(1, 0, 0)) self.alpha_callback = Callback(self.alpha_sample_callback) self.disable_alpha_callback = Callback(self.disable_alpha_sample_callback) self.alpha_instruction = InstructionGroup() self.alpha_disable_instruction = InstructionGroup() self.alpha_sample_enable = False self.canvas.add(Callback(self.setup_gl_context)) self.canvas.add(self.alpha_instruction) self.canvas.add(PushMatrix()) self.canvas.add(UpdateNormalMatrix()) self.canvas.add(PushMatrix()) self.canvas.add(self.fixed_z) self.canvas.add(self.line_displays) self.canvas.add(PopMatrix()) self.canvas.add(PushMatrix()) self.canvas.add(self.past_displays) self.canvas.add(self.future_displays) self.canvas.add(PopMatrix()) self.canvas.add(PushMatrix()) # self.canvas.add(self.fixed_x) # self.canvas.add(self.fixed_y) self.canvas.add(self.plane_displays) self.canvas.add(PopMatrix()) # self.canvas.add(PushMatrix()) # self.canvas.add(self.fixed_x) # self.canvas.add(self.fixed_y) # self.canvas.add(self.fixed_z) # self.canvas.add(Plane(-config['SELF_PLANE_DISTANCE'], size=0.1, color=(0x20/255., 0xD8/255., 0xE9/255.), tr=0.2)) # self.canvas.add(PopMatrix()) self.canvas.add(PopMatrix()) self.canvas.add(self.alpha_disable_instruction) self.canvas.add(Callback(self.reset_gl_context)) self.draw_planes() def add_notes(self, note_data): s = config['LINE_SPACING'] for nd in note_data: if (nd.x, nd.y) not in self.lines and float(nd.x).is_integer() and float(nd.y).is_integer(): self.line_displays.add(Line(nd.x * s, nd.y * s, color=(0.7, 0.5, 0.0))) self.lines.append((nd.x, nd.y)) self.all_notes.extend(note_data) self.all_notes.sort(key=lambda n:n.tick) self.ticks = map(lambda n:n.tick, self.all_notes) def draw_planes(self): for p in self.planes: self.plane_displays.add(Plane(p, color=(0xE9/255., 0xD8/255., 0x3C/255.))) def setup_gl_context(self, *args): gl.glEnable(gl.GL_DEPTH_TEST) def toggle_alpha_sample(self): if self.alpha_sample_enable: self.alpha_instruction.remove(self.alpha_callback) self.alpha_disable_instruction.remove(self.disable_alpha_callback) self.alpha_sample_enable = False else: self.alpha_instruction.add(self.alpha_callback) self.alpha_disable_instruction.add(self.disable_alpha_callback) self.alpha_sample_enable = True def alpha_sample_callback(self, *args): gl.glEnable(gl.GL_SAMPLE_ALPHA_TO_COVERAGE) def reset_gl_context(self, *args): gl.glDisable(gl.GL_DEPTH_TEST) def disable_alpha_sample_callback(self, *args): gl.glDisable(gl.GL_SAMPLE_ALPHA_TO_COVERAGE) def get_look_at(self, x, y, z, azi, ele): dx = - np.sin(azi) * np.cos(ele) dy = np.sin(ele) dz = - np.cos(azi) * np.cos(ele) # Not sure why up has to just be up... upx, upy, upz = (0, 1, 0) mat = Matrix() mat = mat.look_at(x, y, z, x + dx, y + dy, z + dz, upx, upy, upz) return mat def update_camera(self, pos, angle): self.eye_pos = pos self.eye_angle = angle x, y, z = pos azi, ele = angle asp = self.width / float(self.height) mat = self.get_look_at(x, y, z, azi, ele) proj = Matrix() proj.perspective(30, asp, 1, 100) self.canvas['projection_mat'] = proj self.canvas['modelview_mat'] = mat self.fixed_x.x = x self.fixed_y.y = y self.fixed_z.z = z self.fixed_azi.angle = azi * 180/np.pi self.fixed_ele.angle = ele * 180/np.pi def get_notes_in_range(self, start_tick, end_tick): l = bisect.bisect_left(self.ticks, start_tick) r = bisect.bisect_left(self.ticks, end_tick) if r <= 0: return [] return self.all_notes[l:r] def on_update(self, tick): self_plane_z = self.eye_pos[2] - config['SELF_PLANE_DISTANCE'] eye_tick = tick + ( - self.eye_pos[2] / config['UNITS_PER_TICK']) dt = kivyClock.frametime future_range = self.get_notes_in_range(eye_tick, eye_tick + config['VISIBLE_TICK_RANGE']) past_range = self.get_notes_in_range(eye_tick - config['VISIBLE_TICK_RANGE'], eye_tick) # COMPLEX LOGIC TO MAINTAIN LISTS OF VISIBLE NOTES ORDERED BY DISTANCE FROM CAMERA # far future <-> future # future <-> past # past <-> far past # far future -> future fftof = list(x for x in future_range if x not in self.past_notes and x not in self.future_notes) # future -> far future ftoff = list(x for x in self.future_notes if x not in future_range and x not in past_range) # future -> past ftop = list(x for x in past_range if x in self.future_notes) # past -> future ptof = list(x for x in future_range if x in self.past_notes) # past -> far past ptofp = list(x for x in self.past_notes if x not in future_range and x not in past_range) # far past -> past fptop = list(x for x in past_range if x not in self.past_notes and x not in self.future_notes) # handle ff -> f for nd in sorted(fftof, key=lambda n: n.tick): ndisp = NoteDisplay(nd, self.planes, self.ac) self.future_displays.insert(0, ndisp) self.future_notes[nd] = ndisp # handle f -> ff for nd in ftoff: ndisp = self.future_notes[nd] self.future_displays.remove(ndisp) del self.future_notes[nd] # handle f -> p for nd in sorted(ftop, key=lambda n: n.tick): ndisp = self.future_notes[nd] self.future_displays.remove(ndisp) self.past_displays.add(ndisp) self.past_notes[nd] = ndisp del self.future_notes[nd] # handle p -> f for nd in sorted(ptof, key=lambda n: -n.tick): ndisp = self.past_notes[nd] self.past_displays.remove(ndisp) self.future_displays.add(ndisp) self.future_notes[nd] = ndisp del self.past_notes[nd] # handle p -> fp for nd in ptofp: ndisp = self.past_notes[nd] self.past_displays.remove(ndisp) del self.past_notes[nd] # handle fp -> p for nd in sorted(fptop, key=lambda n: -n.tick): ndisp = NoteDisplay(nd, self.planes, self.ac) self.past_displays.insert(0, ndisp) self.past_notes[nd] = ndisp for s in self.future_notes.values() + self.past_notes.values(): pos = s.pos_from_tick(tick) s.set_pos(pos) s.on_update(dt, eye_tick, self.eye_angle) if s.past_me and pos[2] < self_plane_z - 0.5 * config['SELF_PLANE_DISTANCE']: s.past_me = False if pos[2] > self_plane_z and not s.past_me: s.sound(tick, pos) s.past_me = True Logger.debug('Number of notes: %s' % (len(self.future_notes) + len(self.past_notes)))
class String(FloatLayout): open_note_val = NumericProperty(0) num_frets = NumericProperty(12) fret_positions = ListProperty() note_vals = ListProperty() mode_filter = NumericProperty(0b101011010101) root_note_idx = NumericProperty(0) scale_text = StringProperty("") notes_to_highlight = StringProperty("") notes_or_octaves = StringProperty("") animation_prop = NumericProperty(0) hit_prop = NumericProperty(0) def __init__(self, **kwargs): super().__init__(**kwargs) self.string_shadow = Rectangle() self.string_graphic = Rectangle() self.note_markers = InstructionGroup() self.octave_markers = InstructionGroup() self.canvas.add(Color(rgba=[0 / 255, 0 / 255, 0 / 255, 0.25])) self.canvas.add(self.string_shadow) self.canvas.add(Color(rgba=[169 / 255, 169 / 255, 169 / 255, 1])) self.canvas.add(self.string_graphic) self._add_markers() self.canvas.add(self.note_markers) self.canvas.add(self.octave_markers) self.bind(size=self.update_canvas, pos=self.update_canvas) self.anim = Animation() self.hit_anim = Animation() self.play_instrs = [] def _add_markers(self): for i in range(25): marker = Marker() self.note_markers.add(marker) def animate_marker(self, index, *args): markers = self.note_markers.children anim = Animation(animation_prop=1, duration=0.5, t="in_circ") anim.bind(on_start=markers[index].initiate_animation) anim.bind(on_progress=markers[index].update_animation) anim.bind(on_complete=markers[index].end_animation) anim.start(self) def on_touch_down(self, touch): if self.collide_point(*touch.pos): for i in range(len(self.note_markers.children)): self.animate_marker(i) def update_canvas(self, *args): if self.fret_positions: # self.fret_positions is empty during instantiation. # self.update_octave_markers() self.update_string_graphics() self.update_note_markers() def update_string_graphics(self): w, h = self.width, self.height * 0.1 x, y = self.pos cy = y + (self.height / 2) string_y = cy - (h / 2) shadow_height = 3 * h shadow_y = string_y - shadow_height # Shadow effect. self.string_shadow.size = [w, shadow_height] self.string_shadow.pos = [x, cy - shadow_height] # String. self.string_graphic.size = [w, h] self.string_graphic.pos = [x, string_y] def update_note_markers(self, *args): x, y = self.pos r1 = self.height / 2 r2 = r1 * 0.9 rdiff = r1 - r2 for i, (note_val, marker) in enumerate( zip(self.note_vals, self.note_markers.children)): # Make right edge of circle touch left edge of fret bar (where your finger should go!) fret_left = self.fret_positions[i] - ( self.fretboard.fret_bar_width / 2) # Draw 2 concentric circles, c1 and c2. # Circles are defined by a square's lower left corner. c1x, c1y = (fret_left - 2 * r1) + x, y c2x, c2y = c1x + rdiff, c1y + rdiff octave, note_idx = divmod(note_val, 12) included = int( bin(self.mode_filter)[2:][note_idx - self.root_note_idx]) highlighted = int( bin(scale_highlights[self.notes_to_highlight])[2:][ note_idx - self.root_note_idx]) if self.notes_or_octaves == "Notes": color_idx = note_idx - self.root_note_idx color = rainbow[color_idx] else: color_idx = octave - 1 color = octave_colors[color_idx] if self.scale_text == "Scale Degrees": note_idx -= self.root_note_idx note_text = scale_texts[self.scale_text][note_idx] marker.update(i, note_text, c1x, c1y, r1, c2x, c2y, r2, included, highlighted, color) def update_octave_markers(self): self.octave_markers.clear() for i, note_val in enumerate(self.note_vals): self.update_octave_marker(i, note_val) def update_octave_marker(self, i, note_val): if self.fret_ranges: octave = (note_val - self.fretboard.root_note_idx) // 12 left, right = self.fret_ranges[i] width = right - left self.octave_markers.add(octave_colors[octave]) self.octave_markers.add( Rectangle(pos=[left, 0], size=[width, self.height])) def on_open_note_val(self, instance, value): self.note_vals = [ val for val in range(self.open_note_val, self.open_note_val + 25) ] self.update_canvas(instance, value) def on_num_frets(self, instance, value): self.note_vals = [ val for val in range(self.open_note_val, self.open_note_val + 25) ] self.update_canvas(instance, value) def on_root_note_idx(self, instance, value): self.update_canvas(instance, value) def on_mode_filter(self, instance, value): self.update_canvas(instance, value) def on_scale_text(self, instance, value): self.update_note_markers() def on_notes_to_highlight(self, instance, value): self.update_note_markers() def on_notes_or_octaves(self, *args): self.update_note_markers() ### SONG PLAYING METHODS def play_thread(self, lead_in): # The GuitarPro songs' tempo are of form BPM where the B(eat) is always a quarter note. thread = Thread(target=partial(self._play_thread_animation, lead_in), daemon=True) thread.start() def _play_thread_animation(self, lead_in): self.stopped = False markers = self.note_markers.children idx = 0 time.sleep(lead_in) start = time.time() goal = start while not self.stopped: if idx == len(self.play_instrs): return fret_num, seconds = self.play_instrs[idx] if fret_num != -1: # self._play_fret(fret_num, seconds) self.animation_prop = 0 anim = Animation(animation_prop=1, duration=seconds) anim.bind(on_start=markers[fret_num].initiate_animation) anim.bind(on_progress=markers[fret_num].update_animation) anim.bind(on_complete=markers[fret_num].end_animation) self.anim = anim self.hit_prop = 0 hit_anim = Animation(hit_prop=1, duration=min(seconds, 0.1)) hit_anim.bind( on_start=markers[fret_num].initiate_hit_animation) hit_anim.bind( on_progress=markers[fret_num].update_hit_animation) hit_anim.bind(on_complete=markers[fret_num].end_hit_animation) self.hit_anim = hit_anim anim.start(self) hit_anim.start(self) goal += seconds idx += 1 time.sleep(max(goal - time.time(), 0)) # def _play_fret(self, fret_num, seconds): # self.anim.stop(self) # self.animation_prop = 0 # markers = self.note_markers.children # anim = Animation(animation_prop=1, duration=seconds) # anim.bind(on_start=markers[fret_num].initiate_animation) # anim.bind(on_progress=markers[fret_num].update_animation) # anim.bind(on_complete=markers[fret_num].end_animation) # self.anim = anim # anim.start(self) def stop(self): self.stopped = True
class TextureStack(Widget): """Several textures superimposed on one another, and possibly offset by some amount. In 2D games where characters can wear different clothes or hold different equipment, their graphics are often composed of several graphics layered on one another. This widget simplifies the management of such compositions. """ texs = ListProperty() """Texture objects""" offxs = ListProperty() """x-offsets. The texture at the same index will be moved to the right by the number of pixels in this list. """ offys = ListProperty() """y-offsets. The texture at the same index will be moved upward by the number of pixels in this list. """ def _get_offsets(self): return zip(self.offxs, self.offys) def _set_offsets(self, offs): offxs = [] offys = [] for x, y in offs: offxs.append(x) offys.append(y) self.offxs, self.offys = offxs, offys offsets = AliasProperty(_get_offsets, _set_offsets, bind=('offxs', 'offys')) """List of (x, y) tuples by which to offset the corresponding texture.""" _texture_rectangles = DictProperty({}) """Private. Rectangle instructions for each of the textures, keyed by the texture. """ def __init__(self, **kwargs): """Make triggers and bind.""" kwargs['size_hint'] = (None, None) self.translate = Translate(0, 0) self.group = InstructionGroup() super().__init__(**kwargs) self.bind(offxs=self.on_pos, offys=self.on_pos) def on_texs(self, *args): """Make rectangles for each of the textures and add them to the canvas, taking their stacking heights into account. """ if not self.canvas or not self.texs: Clock.schedule_once(self.on_texs, 0) return texlen = len(self.texs) # Ensure each property is the same length as my texs, padding # with 0 as needed for prop in ('offxs', 'offys'): proplen = len(getattr(self, prop)) if proplen > texlen: setattr(self, prop, getattr(self, prop)[:proplen - texlen]) if texlen > proplen: propval = list(getattr(self, prop)) propval += [0] * (texlen - proplen) setattr(self, prop, propval) self.group.clear() self._texture_rectangles = {} w = h = 0 (x, y) = self.pos self.translate.x = x self.translate.y = y self.group.add(PushMatrix()) self.group.add(self.translate) for tex, offx, offy in zip(self.texs, self.offxs, self.offys): rect = Rectangle(pos=(offx, offy), size=tex.size, texture=tex) self._texture_rectangles[tex] = rect self.group.add(rect) tw = tex.width + offx th = tex.height + offy if tw > w: w = tw if th > h: h = th self.size = (w, h) self.group.add(PopMatrix()) if self.group not in self.canvas.children: self.canvas.add(self.group) def on_pos(self, *args): """Translate all the rectangles within this widget to reflect the widget's position. """ (x, y) = self.pos Logger.debug("TextureStack: repositioning to {}".format((x, y))) self.translate.x = x self.translate.y = y def clear(self): """Clear my rectangles, ``texs``, and ``stackhs``.""" self.group.clear() self._texture_rectangles = {} self.texs = [] self.offxs = [] self.offys = [] self.size = [1, 1] def insert(self, i, tex): """Insert the texture into my ``texs``, waiting for the creation of the canvas if necessary. """ if not self.canvas: Clock.schedule_once(lambda dt: TextureStack.insert(self, i, tex), 0) return self.texs.insert(i, tex) self.offxs.insert(i, 0) self.offys.insert(i, 0) def append(self, tex): """``self.insert(len(self.texs), tex)``""" self.insert(len(self.texs), tex) def __delitem__(self, i): """Remove a texture, its rectangle, and its stacking height""" tex = self.texs[i] try: rect = self._texture_rectangles[tex] self.canvas.remove(rect) del self._texture_rectangles[tex] except KeyError: pass del self.offxs[i] del self.offys[i] del self.texs[i] def __setitem__(self, i, v): """First delete at ``i``, then insert there""" if len(self.texs) > 0: self._no_upd_texs = True self.__delitem__(i) self._no_upd_texs = False self.insert(i, v) def pop(self, i=-1): """Delete the offsets and texture at ``i``, returning the texture. """ del self.offxs[i] del self.offys[i] return self.texs.pop(i)
def __init__(self, points=[], **kwargs): super(Figure, self).__init__(**kwargs) self.line_draw = InstructionGroup() self.points_as_added = []
def drawCrossLine(self, key): if len(self.profitPerNumDict) == 0: return aNum = self.profitPerNumDict.get(key) if aNum == None: return keyInt = int(key) index = keyInt - self.min_tickNum if keyInt == 0: shift_xpos = self.ycordWidth elif keyInt > 0: shift_xpos = self.ycordWidth * 2 else: shift_xpos = 0 color = Color() color.rgba = self.CROSS_LINE_COLOR self.canvas.remove_group("cross_line") center_pos = int(self.pillarPoint / 2) instg = InstructionGroup(group="cross_line") instg.add(color) x1 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + shift_xpos + center_pos) y1 = int(self.pos[1] + self.shift_bottom) x2 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + shift_xpos + center_pos) y2 = int(self.pos[1] + self.shift_bottom + self.maxNum * self.yscale) instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg) instg = InstructionGroup(group="cross_line") instg.add(color) x1 = self.pos[0] + self.shift_left y1 = int(self.pos[1] + self.shift_bottom + aNum * self.yscale) x2 = self.pos[0] + self.width - self.shift_right y2 = int(self.pos[1] + self.shift_bottom + aNum * self.yscale) instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg)
class CanvasWidget(FloatLayout): canvas_size = ObjectProperty((512, 512)) scale = NumericProperty(1) texture = ObjectProperty() touch_type = 'move' current_color = [0,0,0,1] @property def scaled_size(self): w, h = self.canvas_size return (w * self.scale, h * self.scale) def __init__(self, **kwargs): super(CanvasWidget, self).__init__(**kwargs) self.size = (512, 512) self._keyboard = Window.request_keyboard(self._keyboard_closed, self) self._keyboard.bind(on_key_down=self._on_keyboard_down) self.img = Image.open('test.png') self.img = self.img = self.img.transpose(Image.FLIP_TOP_BOTTOM) self.texture = Texture.create(size=(512,512)) self.texture.mag_filter = 'nearest' size = 512*512*3 buf = [] for r,g,b,a in self.img.getdata(): buf.extend([r,g,b,a]) #buf = [int(x*255/size) for x in range(size)] #buf = self._flatten_list(self.pixels) self.arr = array('B', buf) self.texture.blit_buffer(self.arr, colorfmt='rgba', bufferfmt='ubyte') with self.canvas: self.test = InstructionGroup() #self.test.add(Color(1, 1, 0, mode='rgb')) self.test.add(Rectangle(texture=self.texture, pos=self.pos, size=self.size, group='heh')) #self.bind(texture=self.on_texture_update) self.bind(pos=self.on_texture_update) self.bind(size=self.on_texture_update) def on_texture_update(self, instance=None, value=None): print('on_texture_update') for inst in self.test.get_group('heh'): if hasattr(inst, 'pos'): inst.pos = self.pos if hasattr(inst, 'size'): inst.size = self.size #self.canvas.clear() #with self.canvas: # Color(1, 1, 0, mode='rgb') # #Rectangle(texture=self.texture, pos=self.pos, size=self.size) # Rectangle(pos=self.pos, size=self.size) def _keyboard_closed(self): self._keyboard.unbind(on_key_down=self._on_keyboard_down) self._keyboard = None def _on_keyboard_down(self, keyboard, keycode, text, modifiers): if keycode[1] == 'q': self.touch_type = 'move' elif keycode[1] == 'w': self.touch_type = 'draw' elif keycode[1] == 'e': r = random.random() g = random.random() b = random.random() print(self.parent.parent.ids.palette.add_color([r,g,b,1])) def on_touch_down(self, touch): if touch.button == 'scrolldown': print('Zoomin\' in') self.set_scale(self.scale * 1.2, touch.pos) elif touch.button == 'scrollup': print('Zoomin\' out') self.set_scale(self.scale / 1.2, touch.pos) else: if self.touch_type == 'draw': x,y = self.project(touch.pos) r,g,b,a = self.current_color self.update_pixel(int(x), int(y), r, g, b, a) self.refresh() touch.grab(self) return True def on_touch_move(self, touch): if touch.grab_current == self: if self.touch_type == 'move': x, y = self.pos dx, dy = touch.dpos self.pos = (x+dx, y+dy) elif self.touch_type == 'draw': x,y = self.project(touch.pos) px, py = self.project(touch.ppos) #self.update_pixel(int(x), int(y), 255, 0, 100, 100) r,g,b,a = self.current_color self.draw_line(px, py, x, y, r,g,b,a) return True def set_color(self, color): self.current_color = color def on_touch_up(self, touch): if touch.grab_current == self: touch.ungrab(self) return True def update_pixel(self, x, y, r, g, b, a): w,h = self.canvas_size index = int((y * w * 4) + 4 * x) self.arr[index] = int(r*255) self.arr[index+1] = int(g*255) self.arr[index+2] = int(b*255) self.arr[index+3] = int(a*255) self.texture.blit_buffer(self.arr, colorfmt='rgba', bufferfmt='ubyte') print('PIXEL: %s,%s' % (int(x), int(y))) def refresh(self): self.canvas.ask_update() def draw_line(self, x0, y0, x1, y1, r,g,b,a): self.update_pixel(int(x0),int(y0),r,g,b,a) self.update_pixel(int(x1),int(y1),r,g,b,a) print('LINE: %s, %s -> %s, %s' % (x0,y0,x1,y1)) x0, y0, x1, y1 = int(x0), int(y0), int(x1), int(y1) steep = abs(y1-y0) > abs(x1-x0) if steep: x0, y0 = y0, x0 x1, y1 = y1, x1 if x0 > x1: x0, x1 = x1, x0 y0, y1 = y1, y0 deltax = x1-x0 deltay = abs(y1-y0) error = int(deltax / 2) ystep = 0 y = y0 if y0 < y1: ystep = 1 else: ystep = -1 for x in range(x0,x1): if steep: self.update_pixel(y, x, r,g,b,a) else: self.update_pixel(x, y, r,g,b,a) error -= deltay if error < 0: y = y + ystep error = error + deltax self.refresh() def redraw_canvas(self): arr = array('B', self.buf) self.texture.blit_buffer(arr, colorfmt='rgba', bufferfmt='ubyte') def is_moveable(self): w, h = self.size return w > Window.size[0] and h > Window.size[1] def set_scale(self, scale, pivot): delta_scale = self.scale - scale prev_w, prev_h = self.size c_w, c_h = self.canvas_size self.scale = scale w, h = (c_w * self.scale, c_h * self.scale) self.size = (w, h) dw = w - prev_w dh = h - prev_h px, py = pivot x, y = self.pos ratio_x = abs(px - x) / w ratio_y = abs(py - y) / h after_x = dw * ratio_x after_y = dh * ratio_y print('current', ratio_x, ratio_y) #self.center = (x - (ax-px)*scale, y - (ay-py)*scale) #if not self.is_moveable(): # self.center = Window.center #else: x,y = self.pos self.pos = (x - after_x, y - after_y) def project(self, point): px,py = point x, y = self.pos ratio = self.canvas_size[0]/self.size[0] return (ratio*(px-x), ratio*(py-y)) def _flatten_list(self, lst): return list(itertools.chain.from_iterable(lst)) def resize(self): print('Resize %s' % self.size) def redraw_region(region=None): # This will redraw a region of the canvas by iterating over # a box of pixels in the pixel map and then drawing a # rectangle for each of them. Every time something is drawn # the rectangle dimensions containing the shape will be sent # through a callback to this function pass
def update_board(self): self.canvas.after.clear() self.players = [] pos_x = 0.85 pos_y = 0.11 self.color_players_list = [[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 1], [1, 1, 0, 1]] self.pos_x_list = [] self.pos_y_list = [] for i in range(len(self.dice_holder_list)): self.dice_holder_list[i].text = str(self.dice_list[i]) ''' for i in range(4): if self.game_elem['players'][i].has_get_out_of_jail_chance_card == True: self.goo_jail_chance_with_player = "is with " + str(self.game_elem['players'][i].player_name) break else: self.goo_jail_chance_with_player = "Inside the deck" for i in range(4): if self.game_elem['players'][i].has_get_out_of_jail_community_chest_card == True: self.goo_jail_cc_with_player = "is with " + str(self.game_elem['players'][i].player_name) break else: self.goo_jail_cc_with_player = "Inside the deck" self.goo_jail_list[0].text = "Community Chest Card \nGet out of jail card \n" + self.goo_jail_cc_with_player self.goo_jail_list[1].text = "Chance Card \nGet out of jail card \n" + self.goo_jail_chance_with_player ''' for i in range(4): text_on_button = " " + self.game_elem['players'][i].player_name + \ "\n Current Cash = " + str(self.game_elem['players'][i].current_cash) + \ "\n # of houses = " + str(self.game_elem['players'][i].num_total_houses) + \ "\n # of hotels = " + str(self.game_elem['players'][i].num_total_hotels) if self.game_elem['players'][i].has_get_out_of_jail_community_chest_card == True: text_on_button = text_on_button + "\nGOO_Jail community card" if self.game_elem['players'][i].has_get_out_of_jail_chance_card == True: text_on_button = text_on_button + "\nGOO_Jail chance card" self.player_detail_list[i].text = text_on_button self.obj_instr_player = InstructionGroup() self.obj_instr_player.add( Color(self.color_players_list[i][0], self.color_players_list[i][1], self.color_players_list[i][2], self.color_players_list[i][3])) try: pos_x_n = self.game_elem['players'][i].current_position / 10 pos_y_n = self.game_elem['players'][i].current_position % 10 except: pos_x_n = 0 pos_y_n = 0 if (pos_x_n == 0): pos_x = 0.85 - (pos_y_n * 0.07) pos_y = 0.11 elif (pos_x_n == 2): pos_x = 0.85 - (10 * (0.07)) + (pos_y_n * 0.07) pos_y = 0.11 + (10 * 0.07) elif (pos_x_n == 1): pos_x = 0.85 - (10 * (0.07)) pos_y = 0.11 + (pos_y_n * 0.07) elif (pos_x_n == 3): pos_x = 0.85 pos_y = 0.11 + (10 * 0.07) - (pos_y_n * 0.07) self.obj_instr_player.add( Ellipse(pos=((pos_x + i * 0.01) * Window.width, pos_y * Window.height), size=(10, 10))) self.players.append(self.obj_instr_player) self.pos_x_list.append(pos_x) self.pos_y_list.append(pos_y) self.canvas.after.add(self.obj_instr_player) count_house = 0 count_hotel = 0 if (self.game_elem['players'][i].assets) != None: self.player_props = [] self.player_props_x = [] self.player_props_y = [] for k in range(len(list(self.game_elem['players'][i].assets))): prop_name = list(self.game_elem['players'][i].assets)[k].name pos_prop = self.game_elem['location_objects'][prop_name].start_position self.obj_instr = InstructionGroup() self.obj_instr.add(Color(self.color_players_list[i][0], self.color_players_list[i][1], self.color_players_list[i][2], self.color_players_list[i][3])) prop_x = pos_prop / 10 prop_y = pos_prop % 10 pos_x_prop = 0 pos_y_prop = 0 if (prop_x == 0): pos_x_prop = 0.835 - (prop_y * 0.07) pos_y_prop = 0.14 elif (prop_x == 2): pos_x_prop = 0.835 - (10 * (0.07)) + (prop_y * 0.07) pos_y_prop = 0.14 + (10 * 0.07) elif (prop_x == 1): pos_x_prop = 0.835 - (10 * (0.07)) pos_y_prop = 0.14 + (prop_y * 0.07) elif (prop_x == 3): pos_x_prop = 0.835 pos_y_prop = 0.14 + (10 * 0.07) - (prop_y * 0.07) self.obj_instr.add(Rectangle(pos=(pos_x_prop * Window.width, pos_y_prop * Window.height), size=(12, 12))) if list(self.game_elem['players'][i].assets)[k].loc_class=='real_estate': if list(self.game_elem['players'][i].assets)[k].num_houses>0: for m in range(list(self.game_elem['players'][i].assets)[k].num_houses): self.obj_instr.add(Color(1,1,1,1)) self.obj_instr.add(Ellipse(pos=((pos_x_prop + (m+1)*0.01) * Window.width, pos_y_prop * Window.height), size=(12, 12))) count_house+=list(self.game_elem['players'][i].assets)[k].num_houses if list(self.game_elem['players'][i].assets)[k].num_hotels>0: for m in range(list(self.game_elem['players'][i].assets)[k].num_hotels): self.obj_instr.add(Color(1,0.1,0.5,1)) self.obj_instr.add(Ellipse(pos=((pos_x_prop + (m+1)*0.01) * Window.width, pos_y_prop * Window.height), size=(12, 12))) count_hotel += list(self.game_elem['players'][i].assets)[k].num_hotels self.player_props.append(self.obj_instr) self.player_props_x.append(pos_x_prop) self.player_props_y.append(pos_y_prop) self.canvas.after.add(self.obj_instr) self.obj_instr_directory.append(self.obj_instr) self.bind(pos=self.update_rect, size=self.update_rect)
class myLine(GridLayout): def __init__(self, **kargs): super(myLine, self).__init__(**kargs) #to remove the lines self.group = InstructionGroup() #set 2 col with 100 height self.cols = 2 self.row_force_default = True self.row_default_height = 70 #angle slider self.angleSlider = Slider(min=0, max=360, value=30) self.add_widget(self.angleSlider) #label for angle slider self.L1 = Label(text="Angle: " + str(self.angleSlider.value)) self.add_widget(self.L1) #scale slider self.scaleSlider = Slider(min=1, max=5, value=3) self.add_widget(self.scaleSlider) #label for the slider self.L2 = Label(text="Scale: " + str(self.scaleSlider.value)) self.add_widget(self.L2) #ratio slider self.ratioSlider = Slider(min=.01, max=.8, value=.67) self.add_widget(self.ratioSlider) #label for the slider self.L3 = Label(text="Ratio: " + str(self.ratioSlider.value)) self.add_widget(self.L3) #attach a call back self.angleSlider.bind(value=self.on_value1) self.scaleSlider.bind(value=self.on_value2) self.ratioSlider.bind(value=self.on_value3) with self.canvas: angle = math.pi / 2 self.drawLine(origin_x, origin_y, math.pi / 2, 30) def on_value1(self, instance, angle): self.L1.text = "Angle: " + str(round(angle, 2)) def on_value2(self, instance, scale): self.L2.text = "Length: " + str(round(scale, 2)) def on_value3(self, instance, ratio): self.L3.text = "Ratio: " + str(round(ratio, 2)) def on_touch_up(self, touch): with self.canvas: angle = math.pi / 2 self.canvas.remove_group("test") self.drawLine(origin_x, origin_y, angle, 30) # def on_touch_move(self, touch): # self.on_touch_up(touch) def drawLine(self, start_x, start_y, angle, length): if length <= 1: return end_x = length * self.scaleSlider.value * math.cos(angle) + start_x end_y = length * self.scaleSlider.value * math.sin(angle) + start_y self.group.add( Line(points=[start_x, start_y, end_x, end_y], group="test")) length *= self.ratioSlider.value self.drawLine(end_x, end_y, angle - self.angleSlider.value * math.pi / 180, length) self.drawLine(end_x, end_y, angle + self.angleSlider.value * math.pi / 180, length)
class CreateBoardWindow(Screen): board_id = ObjectProperty(None) prop_id = ObjectProperty(None) players = [] def __init__(self, game_elem, **kwargs): super().__init__(**kwargs) self.game_elem = game_elem self.color_dict = { "Brown": [0.5859, 0.3, 0, 1], "SkyBlue": [0.68, 0.85, 0.90, 1], "Orchid": [0.5, 0, 0.5, 1], "Red": [1, 0, 0, 1], "Orange": [0.99, 0.64, 0, 1], "Yellow": [1, 1, 0, 1], "Green": [0, 1, 0, 1], "Blue": [0, 0, 1, 1], 'Pink': [1, 0.75, 0.796], None: [0.96, 0.96, 0.86, 1] } self.obj_instr_directory = [] self.dice_list = [] self.start_stop_flag = False self.create_board() def board_layout_caculator(self, num_properties): each_side_num_props = (num_properties / 4) each_block_width = (1 - 2 * (0.11) - 0.01) / (each_side_num_props + 1) return (each_side_num_props, each_block_width) def board_layout_total_tiles_caculator(self, location_seq): num_property_tiles = 0 for loc_obj in location_seq: num_property_tiles += 1 return num_property_tiles def create_board(self): total_num_property_tiles = self.board_layout_total_tiles_caculator( self.game_elem['location_sequence']) #each_side_number_of_props, each_block_size = self.board_layout_caculator(len(self.game_elem['location_sequence'])) each_side_number_of_props, each_block_size = self.board_layout_caculator( total_num_property_tiles) self.num_tiles = each_side_number_of_props self.each_tile_size = each_block_size each_side_number_of_props = int(each_side_number_of_props) Monopoly_center_button = MonopolyButton( text="Play", background_color=self.color_dict[None]) self.board_id.add_widget(Monopoly_center_button) Monopoly_center_button.bind(on_release=self.playing_the_game) pos_x = 0.9 - each_block_size ### 0.1 margins left on both sides of the board pos_y = 0.1 for i in range(each_side_number_of_props): label = (self.game_elem['location_sequence'][i].name).replace( ' ', '\n') num_tiles_spanned_by_property = self.game_elem[ 'location_sequence'][i].end_position - self.game_elem[ 'location_sequence'][i].start_position try: color_t = self.color_dict[str( self.game_elem['location_sequence'][i].color)] except: color_t = self.color_dict[self.game_elem['location_sequence'] [i].color] for j in range(num_tiles_spanned_by_property): property_button = PropertyButton(text=label, background_color=color_t, pos_hint={ "x": pos_x, "y": pos_y }, size_hint=(each_block_size, each_block_size)) self.board_id.add_widget(property_button) pos_x -= each_block_size for i in range(each_side_number_of_props, each_side_number_of_props * 2): if self.game_elem['location_sequence'][ i].name == 'St. James Place': label = 'St.James\nPlace' elif self.game_elem['location_sequence'][ i].name == 'St. Charles Place': label = 'St.Charles\nPlace' elif self.game_elem['location_sequence'][ i].name == 'New York Avenue': label = 'NewYork\nAvenue' else: label = (self.game_elem['location_sequence'][i].name).replace( ' ', '\n') num_tiles_spanned_by_property = self.game_elem[ 'location_sequence'][i].end_position - self.game_elem[ 'location_sequence'][i].start_position try: color_t = self.color_dict[str( self.game_elem['location_sequence'][i].color)] except: color_t = self.color_dict[self.game_elem['location_sequence'] [i].color] for j in range(num_tiles_spanned_by_property): property_button = PropertyButton(text=label, background_color=color_t, pos_hint={ "x": pos_x, "y": pos_y }, size_hint=(each_block_size, each_block_size)) self.board_id.add_widget(property_button) pos_y += each_block_size for i in range(each_side_number_of_props * 2, each_side_number_of_props * 3): if self.game_elem['location_sequence'][i].name == 'Go to Jail': label = 'Goto\nJail' else: label = (self.game_elem['location_sequence'][i].name).replace( ' ', '\n') num_tiles_spanned_by_property = self.game_elem[ 'location_sequence'][i].end_position - self.game_elem[ 'location_sequence'][i].start_position try: color_t = self.color_dict[str( self.game_elem['location_sequence'][i].color)] except: color_t = self.color_dict[self.game_elem['location_sequence'] [i].color] for j in range(num_tiles_spanned_by_property): property_button = PropertyButton(text=label, background_color=color_t, pos_hint={ "x": pos_x, "y": pos_y }, size_hint=(each_block_size, each_block_size)) self.board_id.add_widget(property_button) pos_x += each_block_size for i in range(each_side_number_of_props * 3, each_side_number_of_props * 4): label = (self.game_elem['location_sequence'][i].name).replace( ' ', '\n') num_tiles_spanned_by_property = self.game_elem[ 'location_sequence'][i].end_position - self.game_elem[ 'location_sequence'][i].start_position try: color_t = self.color_dict[str( self.game_elem['location_sequence'][i].color)] except: color_t = self.color_dict[self.game_elem['location_sequence'] [i].color] for j in range(num_tiles_spanned_by_property): property_button = PropertyButton(text=label, background_color=color_t, pos_hint={ "x": pos_x, "y": pos_y }, size_hint=(each_block_size, each_block_size)) self.board_id.add_widget(property_button) pos_y -= each_block_size monopoly_display_button = Button( text="MONOPOLY\n PLAY-PAUSE", background_color=[0.96, 0.96, 0.86, 1], pos_hint={ "x": 0.48, "y": 0.48 }, size_hint=(0.07, 0.07)) self.board_id.add_widget(monopoly_display_button) monopoly_display_button.bind(on_release=self.toggle_button_func) self.goo_jail_chance_with_player = " " self.goo_jail_cc_with_player = " " get_out_of_jail_chestcard_button = Button(text="Community Chest Card" + \ self.goo_jail_cc_with_player, background_color=[0.96, 0.96, 0.86, 1], pos_hint={"x": 0.3, "top": 0.7}, size_hint=(0.12, 0.10)) self.board_id.add_widget(get_out_of_jail_chestcard_button) get_out_of_jail_chancecard_button = Button(text="Chance Card" + \ self.goo_jail_chance_with_player, background_color=[0.96, 0.96, 0.86, 1], pos_hint={"x": 0.6, "top": 0.35}, size_hint=(0.12, 0.10)) self.board_id.add_widget(get_out_of_jail_chancecard_button) self.goo_jail_list = [] self.goo_jail_list.append(get_out_of_jail_chestcard_button) self.goo_jail_list.append(get_out_of_jail_chancecard_button) self.color_players_list = [[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 1], [0.95, 0.95, 0, 1]] player_details_button_pos_y = 0.8 self.player_detail_list = [] for i in range(4): player_detail_button = Button( text=" ", background_color=self.color_players_list[i], pos_hint={ "x": 0, "top": player_details_button_pos_y - i * 0.18 }, size_hint=(0.11, 0.16)) self.board_id.add_widget(player_detail_button) self.player_detail_list.append(player_detail_button) player_details_heading_button = Button( text="Player details", background_color=[0.96, 0.96, 0.86, 1], pos_hint={ "x": 0, "top": 0.87 }, size_hint=(0.11, 0.05)) self.board_id.add_widget(player_details_heading_button) die_roll_heading_button = Button( text="Dice Roll", background_color=[0.96, 0.96, 0.86, 1], pos_hint={ "x": 0.92, "top": 0.87 }, size_hint=(0.07, 0.05)) self.board_id.add_widget(die_roll_heading_button) self.dice_holder_list = [] for i in range(len(self.game_elem['die_sequence'])): die_roll_num = Button(text=" ", background_color=[0.96, 0.96, 0.86, 1], pos_hint={ "x": 0.93, "top": 0.87 - (i + 1) * 0.10 }, size_hint=(0.05, 0.06)) self.board_id.add_widget(die_roll_num) self.dice_holder_list.append(die_roll_num) def playing_the_game(self, *args): print("playing") self.start_stop_flag = True threading.Thread(target=self.simulate_game_instance).start() def toggle_button_func(self, *args): if self.start_stop_flag == False: self.start_stop_flag = True elif self.start_stop_flag == True: self.start_stop_flag = False print('PAUSING THE GAME.... CLICK MONOPOLY BUTTON TO RESUME GAME') def simulate_game_instance(self, history_log_file=None, np_seed=838885): """ Simulate a game instance. :param game_elements: The dict output by set_up_board :param np_seed: The numpy seed to use to control randomness. :return: None """ logger.debug("size of board " + str(len(self.game_elem['location_sequence']))) np.random.seed(np_seed) np.random.shuffle(self.game_elem['players']) self.game_elem['seed'] = np_seed self.game_elem['card_seed'] = np_seed self.game_elem['choice_function'] = np.random.choice num_die_rolls = 0 # game_elements['go_increment'] = 100 # we should not be modifying this here. It is only for testing purposes. # One reason to modify go_increment is if your decision agent is not aggressively trying to monopolize. Since go_increment # by default is 200 it can lead to runaway cash increases for simple agents like ours. logger.debug( 'players will play in the following order: ' + '->'.join([p.player_name for p in self.game_elem['players']])) logger.debug('Beginning play. Rolling first die...') current_player_index = 0 num_active_players = 4 winner = None while num_active_players > 1: self.disable_history() if self.start_stop_flag == True: current_player = self.game_elem['players'][ current_player_index] while current_player.status == 'lost': current_player_index += 1 current_player_index = current_player_index % len( self.game_elem['players']) current_player = self.game_elem['players'][ current_player_index] current_player.status = 'current_move' # pre-roll for current player + out-of-turn moves for everybody else, # till we get num_active_players skip turns in a row. skip_turn = 0 if current_player.make_pre_roll_moves( self.game_elem) == 2: #2 is the special skip-turn code skip_turn += 1 out_of_turn_player_index = current_player_index + 1 out_of_turn_count = 0 while skip_turn != num_active_players and out_of_turn_count <= 200: out_of_turn_count += 1 # print('checkpoint 1') out_of_turn_player = self.game_elem['players'][ out_of_turn_player_index % len(self.game_elem['players'])] if out_of_turn_player.status == 'lost': out_of_turn_player_index += 1 continue oot_code = out_of_turn_player.make_out_of_turn_moves( self.game_elem) # add to game history self.game_elem['history']['function'].append( out_of_turn_player.make_out_of_turn_moves) params = dict() params['self'] = out_of_turn_player params['current_gameboard'] = self.game_elem self.game_elem['history']['param'].append(params) self.game_elem['history']['return'].append(oot_code) if oot_code == 2: skip_turn += 1 else: skip_turn = 0 out_of_turn_player_index += 1 # now we roll the dice and get into the post_roll phase, # but only if we're not in jail. r = roll_die(self.game_elem['dies'], np.random.choice) self.dice_list = r for i in range(len(r)): self.game_elem['die_sequence'][i].append(r[i]) # add to game history self.game_elem['history']['function'].append(roll_die) params = dict() params['die_objects'] = self.game_elem['dies'] params['choice'] = np.random.choice self.game_elem['history']['param'].append(params) self.game_elem['history']['return'].append(r) num_die_rolls += 1 self.game_elem['current_die_total'] = sum(r) logger.debug('dies have come up ' + str(r)) if not current_player.currently_in_jail: check_for_go = True move_player_after_die_roll(current_player, sum(r), self.game_elem, check_for_go) # add to game history self.game_elem['history']['function'].append( move_player_after_die_roll) params = dict() params['player'] = current_player params['rel_move'] = sum(r) params['current_gameboard'] = self.game_elem params['check_for_go'] = check_for_go self.game_elem['history']['param'].append(params) self.game_elem['history']['return'].append(None) current_player.process_move_consequences(self.game_elem) # add to game history self.game_elem['history']['function'].append( current_player.process_move_consequences) params = dict() params['self'] = current_player params['current_gameboard'] = self.game_elem self.game_elem['history']['param'].append(params) self.game_elem['history']['return'].append(None) # post-roll for current player. No out-of-turn moves allowed at this point. current_player.make_post_roll_moves(self.game_elem) # add to game history self.game_elem['history']['function'].append( current_player.make_post_roll_moves) params = dict() params['self'] = current_player params['current_gameboard'] = self.game_elem self.game_elem['history']['param'].append(params) self.game_elem['history']['return'].append(None) else: current_player.currently_in_jail = False # the player is only allowed to skip one turn (i.e. this one) if current_player.current_cash < 0: code = current_player.agent.handle_negative_cash_balance( current_player, self.game_elem) # add to game history self.game_elem['history']['function'].append( current_player.agent.handle_negative_cash_balance) params = dict() params['player'] = current_player params['current_gameboard'] = self.game_elem self.game_elem['history']['param'].append(params) self.game_elem['history']['return'].append(code) if code == -1 or current_player.current_cash < 0: current_player.begin_bankruptcy_proceedings( self.game_elem) # add to game history self.game_elem['history']['function'].append( current_player.begin_bankruptcy_proceedings) params = dict() params['self'] = current_player params['current_gameboard'] = self.game_elem self.game_elem['history']['param'].append(params) self.game_elem['history']['return'].append(None) num_active_players -= 1 diagnostics.print_asset_owners(self.game_elem) diagnostics.print_player_cash_balances(self.game_elem) if num_active_players == 1: for p in self.game_elem['players']: if p.status != 'lost': winner = p p.status = 'won' else: current_player.status = 'waiting_for_move' current_player_index = (current_player_index + 1) % len( self.game_elem['players']) ''' The following line determines the speed of your game visualization and game. 0.1 is the default setting for this package. You can reduce it if you want the game to run faster or increase it to slow down the execution. ''' time.sleep(0.05) self.update_board() if diagnostics.max_cash_balance( self.game_elem ) > 300000: # this is our limit for runaway cash for testing purposes only. # We print some diagnostics and return if any player exceeds this. diagnostics.print_asset_owners(self.game_elem) diagnostics.print_player_cash_balances(self.game_elem) return logger.debug('printing final asset owners: ') diagnostics.print_asset_owners(self.game_elem) logger.debug('number of dice rolls: ' + str(num_die_rolls)) logger.debug('printing final cash balances: ') diagnostics.print_player_cash_balances(self.game_elem) if winner: logger.debug('We have a winner: ' + winner.player_name) return def disable_history(self): self.game_elem['history'] = dict() self.game_elem['history']['function'] = list() self.game_elem['history']['param'] = list() self.game_elem['history']['return'] = list() def update_board(self): self.canvas.after.clear() self.players = [] pos_x = 0.9 - self.each_tile_size + 0.01 pos_y = 0.11 self.color_players_list = [[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 1], [1, 1, 0, 1]] self.pos_x_list = [] self.pos_y_list = [] for i in range(len(self.dice_holder_list)): self.dice_holder_list[i].text = str(self.dice_list[i]) for i in range(4): text_on_button = " "+ self.game_elem['players'][i].player_name + \ "\n Current Cash = " + str(self.game_elem['players'][i].current_cash) + \ "\n # of houses = " + str(self.game_elem['players'][i].num_total_houses) + \ "\n # of hotels = " + str(self.game_elem['players'][i].num_total_hotels) if (self.game_elem['players'] [i].has_get_out_of_jail_community_chest_card == True): text_on_button = text_on_button + "\nGOO_Jail community card" if (self.game_elem['players'][i].has_get_out_of_jail_chance_card == True): text_on_button = text_on_button + "\nGOO_Jail chance card" self.player_detail_list[i].text = text_on_button self.obj_instr_player = InstructionGroup() self.obj_instr_player.add( Color(self.color_players_list[i][0], self.color_players_list[i][1], self.color_players_list[i][2], self.color_players_list[i][3])) try: pos_x_n = int(self.game_elem['players'][i].current_position / 10) pos_y_n = int(self.game_elem['players'][i].current_position % 10) except: pos_x_n = 0 pos_y_n = 0 if (pos_x_n == 0): pos_x = (0.9 - self.each_tile_size + 0.01) - (pos_y_n * self.each_tile_size) pos_y = 0.11 elif (pos_x_n == 2): pos_x = (0.9 - self.each_tile_size + 0.01) - ( self.num_tiles * (self.each_tile_size)) + (pos_y_n * self.each_tile_size) pos_y = 0.11 + (self.num_tiles * self.each_tile_size) elif (pos_x_n == 1): pos_x = (0.9 - self.each_tile_size + 0.01) - (self.num_tiles * (self.each_tile_size)) pos_y = 0.11 + (pos_y_n * self.each_tile_size) elif (pos_x_n == 3): pos_x = (0.9 - self.each_tile_size + 0.01) pos_y = 0.11 + (self.num_tiles * self.each_tile_size) - ( pos_y_n * self.each_tile_size) self.obj_instr_player.add( Ellipse(pos=((pos_x + i * 0.01) * Window.width, pos_y * Window.height), size=(10, 10))) self.players.append(self.obj_instr_player) self.pos_x_list.append(pos_x) self.pos_y_list.append(pos_y) self.canvas.after.add(self.obj_instr_player) count_house = 0 count_hotel = 0 if (self.game_elem['players'][i].assets) != None: self.player_props = [] self.player_props_x = [] self.player_props_y = [] for k in range(len(list(self.game_elem['players'][i].assets))): prop_name = list( self.game_elem['players'][i].assets)[k].name pos_prop = self.game_elem['location_objects'][ prop_name].start_position self.obj_instr = InstructionGroup() self.obj_instr.add( Color(self.color_players_list[i][0], self.color_players_list[i][1], self.color_players_list[i][2], self.color_players_list[i][3])) each_side_num_tiles = self.num_tiles side = 0 if pos_prop >= 0 and pos_prop < each_side_num_tiles: side = 0 elif pos_prop >= each_side_num_tiles and pos_prop < 2 * each_side_num_tiles: side = 1 elif pos_prop >= 2 * each_side_num_tiles and pos_prop < 3 * each_side_num_tiles: side = 2 else: side = 3 #prop_x = int(pos_prop / 10) prop_y = pos_prop - side * each_side_num_tiles pos_x_prop = 0 pos_y_prop = 0 if (side == 0): pos_x_prop = 0.9 - self.each_tile_size + 0.01 - ( prop_y * self.each_tile_size) pos_y_prop = 0.14 elif (side == 2): pos_x_prop = 0.9 - self.each_tile_size + 0.01 - ( self.num_tiles * (self.each_tile_size)) + (prop_y * self.each_tile_size) pos_y_prop = 0.14 + (self.num_tiles * self.each_tile_size) elif (side == 1): pos_x_prop = 0.9 - self.each_tile_size + 0.01 - ( self.num_tiles * (self.each_tile_size)) pos_y_prop = 0.14 + (prop_y * self.each_tile_size) elif (side == 3): pos_x_prop = 0.9 - self.each_tile_size + 0.01 pos_y_prop = 0.14 + (self.num_tiles * self.each_tile_size) - ( prop_y * self.each_tile_size) self.obj_instr.add( Rectangle(pos=(pos_x_prop * Window.width, pos_y_prop * Window.height), size=(12, 12))) if list(self.game_elem['players'] [i].assets)[k].loc_class == 'real_estate': if list(self.game_elem['players'] [i].assets)[k].num_houses > 0: for m in range( list(self.game_elem['players'][i].assets) [k].num_houses): self.obj_instr.add(Color(1, 1, 1, 1)) self.obj_instr.add( Ellipse( pos=((pos_x_prop + (m + 1) * 0.01) * Window.width, pos_y_prop * Window.height), size=(12, 12))) count_house += list(self.game_elem['players'] [i].assets)[k].num_houses if list(self.game_elem['players'] [i].assets)[k].num_hotels > 0: for m in range( list(self.game_elem['players'][i].assets) [k].num_hotels): self.obj_instr.add(Color(1, 0.1, 0.5, 1)) self.obj_instr.add( Ellipse( pos=((pos_x_prop + (m + 1) * 0.01) * Window.width, pos_y_prop * Window.height), size=(12, 12))) count_hotel += list(self.game_elem['players'] [i].assets)[k].num_hotels self.player_props.append(self.obj_instr) self.player_props_x.append(pos_x_prop) self.player_props_y.append(pos_y_prop) self.canvas.after.add(self.obj_instr) self.obj_instr_directory.append(self.obj_instr) self.bind(pos=self.update_rect, size=self.update_rect) def update_rect(self, *args): self.players[0].pos = (self.pos_x_list[0] * Window.width, self.pos_y_list[0] * Window.height) self.players[1].pos = ((self.pos_x_list[1] + 0.01) * Window.width, self.pos_y_list[0] * Window.height) self.players[2].pos = ((self.pos_x_list[2] + 0.02) * Window.width, self.pos_y_list[1] * Window.height) self.players[3].pos = ((self.pos_x_list[3] + 0.03) * Window.width, self.pos_y_list[3] * Window.height) for i in range(len(self.player_props)): self.player_props[i].children[2].pos = (self.player_props_x[i] * Window.width, self.player_props_y[i] * Window.height) def popup_window(self, property_name): show = P() property_name_mod = property_name.replace("\n", " ") str_prop = "Name of the property: " + property_name_mod if self.game_elem['location_objects'][str( property_name_mod)].loc_class == 'real_estate': str_prop = str_prop + "\nCost: $" + str(self.game_elem['location_objects'][str(property_name_mod)].price) + \ "\nRent: $" + str(self.game_elem['location_objects'][str(property_name_mod)].rent) + \ "\nRent with 1 house: $" + str( self.game_elem['location_objects'][str(property_name_mod)].rent_1_house) + \ "\nRent with 2 house: $" + str( self.game_elem['location_objects'][str(property_name_mod)].rent_2_houses) + \ "\nRent with 3 house: $" + str( self.game_elem['location_objects'][str(property_name_mod)].rent_3_houses) + \ "\nRent with 4 house: $" + str( self.game_elem['location_objects'][str(property_name_mod)].rent_4_houses) + \ "\nRent with a hotel: $" + str( self.game_elem['location_objects'][str(property_name_mod)].rent_hotel) + \ "\nMortgage: $" + str(self.game_elem['location_objects'][str(property_name_mod)].mortgage) + \ "\nHouse cost: $" + str( self.game_elem['location_objects'][str(property_name_mod)].price_per_house) elif self.game_elem['location_objects'][str( property_name_mod)].loc_class == 'tax': str_prop = str_prop + "Pay as TAX $" + str( self.game_elem['location_objects'][str( property_name_mod)].amount_due) elif self.game_elem['location_objects'][str( property_name_mod)].loc_class == 'railroad': str_prop = str_prop + "\nCost: $" + str(self.game_elem['location_objects'][str(property_name_mod)].price) + \ "\nMortgage: $" + str(self.game_elem['location_objects'][str(property_name_mod)].mortgage) elif self.game_elem['location_objects'][str( property_name_mod)].loc_class == 'utility': str_prop = str_prop + "\nCost: $" + str(self.game_elem['location_objects'][str(property_name_mod)].price) + \ "\nMortgage: $" + str(self.game_elem['location_objects'][str(property_name_mod)].mortgage) + \ "\n\nIf one UTILITY is owned, rent is 4 times\n amount shown on dice." + \ "\nIf both utilities are owned, rent is 10 times\n amount shown on dice." elif self.game_elem['location_objects'][str( property_name_mod)].loc_class == 'action': str_prop = "Pick a " + property_name_mod + " Card" elif self.game_elem['location_objects'][str( property_name_mod)].loc_class == 'do_nothing': pass show.ids.popup_id.text = str_prop popup_window = Popup(title=property_name_mod, content=show, size_hint=(None, None), size=(400, 400)) popup_window.open()
class TextureStack(Widget): """Several textures superimposed on one another, and possibly offset by some amount. In 2D games where characters can wear different clothes or hold different equipment, their graphics are often composed of several graphics layered on one another. This widget simplifies the management of such compositions. """ texs = ListProperty() """Texture objects""" offxs = ListProperty() """x-offsets. The texture at the same index will be moved to the right by the number of pixels in this list. """ offys = ListProperty() """y-offsets. The texture at the same index will be moved upward by the number of pixels in this list. """ group = ObjectProperty() """My ``InstructionGroup``, suitable for addition to whatever ``canvas``.""" def _get_offsets(self): return zip(self.offxs, self.offys) def _set_offsets(self, offs): offxs = [] offys = [] for x, y in offs: offxs.append(x) offys.append(y) self.offxs, self.offys = offxs, offys offsets = AliasProperty( _get_offsets, _set_offsets, bind=('offxs', 'offys') ) """List of (x, y) tuples by which to offset the corresponding texture.""" _texture_rectangles = DictProperty({}) """Private. Rectangle instructions for each of the textures, keyed by the texture. """ def __init__(self, **kwargs): """Make triggers and bind.""" kwargs['size_hint'] = (None, None) self.translate = Translate(0, 0) self.group = InstructionGroup() super().__init__(**kwargs) self.bind(offxs=self.on_pos, offys=self.on_pos) def on_texs(self, *args): """Make rectangles for each of the textures and add them to the canvas.""" if not self.canvas or not self.texs: Clock.schedule_once(self.on_texs, 0) return texlen = len(self.texs) # Ensure each property is the same length as my texs, padding # with 0 as needed for prop in ('offxs', 'offys'): proplen = len(getattr(self, prop)) if proplen > texlen: setattr(self, prop, getattr(self, prop)[:proplen-texlen]) if texlen > proplen: propval = list(getattr(self, prop)) propval += [0] * (texlen - proplen) setattr(self, prop, propval) self.group.clear() self._texture_rectangles = {} w = h = 0 (x, y) = self.pos self.translate.x = x self.translate.y = y self.group.add(PushMatrix()) self.group.add(self.translate) for tex, offx, offy in zip(self.texs, self.offxs, self.offys): rect = Rectangle( pos=(offx, offy), size=tex.size, texture=tex ) self._texture_rectangles[tex] = rect self.group.add(rect) tw = tex.width + offx th = tex.height + offy if tw > w: w = tw if th > h: h = th self.size = (w, h) self.group.add(PopMatrix()) self.canvas.add(self.group) def on_pos(self, *args): """Translate all the rectangles within this widget to reflect the widget's position. """ (x, y) = self.pos self.translate.x = x self.translate.y = y def clear(self): """Clear my rectangles and ``texs``.""" self.group.clear() self._texture_rectangles = {} self.texs = [] self.size = [1, 1] def insert(self, i, tex): """Insert the texture into my ``texs``, waiting for the creation of the canvas if necessary. """ if not self.canvas: Clock.schedule_once( lambda dt: self.insert(i, tex), 0) return self.texs.insert(i, tex) def append(self, tex): """``self.insert(len(self.texs), tex)``""" self.insert(len(self.texs), tex) def __delitem__(self, i): """Remove a texture and its rectangle""" tex = self.texs[i] try: rect = self._texture_rectangles[tex] self.canvas.remove(rect) del self._texture_rectangles[tex] except KeyError: pass del self.texs[i] def __setitem__(self, i, v): """First delete at ``i``, then insert there""" if len(self.texs) > 0: self._no_upd_texs = True self.__delitem__(i) self._no_upd_texs = False self.insert(i, v) def pop(self, i=-1): """Delete the texture at ``i``, and return it.""" return self.texs.pop(i)
def _gl_setup(self): self.drip_texture = CoreImage("resources/images/drop.png", mipmap=True).texture self.drips_instruction = InstructionGroup() self.model_instruction = InstructionGroup() print(self.canvas.children)
class Display(Widget): axis_resolution = NumericProperty(10) axis_max_value = NumericProperty(10) axis_x_marker_size = (4, 8) axis_y_marker_size = (8, 4) last_inside = BooleanProperty(False) objects = ListProperty([]) robots = ListProperty([]) tasks = ListProperty([]) mu_tasks = ListProperty([]) selected_object = ObjectProperty(None) is_object_selected = BooleanProperty(False) dummy_object = DisplayObject('Dummy',name='Dummy',local_pos=(math.inf, math.inf), \ z_pos = -1,\ default_size=(0, 0)) def __init__(self, **kwargs): super(Display, self).__init__(**kwargs) self.rect_x_ig = InstructionGroup() self.rect_x_ig.add(Color(1,1,1)) self.rect_x = Rectangle(size=(self.width,2), pos=(self.center_x - self.width/2, self.center_y-1)) self.rect_x_ig.add(self.rect_x) self.canvas.add(self.rect_x_ig) self.rect_y_ig = InstructionGroup() self.rect_y_ig.add(Color(1,1,1)) self.rect_y = Rectangle(size=(2,self.height), pos=(self.center_x - 1, self.center_y-self.height/2)) self.rect_y_ig.add(self.rect_y) self.canvas.add(self.rect_y_ig) values = range(2*self.axis_resolution+1) values_x = list(map(lambda x: self._calculate_axis_value(x, self.axis_resolution, self.width), values)) values_y = list(map(lambda x: self._calculate_axis_value(x, self.axis_resolution, self.height), values)) self.rects_x = [] self.rects_y = [] self.rects_x_ig = [] self.rects_y_ig = [] for value_x in values_x: self.rects_x += [Rectangle(size=self.axis_x_marker_size, pos=self._calculate_axis_x_marker_pos(value_x, self))] self.rects_x_ig += [self.rects_x[-1]] self.canvas.add(self.rects_x_ig[-1]) for value_y in values_y: self.rects_y += [Rectangle(size=self.axis_y_marker_size, pos=self._calculate_axis_y_marker_pos(value_y, self))] self.rects_y_ig += [self.rects_y[-1]] self.canvas.add(self.rects_y_ig[-1]) self.bind(size=self._update_rect, pos=self._update_rect, axis_resolution=self._update_rect, axis_max_value=self._update_rect) Window.bind(mouse_pos=self.on_mouse_pos) self.coordinate_label = Label(text='0,0') def add_robot(self, new_robot): name_exists = any([new_robot.name == robot.name for robot in self.objects if robot.obj_type is 'Robot']) if not name_exists: self.robots.append(new_robot) robot_representation = RobotRepresentation(new_robot, \ name=new_robot.name, \ local_pos=new_robot.position, \ z_pos = len(self.objects),\ default_size=(RobotRepresentation.default_width, RobotRepresentation.default_height)) self.add_display_object(robot_representation) def add_task(self, new_task): name_exists = any([new_task.name == task.name for task in self.objects if task.obj_type is 'Task']) if not name_exists: self.tasks.append(new_task) for mu_task in new_task.mu_tasks: self.mu_tasks.append(mu_task) mu_task_representation = MuTaskRepresentation(name=new_task.name+','+mu_task.name, task=new_task, mu_task=mu_task, local_pos=mu_task.position, z_pos = len(self.objects), default_size=(MuTaskRepresentation.default_width, MuTaskRepresentation.default_height)) self.add_display_object(mu_task_representation) def clear_display(self): for obj in self.objects: self.remove_widget(obj) self.objects = [] self.robots.clear() self.mu_tasks.clear() self.tasks.clear() def add_display_object(self, new_object): self.objects.append(new_object) self.add_widget(new_object) new_object.pos = new_object.calculate_canvas_position(self.center, self.size, self.axis_max_value) @staticmethod def _calculate_axis_value(original_value, axis_resolution, axis_total_size): return ((original_value-axis_resolution)/axis_resolution)*(axis_total_size/2) def _calculate_axis_x_marker_pos(self, marker_value, reference): return reference.center_x+marker_value-(self.axis_x_marker_size[0])/2, reference.center_y-(self.axis_x_marker_size[1])/2 def _calculate_axis_y_marker_pos(self, marker_value, reference): return reference.center_x-(self.axis_y_marker_size[0])/2, reference.center_y+marker_value-(self.axis_y_marker_size[1])/2 def _update_rect(self, instance, value): values = range(2*self.axis_resolution+1) values_x = list(map(lambda x: self._calculate_axis_value(x, self.axis_resolution, self.width), values)) values_y = list(map(lambda x: self._calculate_axis_value(x, self.axis_resolution, self.height), values)) self.rect_x.size = instance.width, 2 self.rect_x.pos = instance.center_x - instance.width/2, instance.center_y-1 self.rect_y.size = 2, self.height self.rect_y.pos = self.center_x - 1, self.center_y-self.height/2 for value_x, rect in zip(values_x, self.rects_x): rect.pos = self._calculate_axis_x_marker_pos(value_x, instance) rect.size = self.axis_x_marker_size for value_y,rect in zip(values_y, self.rects_y): rect.pos = self._calculate_axis_y_marker_pos(value_y, instance) rect.size = self.axis_y_marker_size if len(self.rects_x) > len(values_x): for i in range(len(self.rects_x), len(values_x), -1): self.canvas.remove(self.rects_x_ig[i-1]) self.rects_x.pop() self.rects_x_ig.pop() elif len(self.rects_x) < len(values_x): for i in range(len(self.rects_x), len(values_x)): self.rects_x += [Rectangle(size=self.axis_x_marker_size, pos=self._calculate_axis_x_marker_pos(values_x[i], self))] self.rects_x_ig += [self.rects_x[-1]] self.canvas.add(self.rects_x_ig[-1]) if len(self.rects_y) > len(values_y): for i in range(len(self.rects_y), len(values_y), -1): self.canvas.remove(self.rects_y_ig[i-1]) self.rects_y.pop() self.rects_y_ig.pop() elif len(self.rects_y) < len(values_y): for i in range(len(self.rects_y), len(values_y)): self.rects_y += [Rectangle(size=self.axis_y_marker_size, pos=self._calculate_axis_y_marker_pos(values_y[i], self))] self.rects_y_ig += [self.rects_y[-1]] self.canvas.add(self.rects_y_ig[-1]) for obj in self.objects: obj.pos = obj.calculate_canvas_position(instance.center, instance.size, self.axis_max_value) def on_touch_down(self, value): pos = value.pos if not self.collide_point(*self.to_widget(*pos)): return candidates = [ candidate for candidate in self.objects if candidate.collide_point(*self.to_widget(*pos))] top_candidate = max(candidates, key=lambda x: x.z_pos, default=None) if top_candidate is not None: # if not self.is_object_selected or (self.is_object_selected and not top_candidate.collide_widget(self.selected_object)): if not self.is_object_selected or (self.is_object_selected and self.selected_object not in candidates): self.selected_object = top_candidate self.is_object_selected = True else: if self.is_object_selected: self.is_object_selected = False self.selected_object = self.dummy_object def on_touch_move(self, value): pos = value.pos if not self.collide_point(*self.to_widget(*pos)): return if self.is_object_selected: self.selected_object.move_canvas(value.pos) def on_object_menu_selected(self, instance, value): if self.is_object_selected: if self.selected_object == value: return else: options = [ obj for obj in self.objects if obj == value] if len(options) == 1: self.selected_object = options[0] else: self.selected_object = self.dummy_object self.is_object_selected = False else: options = [ obj for obj in self.objects if obj == value] if len(options) == 1: self.selected_object = options[0] self.is_object_selected = True else: self.selected_object = self.dummy_object self.is_object_selected = False def on_mouse_pos(self, *args): if not self.get_root_window(): return pos = args[1] inside = self.collide_point(*self.to_widget(*pos)) if inside: self.coordinate_label.pos = pos local_pos = self._calculate_axis_x_marker_pos(0, self) local_pos = round((pos[0] - self.center_x)*(self.axis_max_value)/(self.width/2),2), round((pos[1] - self.center_y)*(self.axis_max_value)/(self.height/2), 2) self.coordinate_label.text = str(local_pos) self.coordinate_label.size = self.coordinate_label.texture_size if self.last_inside != inside: if inside: self.add_widget(self.coordinate_label) else: self.remove_widget(self.coordinate_label) self.last_inside = inside
class PrinterAnimation(RelativeLayout): padding = NumericProperty(40) printer_actual_dimensions = ListProperty([10, 10, 80]) printer_current_actual_height = NumericProperty(0.0) print_area_height = NumericProperty(1) print_area_width = NumericProperty(1) print_area_left = NumericProperty(0) print_area_bottom = NumericProperty(40) container_padding = NumericProperty(0) container_left = NumericProperty(0) container_width = NumericProperty(0) container_bottom = NumericProperty(0) container_height = NumericProperty(0) laser_size = ListProperty([40, 40]) resin_height = NumericProperty(20) water_height = NumericProperty(20) scale = NumericProperty(1.0) resin_color = ListProperty([0.0, 0.8, 0.0, 0.6]) water_color = ListProperty([0.2, 0.2, 1.0, 0.6]) container_color = ListProperty([1.0, 1.0, 1.0, 1.0]) laser_color_edge2 = ListProperty([0.0, 0.0, 0.5, 1.0]) laser_color_edge = ListProperty([0.0, 0.0, 1.0, 1.0]) laser_color = ListProperty([0.7, 1.0, 1.0, 1.0]) drip_history = ListProperty() laser_points = ListProperty() middle_x = NumericProperty(52) laser_pos = NumericProperty(60) laser_speed = NumericProperty(1) refresh_rate = NumericProperty(1.0) def __init__(self, **kwargs): super(PrinterAnimation, self).__init__(**kwargs) self.drip_time_range = 5 self.waiting_for_drips = True self.refresh_rate = App.get_running_app().refresh_rate self._gl_setup() self.axis_history = [] self.drips = 0 self.line_x = [] self.line_y = [] self.last_height = 0.0 self.min_height = 0.0 self.last_x_min = 0.0 self.last_x_max = 1.0 self.is_on_canvas = False def on_printer_actual_dimensions(self, instance, value): self.min_height = self.printer_actual_dimensions[2] / 400.0 self.on_size(None) def _gl_setup(self): self.drip_texture = CoreImage("resources/images/drop.png", mipmap=True).texture self.drips_instruction = InstructionGroup() self.model_instruction = InstructionGroup() print(self.canvas.children) # self.canvas.add(self.drips_instruction) # self.canvas.add(self.model_instruction) def on_size(self, *largs): bounds_y = (self.height * 0.7) - self.resin_height bounds_x = self.width - (self.padding * 2) printer_x = self.printer_actual_dimensions[0] printer_y = self.printer_actual_dimensions[2] self.laser_pos = self.width / 2 self.scale = min(bounds_y / printer_y, bounds_x / printer_x) Logger.info("Scale: {}".format(self.scale)) self.print_area_width = printer_x * self.scale self.print_area_height = printer_y * self.scale def redraw(self, key): self._draw_drips() self._draw_laser() self._draw_model() if not self.is_on_canvas: self.canvas.insert(4, self.drips_instruction) self.canvas.insert(4, self.model_instruction) self.is_on_canvas = True Clock.unschedule(self.redraw) Clock.schedule_once(self.redraw, self.refresh_rate) def reset(self): self.axis_history = [] self.line_x = [] self.line_y = [] self.last_height = 0 self.min_height = 0.0 self.laser_points = [] self.drip_history = [] self.waiting_for_drips = True self.printer_current_actual_height = 0 self.redraw('') Clock.unschedule(self.redraw) def animation_start(self, *args): Clock.unschedule(self.redraw) self.axis_history = [] self.line_x = [] self.line_y = [] self.last_height = 0 self.min_height = 0.0 self.laser_points = [] self.drip_history = [] Clock.schedule_once(self.redraw, self.refresh_rate) def animation_stop(self): Clock.unschedule(self.redraw) self.axis_history = [] self.line_x = [] self.line_y = [] self.last_height = 0 self.min_height = 0.0 self.laser_points = [] self.drip_history = [] def _draw_drips(self): self.drips_instruction.clear() self.drips_instruction.add(Color(1, 1, 1, 1)) top = time.time() bottom = top - self.drip_time_range drips_in_history = len(self.drip_history) for (index, drip_time) in zip(range(drips_in_history, 0, -1), self.drip_history): if drip_time > bottom: time_ago = top - drip_time y_pos_percent = (self.drip_time_range - time_ago) / self.drip_time_range drip_pos_y = (self.height * y_pos_percent) + self.padding xoff = 10 + math.sin((len(self.drip_history) - index) / (2 * math.pi)) * 20 self.drips_instruction.add(Rectangle(size=[12, 16], pos=[self.print_area_left + xoff, drip_pos_y], texture=self.drip_texture)) def _draw_laser(self): if self.waiting_for_drips: self.laser_points = [] else: x_min = self.print_area_left + (self.last_x_min * self.print_area_width) x_max = self.print_area_left + (self.last_x_max * self.print_area_width) if (self.laser_pos >= x_max): self.laser_pos = x_max self.laser_speed = abs(self.laser_speed) * -1 if (self.laser_pos <= x_min): self.laser_pos = x_min self.laser_speed = abs(self.laser_speed) self.laser_pos += self.laser_speed laser_x = self.laser_pos self.laser_points = [self.middle_x, self.height - self.padding, laser_x, self.water_height + self.print_area_bottom + self.resin_height] def _draw_model(self): if self.axis_history: model_height = self.axis_history[-1][2] if model_height > (self.last_height + self.min_height) or not self.line_x: x1, y1, x2, y2 = self._get_pixels(self.axis_history[-1]) self.last_x_min = x1 self.last_x_max = x2 self.line_x.insert(0, x1) self.line_x.append(x2) self.line_y.insert(0, y1) self.line_y.append(y2) self.last_height = model_height points = [] for idx in range(0, len(self.line_x)): x = int(self.print_area_left + (self.line_x[idx] * self.print_area_width)) y = int(self.print_area_bottom + self.resin_height + (self.line_y[idx] * self.print_area_height)) - 2 points.append(x) points.append(y) self.model_instruction.clear() self.model_instruction.add(Color(rgba=(1.0, 0.0, 0.0, 1.0))) self.model_instruction.add(Line(points=points, width=2, close=True)) else: self.model_instruction.clear() def _get_pixels(self, data): pixel_height = data[2] / self.printer_actual_dimensions[2] pixel_pos_min = (data[0][0] + (self.printer_actual_dimensions[1] / 2.0)) / self.printer_actual_dimensions[1] pixel_pos_max = (data[0][1] + (self.printer_actual_dimensions[1] / 2.0)) / self.printer_actual_dimensions[1] return [pixel_pos_min, pixel_height, pixel_pos_max, pixel_height]
def __init__(self, width, height, canvas, ac, eye_pos, eye_angle): super(DisplayController, self).__init__() self.width = width self.height = height self.canvas = canvas self.eye_pos = eye_pos self.eye_angle = eye_angle self.ac = ac self.canvas.shader.source = resource_find('data/simple.glsl') self.all_notes = [] self.future_notes = {} self.past_notes = {} self.ticks = [] # self.planes = range(0, 10 * config['PLANE_SPACING'], config['PLANE_SPACING']) self.planes = [] self.lines = [] self.past_displays = InstructionGroup() self.future_displays = InstructionGroup() self.plane_displays = InstructionGroup() self.line_displays = InstructionGroup() self.fixed_x = Translate(0, 0, 0) self.fixed_y = Translate(0, 0, 0) self.fixed_z = Translate(0, 0, 0) self.fixed_azi = Rotate(origin=(0, 0, 0), axis=(0, 1, 0)) self.fixed_ele = Rotate(origin=(0, 0, 0), axis=(1, 0, 0)) self.alpha_callback = Callback(self.alpha_sample_callback) self.disable_alpha_callback = Callback(self.disable_alpha_sample_callback) self.alpha_instruction = InstructionGroup() self.alpha_disable_instruction = InstructionGroup() self.alpha_sample_enable = False self.canvas.add(Callback(self.setup_gl_context)) self.canvas.add(self.alpha_instruction) self.canvas.add(PushMatrix()) self.canvas.add(UpdateNormalMatrix()) self.canvas.add(PushMatrix()) self.canvas.add(self.fixed_z) self.canvas.add(self.line_displays) self.canvas.add(PopMatrix()) self.canvas.add(PushMatrix()) self.canvas.add(self.past_displays) self.canvas.add(self.future_displays) self.canvas.add(PopMatrix()) self.canvas.add(PushMatrix()) # self.canvas.add(self.fixed_x) # self.canvas.add(self.fixed_y) self.canvas.add(self.plane_displays) self.canvas.add(PopMatrix()) # self.canvas.add(PushMatrix()) # self.canvas.add(self.fixed_x) # self.canvas.add(self.fixed_y) # self.canvas.add(self.fixed_z) # self.canvas.add(Plane(-config['SELF_PLANE_DISTANCE'], size=0.1, color=(0x20/255., 0xD8/255., 0xE9/255.), tr=0.2)) # self.canvas.add(PopMatrix()) self.canvas.add(PopMatrix()) self.canvas.add(self.alpha_disable_instruction) self.canvas.add(Callback(self.reset_gl_context)) self.draw_planes()
class LinePlot(Widget): viewport = ListProperty(None) line_width = NumericProperty(5.) line_color = ListProperty([0,.8,1]) border_width = NumericProperty(5) border_color = ListProperty([.3,.3,.3]) flattened_points = ListProperty(None) tick_distance_x = NumericProperty(None) tick_distance_y = NumericProperty(None) tick_color = ListProperty([.3,.3,.3]) select_circle = ListProperty([0,0,0]) def __init__(self, points, **kwargs): # calculate some basic information about the data self.points = points self.points_x = zip(*points)[0] self.points_y = zip(*points)[1] # if we could figure out how to draw an arbitrary number of ticks in kv, this would be cleaner self.ticks = InstructionGroup() self.tick_translate = Translate() super(LinePlot, self).__init__(**kwargs) self.canvas.insert(0, self.ticks) self.viewport = (min(self.points_x), min(self.points_y), max(self.points_x), max(self.points_y)) # recalculate viewport when size changes def on_size(self, instance, value): self.on_viewport(None, self.viewport) def on_pos(self, instance, value): self.tick_translate.xy = self.x, self.y def on_viewport(self, instance, value): if value is None or len(value) != 4: return print value self.vp_width_convert = float(self.width)/(value[2] - value[0]) self.vp_height_convert = float(self.height)/(value[3] - value[1]) # calculate the actual display points based on the viewport and self.size self.display_points = [self.to_display_point(*p) for p in self.points if value[0] <= p[0] <= value[2] and value[1] <= p[1] <= value[3]] self.flattened_points = [item for sublist in self.display_points for item in sublist] self.draw_ticks() # it would be real nice if we could figure out how to do this in kv def draw_ticks(self): self.ticks.clear() self.ticks.add(Color(*self.tick_color, mode='rgb')) self.ticks.add(PushMatrix()) self.ticks.add(self.tick_translate) if self.tick_distance_x is not None: first_x_tick = self.tick_distance_x*(int(self.viewport[0]/self.tick_distance_x) + 1) for x in drange(first_x_tick, self.viewport[2], self.tick_distance_x): start = self.to_display_point(x, self.viewport[1]) stop = self.to_display_point(x, self.viewport[3]) self.ticks.add(Line(points=[start[0], start[1], stop[0], stop[1]])) if self.tick_distance_y is not None: first_y_tick = self.tick_distance_y*(int(self.viewport[1]/self.tick_distance_y) + 1) for y in drange(first_y_tick, self.viewport[3], self.tick_distance_y): start = self.to_display_point(self.viewport[0], y) stop = self.to_display_point(self.viewport[2], y) self.ticks.add(Line(points=[start[0], start[1], stop[0], stop[1]])) self.ticks.add(PopMatrix()) def to_display_point(self, x, y): return (self.vp_width_convert*(x-self.viewport[0]), self.vp_height_convert*(y-self.viewport[1])) def select_point(self, x, y): # get point from self.displaypoints that is closest to x distances = [abs((x - self.x) - d[0]) for d in self.display_points] idx = min(xrange(len(distances)),key=distances.__getitem__) self.select_circle = [self.display_points[idx][0], self.display_points[idx][1], 20] return self.points[idx] def to_xy(self, x, y): xt = (x - self.x)/self.vp_width_convert+self.viewport[0] yt = (y - self.y)/self.vp_height_convert+self.viewport[1] return (xt, yt)
def drawCrossLine(self, aIndex): """ 繪製十字線 """ dataNum = len(self.dataDict) if dataNum == 0: return if aIndex >= self.dispMax: index = self.dispMax - 1 elif aIndex >= self.dispNum: index = self.dispNum - 1 elif aIndex < 0: index = 0 else: index = aIndex self.crossLineIndex = index if self.infoFunc == None: self._showInfo(index) else: aKey = self.keyList[self.scopeIdx[0] + index] aValue = self.dataDict.get(aKey) self.infoFunc({"TechType":self.techType, "TD":aKey, "Value":aValue}) if self.isDrawCrossLine == False: return groupStr = self.instGroup + "cross_line" self.canvas.remove_group(groupStr) color = Color() color.rgba = self.CROSS_LINE_COLOR instg = InstructionGroup(group=groupStr) instg.add(color) x1 = self.chartPos[0] + (index + 1) * (self.tickWide + self.tickGap) - self.backGap y1 = self.chartPos[1] x2 = x1 y2 = self.chartPos[1] + self.chartSize[1] instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg) aKey = self.keyList[self.scopeIdx[0] + index] aValue = self.dataDict.get(aKey) instg = InstructionGroup(group=groupStr) instg.add(color) x1 = self.chartPos[0] y1 = self.chartPos[1] + self.baseYPos + aValue * self.yscale x2 = self.chartPos[0] + self.chartSize[0] y2 = y1 instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg)
def drawCordInfo(self): # 100-Start: 標示y軸資訊 initStepUp = 1 if self.maxNum < 8: initStepUp = 1 elif self.maxNum < 10: initStepUp = 2 else: initStepUp = int(self.maxNum / 5) x0 = self.pos[0] + ((self.width - self.shift_left - self.shift_right) / 2) + self.shift_left - 30 y0 = self.pos[1] + self.height - self.shift_top + 5 alabel = SCordLabel(pos=(x0,y0),size_hint=(None,None)) alabel.width = 60 alabel.height = 20 alabel.text = "(X軸:獲利率,Y軸:交易次數)" alabel.color = self.CORD_INFO_COLOR self.add_widget(alabel) frameColor = Color() frameColor.rgba = self.FRAME_COLOR stepUp = initStepUp while(stepUp <= self.maxNum): instg = InstructionGroup(group="frame") instg.add(frameColor) x1 = self.center_xpos - 5 y1 = int(self.pos[1] + self.shift_bottom + stepUp * self.yscale) x2 = self.center_xpos y2 = int(self.pos[1] + self.shift_bottom + stepUp * self.yscale) instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg) x0 = self.center_xpos - self.ycordWidth y0 = int(self.pos[1] + self.shift_bottom + stepUp * self.yscale) - 10 alabel = SCordLabel(pos=(x0,y0),size_hint=(None,None)) alabel.width = 36 alabel.height = 20 alabel.text = str(stepUp) alabel.color = self.CORD_INFO_COLOR self.add_widget(alabel) stepUp += initStepUp # 100-End. # 200-Start: 標示x軸資訊 center_pos = int(self.pillarPoint / 2) remainder = None for i in range(self.min_tickNum, self.max_tickNum + 1): remainder = i % 10 if remainder != 0 and i != -1 and i != 0 and i != 1 and i != self.min_tickNum and i != self.max_tickNum: continue index = i - self.min_tickNum if i >= 0: tmp = self.max_tickNum - i if tmp <= 8 and i != self.max_tickNum: continue if i == 0: shift_xpos = self.ycordWidth else: shift_xpos = self.ycordWidth * 2 else: if index <= 8 and i != self.min_tickNum: continue shift_xpos = 0 instg = InstructionGroup(group="frame") instg.add(frameColor) x1 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + center_pos + shift_xpos) y1 = int(self.pos[1] + self.shift_bottom) x2 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + center_pos + shift_xpos) y2 = int(self.pos[1] + self.shift_bottom - 5) instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg) x0 = int(self.pos[0] + self.shift_left + index * self.pillarSumPoint + center_pos + shift_xpos - 18) y0 = int(self.pos[1] + self.shift_bottom) - 25 alabel = SCordLabel(pos=(x0,y0),size_hint=(None,None)) alabel.width = 36 alabel.height = 20 if i == self.min_tickNum: alabel.text = "<=" + str(i) + "%" elif i == self.max_tickNum: alabel.text = ">=" + str(i) + "%" else: alabel.text = str(i) + "%" alabel.color = self.CORD_INFO_COLOR self.add_widget(alabel)
def _drawLine(self, aDict, dispIdx, isLastFlag): """ """ groupStr = self.instGroup if isLastFlag == True: groupStr += "_lastData" else: groupStr += "_curvData" instg = InstructionGroup(group=groupStr) color = Color() color.rgba = self.KLINE_COLOR instg.add(color) #(self.tickWide + self.tickGap)代表顯示一筆資料,在x軸方向所需的總點數 x1 = self.chartPos[0] + (dispIdx + 1) * (self.tickWide + self.tickGap) - self.backGap y1 = self.chartPos[1] + (aDict.get("HP") - self.lowestValue) * self.yscale x2 = x1 y2 = self.chartPos[1] + (aDict.get("LP") - self.lowestValue) * self.yscale instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg) instg = InstructionGroup(group=groupStr) color = Color() openPrice = aDict.get("OP") closePrice = aDict.get("CP") if closePrice > openPrice: color.rgba = self.SOLID_COLOR instg.add(color) x1 = self.chartPos[0] + dispIdx * (self.tickWide + self.tickGap) + self.tickGap y1 = self.chartPos[1] + (openPrice - self.lowestValue) * self.yscale instg.add( Rectangle(pos=(x1, y1), size=(self.tickWide, (closePrice - openPrice) * self.yscale))) elif closePrice < openPrice: color.rgba = self.VIRTUAL_COLOR instg.add(color) x1 = self.chartPos[0] + dispIdx * (self.tickWide + self.tickGap) + self.tickGap y1 = self.chartPos[1] + (closePrice - self.lowestValue) * self.yscale instg.add( Rectangle(pos=(x1, y1), size=(self.tickWide, (openPrice - closePrice) * self.yscale))) else: color.rgba = self.KLINE_COLOR instg.add(color) x1 = self.chartPos[0] + dispIdx * (self.tickWide + self.tickGap) + self.tickGap y1 = self.chartPos[1] + (closePrice - self.lowestValue) * self.yscale x2 = self.chartPos[0] + (dispIdx + 1) * (self.tickWide + self.tickGap) y2 = y1 instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg)
def __init__(self, **kwargs): super(BackgroundLabel, self).__init__(**kwargs) self.IG = InstructionGroup() self.background_color = (0, 0, 0, 1) self.color = (1, 1, 1, 1)
class Main(FloatLayout): snake = ListProperty([(0,0)]) rangeSnake = ListProperty([0,0,Window.width,Window.height]) startSpeed = NumericProperty(30) def __init__(self, **kwargs): super(Main, self).__init__(**kwargs) self.keyboard = Controls() self.count = 0 self.bind(size=self.up,pos=self.up) def up(self,*args): self.rangeSnake[0] = self.pos[0] self.rangeSnake[1] = self.pos[1] self.rangeSnake[2] = self.pos[0] + self.size[0] self.rangeSnake[3] = self.pos[1] + self.size[1] self.snake[0] = self.pos def start(self,*dt): self.canvas.clear() Clock.unschedule(self.move) self.food() Clock.schedule_interval(self.move,1./(self.startSpeed+self.count)) def restart(self, *dt): self.canvas.clear() self.clear_widgets() Clock.unschedule(self.move) self.foods() self.snake = [ self.pos] self.keyboard.direction = "right" Clock.schedule_interval(self.move,1./(self.startSpeed+self.count)) def stop(self,*dt): Clock.unschedule(self.move) def continue_move(self): Clock.unschedule(self.move) Clock.schedule_interval(self.move,1./(self.startSpeed+self.count)) def food(self,*args): self.foodblue = InstructionGroup() self.foodblue.add(Color(1, 0, 0, 1)) x = random.randint(int(self.rangeSnake[0]), int(self.rangeSnake[2]-10)) y = random.randint(int(self.rangeSnake[1]), int(self.rangeSnake[3]-10)) self.food = Rectangle(pos=(x,y), size=(10,10)) self.foodblue.add(self.food) def foods(self): self.count += 1 x = random.randint(int(self.rangeSnake[0]), int(self.rangeSnake[2]-10)) y = random.randint(int(self.rangeSnake[1]), int(self.rangeSnake[3]-10)) for a,b in self.snake: if x > a+10 or y >b+10 or x < a- 10 or y<b-10: pass else: self.foods() return self.food.pos = (x,y) def move(self,*dt): self.canvas.clear() self.canvas.add(self.foodblue) x,y = self.snake[-1] if abs(self.snake[-1][0] -self.food.pos[0])<10 and abs(self.snake[-1][1] -self.food.pos[1])<10:#吃到食物 x,y = self.snake[-1] if self.keyboard.direction == "left": for i in range(1,11): x1,y1 = x-i,y self.snake.append((x1,y1)) elif self.keyboard.direction == "right": for i in range(1,11): x1,y1 = x+i,y self.snake.append((x1,y1)) elif self.keyboard.direction == "up": for i in range(1,11): x1,y1 = x,y+i self.snake.append((x1,y1)) elif self.keyboard.direction == "down": for i in range(1,11): x1,y1 = x,y-i self.snake.append((x1,y1)) self.foods() else: if self.keyboard.direction == "left": x,y = x-1,y if x < self.rangeSnake[0] : self.gameover() for a,b in self.snake: if x >a and x-a<10 and abs(b-y)<10: self.gameover() break elif self.keyboard.direction == "right": x,y = x+1,y if x+10 > self.rangeSnake[2]: self.gameover() for a,b in self.snake: if a>x and a-x < 10 and abs(b-y)< 10: self.gameover() break elif self.keyboard.direction == "up": x,y = x,y+1 if y+10 >self.rangeSnake[3]: self.gameover() for a,b in self.snake: if b>y and b-y < 10 and abs(x-a)<10: self.gameover() break elif self.keyboard.direction == "down": x,y = x,y-1 if y < self.rangeSnake[1]: self.gameover() for a,b in self.snake: if y >b and y-b>10 and abs(x-a)<10: self.gameover() break self.snake.append((x,y)) del self.snake[0] for i in self.snake: snake = InstructionGroup() snake.add(Color(0, 0, 1, 1)) snake.add(Rectangle(pos=i, size=(10,10))) self.canvas.add(snake) def gameover(self): Clock.unschedule(self.move) btn = Button(text="Game is over",size_hint=(1,1),pos_hint={"center_x":.5,"center_y":.5}) self.add_widget(btn) btn.bind(on_release=self.restart )
class sniffWidget(Widget): # two button as property btn1 = ObjectProperty(None) btn2 = ObjectProperty(None) def __init__(self, iface, amount, tag, func, serv_addr, bufsize=1024): """ iface: interface to sniff on amount: max amount of latest rssis to maintain tag: value for tag field, used as sign func: function to process rssi list, should takes list of rssis in and output another list of single output value serv_addr: server addr, format as (HOST, PORT) bufsize: max size of receive buf, should be big enough """ super(sniffWidget, self).__init__() self.iface = iface self.amount = amount self.tag = tag self.rssi_dict = {} self.rssi_dict["tag"] = tag self.prcs_dict = {} self.prcs_dict["tag"] = self.tag self.func = func # server addr self.serv_addr = serv_addr self.bufsize = bufsize # client socket # use ipv4 udp self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #self.sock.settimeout(3.0) # initial communication with server self.config() # visualize aps #self.visual_aps() # initial coords self.coords = (0, 0) # used to record all instructions that draw user-dots self.obj = InstructionGroup() self.objects = [] # used to indicate whether update should be down actually self.update_flag = 0 # children widget, 2 buttons # define event behavior for those two def _on_press1(instance): # change the text and flag if instance.flag == -1: instance.flag = 1 instance.text = "Pause" instance.parent.set_flag() elif instance.flag == 0: instance.flag = 1 instance.text = "Pause" instance.parent.set_flag() elif instance.flag == 1: instance.flag = 0 instance.text = "Resume" instance.parent.unset_flag() def _on_press2(instance): # clear the canvas and re-initial btn1 instance.parent.clear() instance.parent.btn1.reinit() instance.parent.unset_flag() self.btn1.bind(on_press=_on_press1) self.btn2.bind(on_press=_on_press2) def config(self): name_dict = {"tag": self.tag} # send the tag self.sock.sendto(json.dumps(name_dict).encode('utf-8'), self.serv_addr) # receive the configuration of APs recv_msg, addr = self.sock.recvfrom(self.bufsize) recv_msg = str(recv_msg, encoding="utf-8") if addr == self.serv_addr: self.config_dict = json.loads(recv_msg) self.ssids = self.config_dict.keys() for ssid in self.ssids: self.rssi_dict[ssid] = [] self.prcs_dict[ssid] = [] return # if fail, then exit raise Exception("connect to server {} failed, please \ check your network connection and try again".format( self.serv_addr)) sys.exit() def visual_aps(self): with self.canvas: Color(1, 0, 0) d = 20.0 for ssid in self.ssids: x, y = self.config_dict[ssid] print(x * Window.size[0]) print(y * Window.size[1]) Ellipse(pos=(x * Window.size[0], y * Window.size[1]), size=(d, d)) def sniff(self, dt): num = len(self.ssids) for ssid in self.ssids: data = sniff_rssi(self.iface, ssid, 1, dt) #data_dict = sniff_rssi_cmd(self.iface, self.ssids, 1, dt) self.rssi_dict[ssid] += data def aging(self): """ only keep the latest "amount" rssi values """ for ssid in self.ssids: if len(self.rssi_dict[ssid]) > self.amount: self.rssi_dict[ssid] = self.rssi_dict[ssid][-1 * self.amount:] def process(self): """ process the rssis """ for ssid in self.ssids: self.prcs_dict[ssid] = self.func(self.rssi_dict[ssid]) def sendrecv(self): msg = json.dumps(self.prcs_dict) # send self.sock.sendto(msg.encode("utf-8"), self.serv_addr) # recv recv_msg, addr = self.sock.recvfrom(self.bufsize) recv_msg = str(recv_msg, encoding="utf-8") if addr == self.serv_addr: recv_dict = json.loads(recv_msg) self.coords = (recv_dict["x"], recv_dict["y"]) def visualize(self): self.obj = InstructionGroup() d = 20. x, y = self.coords self.obj.add(Color(0, 1, 0)) self.obj.add( Ellipse(pos=(x * Window.size[0], y * Window.size[1]), size=(d, d))) self.canvas.add(self.obj) self.objects.append(self.obj) def clear(self): # clear all user dots for obj in self.objects: self.canvas.remove(obj) self.objects = [] def set_flag(self): self.update_flag = 1 def unset_flag(self): self.update_flag = 0 def update(self, dt): print("in update") if self.update_flag: # update periodic of interval dt(s) # 1.sniff self.sniff(dt * 0.08 / len(self.ssids)) # 2.aging self.aging() print(self.rssi_dict) # 3.process self.process() # 4.sendrecv self.sendrecv() # 5.visualize self.visualize()
class PrinterAnimation(RelativeLayout): padding = NumericProperty(40) printer_actual_dimensions = ListProperty([10, 10, 80]) printer_current_actual_height = NumericProperty(0.0) print_area_height = NumericProperty(1) print_area_width = NumericProperty(1) print_area_left = NumericProperty(0) print_area_bottom = NumericProperty(40) container_padding = NumericProperty(0) container_left = NumericProperty(0) container_width = NumericProperty(0) container_bottom = NumericProperty(0) container_height = NumericProperty(0) laser_size = ListProperty([40, 40]) resin_height = NumericProperty(20) water_height = NumericProperty(20) scale = NumericProperty(1.0) resin_color = ListProperty([0.0, 0.8, 0.0, 0.6]) water_color = ListProperty([0.2, 0.2, 1.0, 0.6]) container_color = ListProperty([1.0, 1.0, 1.0, 1.0]) laser_color_edge2 = ListProperty([0.0, 0.0, 0.5, 1.0]) laser_color_edge = ListProperty([0.0, 0.0, 1.0, 1.0]) laser_color = ListProperty([0.7, 1.0, 1.0, 1.0]) drip_history = ListProperty() laser_points = ListProperty() middle_x = NumericProperty(52) laser_pos = NumericProperty(60) laser_speed = NumericProperty(1) refresh_rate = NumericProperty(1.0) def __init__(self, **kwargs): super(PrinterAnimation, self).__init__(**kwargs) self.drip_time_range = 5 self.waiting_for_drips = True self.refresh_rate = App.get_running_app().refresh_rate self._gl_setup() self.axis_history = [] self.drips = 0 self.line_x = [] self.line_y = [] self.last_height = 0.0 self.min_height = 0.0 self.last_x_min = 0.0 self.last_x_max = 1.0 self.is_on_canvas = False def on_printer_actual_dimensions(self, instance, value): self.min_height = self.printer_actual_dimensions[2] / 400.0 self.on_size(None) def _gl_setup(self): self.drip_texture = CoreImage("resources/images/drop.png", mipmap=True).texture self.drips_instruction = InstructionGroup() self.model_instruction = InstructionGroup() print(self.canvas.children) # self.canvas.add(self.drips_instruction) # self.canvas.add(self.model_instruction) def on_size(self, *largs): bounds_y = (self.height * 0.7) - self.resin_height bounds_x = self.width - (self.padding * 2) printer_x = self.printer_actual_dimensions[0] printer_y = self.printer_actual_dimensions[2] self.laser_pos = self.width / 2 self.scale = min(bounds_y / printer_y, bounds_x / printer_x) Logger.info("Scale: {}".format(self.scale)) self.print_area_width = printer_x * self.scale self.print_area_height = printer_y * self.scale def redraw(self, key): self._draw_drips() self._draw_laser() self._draw_model() if not self.is_on_canvas: self.canvas.insert(4, self.drips_instruction) self.canvas.insert(4, self.model_instruction) self.is_on_canvas = True Clock.unschedule(self.redraw) Clock.schedule_once(self.redraw, self.refresh_rate) def animation_start(self, *args): Clock.unschedule(self.redraw) self.axis_history = [] self.line_x = [] self.line_y = [] self.last_height = 0 self.min_height = 0.0 self.laser_points = [] self.drip_history = [] Clock.schedule_once(self.redraw, self.refresh_rate) def animation_stop(self): Clock.unschedule(self.redraw) self.axis_history = [] self.line_x = [] self.line_y = [] self.last_height = 0 self.min_height = 0.0 self.laser_points = [] self.drip_history = [] def _draw_drips(self): self.drips_instruction.clear() self.drips_instruction.add(Color(1, 1, 1, 1)) top = time.time() bottom = top - self.drip_time_range drips_in_history = len(self.drip_history) for (index, drip_time) in zip(range(drips_in_history, 0, -1), self.drip_history): if drip_time > bottom: time_ago = top - drip_time y_pos_percent = (self.drip_time_range - time_ago) / self.drip_time_range drip_pos_y = (self.height * y_pos_percent) + self.padding xoff = 10 + math.sin((len(self.drip_history) - index) / (2 * math.pi)) * 20 self.drips_instruction.add(Rectangle(size=[12, 16], pos=[self.print_area_left + xoff, drip_pos_y], texture=self.drip_texture)) def _draw_laser(self): if self.waiting_for_drips: self.laser_points = [] else: x_min = self.print_area_left + (self.last_x_min * self.print_area_width) x_max = self.print_area_left + (self.last_x_max * self.print_area_width) if (self.laser_pos >= x_max): self.laser_pos = x_max self.laser_speed = abs(self.laser_speed) * -1 if (self.laser_pos <= x_min): self.laser_pos = x_min self.laser_speed = abs(self.laser_speed) self.laser_pos += self.laser_speed laser_x = self.laser_pos self.laser_points = [self.middle_x, self.height - self.padding, laser_x, self.water_height + self.print_area_bottom + self.resin_height] def _draw_model(self): if self.axis_history: model_height = self.axis_history[-1][2] if model_height > (self.last_height + self.min_height) or not self.line_x: x1, y1, x2, y2 = self._get_pixels(self.axis_history[-1]) self.last_x_min = x1 self.last_x_max = x2 self.line_x.insert(0, x1) self.line_x.append(x2) self.line_y.insert(0, y1) self.line_y.append(y2) self.last_height = model_height points = [] for idx in range(0, len(self.line_x)): x = int(self.print_area_left + (self.line_x[idx] * self.print_area_width)) y = int(self.print_area_bottom + self.resin_height + (self.line_y[idx] * self.print_area_height)) - 2 points.append(x) points.append(y) self.model_instruction.clear() self.model_instruction.add(Color(rgba=(1.0, 0.0, 0.0, 1.0))) self.model_instruction.add(Line(points=points, width=2, close=True)) def _get_pixels(self, data): pixel_height = data[2] / self.printer_actual_dimensions[2] pixel_pos_min = (data[0][0] + (self.printer_actual_dimensions[1] / 2.0)) / self.printer_actual_dimensions[1] pixel_pos_max = (data[0][1] + (self.printer_actual_dimensions[1] / 2.0)) / self.printer_actual_dimensions[1] return [pixel_pos_min, pixel_height, pixel_pos_max, pixel_height]
class TabWidget(Widget): open_repeat_opac = NumericProperty(0) close_repeat_opac = NumericProperty(0) selected_opac = NumericProperty(0) timesig_width = NumericProperty(64) open_repeat_width = NumericProperty(0) close_repeat_width = NumericProperty(0) measure_end = NumericProperty(0) def get_barline_x(self): return self.x + self.timesig_width barline_x = AliasProperty(get_barline_x, None, bind=['x', 'timesig_width'], cache=True) def get_measure_start(self): return self.x + self.timesig_width + self.open_repeat_width measure_start = AliasProperty( get_measure_start, None, bind=['x', 'timesig_width', 'open_repeat_width'], cache=True) def __init__(self, tabbuilder=None, idx=0, total_measures=0, **kwargs): self.tabbuilder = tabbuilder self.idx = idx self.total_measures = total_measures self.step_y = 20 self.measure_width = 512 # width of a 4/4 measure only, sort of a step_x. self.starts_with_tie = False self.ends_with_slide = False self.is_selected = False super().__init__(**kwargs) self.glyphs = InstructionGroup() self.backgrounds = InstructionGroup() self.note_glyphs = InstructionGroup() self.num_glyphs = InstructionGroup() self.tuplet_count = 0 self.canvas.add(white) self.canvas.add(self.backgrounds) self.canvas.add(black) self.canvas.add(self.glyphs) def build_measure(self, gp_measure: guitarpro.models.Measure): if self.x == 0: self.draw_timesig(gp_measure) self.draw_measure_number(gp_measure) self.draw_open_repeat(gp_measure) self.gp_beats, self.xmids = self.add_staff_glyphs(gp_measure) self.draw_note_effects(self.gp_beats, self.xmids) gp_beat_groups = self.gp_beat_groupby(self.gp_beats) self.add_note_glyphs(gp_beat_groups, self.xmids) self.draw_close_repeat(gp_measure) self.draw_measure_count() def draw_timesig(self, gp_measure: guitarpro.models.Measure): num, den = gp_measure.timeSignature.numerator, gp_measure.timeSignature.denominator.value num_glyph = CoreLabel(text=str(num), font_size=50, font_name='./fonts/PatuaOne-Regular') den_glyph = CoreLabel(text=str(den), font_size=50, font_name='./fonts/PatuaOne-Regular') num_glyph.refresh() den_glyph.refresh() num_x = (self.barline_x / 2) - (num_glyph.texture.width / 2) den_x = (self.barline_x / 2) - (den_glyph.texture.width / 2) num_instr = Rectangle(pos=(num_x, self.y + self.step_y * 5), size=(num_glyph.texture.size)) den_instr = Rectangle(pos=(den_x, self.y + self.step_y * 3), size=(den_glyph.texture.size)) num_instr.texture = num_glyph.texture den_instr.texture = den_glyph.texture self.glyphs.add(num_instr) self.glyphs.add(den_instr) def draw_measure_number(self, gp_measure: guitarpro.models.Measure): num = gp_measure.header.number num_glyph = CoreLabel(text=str(num), font_size=14, font_name='./fonts/Arial') num_glyph.refresh() num_x = self.barline_x - num_glyph.width num_y = self.y + self.step_y * 8 num_instr = Rectangle(pos=(num_x, num_y), size=num_glyph.texture.size) num_instr.texture = num_glyph.texture self.glyphs.add(num_instr) def draw_measure_count(self): # TODO: Once copy/delete buttons are added, update measure counts. measure_count = str(self.idx + 1) + ' / ' + str(self.total_measures) count_glyph = CoreLabel(text=measure_count, font_size=14, font_name='./fonts/Arial') count_glyph.refresh() count_x = self.right - (count_glyph.width + 5) count_y = self.y count_instr = Rectangle(pos=(count_x, count_y), size=count_glyph.size) count_instr.texture = count_glyph.texture self.glyphs.add(count_instr) def draw_open_repeat(self, gp_measure: guitarpro.models.Measure): if gp_measure.isRepeatOpen: self.open_repeat_opac = 1 self.open_repeat_width = 25 def draw_close_repeat(self, gp_measure: guitarpro.models.Measure): if gp_measure.repeatClose > 0: self.close_repeat_opac = 1 self.close_repeat_width = 25 def add_staff_glyphs(self, gp_measure: guitarpro.models.Measure): gp_beats, xmids = [], [] for gp_voice in gp_measure.voices[:-1]: xpos = self.measure_start for beat_idx, gp_beat in enumerate(gp_voice.beats): note_dur = 1 / gp_beat.duration.value tuplet_mult = gp_beat.duration.tuplet.times / gp_beat.duration.tuplet.enters beat_width = note_dur * tuplet_mult * self.measure_width if gp_beat.duration.isDotted: beat_width *= 3 / 2 elif gp_beat.duration.isDoubleDotted: beat_width *= 7 / 4 beat_mid = self.add_beat_glyph(gp_beat, xpos) xmids += [beat_mid] gp_beats += [gp_beat] xpos += beat_width self.measure_end = xpos return gp_beats, xmids def add_beat_glyph(self, gp_beat: guitarpro.models.Beat, xpos: float): # If notes list is empty, rest for gp_beat.duration.value. if not gp_beat.notes: self.draw_rest(gp_beat, xpos) return xpos for gp_note in gp_beat.notes: xmid = self.draw_fretnum(gp_note, xpos) return xmid def draw_fretnum(self, gp_note: guitarpro.models.Note, xpos: float): fret_text = str(gp_note.value) if gp_note.type.name == 'tie': fret_text = ' ' if gp_note.type.name == 'dead': fret_text = 'X' if gp_note.effect.isHarmonic: fret_text = '<' + fret_text + '>' fret_num_glyph = CoreLabel(text=fret_text, font_size=16, font_name='./fonts/Arial', bold=True) fret_num_glyph.refresh() ypos = self.y + self.step_y * ( 8 - (gp_note.string - 1)) - fret_num_glyph.height / 2 background = Rectangle(pos=(xpos, ypos), size=fret_num_glyph.texture.size) fret_num_instr = Rectangle(pos=(xpos, ypos), size=fret_num_glyph.texture.size) fret_num_instr.texture = fret_num_glyph.texture self.backgrounds.add(background) self.glyphs.add(fret_num_instr) xmid = xpos + (fret_num_glyph.texture.width / 2) return xmid def gp_beat_groupby(self, gp_beats: List[guitarpro.models.Beat]): beat_groups, cur_group = [], [] prev_dur = None i = 0 while i < len(gp_beats): gp_beat = gp_beats[i] # Add rests by themselves. if not gp_beat.notes: if cur_group: beat_groups.append(cur_group[:]) cur_group = [] beat_groups.append([gp_beat]) prev_dur = None i += 1 # Add notes within a tuplet together. elif gp_beat.duration.tuplet.enters != 1: if cur_group: beat_groups.append(cur_group[:]) cur_group = [] tuplet_num = gp_beat.duration.tuplet.enters beat_groups.append(gp_beats[i:i + tuplet_num]) prev_dur = None i += tuplet_num # Group this single note with a previously existing group. elif gp_beat.duration.value == prev_dur and not ( gp_beat.duration.isDotted or gp_beat.duration.isDoubleDotted or any(gp_note.effect.slides for gp_note in gp_beat.notes)): cur_group += [gp_beat] i += 1 # End the previous group and start a new one. else: if cur_group: beat_groups += [cur_group[:]] cur_group = [gp_beat] prev_dur = gp_beat.duration.value i += 1 if cur_group: beat_groups += [cur_group[:]] return beat_groups def add_note_glyphs(self, gp_beat_groups: List[guitarpro.models.Beat], xmids: List[float]): bg = x = 0 while bg < len(gp_beat_groups): group = gp_beat_groups[bg] gp_beat = group[0] # Rest or single note. if len(group) == 1: if gp_beat.notes: self.draw_stem(gp_beat, xmids[x]) self.draw_flags(gp_beat, xmids[x]) x += 1 # Tuplet. elif gp_beat.duration.tuplet.enters != 1: num_tuplet = gp_beat.duration.tuplet.enters tuplet_mids = xmids[x:x + num_tuplet] self.draw_tuplet(gp_beat, tuplet_mids) x += num_tuplet # Beamed note. elif len(group) % 2 == 0: num_notes = len(group) self.draw_beamed_notes(gp_beat, xmids[x:x + num_notes]) x += num_notes # Mix of beamed note and single note. else: num_notes = len(group) - 1 self.draw_beamed_notes(gp_beat, xmids[x:x + num_notes]) x += num_notes self.draw_stem(gp_beat, xmids[x]) self.draw_flags(gp_beat, xmids[x]) x += 1 bg += 1 def draw_rest(self, gp_beat: guitarpro.models.Beat, xpos: float): # The only font I can find for rests doesn't follow the unicode standard. step_y = self.step_y unicode_rests = { 1: u'\u1D13B', 2: u'\u1D13C', 4: u'\u1D13D', 8: u'\u1D13E', 16: u'\u1D13F' } rests = { 1: u'\uE102', 2: u'\uE103', 4: u'\uE107', 8: u'\uE109', 16: u'\uE10A', 32: u'\uE10B' } rest_ys = { 1: step_y * 4, 2: step_y * 3, 4: step_y * 2.5, 8: step_y * 3, 16: step_y * 3, 32: step_y * 2.5 } rest, rest_y = rests[gp_beat.duration.value], rest_ys[ gp_beat.duration.value] rest_glyph = CoreLabel(text=rest, font_size=32, font_name='./fonts/mscore-20') rest_glyph.refresh() rest_instr = Rectangle(pos=(xpos, self.y + rest_y), size=rest_glyph.texture.size) rest_instr.texture = rest_glyph.texture background = Rectangle(pos=(xpos, self.y + rest_y), size=rest_glyph.texture.size) # self.backgrounds.add(background) # Looks bad because of mscore-20 font. self.glyphs.add(rest_instr) if gp_beat.duration.isDotted or gp_beat.duration.isDoubleDotted: ypos = rest_y + rest_glyph.texture.height * 0.75 self.draw_dots(gp_beat, xpos, ypos) def draw_stem(self, gp_beat: guitarpro.models.Beat, xpos: float): lower = (xpos, self.y + self.step_y * 1.5) if gp_beat.duration.value == 1: return if gp_beat.duration.value == 2: upper = (xpos, self.y + self.step_y * 2) else: upper = (xpos, self.y + self.step_y * 2.5) stem = Line(points=(*lower, *upper), width=1, cap='square') if gp_beat.duration.isDotted or gp_beat.duration.isDoubleDotted: xpos, ypos = lower ypos += 2 self.draw_dots(gp_beat, xpos, ypos) self.glyphs.add(stem) def draw_flags(self, gp_beat: guitarpro.models.Beat, xpos: float): # Texture created by mscore-20 font is unnecessarily tall, hard to place exactly. flags = { 1: '', 2: '', 4: '', 8: u'\uE194', 16: u'\uE197', 32: u'\uE198' } flag = flags[gp_beat.duration.value] flag_glyph = CoreLabel(text=flag, font_size=32, font_name='./fonts/mscore-20') flag_glyph.refresh() flag_instr = Rectangle(pos=(xpos, self.y - self.step_y * 1.5), size=flag_glyph.texture.size) flag_instr.texture = flag_glyph.texture self.glyphs.add(flag_instr) def draw_tuplet(self, gp_beat: guitarpro.models.Beat, xmids: List[float]): xmin, xmax = xmids[0], xmids[-1] for xpos in xmids: self.draw_stem(gp_beat, xpos) if gp_beat.duration.value == 8: self.draw_eightnote_beam(xmin, xmax) if gp_beat.duration.value == 16: self.draw_eightnote_beam(xmin, xmax) self.draw_sixteenthnote_beam(xmin, xmax) xmid = (xmin + xmax) / 2 text_glyph = CoreLabel(text=str(gp_beat.duration.tuplet.enters), font_size=14, font_name='./fonts/Arial') text_glyph.refresh() text_instr = Rectangle(pos=(xmid - text_glyph.texture.width / 2, self.y + self.step_y * 0.5), size=text_glyph.texture.size) text_instr.texture = text_glyph.texture self.glyphs.add(text_instr) def draw_beamed_notes(self, gp_beat: guitarpro.models.Beat, xmids: List[float]): xmin, xmax = xmids[0], xmids[-1] for xpos in xmids: self.draw_stem(gp_beat, xpos) if gp_beat.duration.value == 8: self.draw_eightnote_beam(xmin, xmax) if gp_beat.duration.value == 16: self.draw_eightnote_beam(xmin, xmax) self.draw_sixteenthnote_beam(xmin, xmax) def draw_eightnote_beam(self, xmin: float, xmax: float): lowbeam = Line(points=(xmin, self.y + self.step_y * 1.5, xmax, self.y + self.step_y * 1.5), width=1.4, cap='square') self.glyphs.add(lowbeam) def draw_sixteenthnote_beam(self, xmin: float, xmax: float): highbeam = Line(points=(xmin, self.y + self.step_y * 1.75, xmax, self.y + self.step_y * 1.75), width=1.1, cap='square') self.glyphs.add(highbeam) def draw_dots(self, gp_beat: guitarpro.models.Beat, xpos: float, ypos: float): xpos += 4 dot_size = (3, 3) if gp_beat.duration.isDotted: dot = Ellipse(pos=(xpos, ypos), size=dot_size) self.glyphs.add(dot) elif gp_beat.duration.isDoubleDotted: dot1 = Ellipse(pos=(xpos, ypos), size=dot_size) dot2 = Ellipse(pos=(xpos + 4, ypos), size=dot_size) self.glyphs.add(dot1) self.glyphs.add(dot2) def draw_note_effects(self, gp_beats: List[guitarpro.models.Beat], xmids: List[float]): for i, (gp_beat, xmid) in enumerate(zip(gp_beats, xmids)): for gp_note in gp_beat.notes: if gp_note.type.name == "tie": if i != 0: self.draw_tie(gp_note, xmids[i - 1], xmids[i]) else: self.starts_with_tie = True elif gp_note.effect.slides: if i != len(xmids) - 1: self.draw_slide(gp_note, xmids[i], xmids[i + 1]) else: self.ends_with_slide = True def draw_tie(self, gp_note: guitarpro.models.Note, start: float, end: float): string_y = self.y + self.step_y * (8 - (gp_note.string - 1)) line_mid = (start + end) / 2 points = (start, string_y - self.step_y / 3, line_mid, string_y - self.step_y, end, string_y - self.step_y / 3) tie_line = Bezier(points=points) self.glyphs.add(tie_line) def draw_tie_across_measures(self, gp_beat: guitarpro.models.Beat, start: float, end: float): for gp_note in gp_beat.notes: if gp_note.type.name == "tie": self.draw_tie(gp_note, start, end) def draw_slide(self, gp_note: guitarpro.models.Note, start, end): # There are 7 guitarpro.models.SlideTypes. So far only shiftSlideto, value == 1. string_y = self.y + self.step_y * (8 - (gp_note.string - 1)) padding = 10 start += padding end -= padding points = (start, string_y + self.step_y / 4, end, string_y - self.step_y / 4) slide_line = Line(points=points) self.glyphs.add(slide_line) def on_touch_down(self, touch): if self.collide_point(touch.x, touch.y): self.tabbuilder.no_tabwidgets_touched = False self.tabbuilder.select(self) return True return super().on_touch_down(touch) def select(self): self.is_selected = True self.selected_opac = 0.5 def unselect(self): self.is_selected = False self.selected_opac = 0
def drawCordFrame(self): # 畫一條橫線 instg = InstructionGroup(group="frame") frameColor = Color() frameColor.rgba = self.FRAME_COLOR instg.add(frameColor) x1 = int(self.pos[0] + self.shift_left) y1 = int(self.pos[1] + self.shift_bottom) x2 = int(self.pos[0] + self.width - self.shift_right) y2 = int(self.pos[1] + self.shift_bottom) instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg) # 畫一條豎線 instg = InstructionGroup(group="frame") instg.add(frameColor) center_pos = int(self.pillarPoint / 2) self.center_xpos = int(self.pos[0] + self.shift_left + (self.min_tickNum * -1) * self.pillarSumPoint + self.ycordWidth + center_pos) x1 = self.center_xpos y1 = int(self.pos[1] + self.shift_bottom) x2 = self.center_xpos y2 = int(self.pos[1] + self.height - self.shift_top) instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg)
def update_board(self): self.canvas.after.clear() self.players = [] pos_x = 0.9 - self.each_tile_size + 0.01 pos_y = 0.11 self.color_players_list = [[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 1], [1, 1, 0, 1]] self.pos_x_list = [] self.pos_y_list = [] for i in range(len(self.dice_holder_list)): self.dice_holder_list[i].text = str(self.dice_list[i]) for i in range(4): text_on_button = " "+ self.game_elem['players'][i].player_name + \ "\n Current Cash = " + str(self.game_elem['players'][i].current_cash) + \ "\n # of houses = " + str(self.game_elem['players'][i].num_total_houses) + \ "\n # of hotels = " + str(self.game_elem['players'][i].num_total_hotels) if (self.game_elem['players'] [i].has_get_out_of_jail_community_chest_card == True): text_on_button = text_on_button + "\nGOO_Jail community card" if (self.game_elem['players'][i].has_get_out_of_jail_chance_card == True): text_on_button = text_on_button + "\nGOO_Jail chance card" self.player_detail_list[i].text = text_on_button self.obj_instr_player = InstructionGroup() self.obj_instr_player.add( Color(self.color_players_list[i][0], self.color_players_list[i][1], self.color_players_list[i][2], self.color_players_list[i][3])) try: pos_x_n = int(self.game_elem['players'][i].current_position / 10) pos_y_n = int(self.game_elem['players'][i].current_position % 10) except: pos_x_n = 0 pos_y_n = 0 if (pos_x_n == 0): pos_x = (0.9 - self.each_tile_size + 0.01) - (pos_y_n * self.each_tile_size) pos_y = 0.11 elif (pos_x_n == 2): pos_x = (0.9 - self.each_tile_size + 0.01) - ( self.num_tiles * (self.each_tile_size)) + (pos_y_n * self.each_tile_size) pos_y = 0.11 + (self.num_tiles * self.each_tile_size) elif (pos_x_n == 1): pos_x = (0.9 - self.each_tile_size + 0.01) - (self.num_tiles * (self.each_tile_size)) pos_y = 0.11 + (pos_y_n * self.each_tile_size) elif (pos_x_n == 3): pos_x = (0.9 - self.each_tile_size + 0.01) pos_y = 0.11 + (self.num_tiles * self.each_tile_size) - ( pos_y_n * self.each_tile_size) self.obj_instr_player.add( Ellipse(pos=((pos_x + i * 0.01) * Window.width, pos_y * Window.height), size=(10, 10))) self.players.append(self.obj_instr_player) self.pos_x_list.append(pos_x) self.pos_y_list.append(pos_y) self.canvas.after.add(self.obj_instr_player) count_house = 0 count_hotel = 0 if (self.game_elem['players'][i].assets) != None: self.player_props = [] self.player_props_x = [] self.player_props_y = [] for k in range(len(list(self.game_elem['players'][i].assets))): prop_name = list( self.game_elem['players'][i].assets)[k].name pos_prop = self.game_elem['location_objects'][ prop_name].start_position self.obj_instr = InstructionGroup() self.obj_instr.add( Color(self.color_players_list[i][0], self.color_players_list[i][1], self.color_players_list[i][2], self.color_players_list[i][3])) each_side_num_tiles = self.num_tiles side = 0 if pos_prop >= 0 and pos_prop < each_side_num_tiles: side = 0 elif pos_prop >= each_side_num_tiles and pos_prop < 2 * each_side_num_tiles: side = 1 elif pos_prop >= 2 * each_side_num_tiles and pos_prop < 3 * each_side_num_tiles: side = 2 else: side = 3 #prop_x = int(pos_prop / 10) prop_y = pos_prop - side * each_side_num_tiles pos_x_prop = 0 pos_y_prop = 0 if (side == 0): pos_x_prop = 0.9 - self.each_tile_size + 0.01 - ( prop_y * self.each_tile_size) pos_y_prop = 0.14 elif (side == 2): pos_x_prop = 0.9 - self.each_tile_size + 0.01 - ( self.num_tiles * (self.each_tile_size)) + (prop_y * self.each_tile_size) pos_y_prop = 0.14 + (self.num_tiles * self.each_tile_size) elif (side == 1): pos_x_prop = 0.9 - self.each_tile_size + 0.01 - ( self.num_tiles * (self.each_tile_size)) pos_y_prop = 0.14 + (prop_y * self.each_tile_size) elif (side == 3): pos_x_prop = 0.9 - self.each_tile_size + 0.01 pos_y_prop = 0.14 + (self.num_tiles * self.each_tile_size) - ( prop_y * self.each_tile_size) self.obj_instr.add( Rectangle(pos=(pos_x_prop * Window.width, pos_y_prop * Window.height), size=(12, 12))) if list(self.game_elem['players'] [i].assets)[k].loc_class == 'real_estate': if list(self.game_elem['players'] [i].assets)[k].num_houses > 0: for m in range( list(self.game_elem['players'][i].assets) [k].num_houses): self.obj_instr.add(Color(1, 1, 1, 1)) self.obj_instr.add( Ellipse( pos=((pos_x_prop + (m + 1) * 0.01) * Window.width, pos_y_prop * Window.height), size=(12, 12))) count_house += list(self.game_elem['players'] [i].assets)[k].num_houses if list(self.game_elem['players'] [i].assets)[k].num_hotels > 0: for m in range( list(self.game_elem['players'][i].assets) [k].num_hotels): self.obj_instr.add(Color(1, 0.1, 0.5, 1)) self.obj_instr.add( Ellipse( pos=((pos_x_prop + (m + 1) * 0.01) * Window.width, pos_y_prop * Window.height), size=(12, 12))) count_hotel += list(self.game_elem['players'] [i].assets)[k].num_hotels self.player_props.append(self.obj_instr) self.player_props_x.append(pos_x_prop) self.player_props_y.append(pos_y_prop) self.canvas.after.add(self.obj_instr) self.obj_instr_directory.append(self.obj_instr) self.bind(pos=self.update_rect, size=self.update_rect)
class FrameCanvas(RelativeLayout): def __init__(self, app): super(FrameCanvas, self).__init__() self._app = app self.bind(width=app.seek_video) self.bind(height=app.seek_video) self.touch_points = [] self._select_event = None self._select_center_xy = None self._select_radius = None self._select_circle = None def on_touch_down(self, touch): if not self.collide_point(*touch.pos): return False if self._app._cap is None: return False if self._app._play_pause_btn.text != "Play": return False canvas_xy = (touch.pos[0] - self.pos[0], touch.pos[1] - self.pos[1]) if ((self._select_center_xy is None) or (_sq_distance( canvas_xy, self._select_center_xy) >= self._select_radius**2)): self._select_center_xy = canvas_xy self._select_radius = 0 if self._select_circle is not None: self.canvas.remove(self._select_circle) self._select_circle = None if self._select_event is not None: self._select_event.cancel() self._select_event = Clock.schedule_interval(self._inc_selection, 0.01) return True def _inc_selection(self, *args, **kwargs): self._select_radius += 1 frame_xy1 = self._app._cap.canvas_xy_to_frame_xy( self._select_center_xy[0] - self._select_radius, self._select_center_xy[1] + self._select_radius) frame_xy2 = self._app._cap.canvas_xy_to_frame_xy( self._select_center_xy[0] + self._select_radius, self._select_center_xy[1] - self._select_radius) if frame_xy1 is None or frame_xy2 is None: self._select_radius -= 1 return if self._select_circle is not None: self.canvas.remove(self._select_circle) self._select_circle = InstructionGroup() self._select_circle.add(Color(1, 0, 0)) self._select_circle.add( Line(circle=(self._select_center_xy) + (self._select_radius, ), width=dp(3))) self.canvas.add(self._select_circle) def on_touch_up(self, touch): if self._select_event is not None: self._select_event.cancel() self._select_event = None if self._select_center_xy is not None: self._app._process_btn.disabled = False def clear_selection(self): self.on_touch_up(None) if self._select_circle is not None: self.canvas.remove(self._select_circle) self._select_circle = None self._select_center_xy = None self._select_radius = None self._app._process_btn.disabled = True def get_selection(self): if self._select_center_xy is None: return None frame_xy1 = self._app._cap.canvas_xy_to_frame_xy( self._select_center_xy[0] - self._select_radius, self._select_center_xy[1] + self._select_radius) frame_xy2 = self._app._cap.canvas_xy_to_frame_xy( self._select_center_xy[0] + self._select_radius, self._select_center_xy[1] - self._select_radius) return (frame_xy1, frame_xy2)
class Fretboard(StencilView, FloatLayout): strings = ListProperty() num_frets = NumericProperty(24) tuning = ListProperty([40, 45, 50, 55, 59, 64]) fret_ranges = ListProperty() fret_positions = ListProperty() root_note_idx = NumericProperty(0) mode_filter = NumericProperty(0b101011010101) box_x = NumericProperty(0) box_y = NumericProperty(0) box_pos = ReferenceListProperty(box_x, box_y) scale_text = StringProperty("") notes_to_highlight = StringProperty("") notes_or_octaves = StringProperty("") def __init__(self, **kwargs): super().__init__(**kwargs) self.fret_bar_width = self.width * (0.1 / 24.75) self.relative_fret_positions = self.calc_relative_fret_positions() self.fret_positions = self.calc_fret_positions(self) self.fret_ranges = self.calc_fret_ranges(self) self.fingerboard = Rectangle() self.fret_bars = InstructionGroup() self.inlays = InstructionGroup() self._add_fret_bars() self._add_inlays() # When launching Fretboard as App, need to use canvas.before.. self.canvas.before.add(brown) self.canvas.before.add(self.fingerboard) self.canvas.before.add(black) self.canvas.before.add(self.fret_bars) self.canvas.before.add(white) self.canvas.before.add(self.inlays) def _add_fret_bars(self): """Add Rectangles to display fret bars. Setting maximum to 24 frets (25 with nut) - the most on any common guitar. When less frets are chosen, some will be drawn off screen.""" for fret in range(25): self.fret_bars.add(Rectangle()) def _add_inlays(self): """Add Ellipses to display inlays. There will be a maximum of 12 for a 24-fret guitar (for a typical Fender style). When less frets are chosen, some will be drawn off screen.""" for inlay in range(12): self.inlays.add(Ellipse()) def calc_relative_fret_positions(self): """Calculate relative position of frets on a 24-fret fretboard. Each fret position is in the range [0, 1], where 1 is the full length of the fretboard.""" # Ratio of fret[i]/fret[i+1] for 12-tone equal temperament. temperament = 2**(1 / 12) # All fret_pos in fret_positions represent % of guitar string; 12th fret_pos == 0.5. # All fret_pos in range [0, 0.75] for 24 fret guitar. fret_positions = [ 1 - (1 / (temperament**fret_num)) for fret_num in range(25) ] # Stretch fret_positions to represent % of fretboard instead. # All fret_pos now in range [0, 1]. fret_positions = [ fret_pos / fret_positions[-1] for fret_pos in fret_positions ] # Tricky: 0th fret cannot occur at 0; need room to its left to display open note info. # Move 0th fret up for nut and scale remaining appropriately. # All fret_pos now in range [nut_width_ratio, 1]. nut_width_ratio = 0.03 fret_positions = [((1 - nut_width_ratio) * fret_pos) + nut_width_ratio for fret_pos in fret_positions] return fret_positions def calc_fret_positions(self, box): """Calculate position of each fret based on fretboard's current width.""" # Normalize relative_fret_positions so that we only draw self.num_frets on the screen. # Any frets with a normalized_fret_position > 1 will be drawn off screen. rightmost = self.relative_fret_positions[self.num_frets] normalized_fret_positions = [ fret_pos / rightmost for fret_pos in self.relative_fret_positions ] # Calculate the actual x position of each fret. self.fret_positions = [ fret_pos * box.width + box.x for fret_pos in normalized_fret_positions ] return self.fret_positions def calc_fret_ranges(self, box): """Calculate x positions of fretboard between frets for use in displaying octaves.""" # Gibson ratio of fret bar width to scale length. self.fret_bar_width = box.width * (0.1 / 24.75) cur_right = box.x fret_ranges = [] for fret_pos in self.fret_positions: next_left = fret_pos - (self.fret_bar_width / 2) fret_ranges.append((cur_right, next_left)) cur_right = (next_left + self.fret_bar_width) self.fret_ranges = fret_ranges return self.fret_ranges def update_canvas(self, *args): # With box now resized, recalculate & redraw everything. Having trouble drawing things # in order using mixture of python and kv lang. Order is explicit here. box = self.ids.box self.calc_fret_positions(box) self.calc_fret_ranges(box) self.update_fingerboard(box) self.update_fret_bars(box) self.update_inlays(box) def update_fingerboard(self, box): self.fingerboard.size = box.size self.fingerboard.pos = box.pos def update_fret_bars(self, box): # When adding Rectangle to InstructionGroup, BindTextures are added first. self.fret_bar_width = self.width * (0.1 / 24.75) rects = [ obj for obj in self.fret_bars.children if isinstance(obj, Rectangle) ] for fret_pos, rect in zip(self.fret_positions, rects): x_pos = fret_pos - (self.fret_bar_width / 2) rect.size = [self.fret_bar_width, box.height] rect.pos = [x_pos, box.y] def update_inlays(self, box): inlays = [ obj for obj in self.inlays.children if isinstance(obj, Ellipse) ] inlay_num = 0 d = box.width * 0.01 for i, fret_range in enumerate(self.fret_ranges): # Double circular inlay at fret 12. if i != 0 and i % 12 == 0: x_pos = (sum(fret_range) / 2) y_pos1 = (box.height / 3) + box.y y_pos2 = 2 * (box.height / 3) + box.y inlay1 = inlays[inlay_num] inlay2 = inlays[inlay_num + 1] inlay1.size = [d, d] inlay2.size = [d, d] inlay1.pos = [x_pos - d / 2, y_pos1 - d / 2] inlay2.pos = [x_pos - d / 2, y_pos2 - d / 2] inlay_num += 2 # Single circular inlay. elif i in [3, 5, 7, 9, 15, 17, 19, 21]: x_pos = (sum(fret_range) / 2) y_pos = (box.height / 2) + box.y inlay = inlays[inlay_num] inlay.size = [d, d] inlay.pos = [x_pos - d / 2, y_pos - d / 2] inlay_num += 1 def on_size(self, *args): """Resize the BoxLayout that holds the fretboard to maintain a guitar neck aspect ratio.""" target_ratio = 10 width, height = self.size # Check which size is the limiting factor. if width / height > target_ratio: # Window is "wider" than target, so the limitation is the height. self.ids.box.height = height self.ids.box.width = height * target_ratio else: self.ids.box.width = width self.ids.box.height = width / target_ratio def on_box_pos(self, *args): self.update_canvas() def on_num_frets(self, *args): self.calc_fret_positions(self) self.update_canvas() ### SONG PLAYING METHODS def prep_play(self, flat_song: List[List[guitarpro.models.Measure]], track_num=0, tempo_mult=1): flat_track = flat_song[track_num] self.build_track_tuning(flat_track) self.build_string_play_instr(flat_song[track_num], tempo_mult) def build_track_tuning(self, flat_track: List[guitarpro.models.Measure]): # GuitarPro song doesn't have the track's guitar tuning? Dumb. track_tuning = [-1] * 6 for gp_measure in flat_track: for gp_voice in gp_measure.voices[:-1]: for gp_beat in gp_voice.beats: for gp_note in gp_beat.notes: string_idx = 6 - gp_note.string fret_num = gp_note.value note_val = gp_note.realValue track_tuning[string_idx] = note_val - fret_num if not any(tuning == -1 for tuning in track_tuning): break # Possible that some strings weren't played the whole song... just assume its in standard. for i in range(6): if track_tuning[i] == -1: track_tuning[i] = self.tuning[i] self.tuning = track_tuning print("Fretboard.build_track_tuning ", self.tuning, "\n") def build_string_play_instr(self, flat_track: List[guitarpro.models.Measure], tempo_mult: float) -> None: # Build list of notes to play length of that beat in seconds. string_instrs = [[], [], [], [], [], []] for gp_measure in flat_track: for gp_voice in gp_measure.voices[:-1]: for gp_beat in gp_voice.beats: beat_instr = self.build_beat_instr(gp_beat, tempo_mult) for string_idx, (fret_num, seconds) in enumerate(beat_instr): string_instrs[string_idx].append((fret_num, seconds)) # Eliminate faulty ghost notes. for string_instr in string_instrs: for i, (fret_num, seconds) in enumerate(string_instr): if fret_num == -2: string_instr[i] = (string_instr[i - 1][0], seconds) for i in range(6): self.strings[i].play_instrs = string_instrs[i] print("Fretboard.build_string_instr ") def build_beat_instr(self, gp_beat: guitarpro.models.Beat, tempo_mult: float): tempo = gp_beat.voice.measure.tempo.value # results_log = open('./results_log.txt', 'a') # results_log.write(str(gp_beat.voice.measure.header.number) + " ") # results_log.write(str(gp_beat.voice.measure.tempo.value) + "\n") spb = 60 / (tempo * tempo_mult) percent_quarter_note = 4 / gp_beat.duration.value percent_quarter_note *= (gp_beat.duration.tuplet.times / gp_beat.duration.tuplet.enters) if gp_beat.duration.isDotted: percent_quarter_note *= 3 / 2 elif gp_beat.duration.isDoubleDotted: percent_quarter_note *= 7 / 4 seconds = spb * percent_quarter_note fret_nums = [-1] * 6 for gp_note in gp_beat.notes: string_idx = 6 - gp_note.string fret_num = gp_note.value if gp_note.effect.ghostNote or gp_note.type.name == 'tie': fret_num = -2 fret_nums[string_idx] = fret_num beat_instr = [fret_nums, [seconds] * 6] return list(zip(*beat_instr)) def play(self, lead_in): for i in range(6): self.strings[i].play_thread(lead_in) def stop(self): for i in range(6): self.strings[i].stop()
class CustomBoxLayout(BoxLayout): def __init__(self, *args, **kwargs): if 'color' in kwargs: self.background_color = kwargs['color'] del kwargs['color'] else: self.background_color = hex_color("#333333") if 'border_color' in kwargs: self.border_color = kwargs['border_color'] del kwargs['border_color'] else: self.border_color = hex_color("#595959") # left, top, right, bottom if 'border' in kwargs: self.border = kwargs['border'] if not isinstance(self.border, tuple): self.border = tuple([self.border] * 4) del kwargs['border'] else: self.border = (0, 0, 0, 0) super(CustomBoxLayout, self).__init__(*args, **kwargs) self.draw_instructions = None self.updateDraw() self.bind(size=self._update_rect, pos=self._update_rect) def updateDraw(self): if self.draw_instructions is not None: self.canvas.before.remove(self.draw_instructions) self.draw_instructions = InstructionGroup() self.draw_instructions.add(Color(*self.border_color)) self.border_rect = Rectangle(size=self.size, pos=self.pos) self.draw_instructions.add(self.border_rect) self.draw_instructions.add(Color(*self.background_color)) p, s = self._get_background_rect(self.pos, self.size) self.rect = Rectangle(pos=p, size=s) self.draw_instructions.add(self.rect) self.canvas.before.add(self.draw_instructions) def updateColor(self, color): if color is None: self.background_color = hex_color("#333333") else: self.background_color = color self.updateDraw() def changeBorderColor(self, color): if color is None: self.border_color = hex_color("#595959") else: self.border_color = color self.updateDraw() def _update_rect(self, instance, value): self.border_rect.pos = instance.pos self.border_rect.size = instance.size p, s = self._get_background_rect(instance.pos, instance.size) self.rect.pos = p self.rect.size = s def _get_background_rect(self, pos, size): left, top, right, bottom = self.border bg_pos = [pos[0], pos[1]] bg_size = [size[0], size[1]] bg_pos[0] += left bg_size[0] -= left bg_pos[1] += bottom bg_size[1] -= bottom bg_size[0] -= right bg_size[1] -= top return bg_pos, bg_size
class MapViewer(ScatterPlane): def __init__(self, **kwargs): kwargs.setdefault('do_rotation', False) kwargs.setdefault('show_border', False) kwargs.setdefault('close_on_idle', False) kwargs.setdefault('scale_min', 1) super(MapViewer, self).__init__(**kwargs) # init ScatterPlane with above parameters self.map = None self.tilesize = (0, 0) self.tileCache = TileCache() self._zoom = 0 # intern var managed by a property self.reticule = None self.show_arrow = False self.arrow = type('DefaultArrow', (), {'azimuth': 0}) # creation a a default object, so azimth can still be set self.idle = True # used by self.update # variable contenant la dernière position gps self.last_pos = (0, 0) self.last_pos_wgs84 = (0, 0) self.locked_on_pos = False # The path self.path = None self.path_width = 5.0 self.tracking_path = False self._path_zoom = 0 # intern var to track a zoom change # Layers self.map_layer = None self.path_layer = None # Variables relative to layers self.map_cleanup_scheduled = False # Reposition tasks self.reposition_executor = None # Finally, as every user action implies a change of x and/or y value, # we bind those properties change on the update self.bind(x=self.update, y=self.update) def view_map(self, _map): # Prepare the map self._prepare_map(_map) # Set the last pos in map coord if possible self._init_last_pos(_map) # Adding the map layer self.map_layer = InstructionGroup() self.canvas.add(self.map_layer) # Adding the path layer self.path_layer = InstructionGroup() self.path_layer.add(Color(1, 0, 0, 0.5)) self.path = Line(width=self.path_width) self.path_layer.add(self.path) self.canvas.add(self.path_layer) # Creation of the reposition task executor # Update the reticule and if needed the arrow position self.reposition_executor = RepositionExecutor(0.1) if self.reticule is not None: self.reposition_executor.add_reposition_task(lambda: self.set_reticule_pos(*self.last_pos)) self.reposition_executor.add_reposition_task(lambda: self.set_arrow_pos()) # The first time we view a map we have to trigger the first tile drawing and reposition the reticule Clock.schedule_once(self.update_map, 0) self.reposition_executor.execute() def view_map_for_calibration(self, _map): # Prepare the map self._prepare_map(_map) # Adding the map layer self.map_layer = InstructionGroup() self.canvas.add(self.map_layer) # Creation of the reposition task executor self.reposition_executor = RepositionExecutor(0.1) # The first time we view a map we have to trigger the first tile drawing and reposition the reticule Clock.schedule_once(self.update_map, 0) def _prepare_map(self, _map): # Cleanup the canvas, reinitialize variables self.canvas.clear() self.idle = True self.scale = 1 self.pos = 0, 0 self.tileCache.__init__() self.map = _map self.tilesize = _map.get_tile_size() # Here we set the maximum scale of the Scatter, information retrieved from max_zoom in calibration.ini self.scale_max = pow(2, _map.get_max_zoom()) # Save the path of the map's calibration file in application settings config.save_last_map_path(_map.calibration_file_path) def update(self, obj, value, delay=UPDATE_DELAY): """ To prevent overuse of update_map, each change of position triggers an update of the map after UPDATE_DELAY sec. For instance, the position of the reticule has to be updated. """ if self.map is None: return # Pause the Loader, to prevent ui blocking Loader.pause() # Reposition widgets that need to be repositioned self.reposition_executor.execute() # Trigger the map update if self.idle: self.idle = False else: Clock.unschedule(self.update_map) Clock.schedule_once(self.update_map, delay) # Resume the Loader after a short time Clock.schedule_once(MapViewer.resume_loading, 0.1) def update_map(self, dt): # First, we get the current area covered on the ScatterPlane area = self.get_covered_area() map_area = (0, 0, self.tilesize[0], self.tilesize[1]) # Then, we make the list of tiles corresponding to that area tile_list = self.generate_tile_list(self.zoom, map_area, area) # Before drawing the tiles, we may have to perform a cleanup of the map layer if self.map_cleanup_scheduled: self.map_layer.clear() self.tileCache.__init__() self.map_cleanup_scheduled = False # Tiles drawing self.draw_tiles(tile_list) # We schedule a cleanup, which will be done if the app is inactive at the time of the callback execution Clock.schedule_once(partial(self.cleanup, tile_list), CLEANUP_DELAY) self.idle = True # logger.debug("container : %s" % self.tileCache.container.values()) # If we are showing the path, we update its view (adjust the thickness) if self.tracking_path: self.format_path() @staticmethod def resume_loading(dt): Loader.resume() @property def zoom(self): """Get zoom from current scale""" # At each zoom step forward, we cover an area twice as small as the former area self._zoom = log(self.scale, 2) return self._zoom def get_covered_area(self): parent = self.parent xmin = parent.x xmax = parent.x + parent.width ymin = parent.y ymax = parent.y + parent.height # Coordinates in ScatterPlane # Here, local and window coordinates are the same because ScatterPlane's origin # corresponds to the windows's origin xmin, ymin = self.to_local(xmin, ymin) # (x,y) coord of the bottom left corner xmax, ymax = self.to_local(xmax, ymax) # (x,y) coord of the top right corner return xmin, ymin, xmax, ymax def out_of_scope(self): logger.debug("OUT OF SCOPE") return [] @staticmethod def extend_tile_view(tab, maxindex): if len(tab): if tab[0] > 0: tab.insert(0, tab[0] - 1) if tab[-1] < maxindex - 1: tab.append(tab[-1] + 1) def generate_tile_list(self, zoom, map_area, area): """ Generates the list of tiles that should be visible for the given zoom level and the area visible on the scatterPlane """ xmin0, ymin0, xmax0, ymax0 = map_area # area for zoom=0, one unique tile xmin, ymin, xmax, ymax = area # Overlap test if xmax <= xmin0 or xmin >= xmax0 or ymin >= ymax0 or ymax <= ymin0: return self.out_of_scope() # coordinates of the intersection between map_area and area xmin_inter = max(xmin0, xmin) xmax_inter = min(xmax0, xmax) ymin_inter = max(ymin0, ymin) ymax_inter = min(ymax0, ymax) # If the current zoom is already an integer, we take its value. # Otherwise, we take its superior int value because we want to # identify which tiles of the next zoom level have to be displayed zoom_int = int(zoom if zoom == int(zoom) else int(zoom) + 1) targeted_scale = pow(2, zoom_int) tile_width = (xmax0 - xmin0) / float(targeted_scale) startx_index = int(xmin_inter / tile_width) endx_index = int(xmax_inter / tile_width) # Calculation of the indexes on x axis x_indexes = [] append = x_indexes.append for x in range(startx_index, endx_index + 1): append(x) MapViewer.extend_tile_view(x_indexes, targeted_scale) starty_index = int(ymin_inter / tile_width) endy_index = int(ymax_inter / tile_width) # Calculation of the indexes on y axis y_indexes = [] append = y_indexes.append for y in range(starty_index, endy_index + 1): append(y) MapViewer.extend_tile_view(y_indexes, targeted_scale) tile_list = [] append = tile_list.append for x in x_indexes: for y in y_indexes: tile = Tile() # tile.canvas = self.canvas tile.pos = Vector(x, y) * tile_width tile.size = (tile_width, tile_width) tile.x = x tile.y = y tile.zoom = zoom_int append(tile) return tile_list # The good damn right way to do it def draw_tile(self, proxy): if proxy.image.texture: self.map_layer.add( Rectangle(pos=proxy.pos, size=proxy.size, texture=proxy.image.texture, group=proxy.zoom)) def draw_tiles(self, tile_list): for tile in tile_list: image_id = tile.get_id() if self.tileCache.add_tile(tile.zoom, image_id): image = self.map.get_tile(tile.zoom, tile.x, tile.y) if image is None: continue image.create_property("pos", tile.pos) image.create_property("size", tile.size) image.create_property("zoom", str(int(tile.zoom))) image.bind(on_load=self.draw_tile) # if image.loaded: # only useful when Loader actually caches images # image.dispatch("on_load") def cleanup(self, tile_list, *largs): """ Cleanup is achieved when the app is considered inactive, ie when self.idle = True. """ if not self.idle: return zoom = self.zoom zoom_int = int(zoom if zoom == int(zoom) else int(zoom) + 1) print "debut cleanup, conserve zoom", zoom_int for _zoom in TileCache.get_unnecessary_zooms(self.tileCache.container.keys(), zoom_int): try: print "suppr zoom", _zoom self.map_layer.remove_group(str(_zoom)) self.tileCache.remove_tiles_for_zoom(_zoom) except: logger.debug("the canvas doesn't contains the zoom %s" % _zoom) if self.tileCache.is_tile_overfull(zoom_int): self.map_cleanup_scheduled = True # logger.debug("cleanup done, container : %s" % self.tileCache.container.values()) def set_reticule(self, reticule): self.reticule = reticule def set_reticule_pos(self, x, y): """ :param x: x position on the map in the range [0,tile_width] :param y: y position on the map in the range [0,tile_height] :return: """ # TODO : remplacer cette méthode par set_movable_widget_pos ? (cf plus bas) self.reticule.set_center_x(self.x + x * self.scale) self.reticule.set_center_y(self.y + y * self.scale) def set_movable_widget_pos(self, widget, x, y): """ Position a widget given the local coordinates of its center. :param x: x position on the map in the range [0,tile_width] :param y: y position on the map in the range [0,tile_height] """ if widget: widget.set_center_x(self.x + x * self.scale) widget.set_center_y(self.y + y * self.scale) def add_movable_widget(self, widget): """Actions done when a movable widget is added to the MapViewer.""" # Add a reposition task self.reposition_executor.add_reposition_task(lambda: self.set_movable_widget_pos( widget, *widget.pos_local)) def set_arrow_pos(self): """Must be called after set_reticule_pos""" if self.show_arrow: self.arrow.set_center_x(self.reticule.get_center_x()) self.arrow.set_center_y(self.reticule.get_center_y()) def set_orientation_arrow(self, arrow): self.show_arrow = True self.arrow = arrow def update_azimuth(self, instance, angle): self.arrow.azimuth = -angle def _init_last_pos(self, _map): """Initialize the last position in the _map projection coordinates, given the last known wgs84 position. This is used in view_map method. """ if self.last_pos_wgs84 is not None: self.last_pos = _map.get_map_coord(*self.last_pos_wgs84) else: self.last_pos = (0, 0) def update_pos(self, instance, value): # Remember the position, even if there is no map self.last_pos_wgs84 = value # If there is no map, no need to go further if self.map is None: return # Conversion from wgs84 coord to map coord x, y = self.map.get_map_coord(*value) # Remember this position too self.last_pos = x, y # Update the reticule pos self.set_reticule_pos(x, y) # Update the orientation arrow pos if necessary if self.show_arrow: self.set_arrow_pos() # Update the path if self.tracking_path: self.update_path(x, y) # If we are locked on pos, we center the view on the last known position if self.locked_on_pos: self.center_on_last_pos() def update_path(self, x, y): self.path.points += x, y def toggle_tracking_path(self, obj): if self.tracking_path: self.tracking_path = False # Creation of a new path self.path = Line(width=self.path_width) else: self.tracking_path = True def format_path(self, *args): """This updates the width of the path to be consistent with the scale. """ if self._path_zoom != self.zoom: self.path.width = self.path_width / self.scale self._path_zoom = self.zoom def center_on_last_pos(self, *args): scale = self.scale new_x = Window.size[0]/2 - self.last_pos[0]*scale new_y = Window.size[1]/2 - self.last_pos[1]*scale Animation.cancel_all(self) anim = Animation(x=new_x, y=new_y, t='in_out_quad', duration=0.5) anim.start(self) def get_dist_to_center(self): """ :return: The distance in meters between the last known position and the position represented by the middle of the screen. If no distance can be calculated, it returns -1. """ if self.map is None: return -1 try: merc_x, merc_y = self.map.map_coord_to_map_projection(*self.to_local(Window.size[0]/2, Window.size[1]/2)) except ZeroDivisionError: return -1 lat, lon = Map.to_geographic(merc_x, merc_y) lat_last, lon_last = self.last_pos_wgs84 dist = Map.distance(lat_last, lon_last, lat, lon) return dist def transform_with_touch(self, touch): if self.locked_on_pos: if len(self._touches) == 1: return False changed = False # We have more than one touch... list of last known pos points = [Vector(self._last_touch_pos[t]) for t in self._touches if t is not touch] # Add current touch last points.append(Vector(touch.pos)) # We only want to transform if the touch is part of the two touches # farthest apart! So first we find anchor, the point to transform # around as another touch farthest away from current touch's pos anchor_ = max(points[:-1], key=lambda p: p.distance(touch.pos)) # Now we find the touch farthest away from anchor, if its not the # same as touch. Touch is not one of the two touches used to transform farthest = max(points, key=anchor_.distance) if farthest is not points[-1]: return changed # Ok, so we have touch, and anchor, so we can actually compute the # transformation old_line = Vector(*touch.ppos) - anchor_ new_line = Vector(*touch.pos) - anchor_ if not old_line.length(): # div by zero return changed # pol : we don't want rotation here # angle = radians(new_line.angle(old_line)) * self.do_rotation # self.apply_transform(Matrix().rotate(angle, 0, 0, 1), anchor=anchor) # pol : trick -> change the origin!! anchor = Vector(self.to_parent(*self.last_pos)) if self.do_scale: scale = new_line.length() / old_line.length() new_scale = scale * self.scale if new_scale < self.scale_min: scale = self.scale_min / self.scale elif new_scale > self.scale_max: scale = self.scale_max / self.scale self.apply_transform(Matrix().scale(scale, scale, scale), anchor=anchor) changed = True return changed super(MapViewer, self).transform_with_touch(touch)
class ScatterBase(ScatterLayout): name = StringProperty() _hold_triggered = BooleanProperty(False) selected = BooleanProperty(False) scale_min = NumericProperty(.2) do_rotation = BooleanProperty(False) do_scale = BooleanProperty(False) do_translation = BooleanProperty(False) parent_width = NumericProperty() parent_height = NumericProperty() # Check if the touch collides with any of the children widgets def collide_point(self, x, y): local_x,local_y = self.to_local(x, y) for child in self.content.walk(restrict=True): if child==self.content: continue if child.collide_point(local_x, local_y): return True return False def get_full_bbox_parent(self, *args): all_corners = [] # Can also iterate through self.content.walk(restrict=True), but takes longer for child in self.content.children: if child == self.content: continue all_corners += [child.pos, (child.x, child.top), (child.right, child.y), (child.right, child.top)] all_corners_parent = [self.to_parent(*point) for point in all_corners] xmin = min([point[0] for point in all_corners_parent]) ymin = min([point[1] for point in all_corners_parent]) xmax = max([point[0] for point in all_corners_parent]) ymax = max([point[1] for point in all_corners_parent]) return (xmin, ymin), (xmax-xmin, ymax-ymin) full_bbox_parent = AliasProperty(get_full_bbox_parent, None) def on_touch_down(self, touch): if self.collide_point(*touch.pos): self._hold_triggered = False # If this is the "selected widget", treat as a movable scatter if self.selected: return super(ScatterBase, self).on_touch_down(touch) # Only detect on_hold if there is no currently selected widget if not self.selected: Clock.schedule_once(self.on_hold, .6) def on_touch_up(self,touch): # Unschedule on_hold for short presses if not self._hold_triggered: Clock.unschedule(self.on_hold) if self.selected: super(ScatterBase, self).on_touch_up(touch) def on_hold(self, *args): app = App.get_running_app() # 1. If already selected, do nothing if self.selected: return # 2. If a selected widget already exists, do nothing if not app.root.manager.layout_screen.selected_widget: self._hold_triggered = True app.root.manager.layout_screen.edit_widget(self) def on_transform_with_touch(self,*args): self.check_widget() # When widget is changed, check to make sure it is still in bounds of mirror def check_widget(self, *args): (bbox_x,bbox_y),(bbox_width,bbox_height) = self.full_bbox_parent # 1. Size check if bbox_width > self.parent_width: widget_to_bbox_ratio = bbox_width/self.parent_width self.scale = self.scale/widget_to_bbox_ratio if bbox_height > self.parent_height: widget_to_bbox_ratio = bbox_height/self.parent_height self.scale = self.scale/widget_to_bbox_ratio # 2. Translation check - Make sure widget is within mirror bbox_right = bbox_x+bbox_width bbox_top = bbox_y+bbox_height if bbox_x < 0: self.x -= bbox_x if bbox_right > self.parent_width: self.x += self.parent_width - bbox_right if bbox_y < 0: self.y -= bbox_y if bbox_top > self.parent_height: self.y += self.parent_height - bbox_top def select(self, *args): # 0. Set as selected self.selected = True # 1. Locate outermost bounding box of widget all_corners = [] for widget in self.content.walk(restrict=True): if widget == self.content: continue all_corners += [widget.pos, (widget.x, widget.top), (widget.right, widget.y), (widget.right, widget.top)] xmin = min([point[0] for point in all_corners]) ymin = min([point[1] for point in all_corners]) xmax = max([point[0] for point in all_corners]) ymax = max([point[1] for point in all_corners]) # 2. Draw outline around widget self.outline = InstructionGroup() self.outline.clear() self.outline.add(Color(.67, .816, .95, 1)) self.outline.add(Line(points=[xmin, ymin, xmax, ymin, xmax, ymax, xmin, ymax], width=2, joint='none', close=True)) self.canvas.add(self.outline) # 3. Bring to front, make movable self.do_translation = True self.do_scale = True if self.rotation != 0: self.do_rotation = True self.auto_bring_to_front = True def unselect(self, *args): # 0. Deselect self.selected = False # 1. Remove outline self.canvas.remove(self.outline) # 2. Lock widget self.do_translation = False self.do_scale = False self.do_rotation = False self.auto_bring_to_front = False
def _drawLine(self, preClose, aDict, dispIdx, isLastFlag): """ """ groupStr = self.instGroup if isLastFlag == True: groupStr += "_lastData" else: groupStr += "_curvData" instg = InstructionGroup(group=groupStr) color = Color() volume = aDict.get("VOL") closePrice = aDict.get("CP") if closePrice > preClose: color.rgba = self.UP_COLOR instg.add(color) x1 = self.chartPos[0] + dispIdx * (self.tickWide + self.tickGap) + self.tickGap y1 = self.chartPos[1] instg.add( Rectangle(pos=(x1, y1), size=(self.tickWide, (volume - self.lowestValue) * self.yscale))) elif closePrice < preClose: color.rgba = self.DOWN_COLOR instg.add(color) x1 = self.chartPos[0] + dispIdx * (self.tickWide + self.tickGap) + self.tickGap y1 = self.chartPos[1] instg.add( Rectangle(pos=(x1, y1), size=(self.tickWide, (volume - self.lowestValue) * self.yscale))) else: color.rgba = self.EQUAL_COLOR instg.add(color) x1 = self.chartPos[0] + dispIdx * (self.tickWide + self.tickGap) + self.tickGap y1 = self.chartPos[1] instg.add( Rectangle(pos=(x1, y1), size=(self.tickWide, (volume - self.lowestValue) * self.yscale))) self.canvas.add(instg)
class Piece(SparseGridLayout, TetrisAware): map = ListProperty([]) def __init__(self, color=(1, 1, 1, 1), **kwargs): self.color = color self.size_hint = (None, None) super(SparseGridLayout, self).__init__(**kwargs) self.bind(map=self.on_map) self.keyboard = App.get_running_app().keyboard self.keyboard.bind( on_key_down=self.on_keypress, on_key_up=self.on_keyrelease ) self.base_delay = self.keyboard.repeat_delay self.base_speed = self.keyboard.repeat_speed self.vertical = False """ One may wonder, when entering the realms of Piece.update(), "what exactly is delay_lambda?". It is what makes a piece remain controllable after having touched the ground, for a static duration (.5). It is checked in move() and rotate() - if check_lock notices the Piece isn't right above the ground anymore, it triggers "normal" gravity back by calling on_parent. Finally, the lock timeout is necessarily called after the static duration (.5), to lock the piece if its height hasn't changed (we discard the false-positive if it has). """ self.delay_lambda = None def on_parent(self, *args): if self.parent: level = self.parent.parent.level Clock.schedule_interval( self.update, .5 * (.75 + (.05 * (4 - (level % 4)))) ** level ) def on_map(self, instance, value): current_child = 0 for y in range(len(self.map)): for x in range(len(self.map[y])): if self.map[y][x] == 'x': if len(self.children) < sum(line.count('x') for line in self.map): self.add_widget(Block(coords=(x, y), color=self.color)) else: self.children[current_child].coords = (x, y) current_child += 1 self.do_layout() def update(self, *args): if not self.parent: Clock.unschedule(self.update) self.keyboard_closed() return if self.tetris_coords[1] == 0 or self.collide_piece('down'): self.do_layout() self.remove_children() self.keyboard_closed() self.parent.check_line() self.parent.parent.spawn.new_piece() if self.parent: self.parent.remove_widget(self) else: self.tetris_coords[1] -= 1 self.check_lock(retrigger=True) def check_lock(self, retrigger=False): if not self.delay_lambda and (self.tetris_coords[1] == 0 or self.collide_piece('down')): self.trigger_lock() elif self.delay_lambda and (self.tetris_coords[1] > 0 and not self.collide_piece('down')): self.reset_lock() elif retrigger and self.delay_lambda: Clock.unschedule(self.delay_lambda) self.trigger_lock() def trigger_lock(self): Clock.unschedule(self.update) y = self.tetris_coords[1] self.delay_lambda = lambda *args: self.lock_timeout(y) Clock.schedule_once(self.delay_lambda, .5) def reset_lock(self): self.on_parent() Clock.unschedule(self.delay_lambda) self.delay_lambda = None def lock_timeout(self, y): if self.tetris_coords[1] == y: self.update() self.on_parent() self.delay_lambda = None def remove_children(self): for child in self.children[:]: child.pos_hint = {} self.remove_widget(child) self.parent.add_widget(child) def collide_piece(self, direction='down', map=[], coords=[]): if self.parent: for child in self.parent.children: if hasattr(child, 'tetris_coords') and child != self: if direction == 'cw' or direction == 'ccw': for y in range(len(map)): for x in range(len(map[y])): if map[y][x] == 'x': if coords[0] + x == child.tetris_coords[0]\ and coords[1] + y == child.tetris_coords[1]: return True else: for own_child in self.children: if direction == 'down': if own_child.tetris_coords[1] - 1 == child.tetris_coords[1]\ and own_child.tetris_coords[0] == child.tetris_coords[0]: return True if direction == 'left': if own_child.tetris_coords[0] - 1 == child.tetris_coords[0]\ and own_child.tetris_coords[1] == child.tetris_coords[1]: return True if direction == 'right': if own_child.tetris_coords[0] + 1 == child.tetris_coords[0]\ and own_child.tetris_coords[1] == child.tetris_coords[1]: return True if direction == 'current': if own_child.tetris_coords[0] == child.tetris_coords[0]\ and own_child.tetris_coords[1] == child.tetris_coords[1]: return True return False def on_tetris_coords(self, *args): if hasattr(self, 'map') and self.parent: if self.tetris_coords[0] < 0: self.tetris_coords[0] = 0 if self.tetris_coords[0] + len(self.map[0]) > self.parent.cols: self.tetris_coords[0] = self.parent.cols - len(self.map[0]) if self.tetris_coords[1] < 0: self.tetris_coords[1] = 0 if self.tetris_coords[1] + len(self.map) > self.parent.rows: self.tetris_coords[1] = self.parent.rows - len(self.map) if hasattr(self.parent, 'coord_to_pos'): self.pos = self.parent.coord_to_pos(*self.tetris_coords) for child in self.children: child.tetris_coords = [self.tetris_coords[0] + child.col, self.tetris_coords[1] + child.row] def do_layout(self, *args): super(Piece, self).do_layout(*args) if hasattr(self, 'outline'): self.canvas.before.remove(self.outline) self.outline = InstructionGroup() for child in self.children: self.outline.add(Color(.5, .8, 1, .8)) self.outline.add(Line( points=[ child.x - 1, child.y - 1, child.right + 1, child.y - 1, child.right + 1, child.top + 1, child.x - 1, child.top + 1 ], close=True, width=1.5 )) if self.canvas.before: self.canvas.before.add(self.outline) if len(self.children) == 0: if hasattr(self, 'outline'): self.canvas.before.remove(self.outline) def move(self, direction): if direction == 'left' and not self.collide_piece('left'): self.tetris_coords[0] -= 1 if direction == 'right' and not self.collide_piece('right'): self.tetris_coords[0] += 1 if direction == 'down': self.keyboard.repeat_delay = 0 self.keyboard.repeat_speed /= 4 self.update() self.check_lock() def rotate(self, **kwargs): direction = 'ccw' if 'direction' in kwargs: direction = kwargs['direction'] new_map = self.rotate_map(direction) new_coords = self.rotate_coords(new_map) if self.collide_piece(direction, new_map, new_coords): return self.vertical = not self.vertical self.map = new_map self.tetris_coords = new_coords self.check_lock() def rotate_map(self, direction): new_map = zip(*self.map[::-1]) if direction == 'cw': for i in range(2): new_map = zip(*new_map[::-1]) return new_map def rotate_coords(self, new_map): map_diff = [ len(self.map[0]) - len(new_map[0]), len(self.map) - len(new_map) ] for i in range(len(map_diff)): if self.vertical: map_diff[i] = floor(map_diff[i] / 2.) else: map_diff[i] = ceil(map_diff[i] / 2.) return self.tetris_coords[0] + map_diff[0], self.tetris_coords[1] + map_diff[1] def on_keypress(self, keyboard, key, keycode, modifiers): self.reset_keyboard_repeat() if key == 113: # 'q' on qwerty self.rotate(direction='ccw') elif key == 101: # 'e' self.rotate(direction='cw') elif key == 97: # 'a' on qwerty self.move('left') elif key == 100: # 'd' self.move('right') elif key == 115: # 's' self.move('down') elif key == 122: # 'z' on qwerty self.rotate(direction='ccw') elif key == 120: # 'x' self.rotate(direction='cw') elif key == 276: # left arrow self.move('left') elif key == 275: # right arrow self.move('right') elif key == 273: # up arrow self.rotate(direction='ccw') elif key == 274: # down arrow self.move('down') else: return True return False def on_keyrelease(self, keyboard, keycode): self.reset_keyboard_repeat() def reset_keyboard_repeat(self): self.keyboard.repeat_delay = self.base_delay self.keyboard.repeat_speed = self.base_speed def keyboard_closed(self): self.reset_keyboard_repeat() self.keyboard.unbind( on_key_down=self.on_keypress, on_key_up=self.on_keyrelease )