class Snake(Widget): body = props.ListProperty() size = props.ListProperty([SIZE, SIZE]) def __init__(self, canvas): super().__init__() self.canvas = canvas for _ in range(4): self._grow([300, 300]) @property def head_position(self): return self.body[0].pos def _grow(self, pos): with self.canvas: Color(0, 0, 1) head = Ellipse(pos=pos, size=self.size) self.body.append(head) def check_self_collision(self, next_head_pos): """ Проверка на столкновение головы змеи с телом """ for body_segment in self.body[1:]: if list(body_segment.pos) == next_head_pos: return True return False def move_to(self, next_pos, grow=False): for i, segment in enumerate(self.body): self.body[i].pos, next_pos = next_pos, segment.pos if grow: self._grow(next_pos)
class InfoDayConfig(Screen): colorHora = Properties.ListProperty([1, 1, 1, 1]) formatoHora = Properties.ListProperty(["24h", False]) colorFecha = Properties.ListProperty([1, 1, 1, 1]) formatoFecha = Properties.StringProperty("dd/mm") colorTemp = Properties.ListProperty([1, 1, 1, 1]) formatoTemp = Properties.StringProperty("metric") formatoClima = Properties.NumericProperty(2) c_id = Properties.StringProperty('6361046') activeInter = Properties.BooleanProperty(True) colorInter = Properties.ListProperty([1, 1, 1, 1]) def __init__(self, **kwargs): super(InfoDayConfig, self).__init__(**kwargs) self.pos_hint = {'center_y': 0.5, 'center_x': 0.5} self.getAllInter() def saveConfig(self): #guardar las configs if self.ids.textinput.text == "": self.c_id = self.ids.textinput.hint_text else: self.c_id = self.ids.textinput.text dbWrapper.saveHora("hora", self.formatoHora, self.colorHora) dbWrapper.saveFecha("fecha", self.formatoFecha, self.colorFecha) dbWrapper.saveTemp("temp", self.formatoTemp, self.colorTemp, self.c_id) dbWrapper.saveClima("weather", self.formatoClima, self.c_id) dbWrapper.saveInfoState(self.activeInter) dbWrapper.saveInternationalConfig("inter", self.colorInter) def getAllInter(self): datos = dbWrapper.getAllInterByMonth(str(strftime('%m'))) for j in datos: layout = BoxLayout(orientation='horizontal', size_hint_y=None, height=20, padding=[-40, 0, 0, 0]) layout.add_widget(Texto(text=str(j.dia))) layout.add_widget( Texto(text=str(j.info if len(j.info) < 25 else '...' + j.info[10:35] + '...'))) self.ids.todos.add_widget(layout) def pressedBack(self, widget): anim = Animation(pos_hint={"center_x": .5, "y": -.03}, duration=.1) anim += Animation(pos_hint={"center_x": .5, "y": 0}, duration=.1) anim.bind(on_complete=partial(self.goToMenuScreen)) anim.start(widget) def goToMenuScreen(self, widget, selected): self.saveConfig() App.get_running_app().root.transition = FadeTransition(duration=.3) App.get_running_app().root.current = "menu"
class Keybind(Button): """ Stores keybindings and manages actually sending them out of TabletKeyApp and to the next window. """ bound_keys = kp.ListProperty([]) tab_back = kp.BooleanProperty(False) position = kp.ListProperty([0, 0]) def output(self) -> dict: """ :return: A dictionary containing the vital binding properties of the Keybind so that they can be saved. """ return dict( position=self.pos, binding='+'.join(self.bound_keys), tab_back=self.tab_back ) def setup(self, name: str, binding: str, position: (list, tuple) = None, tab_back: bool = False) -> None: """ Sets a Keybind button up, or overwrites the existing properties if used on an existing Keybind object. :param name: A string, the user-supplied name of the keybinding to display on the button. :param binding: A string with each keyboard key separated by a plus (+) sign. :param position: A list or tuple, currently mostly a placeholder for when user-specified Keybind button placement is implemented. :param tab_back: A boolean, indicates whether, when this Keybind is pressed, the user wants to immediately tab back to the TabletKeyApp window. :return: None """ self.bound_keys = binding.split('+') self.tab_back = tab_back self.position = position if position is not None else [0, 0] self.text = name def send(self) -> None: """ Uses pyautogui to send the contents of the Keybind to the next window. :return: None """ pg.hotkey('alt', 'tab') # A slight delay is necessary to successfully input the # keystroke into the other window. time.sleep(0.1) pg.hotkey(*self.bound_keys) if self.tab_back: time.sleep(0.1) pg.hotkey('alt', 'tab')
class Apple(Widget): coord = props.ListProperty([250, 300]) body = props.ObjectProperty(None) def __init__(self, canvas): super().__init__() self.canvas = canvas with self.canvas: Color(1, 0, 0) self.body = Ellipse(pos=self.coord, size=(SIZE, SIZE)) def check_collision(self, coord): print(self.coord, coord) if coord[0] <= self.coord[0] + SIZE/2 <= coord[0] + SIZE \ and coord[1] <= self.coord[1] + SIZE/2 <= coord[1] + SIZE: print("check_collision") return True return False def new_position(self, snake): print("new_position") while True: apple_x = random.randint(SIZE, Window.size[0] - SIZE) apple_y = random.randint(SIZE, Window.size[1] - SIZE) apple_x -= apple_x % SIZE apple_y -= apple_y % SIZE for segment in snake.body: if [apple_x, apple_y] == segment.pos: continue self.coord = [apple_x, apple_y] self.body.pos = [apple_x, apple_y] return
class TempWidget(Image, EventDispatcher): text = Properties.StringProperty('') unit = Properties.StringProperty() c_id = Properties.StringProperty() chosenColor = Properties.ListProperty() def on_text(self, *_): # Just get large texture: l = Label(text=self.text) l.font_size = '1000dp' # something that'll give texture bigger than phone's screen size l.color = self.color l.texture_update() # Set it to image, it'll be scaled to image size automatically: self.texture = l.texture def __init__(self, **kwargs): super(TempWidget, self).__init__(**kwargs) currentTemp = getTemp() self.chosenColor = currentTemp.color self.unit = currentTemp.formato self.c_id = currentTemp.c_id self.color = self.chosenColor self.bind(chosenColor=self.update_temp) #Temperature self.text = str( int(getWeatherReducedByCityId(self.c_id, self.unit)['temp'])) + "º" Clock.schedule_interval(self.update_temp, 200) def update_temp(self, *args): self.text = str( int(getWeatherReducedByCityId(self.c_id, self.unit)['temp'])) + "º" self.color = self.chosenColor
class TwitterConfig(Screen): colorInter = Properties.ListProperty([1, 1, 1, 1]) activeInter = Properties.BooleanProperty(False) halign = Properties.StringProperty('left') def __init__(self, **kwargs): super(TwitterConfig, self).__init__(**kwargs) self.pos_hint = {'center_y': 0.5, 'center_x': 0.5} def changeHalign(self, halign): self.halign = halign def saveConfig(self): #guardar las configs print(self.activeInter) dbWrapper.saveTwitter(self.activeInter, self.colorInter, self.halign) def pressedBack(self, widget): anim = Animation(pos_hint={"center_x": .5, "y": -.03}, duration=.1) anim += Animation(pos_hint={"center_x": .5, "y": 0}, duration=.1) anim.bind(on_complete=partial(self.goToMenuScreen)) anim.start(widget) def goToMenuScreen(self, widget, selected): self.saveConfig() App.get_running_app().root.transition = FadeTransition(duration=.3) App.get_running_app().root.current = "menu"
class ScatterColoredLabel(Scatter): background_color = Properties.ListProperty((0, 0, 0, 1)) visible = Properties.BooleanProperty() saveOnDBEvent = Properties.ObjectProperty() noteId = Properties.NumericProperty() text = Properties.StringProperty() def on_pos(self, instance, value): try: self.saveOnDBEvent.cancel() except: logging.info('Notes: No previous event') self.saveOnDBEvent = Clock.schedule_once(self.saveOnDB, 5) def saveOnDB(self, dt): noteToSave = Notes( _id=self.noteId, pinned=self.visible, text=self.text, posX=self.pos[0], posY=self.pos[1], scale=self.scale, rotation=self.rotation, rgb=[ self.background_color[0]*255, self.background_color[1]*255, self.background_color[2]*255, self.background_color[3], ], ) noteToSave.save() logging.info('DB: Updated note with id: ' + str(self.noteId))
class AppMenuTextItem(ToggleButton, AbstractMenuItem): label = kp.ObjectProperty(None) text = kp.StringProperty('') font_size = kp.NumericProperty(14) color = kp.ListProperty([1, 1, 1, 1]) def on_release(self): submenu = self.get_submenu() if self.state == 'down': root = self._root_parent submenu.bounding_box_widget = root.bounding_box if root.bounding_box else root.parent submenu.bind(visible=self.on_visible) submenu.show(self.x, self.y - 1) for sibling in self.siblings: if sibling.get_submenu() is not None: sibling.state = 'normal' sibling.get_submenu().hide() self.parent._setup_hover_timer() else: self.parent._cancel_hover_timer() submenu.hide() def on_visible(self, *args): submenu = self.get_submenu() if self.width > submenu.get_max_width(): submenu.width = self.width def _check_submenu(self): super(AppMenuTextItem, self)._check_submenu() self.disabled = (self.get_submenu() is None)
class Hex(Label): tile_color = properties.ListProperty([0, 1, 0, 0.5]) def __init__(self, **kwargs): super(Hex, self).__init__(**kwargs) for hue in range(0, 3): self.tile_color[hue] = random.random()
class Application(App): '''A form manager demonstrating the power of RecycleView's key_viewclass property. ''' data = P.ListProperty() def build(self): root = Builder.load_string(KV) rv = root.ids.rv self.data = [ self.create_random_input(rv, index) for index in range(20) ] return root def handle_update(self, value, index): if None not in (index, value): self.data[index]['value'] = value def create_random_input(self, rv, index): return choice((self.create_textinput, self.create_checkbox, self.create_spinner))(rv, index) def create_spinner(self, rv, index): """ create a dict of data for a spinner """ return { 'index': index, 'widget': 'RVSpinner', 'value': '', 'values': [letter * 5 for letter in ascii_lowercase[:5]], 'ready': True, } def create_checkbox(self, rv, index): """ create a dict of data for a checkbox """ return { 'index': index, 'widget': 'RVCheckBox', 'value': choice((True, False)), 'title': ''.join(choices(ascii_lowercase, k=10)), 'ready': True, } def create_textinput(self, rv, index): """ create a dict of data for a textinput """ return { 'index': index, 'widget': 'RVTextInput', 'value': ''.join(choices(ascii_lowercase, k=10)), 'title': ''.join(choices(ascii_lowercase, k=10)), 'ready': True, }
class GameApp(App): table_size = kp.ListProperty(calc_table_size(*Window.size)) def build(self): self.width = Window.width self.height = Window.height self.game = Game() Clock.schedule_interval(self.game.update, 1.0 / FPS) return self.game
class CommandTerminal(KivyCmd): text = prop.StringProperty() ''' property where the logs are stored ''' top_pannel_items = prop.ListProperty() def __init__(self, **kwargs): super().__init__(**kwargs) clearbtn = Factory.TopPanelButton(icon='fa-trash-o') self.top_pannel_items.append(clearbtn)
class UnorderedDeskWidget(GridLayout): cards = prop.ListProperty() def __init__(self, **kwargs): pass def on_place_on(self, *cards, **kwargs): pass def on_take_off(self, *cards, **kwargs): pass
class MenuBar(box.BoxLayout): '''Background color, in the format (r, g, b, a).''' background_color = prop.ListProperty([0.2, 0.2, 0.2, 1]) separator_color = prop.ListProperty([0.8, 0.8, 0.8, 1]) selected = prop.BooleanProperty(False) def __init__(self, **kwargs): self.itemsList = [] super(MenuBar, self).__init__(**kwargs) def add_widget(self, item, index=0): if not isinstance(item, MenuItem): raise TypeError("MenuBar accepts only MenuItem widgets") super(MenuBar, self).add_widget(item, index) if index == 0: index = len(self.itemsList) self.itemsList.insert(index, item) def on_touch_down(self, touch): if self.collide_point(*touch.pos) == False: self.selected = False else: self.selected = True super(MenuBar, self).on_touch_down(touch) def on_selected(self, instance, value): for w in self.children: if isinstance(w, MenuSubmenu): if value: w.activate_hover() else: w.deactivate_hover() def close_all_menus(self): for ch in self.children: if isinstance(ch, MenuSubmenu): ch.close()
class Tile(Widget): tile = kp.ListProperty([0, 0]) mapx = kp.NumericProperty() mapy = kp.NumericProperty() def __init__(self, **kwargs): super().__init__() # print("\nTile", kwargs, type(self)) # tilex=col, tiley=row self.tile = [kwargs.get("tilex", 0), kwargs.get("tiley", 0)] def on_tile(self, *args): # print("on_tile", args, self.tile) self.mapx = self.tile[0] * GAME.get("tilesize") self.mapy = self.tile[1] * GAME.get("tilesize")
class ContextMenuText(ContextMenuItem): label = kp.ObjectProperty(None) submenu_postfix = kp.StringProperty(' ...') text = kp.StringProperty('') font_size = kp.NumericProperty(14) color = kp.ListProperty([1, 1, 1, 1]) def __init__(self, *args, **kwargs): super(ContextMenuText, self).__init__(*args, **kwargs) @property def content_width(self): # keep little space for eventual arrow for submenus return self.label.texture_size[0] + 10
class MenuItem(widget.Widget): '''Background color, in the format (r, g, b, a).''' background_color_normal = prop.ListProperty([0.2, 0.2, 0.2, 1]) background_color_down = prop.ListProperty([0.3, 0.3, 0.3, 1]) background_color = prop.ListProperty([]) separator_color = prop.ListProperty([0.8, 0.8, 0.8, 1]) text_color_hovered = prop.ListProperty([1, 1, 1, 1]) text_color_unhovered = prop.ListProperty([.7, .7, .7, 1]) inside_group = prop.BooleanProperty(False) pass
class Chart(BoxLayout): data= kp.ListProperty([]) def __init__(self,**kwargs): super().__init__(**kwargs) self.fig, self.ax1 = plt.subplots() self.ax1.plot([],[],'bo') self.mpl_canvas = self.fig.canvas self.add_widget(self.mpl_canvas) Clock.schedule_interval(self.update,1) def on_data(self,*args): self.ax1.clear() y = [i**2 for i in self.data] self.ax1.plot(self.data,y,'bo-',linewidth=5.0) self.mpl_canvas.draw_idle() def update(self,*args): self.data = random.sample(range(-10,10),5)
class DraggableColoredLabel(DragBehavior, Label): background_color = Properties.ListProperty((0, 0, 0, 1)) visible = Properties.BooleanProperty() saveOnDBEvent = Properties.ObjectProperty() noteId = Properties.NumericProperty() def on_pos(self, instance, value): try: self.bringToFront() self.saveOnDBEvent.cancel() except: logging.info('Notes: No previous event') self.saveOnDBEvent = Clock.schedule_once(self.saveOnDB, 5) def bringToFront(self): parent = self.parent children = parent.children childOnTop = children[0] if (self != childOnTop): parent.remove_widget(self) parent.add_widget(self) def saveOnDB(self, dt): noteToSave = Notes( _id=self.noteId, pinned=self.visible, text=self.text, posX=self.pos[0], posY=self.pos[1], sizeX=self.size_hint[0], sizeY=self.size_hint[1], rgb=[ self.background_color[0]*255, self.background_color[1]*255, self.background_color[2]*255, self.background_color[3], ], ) noteToSave.save() logging.info('DB: Updated note with id: ' + str(self.noteId))
class InternationalConfig(Screen): colorInter = Properties.ListProperty([1, 1, 1, 1]) activeInter = Properties.BooleanProperty(True) def __init__(self, **kwargs): super(InternationalConfig, self).__init__(**kwargs) self.pos_hint = {'center_y': 0.5, 'center_x': 0.5} self.getAllInter() def printt(self, switch): print(switch.active) def saveConfig(self): # guardar las configs dbWrapper.saveInternationalConfig( "inter", self.colorInter if self.activeInter == False else [1, 1, 1, 0]) def getAllInter(self): datos = dbWrapper.getAllInterByMonth(str(strftime('%m'))) for j in datos: layout = BoxLayout(orientation='horizontal', size_hint_y=None, height=20, padding=[-40, 0, 0, 0]) layout.add_widget(Texto(text=str(j.dia))) layout.add_widget( Texto(text=str(j.info if len(j.info) < 25 else '...' + j.info[10:35] + '...'))) self.ids.todos.add_widget(layout) def pressedBack(self, widget): anim = Animation(pos_hint={"center_x": .5, "y": -.03}, duration=.1) anim += Animation(pos_hint={"center_x": .5, "y": 0}, duration=.1) anim.bind(on_complete=partial(self.goToMenuScreen)) anim.start(widget) def goToMenuScreen(self, widget, selected): self.saveConfig() App.get_running_app().root.transition = FadeTransition(duration=.3) App.get_running_app().root.current = "menu"
class CanvasWidget(Widget): colorLinea = Properties.ListProperty((1, 0, 0)) grosorLinea = Properties.NumericProperty(10) def __init__(self, **kwargs): super(CanvasWidget, self).__init__(**kwargs) def on_touch_down(self, touch): if not self.disabled: with self.canvas: Color(*self.colorLinea, mode='rgb') d = self.grosorLinea w = self.grosorLinea*0.5 Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d)) touch.ud['line'] = Line( points=(touch.x, touch.y), size=(d, d), width=w) def on_touch_move(self, touch): if not self.disabled: touch.ud['line'].points += [touch.x, touch.y]
class ClockWidget(Image): text = Properties.StringProperty('') chosenColor = Properties.ListProperty() segundos = Properties.BooleanProperty() horas = Properties.StringProperty() def on_text(self, *_): # Just get large texture:z l = Label(text=self.text) l.font_size = '1000dp' # something that'll give texture bigger than phone's screen size l.color = self.color l.texture_update() # Set it to image, it'll be scaled to image size automatically: self.texture = l.texture def __init__(self, **kwargs): super(ClockWidget, self).__init__(**kwargs) currentHora = getHora() self.chosenColor = currentHora.color self.segundos = currentHora.formato[1] self.horas = currentHora.formato[0] self.color = self.chosenColor self.text = datetime.now().strftime( self.update_secondsAndFormat(self.segundos, self.horas)) Clock.schedule_interval(self.update_time, 1) def update_time(self, *args): self.text = datetime.now().strftime( self.update_secondsAndFormat(self.segundos, self.horas)) self.color = self.chosenColor def update_secondsAndFormat(self, seconds, formato): if (seconds == True and formato == "24h"): return '%H:%M:%S' elif (seconds == True and formato == "12h"): return '%I:%M:%S %p' elif (seconds == False and formato == "24h"): return '%H:%M' else: return '%I:%M %p'
class ErrorLogger(BoxLayout): text = prop.StringProperty() ''' property where the logs are stored ''' top_pannel_items = prop.ListProperty() def __init__(self, **kwargs): super().__init__(**kwargs) clearbtn = Factory.TopPanelButton(icon='fa-trash-o') clearbtn.bind(on_release=self.clear_logs) self.top_pannel_items.append(clearbtn) def log(self, msg): lines = self.text.splitlines() if len(lines) > MAX_LOG_LINES: # clean previous logs self.text = '\n'.join(lines[int(MAX_LOG_LINES / 2):]) self.text += msg + '\n' self.ids.scroll.scroll_y = 0 def clear_logs(self, *args): self.text = ''
class ColoredLabelConfig(GridLayout): editing = Properties.BooleanProperty(False) noteid = Properties.NumericProperty() pinned = Properties.BooleanProperty() bcolor = Properties.ListProperty((0, 0, 0, 1)) texto = Properties.StringProperty() def pinNote(self, noteId, pinned): ColoredLabel.visible = pinned != True self.pinned = pinned != True note = dbWrapper.findNoteById(noteId) note.pinned = pinned != True note.save() def on_editing(self, instance, value): if (value == False): nuevoTexto = self.ids.textValue.text noteToUpdate = Notes(_id=self.noteid, pinned=self.pinned, rgb=[ self.bcolor[0]*255, self.bcolor[1]*255, self.bcolor[2]*255, 1], text=nuevoTexto) noteToUpdate.save() def deleteNote(self): dbWrapper.deleteNoteById(self.noteid)
class DateWidget(Image): text = Properties.StringProperty('') chosenColor = Properties.ListProperty() formato = Properties.StringProperty() def on_text(self, *_): # Just get large texture: l = Label(text=self.text) l.font_size = '1000dp' # something that'll give texture bigger than phone's screen size l.color = self.color l.texture_update() # Set it to image, it'll be scaled to image size automatically: self.texture = l.texture def __init__(self, **kwargs): super(DateWidget, self).__init__(**kwargs) currentFecha = getFecha() self.chosenColor = currentFecha.color self.formato = currentFecha.formato self.color = self.chosenColor self.text = datetime.now().strftime(self.update_Format()) Clock.schedule_interval(self.update_time, 60) def update_time(self, *args): self.text = datetime.now().strftime(self.update_Format()) self.color = self.chosenColor def update_Format(self): if (self.formato == "dd/mm"): return '%d/%m' elif (self.formato == "dd/mm/yyyy"): return '%d/%m/%y' elif (self.formato == "mm/dd"): return '%m/%d' else: return '%m/%d/%y'
class ShadowBehavior(object): shadow_texture1 = props.ObjectProperty(None) shadow_pos1 = props.ListProperty([0, 0]) shadow_size1 = props.ListProperty([0, 0]) shadow_texture2 = props.ObjectProperty(None) shadow_pos2 = props.ListProperty([0, 0]) shadow_size2 = props.ListProperty([0, 0]) elevation = props.NumericProperty(1) _shadows = { 1: (1, 3, 0.12, 1, 2, 0.24), 2: (3, 6, 0.16, 3, 6, 0.23), 3: (10, 20, 0.19, 6, 6, 0.23), 4: (14, 28, 0.25, 10, 10, 0.22), 5: (19, 38, 0.30, 15, 12, 0.22) } # Shadows for each elevation. # Each tuple is: (offset_y1, blur_radius1, color_alpha1, offset_y2, blur_radius2, color_alpha2) # The values are extracted from the css (box-shadow rule). def __init__(self, *args, **kwargs): super(ShadowBehavior, self).__init__(*args, **kwargs) self._update_shadow = _us = Clock.create_trigger(self._create_shadow) self.bind(size=_us, pos=_us, elevation=_us) def _create_shadow(self, *args): # print "update shadow" ow, oh = self.size[0], self.size[1] offset_x = 0 # Shadow 1 shadow_data = self._shadows[self.elevation] offset_y = shadow_data[0] radius = shadow_data[1] w, h = ow + radius * 6.0, oh + radius * 6.0 t1 = self._create_boxshadow(ow, oh, radius, shadow_data[2]) self.shadow_texture1 = t1 self.shadow_size1 = w, h self.shadow_pos1 = self.x - \ (w - ow) / 2. + offset_x, self.y - (h - oh) / 2. - offset_y # Shadow 2 shadow_data = self._shadows[self.elevation] offset_y = shadow_data[3] radius = shadow_data[4] w, h = ow + radius * 6.0, oh + radius * 6.0 t2 = self._create_boxshadow(ow, oh, radius, shadow_data[5]) self.shadow_texture2 = t2 self.shadow_size2 = w, h self.shadow_pos2 = self.x - \ (w - ow) / 2. + offset_x, self.y - (h - oh) / 2. - offset_y def _create_boxshadow(self, ow, oh, radius, alpha): # We need a bigger texture to correctly blur the edges w = ow + radius * 6.0 h = oh + radius * 6.0 w = int(w) h = int(h) texture = Texture.create(size=(w, h), colorfmt='rgba') im = Image.new('RGBA', (w, h), color=(1, 1, 1, 0)) draw = ImageDraw.Draw(im) # the rectangle to be rendered needs to be centered on the texture x0, y0 = (w - ow) / 2., (h - oh) / 2. x1, y1 = x0 + ow - 1, y0 + oh - 1 draw.rectangle((x0, y0, x1, y1), fill=(0, 0, 0, int(255 * alpha))) im = im.filter(ImageFilter.GaussianBlur(radius * RAD_MULT)) texture.blit_buffer(im.tobytes(), colorfmt='rgba', bufferfmt='ubyte') return texture
class MapWidget(Widget): draw_color = properties.ListProperty([0, 0, 0]) background = properties.ListProperty([1, 1, 1]) point_color = properties.ListProperty([0, 0, 0]) point_size = properties.ListProperty([10, 10]) draw_from_text_file = properties.BooleanProperty(False) dragging_map = properties.BooleanProperty(False) translation = properties.ListProperty([0, 0]) translation_last_point = properties.ListProperty([0, 0]) # data_file_path = properties.StringProperty() def __init__(self, **kwargs): working_dir = Path.cwd() self.data_file_path = str(Path(str(working_dir) + "/" + DATA_FILE)) self.objects = [] # Contains all objects that is drawn on the screen # Create empty file if not Path.exists(Path(self.data_file_path)): open(self.data_file_path, "w") super(MapWidget, self).__init__(**kwargs) self.bind(pos=self.resize, size=self.resize) def resize(self, *args): self.pos = self.pos self.size = self.size self.clear_canvas() if self.draw_from_text_file: self.draw_from_data_file() def on_touch_down(self, touch): if self.inside_widget(touch, "touch") and self.draw_from_text_file: self.dragging_map = True self.translation_last_point = [touch.x, touch.y] def on_touch_move(self, touch): # print("Touch: %f, %f" % (touch.x - self.center_x, touch.y - self.center_y)) if self.dragging_map: self.translation[0] += -(self.translation_last_point[0] - touch.x ) # - self.center_x self.translation[1] += -(self.translation_last_point[1] - touch.y ) #- self.center_y self.translation_last_point = [touch.x, touch.y] self.clear_canvas() if self.draw_from_text_file: self.draw_from_data_file() def on_touch_up(self, touch): if self.inside_widget(touch, "touch"): if self.dragging_map: self.dragging_map = False self.translation[0] += -(self.translation_last_point[0] - touch.x) self.translation[1] += -(self.translation_last_point[1] - touch.y) def clear_canvas(self): for obj in self.objects: self.canvas.remove(obj) self.objects.clear() if not self.dragging_map: self.draw_from_text_file = False def inside_widget(self, touch, type): bottom_left_x = self.center_x - self.width / 2 bottom_left_y = self.center_y - self.height / 2 top_right_x = self.center_x + self.width / 2 top_right_y = self.center_y + self.height / 2 if type == "touch": x = touch.pos[0] y = touch.pos[1] return x >= bottom_left_x and x <= top_right_x and y >= bottom_left_y and y <= top_right_y elif type == "pos": x = touch[0] y = touch[1] return x >= bottom_left_x and x <= top_right_x and y >= bottom_left_y and y <= top_right_y def draw_from_data_file(self): if not self.draw_from_text_file: self.draw_from_text_file = True with open(self.data_file_path, "r") as input_file: for line in input_file: line = line.rstrip() line = line.split(",") position = [ self.center_x + int(line[0]) + self.translation[0], self.center_y + int(line[1]) + self.translation[1] ] if self.inside_widget(position, "pos"): self.obj = InstructionGroup() self.obj.add(Color(*self.point_color)) self.obj.add(Ellipse(pos=position, size=self.point_size)) self.objects.append(self.obj) self.canvas.add(self.obj)
class Snake(App): sprite_size = kp.NumericProperty(SPRITE_SIZE) head = kp.ListProperty([0, 0]) snake = kp.ListProperty() length = kp.NumericProperty(LENGTH) fruit = kp.ListProperty([0, 0]) fruit_sprite = kp.ObjectProperty(Fruit) direction = kp.StringProperty(RIGHT, options=(LEFT, UP, RIGHT, DOWN)) buffer_direction = kp.StringProperty(RIGHT, options=(LEFT, UP, RIGHT, DOWN, '')) block_input = kp.BooleanProperty(False) alpha = kp.NumericProperty(0) def on_start(self): self.fruit_sprite = Fruit() self.fruit = self.new_fruit_location self.head = self.new_head_location Clock.schedule_interval(self.move, MOVESPEED) Window.bind(on_keyboard=self.key_handler) def on_fruit(self, *args): self.fruit_sprite.coord = self.fruit if not self.fruit_sprite.parent: self.root.add_widget(self.fruit_sprite) def key_handler(self, _, __, key, *____): try: self.try_change_direction(direction_keys[key]) except KeyError: pass def try_change_direction(self, new_direction): if direction_group[new_direction] != direction_group[self.direction]: if self.block_input: self.buffer_direction = new_direction else: self.direction = new_direction self.block_input = True def on_head(self, *args): self.snake = self.snake[-self.length:]+[self.head] def on_snake(self, *args): for index, coord in enumerate(self.snake): sprite = SPRITES[index] sprite.coord = coord if not sprite.parent: self.root.add_widget(sprite) @property def new_head_location(self): return [randint(2, dim - 2)for dim in[COLS, ROWS]] @property def new_fruit_location(self): while True: fruit = [randint(2, dim)for dim in[COLS, ROWS]] if fruit not in self.snake and fruit != self.fruit: return fruit def move(self, *args): self.block_input = False new_head = [sum(x) for x in zip(self.head, direction_values[self.direction])] if not self.check_in_bounds(new_head) or new_head in self.snake: return self.die() if new_head == self.fruit: self.length += 1 self.fruit = self.new_fruit_location if self.buffer_direction: self.try_change_direction(self.buffer_direction) self.buffer_direction = '' self.head = new_head def check_in_bounds(self, pos): return all(0 <= pos[x] < dim for x, dim in enumerate([COLS, ROWS])) def die(self): self.root.clear_widgets() self.alpha = ALPHA Animation(alpha=0, duration=MOVESPEED).start(self) self.snake.clear() self.length = LENGTH self.fruit = self.new_fruit_location self.head = self.new_head_location
class Sprite(Widget): coord = kp.ListProperty([0, 0]) bgcolor = kp.ListProperty([0, 0, 0, 0])
class GlobalContainer(box.BoxLayout): graph_list = prop.ListProperty([]) active_graph = prop.ObjectProperty(None) name_manager = NameManager.Instance() show_sidepanel = prop.BooleanProperty(True) modestr = prop.StringProperty('insert') itemstr = prop.StringProperty('atom') modes = {'insert': asp.Mode.INSERT, 'select': asp.Mode.SELECT} items = { 'atom': asp.Item.ATOM, 'ellipse': asp.Item.ELLIPSE, 'rectangle': asp.Item.SQUARE } def __init__(self, **kwargs): super(GlobalContainer, self).__init__(**kwargs) self._keyboard = None self.request_keyboard() self.working_dir = './' self.tutorial = None self.popup_stack = [] window.Window.bind(on_resize=self.on_resize) if DEBUG: self.tracker = ClassTracker() self.tracker.track_object(MenuButton) self.all_objects = muppy.get_objects() def request_keyboard(self): self._keyboard = window.Window.request_keyboard( self._keyboard_release, self) self._keyboard.bind(on_key_down=self._on_keyboard_down) def _keyboard_catch(self): self._keyboard.bind(on_key_down=self._on_keyboard_down) def _keyboard_release(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] == 'escape': base.stopTouchApp() elif keycode[1] == 'd': self.set_mode('insert') elif keycode[1] == 's': self.set_mode('select') elif keycode[1] == 'w': self.set_item('atom') elif keycode[1] == 'e': self.set_item('ellipse') elif keycode[1] == 'r': self.set_item('rectangle') elif keycode[1] == 'p': self.active_graph.show_tree(0) elif keycode[1] == 'o': self.view_symbolic_formula() elif keycode[1] == 'n': self.show_gringo_query() elif keycode[1] == 'g': self.show_save() elif keycode[1] == 'l': self.show_load() elif keycode[1] == 'y': print self.name_manager.get_all() print asp.Line.get_all_lines() elif keycode[1] == 't': self.toggle_sidepanel() elif keycode[1] == 'tab': if not self.show_sidepanel: self.toggle_sidepanel() self.ids.atom_input.focus = True elif keycode[1] == '.': if DEBUG: rb = refbrowser.InteractiveBrowser(self) rb.main() # self.all_objects = muppy.get_objects() # sum1 = summary.summarize(self.all_objects) # summary.print_(sum1) # self.tracker.create_snapshot() # self.tracker.stats.print_summary() return True def _focus_name_list(self, value): if value and (asp.AtomWidget.active_atom is not None): previous_name = asp.AtomWidget.active_atom.name for button in self.ids.name_list.children: if (button.text == previous_name) and (button.state != 'down'): button.trigger_action() elif value: if self.ids.name_list.children: self.ids.name_list.children[-1].trigger_action() else: for button in self.ids.name_list.children: if button.state == 'down': button.trigger_action() def on_resize(self, window, width, height): if self.show_sidepanel: self.ids.sidepanel.width = self.width * .15 self.active_graph.size = self.ids.stencilview.size def toggle_sidepanel(self): self.show_sidepanel = not self.show_sidepanel if self.show_sidepanel: width = self.width * .15 else: width = 0 anim.Animation(width=width, d=.15, t='out_quart').start(self.ids.sidepanel) if not self.show_sidepanel: self.ids.sidepanel.focus = False # Also release keyboard #self.update_sourcecode() def update_atom_editor(self, name): editor = self.ids.atom_editor if name == '': editor.disabled = True else: if editor.disabled: editor.disabled = False atom = self.name_manager.get(name) editor.update(atom) def update_atom(self, name, new_name='', new_hook_points=[], is_constant=False): atom = self.name_manager.get(name) if new_name <> '': atom.name = new_name if len(new_hook_points) == 4: atom.hook_points = new_hook_points # print id(atom.hook_points) atom.is_constant = is_constant def register_atom(self, name, hooks=[False, False, False, False], is_constant=False): if name == '': return children = self.ids.name_list.children new_button = None name_to_insert = name i = len(children) - 1 # If the name doesn't exist, register atom if self.name_manager.get(name) is None: self.name_manager.register(name, asp.Atom(name, hooks, is_constant)) # print id(self.name_manager.get(name).hook_points) # Insert in name_list sorted by name while i >= 0: if children[i].text < name_to_insert: #print children[i].text, '<', name_to_insert pass elif children[i].text == name_to_insert: # Already exists if children[i].state != 'down': children[i].trigger_action() return elif children[i].text > name_to_insert: #print children[i].text, '>', name_to_insert temp = children[i].text children[i].text = name_to_insert name_to_insert = temp if new_button == None: new_button = children[i] i -= 1 self.ids.name_list.add_widget(AtomSelectionButton(text=name_to_insert)) if new_button == None: new_button = children[0] if new_button.state == 'down': asp.AtomWidget.active_atom = self.name_manager.get(name) self.update_atom_editor(name) self.set_item('atom') else: new_button.trigger_action() def rename_atom(self, new_name): old_name = '' for button in self.ids.name_list.children: if button.state == 'down': old_name = button.text selected_button = button if (old_name != '') and (new_name != ''): try: atom = self.name_manager.get(old_name) exists = self.name_manager.get(new_name) assert atom is not None assert exists is None except AssertionError: #self.show_error('Name already exists.') print 'Name already exists.' return selected_button.text = new_name atom.name = new_name self.name_manager.unregister(old_name) self.name_manager.register(new_name, atom) self.update_atom_editor(new_name) def delete_atom(self): for button in self.ids.name_list.children: if button.state == 'down': self.name_manager.unregister(button.text) self.active_graph.delete_atom(button.text) asp.AtomWidget.active_atom = None self.ids.name_list.remove_widget(button) self.update_atom_editor('') def clear_atoms(self): self.ids.name_list.clear_widgets() self.name_manager.clear() self.update_atom_editor('') asp.AtomWidget.active_atom = None def new_graph(self): # TODO: Migrate to tab system asp.Line.clear_lines() self.clear_atoms() if self.active_graph is None: g = asp.RootWidget() self.graph_list.append(g) self.active_graph = g self.ids.stencilview.add_widget(g) else: self.active_graph.delete_tree() def close_graph(self): if self.active_graph is not None: asp.Line.clear_lines() self.active_graph.delete_tree() self.active_graph.delete_root() self.clear_atoms() self.graph_list.pop() self.active_graph = None def set_mode(self, mode): try: prev_mode = self.active_graph.mode new_mode = self.modes[mode] if new_mode == asp.Mode.INSERT: self.active_graph.show_hooks() else: if prev_mode == asp.Mode.INSERT: self.active_graph.hide_hooks() self.active_graph.mode = new_mode self.modestr = mode except KeyError as err: print 'ERROR: Invalid mode {0} requested.'.format(str(err)) def set_item(self, item): try: self.active_graph.item = self.items[item] self.itemstr = item except KeyError as err: print 'ERROR: Invalid item {0} requested.'.format(str(err)) except AttributeError: pass if item == 'atom': self._focus_name_list(True) else: self._focus_name_list(False) def push_popup(self, popup): self.popup_stack.append(popup) popup.open() def dismiss_popup(self): popup = self.popup_stack.pop() popup.dismiss() def show_rename_atom(self): content = TextInputDialog(caption="Enter new name", validate_callback=self.rename_atom, cancel=self.dismiss_popup) p = CustomPopup(self, title="Rename atom", content=content, size_hint=(0.4, 0.25)) self.push_popup(p) def show_load(self): content = LoadDialog(load=self.load, cancel=self.dismiss_popup) content.ids.filechooser.path = self.working_dir p = CustomPopup(self, title="Load file", content=content, size_hint=(0.9, 0.9)) self.push_popup(p) def show_save(self): content = SaveDialog(save=self.save, cancel=self.dismiss_popup) content.ids.filechooser.path = self.working_dir p = CustomPopup(self, title="Save file", content=content, size_hint=(0.9, 0.9)) self.push_popup(p) def show_export(self): content = ExportDialog(export=self.export, cancel=self.dismiss_popup) content.ids.filechooser.path = self.working_dir p = CustomPopup(self, title="Export file", content=content, size_hint=(0.9, 0.9)) self.push_popup(p) def show_gringo_query(self): caption = "Enter desired predicates separated by commas" content = TextInputDialog(caption=caption, validate_callback=self.gringo_query, dismiss_on_validate=False, focus=False, cancel=self.dismiss_popup) p = CustomPopup(self, title="Output predicates", content=content, size_hint=(0.4, 0.25)) self.push_popup(p) def show_stable_models(self, solver): models = solver.get_models() content = None if len(models) == 0: content = ErrorDialog('Unsatisfiable', cancel=self.dismiss_popup) else: solver.generate_graph(models[0]) content = StableModelDialog(solver, cancel=self.dismiss_popup) content.ids.img.reload() p = CustomPopup(self, catch_keyboard=False, title="Stable Models", content=content, size_hint=(0.9, 0.9)) self.push_popup(p) def show_error(self, err_str): content = ErrorDialog(err_str, cancel=self.dismiss_popup) p = CustomPopup(self, catch_keyboard=False, title="Error", content=content, size_hint=(0.4, 0.3)) self.push_popup(p) def show_about(self): content = AboutDialog(cancel=self.dismiss_popup) p = CustomPopup(self, catch_keyboard=False, title="About " + __title__, content=content, size_hint=(0.5, 0.5)) self.push_popup(p) def load(self, path, filename): self.close_graph() self.working_dir = path try: f = os.path.join(path, filename[0]) # Temporal line storage. Its contents are arranged as follows: # { line_id: (graph, hook_list) , ... } lines = {} with open(f, 'r') as stream: for line in stream: if line.startswith(NameParser.TOKENS['name']): name, hooks, is_constant = NameParser.parse_name(line) self.register_atom(name, hooks, is_constant) if line.startswith(NameParser.TOKENS['line']): line_id, graph = NameParser.parse_line(line) lines[line_id] = (graph, [None] * len(graph)) new_graph = lang.Builder.load_file(f) self.ids.stencilview.add_widget(new_graph) self.active_graph = new_graph #self.graph_list.pop() self.graph_list.append(new_graph) for w in self.active_graph.walk(restrict=True): if isinstance(w, asp.AtomWidget): w._deferred_init() for i in w.get_line_info(): line_id = i[0] hook_index = i[1] lines[line_id][1][hook_index] = i[2] elif isinstance(w, asp.NexusWidget): for i in w.line_info: line_id = i[0] hook_index = i[1] lines[line_id][1][hook_index] = w for line, info in lines.iteritems(): print line, info asp.Line.build_from_graph(info[0], info[1]) self.set_mode(self.modestr) self.set_item(self.itemstr) self.dismiss_popup() except (KeyboardInterrupt, SystemExit): raise except: self.dismiss_popup() self.close_graph() self.new_graph() self.show_error('Corrupted file.') def save(self, path, filename): self.working_dir = path with open(os.path.join(path, filename), 'w') as stream: stream.write('#:kivy 1.0.9\n\n') for (name, atom) in self.name_manager.get_all(): stream.write( NameParser.get_name_str(name, atom.hook_points, atom.is_constant)) for line in asp.Line.get_all_lines(): stream.write( NameParser.get_line_str(line.line_id, line.get_full_graph())) stream.write('\n') stream.write(self.active_graph.get_tree(0)) self.dismiss_popup() def export(self, path, filename): _, ext = os.path.splitext(filename) if ext == '.png': self.active_graph.export_to_png(os.path.join(path, filename)) elif ext == '.lp': rpn = self.active_graph.get_formula_RPN() constants = self.active_graph.get_constants() solver = eg_solver.Solver() solver.set_formula(rpn, constants) rules = solver.generate_asp_rules() with open(os.path.join(path, filename), 'w') as stream: for r in rules: stream.write(r) stream.write('\n') else: error_str = 'File extension not supported.' print error_str self.show_error(error_str) return self.dismiss_popup() def highlight_variables(self): self.active_graph.highlight_variables() def view_symbolic_formula(self): print self.active_graph.get_formula() def gringo_query(self, show_predicates): def generate_show_statements(predicates): pred_list = predicates.split(',') pred_list = map(lambda s: s.strip(), pred_list) n_args = (lambda name: self.name_manager.get(name).hook_points. count(True)) pred_list = [p + '/' + str(n_args(p)) for p in pred_list] show_list = ['#show {0}.'.format(p) for p in pred_list] return show_list self.dismiss_popup() rpn = self.active_graph.get_formula_RPN() rpn = norm.LIT.TRUE if rpn == '' else rpn constants = self.active_graph.get_constants() print 80 * '-' print 'RPN formula:\n', rpn solver = eg_solver.Solver() result = '' try: show_statements = [] if show_predicates: try: show_statements = generate_show_statements(show_predicates) except Exception: pass solver.set_formula(rpn, constants) result = solver.solve(show=show_statements) except norm.MalformedFormulaError: self.show_error('Malformed formula.') return except RuntimeError, e: print e self.show_error(str(e)) return self.show_stable_models(solver)