def test_listproperty_is_none(): from kivy.properties import ListProperty l1 = ListProperty(None) l1.link(wid, 'l1') assert l1.get(wid) is None l2 = ListProperty([1, 2, 3], allownone=True) l2.link(wid, 'l2') l2.set(wid, None) assert l2.get(wid) is None
def test_listcheck(self): from kivy.properties import ListProperty a = ListProperty() a.link(wid, 'a') a.link_deps(wid, 'a') self.assertEqual(a.get(wid), []) a.set(wid, [1, 2, 3]) self.assertEqual(a.get(wid), [1, 2, 3])
def __init__(self, NuBippyApp, **kwargs): super(PrivateKeyScreen, self).__init__(**kwargs) self.NuBippyApp = NuBippyApp self.passphrase = StringProperty() self.privateKey = StringProperty() self.entropy = ListProperty() self.newKey = BooleanProperty(False) self.isCompressed = True self.isBip = BooleanProperty(False) self.type = False self.prog_string = None # Link to the widgets # New Key page self.mainLayoutNK = self.ids.mainLayoutNK.__self__ self.newKeyAccordionItem = self.ids.newKeyAccordionItem.__self__ self.mainLabelNK = self.ids.mainLabelNK.__self__ self.passfieldLabelNK = self.ids.passfieldLabelNK.__self__ self.passfieldNK = self.ids.passfieldNK.__self__ self.feedbackNK = self.ids.feedbackNK.__self__ self.checkfieldLabelNK = self.ids.checkfieldLabelNK.__self__ self.checkfieldNK = self.ids.checkfieldNK.__self__ self.submitButtonNK = self.ids.submitButtonNK.__self__ self.encryptButtonNK = self.ids.encryptButtonNK.__self__ self.progressBarNK = self.ids.progressBarNK.__self__ self.image = self.ids.image.__self__ #Existing key page self.mainLayoutEK = self.ids.mainLayoutEK.__self__ self.existingKeyAccordionItem = self.ids.existingKeyAccordionItem.__self__ self.mainLabelEK = self.ids.mainLabelEK.__self__ self.privateKeyLabelEK = self.ids.privateKeyLabelEK.__self__ self.privateKeyInputEK = self.ids.privateKeyInputEK.__self__ self.passfieldLabelEK = self.ids.passfieldLabelEK.__self__ self.passfieldEK = self.ids.passfieldEK.__self__ self.feedbackEK = self.ids.feedbackEK.__self__ self.checkfieldLabelEK = self.ids.checkfieldLabelEK.__self__ self.checkfieldEK = self.ids.checkfieldEK.__self__ self.submitButtonEK = self.ids.submitButtonEK.__self__ self.actionButtonEK = self.ids.actionButtonEK.__self__ #remove the widgets that need adding after certain actions. #New Key Page self.mainLayoutNK.remove_widget(self.submitButtonNK) self.mainLayoutNK.remove_widget(self.encryptButtonNK) self.mainLayoutNK.remove_widget(self.progressBarNK) #Existing Key Page self.mainLayoutEK.remove_widget(self.passfieldLabelEK) self.mainLayoutEK.remove_widget(self.passfieldEK) self.mainLayoutEK.remove_widget(self.feedbackEK) self.mainLayoutEK.remove_widget(self.checkfieldLabelEK) self.mainLayoutEK.remove_widget(self.checkfieldEK) self.mainLayoutEK.remove_widget(self.actionButtonEK) self.NuBippyApp.set_info('Private Key') return
class Collection(EventDispatcher): games = ListProperty([]) lazy_games = ListProperty([]) name = StringProperty('Collection') defaultdir = StringProperty('./games/unsaved') lazy_loaded = BooleanProperty(False) finished_loading = BooleanProperty(False) def __init__(self, *args, **kwargs): if platform() == 'android': self.defaultdir = '/sdcard/noGo/collections/unsaved' super(Collection, self).__init__(*args, **kwargs) def __str__(self): return 'SGF collection {0} with {1} games'.format( self.name, self.number_of_games()) def __repr__(self): return self.__str__() def remove_sgf(self, sgf): self.finish_lazy_loading() if sgf in self.games: self.games.remove(sgf) def get_default_dir(self): return '.' + '/' + self.name def number_of_games(self): if not self.finished_loading: return len(self.lazy_games) else: return len(self.games) def lazy_from_list(self, l): name, defaultdir, games = l self.name = name self.defaultdir = defaultdir self.lazy_games = games self.lazy_loaded = True self.finished_loading = False return self def finish_lazy_loading(self): print 'Finishing lazy loading' if not self.finished_loading and self.lazy_loaded: print 'need to load', len(self.lazy_games) for game in self.lazy_games: print 'currently doing', game try: colsgf = CollectionSgf(collection=self).load(game) self.games.append(colsgf) except IOError: print '(lazy) Tried to load sgf that doesn\'t seem to exist. Skipping.' print 'game was', game self.lazy_games = [] self.finished_loading = True def from_list(self, l): name, defaultdir, games = l self.name = name self.defaultdir = defaultdir for game in games: try: print 'finish loading', game colsgf = CollectionSgf(collection=self).load(game) self.games.append(colsgf) except IOError: print 'Tried to load sgf that doesn\'t seem to exist. Skipping.' print 'game was', game #self.games = map(lambda j: CollectionSgf(collection=self).load(j),games) return self def as_list(self): self.finish_lazy_loading() return [ self.name, self.defaultdir, map(lambda j: j.get_filen(), self.games) ] def serialise(self): self.finish_lazy_loading() return json.dumps([SERIALISATION_VERSION, self.as_list()]) def save(self): self.finish_lazy_loading() if platform() == 'android': filen = '/sdcard/noGo/' + self.name + '.json' else: filen = '.' + '/collections/' + self.name + '.json' with open(filen, 'w') as fileh: fileh.write(self.serialise()) return filen def get_filen(self): filen = '.' + '/collections/' + self.name + '.json' return filen def from_file(self, filen): # print 'Trying to load collection from',filen with open(filen, 'r') as fileh: jsonstr = fileh.read() #print 'File contents are',jsonstr version, selflist = json.loads(jsonstr) selflist = jsonconvert(selflist) return self.lazy_from_list(selflist) def add_game(self, can_change_name=True): self.finish_lazy_loading() game = CollectionSgf(collection=self, can_change_name=can_change_name) game.filen = game.get_default_filen() + '.sgf' self.games.append(game) self.save() return game def random_sgf(self): self.finish_lazy_loading() return random.choice(self.games)
class Wrap(Label): '''A white label with automatically wrapped text. .. versionadded:: 0.3.2 ''' background_color = ListProperty([0, 0, 0, 0])
class BaoGame(BoxLayout): stone_locations = ObjectProperty(None) turn_no = NumericProperty(0) scores = ListProperty(None) curr_player = NumericProperty(None) def __init__(self, **kwargs): super(BaoGame, self).__init__(**kwargs) self.engine = Bao.Game() self.link_pits() self.init_stones() def move_stones(self, inst, value): sl = [ s.kivy_obj for s in self.engine.stones if s.pit == inst.pit_obj.id ] for s in sl: my_pos = self.pos_to_coords(s.stone_obj.position, inst) s.x = my_pos[0] s.y = my_pos[1] def pos_to_coords(self, pos, obj, rows=4, cols=4): '''given a position (integer), compute its coordinates inside the supplied `obj`''' if obj.pit_obj.target: rows = 12 x_coord = pos % cols y_coord = pos // cols y_off = obj.height / rows * y_coord x_off = obj.width / cols * x_coord return (obj.x + x_off, obj.y + y_off) def init_stones(self): '''put the stones somewhere. Initially, half in one target, half in the other''' for stone in self.engine.stones: target_pit = self.engine.pits[self.engine.targets[stone.id % 2 + 1]] target_pit.add(stone) my_pos = self.pos_to_coords(stone.position, target_pit.kivy_obj) sz = (target_pit.kivy_obj.width / 3, target_pit.kivy_obj.width / 3) stone.kivy_obj = Stone(size_hint=(None, None), size=sz, pos=my_pos) stone.kivy_obj.color = get_color_from_hex(stone.color) stone.kivy_obj.stone_obj = stone target_pit.kivy_obj.contents.add_widget(stone.kivy_obj) def link_pits(self): for c in self.board_overlay.children: if type(c) is GridLayout: for c2 in c.children: if type(c2) is Pit: c2.board = self c2.pit_obj = self.engine.pits[c2.pit_id] self.engine.pits[c2.pit_id].kivy_obj = c2 c2.bind(pos=self.move_stones, size=self.move_stones) Logger.debug('Link Pits: linked pit {} to {}'.format( c2.pit_id, c2.pit_obj)) def animate_stones(self, stone_list): for stone in stone_list: my_pit = self.engine.pits[stone.pit].kivy_obj my_pos = self.pos_to_coords(stone.position, my_pit) anim = Animation(x=my_pos[0], y=my_pos[1], d=0.5) anim.start(stone.kivy_obj) def on_stone_locations(self, inst, value): '''Update the stones by animating them to their final location''' self.animate_stones(value) def start_game(self): '''Do the initial sow (place) to start a game''' self.engine.initial_place() self.toolbar.start_button.disabled = True self.stone_locations = self.engine.stones[:]
class Mark(Widget): """Marks specific point in time. Should be a child of a BaseTimeline""" timeline = ObjectProperty() LABEL_LEFT = "left" LABEL_CENTER = "center" LABEL_MID_INTERVAL = "mid_interval" LABEL_RIGHT = "right" # fmt: off _label_alignments = [ LABEL_LEFT, LABEL_CENTER, LABEL_MID_INTERVAL, LABEL_RIGHT ] # fmt: on label_align = OptionProperty(LABEL_LEFT, options=_label_alignments) label_padding_x = NumericProperty("2sp") label_padding_y = NumericProperty("2sp") label_y = NumericProperty(None, allownone=True) font_size = BoundedNumericProperty(sp(12), min=sp(12)) has_label = BooleanProperty(True) max_label_width = NumericProperty() mark = ObjectProperty(Rectangle) mark_y = NumericProperty() mark_width = NumericProperty("2sp") mark_height = NumericProperty("100sp") mark_color = ObjectProperty(Color([250 / 255] * 3)) interval = ListProperty() interval_width = NumericProperty(allownone=True) force_visible = BooleanProperty(False) def draw_marks(self, *_, mark_ods: list = None) -> list: """:raises AssertionError: when 2 marks should be visible but aren't""" def make_mark_x() -> tuple[float, list, list]: """:return: current mark x, all mark x's, all visible mark x's""" x = self.timeline.od_to_x(mark_od) mark_xs.append(x) if self.timeline.x <= x <= self.timeline.right: visible_mark_xs.append(x) return x, mark_xs, visible_mark_xs def add_mark_to_canvas(): pos = sp(mark_x), sp(self.mark_y) size = sp(self.mark_width), sp(self.mark_height) self.canvas.add(self.mark(pos=pos, size=size)) def add_label_to_canvas(alignment=None, location: str = None): alignment = alignment or self.label_align hr_date = tl.cdt.od_to_hr_date(mark_od, unit) label = self.make_label(mark_x, hr_date, alignment) if ( location == "left" and label.right >= mid_mark_x - self.label_padding_x ): label.right = mid_mark_x - self.label_padding_x elif ( location == "right" and label.x <= mid_mark_x + self.mark_width + self.label_padding_x ): label.x = mid_mark_x + self.mark_width + self.label_padding_x self.canvas.add( Rectangle( pos=label.pos, size=label.texture_size, texture=label.texture, ) ) self.canvas.clear() self.canvas.add(self.mark_color) mark_xs = [] visible_mark_xs = [] tl = self.timeline unit = self.interval[1] if mark_ods: # skip expensive ordinal calculations if we can for mark_od in mark_ods: mark_x, mark_xs, visible_mark_xs = make_mark_x() elif tl.cdt.is_datetime_unit(unit, "era"): mark_ods = tl.cdt.era_start_ordinals else: # extend_od() widens time span without considering the interval # so the first mark_od needs to be set with next_od() mark_od = tl.cdt.next_od( tl.extended_start_od, self.interval, forward=False ) mark_ods = [mark_od] while mark_od <= tl.extended_end_od: mark_x, mark_xs, visible_mark_xs = make_mark_x() mark_od = tl.cdt.next_od(mark_od, self.interval) mark_ods.append(mark_od) # interval_width is only valid if there are at least two visible marks force_visible = self.force_visible interval_width = float(numpy.diff(visible_mark_xs).mean()) if numpy.isnan(interval_width): if not force_visible: raise RuntimeError("Must be at least 2 visible marks") self.interval_width = None else: self.interval_width = interval_width if force_visible and self.interval_width is None and self.has_label: # force labels to be visible if there are less than 2 visible marks off_screen_mark_od = tl.cdt.next_od( tl.start_od, self.interval, forward=False ) off_screen_mark_x = tl.od_to_x(off_screen_mark_od) mid_mark_od = tl.cdt.next_od(tl.start_od, self.interval) mid_mark_x = tl.od_to_x(mid_mark_od) # may still be off screen mark_ods = [off_screen_mark_od, mid_mark_od] mark_xs = [off_screen_mark_x, mid_mark_x] for idx, mark_x in enumerate(mark_xs): # the marks without labels mark_od = mark_ods[idx] add_mark_to_canvas() marks_drawn = True mark_ods = [tl.start_od, tl.end_od] mark_xs = [tl.x, tl.right] # really should be called label pos alignments = [self.LABEL_LEFT, self.LABEL_RIGHT] pin_locations = "left", "right" else: marks_drawn = False alignments = None pin_locations = None for idx, mark_x in enumerate(mark_xs): mark_od = mark_ods[idx] if not marks_drawn: add_mark_to_canvas() if not self.has_label: continue try: label_align = alignments[idx] pin_location = pin_locations[idx] except TypeError: add_label_to_canvas() else: add_label_to_canvas(label_align, pin_location) return mark_ods def make_label(self, x: int, text: str, alignment: str) -> TextBoundLabel: """:raises: ValueError if alignment is isn't a valid option""" if alignment not in self._label_alignments: raise ValueError(f"{alignment} is not in a valid label alignment") label = TextBoundLabel(text=text, font_size=self.font_size) label.texture_update() if label.width > self.max_label_width: self.max_label_width = label.width + (2 * self.label_padding_x) if alignment == self.LABEL_LEFT: label.x = sp(x + self.label_padding_x) elif alignment == self.LABEL_CENTER: label.center_x = sp(x) elif alignment == self.LABEL_MID_INTERVAL: label.center_x = sp(x + (self.interval_width / 2)) else: # right alignment label.right = x - self.label_padding_x if self.label_y is None: label.top = self.top - self.label_padding_y else: label.y = self.label_y return label
class ADialog(Dialog): logo_program = StringProperty('data/logo/kivy-icon-24.png') '''Логотип приложения. :attr:` logo_program` is a :class:`~kivy.properties.StringProperty` and defaults to 'data/logo/kivy-icon-24.png'. ''' name_program = StringProperty('Kivy 1.9.2') '''Название приложения. :attr:` name_program` is a :class:`~kivy.properties.StringProperty` and defaults to 'Kivy 1.9.2'. ''' user_size_hint = ListProperty((.95, .85)) '''Размер окна :attr: `user_size_hint` is a :class:`~kivy.properties.ListProperty` and defaults to [.95, .85]. ''' info_program = ListProperty([]) Builder.load_file('{}/kv/adialog.kv'.format(Dialog.root)) def __init__(self, **kvargs): super(ADialog, self).__init__(**kvargs) content = self.ids.content box_content = self.ids.box_content height, avatar_size_hint = (self.dp(60), (.05, .9)) self.ids.logo.size_hint = avatar_size_hint self.ids.box_logo_and_title.height = height # Текстовая информация. for info_string in self.info_program: if info_string == '': content.add_widget(SettingSpacer()) continue info_string = \ Label(text=info_string, size_hint_y=None, font_size=self.dp(self.base_font_size), markup=True, on_ref_press=self.events_callback) info_string.bind(size=lambda *args: self._update_label_size(args)) content.add_widget(info_string) self.content = box_content self.size_hint = (self.user_size_hint[0], self.user_size_hint[1]) self.open() def _update_label_size(self, *args): label = args[0][0] if label.id == 'name_program': if not self.flag: label.height = self.dp(52) else: label.height = self.dp(label.texture_size[1] - 8) label.text_size = (self.dp(label.width - 30), None) label.texture_update()
class Text(Widget): """A text widget on a slide.""" widget_type_name = 'Text' merge_settings = ('font_name', 'font_size', 'bold', 'italic', 'halign', 'valign', 'padding_x', 'padding_y', 'text_size', 'shorten', 'mipmap', 'markup', 'line_height', 'max_lines', 'strip', 'shorten_from', 'split_str', 'unicode_errors', 'color', 'casing') animation_properties = ('x', 'y', 'font_size', 'color', 'opacity', 'rotation', 'scale') def __init__(self, mc: "MpfMc", config: dict, key: Optional[str] = None, play_kwargs: Optional[dict] = None, **kwargs) -> None: if 'bitmap_font' in config and config['bitmap_font']: if 'font_name' not in config or not config['font_name']: raise ValueError( "Text widget: font_name is required when bitmap_font is True." ) self._label = BitmapFontLabel(mc, config['font_name']) else: self._label = McFontLabel() self._label.fbind('texture', self.on_label_texture) super().__init__(mc=mc, config=config, key=key) # Special handling for baseline anchor if self.config['anchor_y'] == 'baseline': self.anchor_y = 'bottom' self.adjust_bottom = self._label.get_label().get_descent() * -1 self.original_text = self._get_text_string(config.get('text', '')) self.text_variables = dict() if play_kwargs: self.event_replacements = play_kwargs else: self.event_replacements = kwargs self._process_text(self.original_text) # Bind to all properties that when changed need to force # the widget to be redrawn self.bind(pos=self._draw_widget, size=self._draw_widget, color=self._draw_widget, rotation=self._draw_widget, scale=self._draw_widget) def __repr__(self) -> str: if hasattr(self, '_label') and self._label: return '<Text Widget text={}>'.format(self._label.text) else: return '<Text Widget text=None>' def _draw_widget(self, *args): """Draws the image (draws a rectangle using the image texture)""" del args self.canvas.clear() # Redrawing the widget doesn't reposition, so update manually anchor = (self.x - self.anchor_offset_pos[0], self.y - self.anchor_offset_pos[1]) # Save the updated position as a new variable, such that consecutive text # changes don't introduce gradual shifts in position. pos = self.calculate_rounded_position(anchor) if self._label.text: with self.canvas: Color(*self.color) Rotate(angle=self.rotation, origin=anchor) Scale(self.scale).origin = anchor Rectangle(pos=pos, size=self.size, texture=self._label.texture) def on_label_texture(self, instance, texture): del instance if texture: self.size = texture.size if self.config['anchor_y'] == 'baseline': self.adjust_bottom = self._label.get_label().get_descent() * -1 def update_kwargs(self, **kwargs) -> None: self.event_replacements.update(kwargs) self._process_text(self.original_text) def _get_text_string(self, text: str) -> str: if '$' not in text: return text for text_string in string_finder.findall(text): text = text.replace('${}'.format(text_string), self._do_get_text_string(text_string)) return text def _do_get_text_string(self, text_string: str) -> str: try: return str(self.mc.machine_config['text_strings'][text_string]) except KeyError: # if the text string is not found, put the $ back on return '${}'.format(text_string) @staticmethod def _get_text_vars(text: str): return var_finder.findall(text) def _process_text(self, text: str) -> None: for var_string in self._get_text_vars(text): if var_string in self.event_replacements: text = text.replace('({})'.format(var_string), str(self.event_replacements[var_string])) if self._get_text_vars(text): # monitors won't be added twice, so it's ok to blindly call this self._setup_variable_monitors(text) self.update_vars_in_text(text) def update_vars_in_text(self, text: str) -> None: for var_string in self._get_text_vars(text): if var_string.startswith('machine|'): try: text = text.replace( '(' + var_string + ')', str(self.mc.machine_vars[var_string.split('|')[1]])) except KeyError: text = text.replace('(' + var_string + ')', '') elif self.mc.player: if var_string.startswith('player|'): text = text.replace( '(' + var_string + ')', str(self.mc.player[var_string.split('|')[1]])) continue elif var_string.startswith('player') and '|' in var_string: player_num, var_name = var_string.lstrip('player').split( '|') try: value = self.mc.player_list[int(player_num) - 1][var_name] if value is not None: text = text.replace('(' + var_string + ')', str(value)) else: text = text.replace('(' + var_string + ')', '') except IndexError: text = text.replace('(' + var_string + ')', '') continue elif self.mc.player.is_player_var(var_string): text = text.replace('(' + var_string + ')', str(self.mc.player[var_string])) continue if var_string in self.event_replacements: text = text.replace('({})'.format(var_string), str(self.event_replacements[var_string])) self.update_text(text) def update_text(self, text: str) -> None: if text: if self.config['min_digits']: text = text.zfill(self.config['min_digits']) if self.config['number_grouping']: # find the numbers in the string number_list = [s for s in text.split() if s.isdigit()] # group the numbers and replace them in the string for item in number_list: grouped_item = Text.group_digits(item) text = text.replace(str(item), grouped_item) if self.config.get('casing', None) in ('lower', 'upper', 'title', 'capitalize'): text = getattr(text, self.config['casing'])() self._label.text = text self._label.texture_update() def _player_var_change(self, **kwargs) -> None: del kwargs self.update_vars_in_text(self.original_text) def _machine_var_change(self, **kwargs) -> None: del kwargs self.update_vars_in_text(self.original_text) def _setup_variable_monitors(self, text: str) -> None: for var_string in self._get_text_vars(text): if '|' not in var_string: self.add_player_var_handler(name=var_string) self.add_current_player_handler() else: source, variable_name = var_string.split('|') if source.lower().startswith('player'): if source.lstrip('player'): # we have player num self.add_player_var_handler(name=variable_name) else: # no player num self.add_player_var_handler(name=variable_name) self.add_current_player_handler() elif source.lower() == 'machine': self.add_machine_var_handler(name=variable_name) def add_player_var_handler(self, name: str) -> None: self.mc.events.add_handler('player_{}'.format(name), self._player_var_change) def add_current_player_handler(self) -> None: self.mc.events.add_handler('player_turn_start', self._player_var_change) def add_machine_var_handler(self, name: str) -> None: self.mc.events.add_handler('machine_var_{}'.format(name), self._machine_var_change) def prepare_for_removal(self) -> None: super().prepare_for_removal() self.mc.events.remove_handler(self._player_var_change) self.mc.events.remove_handler(self._machine_var_change) @staticmethod def group_digits(text: str, separator: str = ',', group_size: int = 3) -> str: """Enable digit grouping (i.e. adds comma separators between thousands digits). Args: text: The incoming string of text separator: String of the character(s) you'd like to add between the digit groups. Default is a comma. (",") group_size: How many digits you want in each group. Default is 3. Returns: A string with the separator added. MPF uses this method instead of the Python locale settings because the locale settings are a mess. They're set system-wide and it's really hard to make them work cross-platform and there are all sorts of external dependencies, so this is just way easier. """ digit_list = list(text.split('.')[0]) for i in range(len(digit_list))[::-group_size][1:]: digit_list.insert(i + 1, separator) return ''.join(digit_list) # # Properties # disabled_color = ListProperty([1, 1, 1, .3]) '''The color of the text when the widget is disabled, in the (r, g, b, a) format. .. versionadded:: 1.8.0 :attr:`disabled_color` is a :class:`~kivy.properties.ListProperty` and defaults to [1, 1, 1, .3]. ''' def _get_text(self) -> str: return self._label.text def _set_text(self, text: str) -> None: self._label.text = text text = AliasProperty(_get_text, _set_text) '''Text of the label. ''' def _get_text_size(self) -> list: return self._label.text_size def _set_text_size(self, text_size: list) -> None: self._label.text_size = text_size text_size = AliasProperty(_get_text_size, _set_text_size) '''By default, the label is not constrained to any bounding box. You can set the size constraint of the label with this property. The text will autoflow into the constraints. So although the font size will not be reduced, the text will be arranged to fit into the box as best as possible, with any text still outside the box clipped. This sets and clips :attr:`texture_size` to text_size if not None. .. versionadded:: 1.0.4 For example, whatever your current widget size is, if you want the label to be created in a box with width=200 and unlimited height:: Label(text='Very big big line', text_size=(200, None)) .. note:: This text_size property is the same as the :attr:`~kivy.core.text.Label.usersize` property in the :class:`~kivy.core.text.Label` class. (It is named size= in the constructor.) :attr:`text_size` is a :class:`~kivy.properties.ListProperty` and defaults to (None, None), meaning no size restriction by default. ''' def _get_font_name(self) -> str: return self._label.font_name def _set_font_name(self, font_name: str) -> None: self._label.font_name = font_name font_name = AliasProperty(_get_font_name, _set_font_name) '''Filename of the font to use. The path can be absolute or relative. Relative paths are resolved by the :func:`~kivy.resources.resource_find` function. .. warning:: Depending of your text provider, the font file can be ignored. However, you can mostly use this without problems. If the font used lacks the glyphs for the particular language/symbols you are using, you will see '[]' blank box characters instead of the actual glyphs. The solution is to use a font that has the glyphs you need to display. For example, to display |unicodechar|, use a font such as freesans.ttf that has the glyph. .. |unicodechar| image:: images/unicode-char.png :attr:`font_name` is a :class:`~kivy.properties.StringProperty` and defaults to 'Roboto'. This value is taken from :class:`~kivy.config.Config`. ''' def _get_font_size(self): return self._label.font_size def _set_font_size(self, font_size) -> None: self._label.font_size = font_size font_size = AliasProperty(_get_font_size, _set_font_size) '''Font size of the text, in pixels. :attr:`font_size` is a :class:`~kivy.properties.NumericProperty` and defaults to 15sp. ''' def _get_line_height(self) -> float: return self._label.line_height def _set_line_height(self, line_height: float) -> None: self._label.line_height = line_height bitmap_font = BooleanProperty(False) '''Flag indicating whether or not the font_name attribute refers to a bitmap font.''' line_height = AliasProperty(_get_line_height, _set_line_height) '''Line Height for the text. e.g. line_height = 2 will cause the spacing between lines to be twice the size. :attr:`line_height` is a :class:`~kivy.properties.NumericProperty` and defaults to 1.0. .. versionadded:: 1.5.0 ''' def _get_bold(self) -> bool: return self._label.bold def _set_bold(self, bold: bool) -> None: self._label.bold = bold bold = AliasProperty(_get_bold, _set_bold) '''Indicates use of the bold version of your font. .. note:: Depending of your font, the bold attribute may have no impact on your text rendering. :attr:`bold` is a :class:`~kivy.properties.BooleanProperty` and defaults to False. ''' def _get_italic(self) -> bool: return self._label.italic def _set_italic(self, italic: bool) -> None: self._label.italic = italic italic = AliasProperty(_get_italic, _set_italic) '''Indicates use of the italic version of your font. .. note:: Depending of your font, the italic attribute may have no impact on your text rendering. :attr:`italic` is a :class:`~kivy.properties.BooleanProperty` and defaults to False. ''' def _get_underline(self) -> bool: return self._label.underline def _set_underline(self, underline: bool) -> None: self._label.underline = underline underline = AliasProperty(_get_underline, _set_underline) '''Adds an underline to the text. .. note:: This feature requires the SDL2 text provider. .. versionadded:: 1.10.0 :attr:`underline` is a :class:`~kivy.properties.BooleanProperty` and defaults to False. ''' def _get_strikethrough(self) -> bool: return self._label.strikethrough def _set_strikethrough(self, strikethrough: bool) -> None: self._label.strikethrough = strikethrough strikethrough = AliasProperty(_get_strikethrough, _set_strikethrough) '''Adds a strikethrough line to the text. .. note:: This feature requires the SDL2 text provider. ''' def _get_padding_x(self): return self._label.padding_x def _set_padding_x(self, padding_x): self._label.padding_x = padding_x padding_x = AliasProperty(_get_padding_x, _set_padding_x) '''Horizontal padding of the text inside the widget box. ''' def _get_padding_y(self): return self._label.padding_y def _set_padding_y(self, padding_y): self._label.padding_y = padding_y padding_y = AliasProperty(_get_padding_y, _set_padding_y) '''Vertical padding of the text inside the widget box. ''' padding = ReferenceListProperty(padding_x, padding_y) '''Padding of the text in the format (padding_x, padding_y) :attr:`padding` is a :class:`~kivy.properties.ReferenceListProperty` of (:attr:`padding_x`, :attr:`padding_y`) properties. ''' def _get_halign(self) -> str: return self._label.halign def _set_halign(self, halign: str) -> None: self._label.halign = halign halign = AliasProperty(_get_halign, _set_halign) '''Horizontal alignment of the text. Available options are : left, center, right and justify. .. warning:: This doesn't change the position of the text texture of the Label (centered), only the position of the text in this texture. You probably want to bind the size of the Label to the :attr:`texture_size` or set a :attr:`text_size`. ''' def _get_valign(self) -> str: return self._label.valign def _set_valign(self, valign: str) -> None: self._label.valign = valign valign = AliasProperty(_get_valign, _set_valign) '''Vertical alignment of the text. Available options are : `'bottom'`, `'middle'` (or `'center'`) and `'top'`. .. warning:: This doesn't change the position of the text texture of the Label (centered), only the position of the text within this texture. You probably want to bind the size of the Label to the :attr:`texture_size` or set a :attr:`text_size` to change this behavior. ''' def _get_outline_width(self) -> Optional[int]: return self._label.outline_width def _set_outline_width(self, outline_width: Optional[int]) -> None: self._label.outline_width = outline_width outline_width = AliasProperty(_get_outline_width, _set_outline_width) '''Width in pixels for the outline around the text. No outline will be rendered if the value is None. .. note:: This feature requires the SDL2 text provider. ''' def _get_outline_color(self) -> list: return self._label.outline_color def _set_outline_color(self, outline_color: list) -> None: self._label.outline_color = outline_color outline_color = AliasProperty(_get_outline_color, _set_outline_color) '''The color of the text outline, in the (r, g, b) format. .. note:: This feature requires the SDL2 text provider. ''' def _get_disabled_outline_color(self) -> list: return self._label.disabled_outline_color def _set_disabled_outline_color(self, disabled_outline_color: list) -> None: self._label.disabled_outline_color = disabled_outline_color disabled_outline_color = AliasProperty(_get_disabled_outline_color, _set_disabled_outline_color) '''The color of the text outline when the widget is disabled, in the (r, g, b) format. .. note:: This feature requires the SDL2 text provider. ''' def _get_mipmap(self) -> bool: return self._label.mipmap def _set_mipmap(self, mipmap: bool) -> None: self._label.mipmap = mipmap mipmap = AliasProperty(_get_mipmap, _set_mipmap) '''Indicates whether OpenGL mipmapping is applied to the texture or not. Read :ref:`mipmap` for more information. ''' def _get_shorten(self) -> bool: return self._label.shorten def _set_shorten(self, shorten: bool) -> None: self._label.shorten = shorten shorten = AliasProperty(_get_shorten, _set_shorten) ''' Indicates whether the label should attempt to shorten its textual contents as much as possible if a :attr:`text_size` is given. Setting this to True without an appropriately set :attr:`text_size` will lead to unexpected results. :attr:`shorten_from` and :attr:`split_str` control the direction from which the :attr:`text` is split, as well as where in the :attr:`text` we are allowed to split. ''' def _get_shorten_from(self) -> str: return self._label.shorten_from def _set_shorten_from(self, shorten_from: str) -> None: self._label.shorten_from = shorten_from shorten_from = AliasProperty(_get_shorten_from, _set_shorten_from) '''The side from which we should shorten the text from, can be left, right, or center. For example, if left, the ellipsis will appear towards the left side and we will display as much text starting from the right as possible. Similar to :attr:`shorten`, this option only applies when :attr:`text_size` [0] is not None, In this case, the string is shortened to fit within the specified width. ''' def _get_is_shortened(self) -> bool: return self._label.is_shortened is_shortened = AliasProperty(_get_is_shortened, None) '''This property indicates if :attr:`text` was rendered with or without shortening when :attr:`shorten` is True. ''' def _get_split_str(self) -> str: return self._label.split_str def _set_split_str(self, split_str: str) -> None: self._label.split_str = split_str split_str = AliasProperty(_get_split_str, _set_split_str) '''The string used to split the :attr:`text` while shortening the string when :attr:`shorten` is True. For example, if it's a space, the string will be broken into words and as many whole words that can fit into a single line will be displayed. If :attr:`split_str` is the empty string, `''`, we split on every character fitting as much text as possible into the line. ''' def _get_ellipsis_options(self) -> dict: return self._label.ellipsis_options def _set_ellipsis_options(self, ellipsis_options: dict) -> None: self._label.ellipsis_options = ellipsis_options ellipsis_options = AliasProperty(_get_ellipsis_options, _set_ellipsis_options) '''Font options for the ellipsis string('...') used to split the text. Accepts a dict as option name with the value. Only applied when :attr:`markup` is true and text is shortened. All font options which work for :class:`Label` will work for :attr:`ellipsis_options`. Defaults for the options not specified are taken from the surronding text. .. code-block:: kv Label: text: 'Some very long line which will be cut' markup: True shorten: True ellipsis_options: {'color':(1,0.5,0.5,1),'underline':True} ''' def _get_unicode_errors(self) -> str: return self._label.unicode_errors def _set_unicode_errors(self, unicode_errors: str) -> None: self._label.unicode_errors = unicode_errors unicode_errors = AliasProperty(_get_unicode_errors, _set_unicode_errors) '''How to handle unicode decode errors. Can be `'strict'`, `'replace'` or `'ignore'`. ''' def _get_markup(self) -> bool: return self._label.markup def _set_markup(self, markup: bool) -> None: self._label.markup = markup markup = AliasProperty(_get_markup, _set_markup) '''If True, the text will be rendered using the :class:`~kivy.core.text.markup.MarkupLabel`: you can change the style of the text using tags. Check the :doc:`api-kivy.core.text.markup` documentation for more information. ''' def _get_refs(self) -> dict: return self._label.refs refs = AliasProperty(_get_refs, None) '''List of ``[ref=xxx]`` markup items in the text with the bounding box of all the words contained in a ref, available only after rendering. For example, if you wrote:: Check out my [ref=hello]link[/ref] The refs will be set with:: {'hello': ((64, 0, 78, 16), )} The references marked "hello" have a bounding box at (x1, y1, x2, y2). These co-ordinates are relative to the top left corner of the text, with the y value increasing downwards. You can define multiple refs with the same name: each occurrence will be added as another (x1, y1, x2, y2) tuple to this list. The current Label implementation uses these references if they exist in your markup text, automatically doing the collision with the touch and dispatching an `on_ref_press` event. You can bind a ref event like this:: def print_it(instance, value): print('User click on', value) widget = Label(text='Hello [ref=world]World[/ref]', markup=True) widget.on_ref_press(print_it) .. note:: This works only with markup text. You need :attr:`markup` set to True. ''' def _get_max_lines(self) -> Optional[int]: return self._label.max_lines def _set_max_lines(self, max_lines: Optional[int]) -> None: self._label.max_lines = max_lines max_lines = AliasProperty(_get_max_lines, _set_max_lines) '''Maximum number of lines to use, defaults to 0, which means unlimited. Please note that :attr:`shorten` take over this property. (with shorten, the text is always one line.) ''' def _get_strip(self) -> bool: return self._label.strip def _set_strip(self, strip: bool) -> None: self._label.strip = strip strip = AliasProperty(_get_strip, _set_strip) '''Whether leading and trailing spaces and newlines should be stripped from each displayed line. If True, every line will start at the right or left edge, depending on :attr:`halign`. If :attr:`halign` is `justify` it is implicitly True. .. versionadded:: 1.9.0 :attr:`strip` is a :class:`~kivy.properties.BooleanProperty` and defaults to False. ''' def _get_font_hinting(self) -> Optional[str]: return self._label.font_hinting def _set_font_hinting(self, font_hinting: Optional[str]): self._label.font_hinting = font_hinting font_hinting = AliasProperty(_get_font_hinting, _set_font_hinting) '''What hinting option to use for font rendering. Can be one of `'normal'`, `'light'`, `'mono'` or None. .. note:: This feature requires the SDL2 text provider. ''' def _get_font_kerning(self) -> bool: return self._label.font_kerning def _set_font_kerning(self, font_kerning: bool) -> None: self._label.font_kerning = font_kerning font_kerning = AliasProperty(_get_font_kerning, _set_font_kerning) '''Whether kerning is enabled for font rendering. .. note:: This feature requires the SDL2 text provider. ''' def _get_font_blended(self) -> bool: return self._label.font_blended def _set_font_blended(self, font_blended: bool) -> None: self._label.font_blended = font_blended font_blended = AliasProperty(_get_font_blended, _set_font_blended) '''Whether blended or solid font rendering should be used. .. note:: This feature requires the SDL2 text provider. ''' rotation = NumericProperty(0) '''Rotation angle value of the widget. :attr:`rotation` is an :class:`~kivy.properties.NumericProperty` and defaults to 0. ''' scale = NumericProperty(1.0) '''Scale value of the widget.
class Intro(Screen): outline_col = ListProperty([0.4, 0, 0.9]) def __init__(self, **kwargs): super().__init__(**kwargs) self.outline_anim = None self.press_ok_anim2 = None App.get_running_app().add_callback(CEC_CMD_MAP["OK"], "intro", partial(self.goto_screen, "game")) App.get_running_app().add_callback( CEC_CMD_MAP["RED"], "intro", partial(self.goto_screen, "options")) def on_enter(self): """" The --delay-start argument can delay the start of the application (and thus animations). This allows for easy screen recording, for example. """ if not DELAY_START: self.opening_animations() def on_touch_down(self, touch): """" The --delay-start argument can delay the start of the application (and thus animations). This allows for easy screen recording, for example. Clicking on the screen starts the app in this case. """ if DELAY_START: self.opening_animations() return super(Intro, self).on_touch_down(touch) def opening_animations(self): App.get_running_app().bg_anim.start(App.get_running_app()) anim = Animation(scale=1, opacity=1, t='out_elastic', duration=2) anim.bind(on_complete=self.start_secondary_anims) anim.start(self.ids.feduquiz_title) def start_secondary_anims(self, anim=None, widget=None): self.outline_anim = (Animation(outline_col=[0.9, 0, 0], duration=2) + Animation(outline_col=[0.9, 0.9, 0], duration=2) + Animation(outline_col=[0, 0.9, 0.9], duration=2) + Animation(outline_col=[0, 0, 0.9], duration=2) + Animation(outline_col=[0.9, 0, 0.9], duration=2)) self.outline_anim.repeat = True self.press_ok_anim2 = Animation(opacity=0.5) + Animation(opacity=1) self.press_ok_anim2.repeat = True press_ok_anim1 = Animation(pos_hint={ 'center_x': 0.5, 'center_y': 0.35 }, opacity=1, t='out_circ', duration=1) press_ok_anim1.bind(on_complete=lambda anim, widget: self. press_ok_anim2.start(self.ids.press_ok)) press_ok_anim1.start(self.ids.press_ok) move_title_anim = Animation(pos_hint={ 'center_x': 0.5, 'center_y': 0.6 }, t='out_circ', duration=1) move_title_anim.bind( on_complete=lambda anim, widget: self.outline_anim.start(self)) move_title_anim.start(self.ids.feduquiz_title) def goto_screen(self, screen): self.outline_anim.cancel(self.ids.feduquiz_title) self.press_ok_anim2.cancel(self.ids.press_ok) anim1 = Animation(opacity=0) anim2 = Animation(opacity=0) if screen == "game": anim2.bind(on_complete=App.get_running_app().load_game) if screen == "options": anim2.bind(on_complete=partial(self.set_screen, "options")) anim1.start(self.ids.feduquiz_title) anim2.start(self.ids.press_ok) def set_screen(self, screen, anim=None, widget=None): # Should be done using App's method! if screen == "options": App.get_running_app().snd_machine.mode_menu() else: App.get_running_app().snd_machine.mode_game() self.manager.current = screen
class Bubble(GridLayout): '''Bubble class. See module documentation for more information. ''' background_color = ListProperty([1, 1, 1, 1]) '''Background color, in the format (r, g, b, a). :data:`background_color` is a :class:`~kivy.properties.ListProperty` and defaults to [1, 1, 1, 1]. ''' border = ListProperty([16, 16, 16, 16]) '''Border used for :class:`~kivy.graphics.vertex_instructions.BorderImage` graphics instruction. Used with the :data:`background_image`. It should be used when using custom backgrounds. It must be a list of 4 values: (top, right, bottom, left). Read the BorderImage instructions for more information about how to use it. :data:`border` is a :class:`~kivy.properties.ListProperty` and defaults to (16, 16, 16, 16) ''' background_image = StringProperty( 'atlas://data/images/defaulttheme/bubble') '''Background image of the bubble. :data:`background_image` is a :class:`~kivy.properties.StringProperty` and defaults to 'atlas://data/images/defaulttheme/bubble'. ''' arrow_image = StringProperty( 'atlas://data/images/defaulttheme/bubble_arrow') ''' Image of the arrow pointing to the bubble. :data:`arrow_image` is a :class:`~kivy.properties.StringProperty` and defaults to 'atlas://data/images/defaulttheme/bubble_arrow'. ''' show_arrow = BooleanProperty(True) ''' Indicates whether to show arrow. .. versionadded:: 1.8.0 :data:`show_arrow` is a :class:`~kivy.properties.BooleanProperty` and defaults to `True`. ''' arrow_pos = OptionProperty( 'bottom_mid', options=('left_top', 'left_mid', 'left_bottom', 'top_left', 'top_mid', 'top_right', 'right_top', 'right_mid', 'right_bottom', 'bottom_left', 'bottom_mid', 'bottom_right')) '''Specifies the position of the arrow relative to the bubble. Can be one of: left_top, left_mid, left_bottom top_left, top_mid, top_right right_top, right_mid, right_bottom bottom_left, bottom_mid, bottom_right. :data:`arrow_pos` is a :class:`~kivy.properties.OptionProperty` and defaults to 'bottom_mid'. ''' content = ObjectProperty(None) '''This is the object where the main content of the bubble is held. :data:`content` is a :class:`~kivy.properties.ObjectProperty` and defaults to 'None'. ''' orientation = OptionProperty('horizontal', options=('horizontal', 'vertical')) '''This specifies the manner in which the children inside bubble are arranged. Can be one of 'vertical' or 'horizontal'. :data:`orientation` is a :class:`~kivy.properties.OptionProperty` and defaults to 'horizontal'. ''' limit_to = ObjectProperty(None, allow_none=True) '''Specifies the widget to which the bubbles position is restricted. .. versionadded:: 1.6.0 :data:`limit_to` is a :class:`~kivy.properties.ObjectProperty` and defaults to 'None'. ''' def __init__(self, **kwargs): self._prev_arrow_pos = None self._arrow_layout = BoxLayout() self._bk_img = Image(source=self.background_image, allow_stretch=True, keep_ratio=False, color=self.background_color) self.background_texture = self._bk_img.texture self._arrow_img = Image(source=self.arrow_image, color=self.background_color) self.content = content = BubbleContent(parent=self) super(Bubble, self).__init__(**kwargs) content.parent = None self.add_widget(content) self.on_arrow_pos() def add_widget(self, *l): content = self.content if content is None: return if l[0] == content or l[0] == self._arrow_img\ or l[0] == self._arrow_layout: super(Bubble, self).add_widget(*l) else: content.add_widget(*l) def remove_widget(self, *l): content = self.content if not content: return if l[0] == content or l[0] == self._arrow_img\ or l[0] == self._arrow_layout: super(Bubble, self).remove_widget(*l) else: content.remove_widget(l[0]) def clear_widgets(self, **kwargs): content = self.content if not content: return if kwargs.get('do_super', False): super(Bubble, self).clear_widgets() else: content.clear_widgets() def on_show_arrow(self, instance, value): self._arrow_img.opacity = int(value) def on_parent(self, instance, value): Clock.schedule_once(self._update_arrow) def on_pos(self, instance, pos): lt = self.limit_to if lt and lt is not object: self.limit_to = object if lt is EventLoop.window: lt.x = lt.y = 0 lt.top = EventLoop.window.height lt.right = EventLoop.window.width self.x = max(self.x, lt.x) self.right = min(self.right, lt.right) self.top = min(self.top, lt.top) self.y = max(self.y, lt.y) self.limit_to = lt def on_background_image(self, *l): self._bk_img.source = self.background_image def on_background_color(self, *l): if self.content is None: return self._arrow_img.color = self._bk_img.color = self.background_color def on_orientation(self, *l): content = self.content if not content: return if self.orientation[0] == 'v': content.cols = 1 content.rows = 99 else: content.cols = 99 content.rows = 1 def on_arrow_image(self, *l): self._arrow_img.source = self.arrow_image def on_arrow_pos(self, *l): self_content = self.content if not self_content: Clock.schedule_once(self.on_arrow_pos) return if self_content not in self.children: Clock.schedule_once(self.on_arrow_pos) return self_arrow_pos = self.arrow_pos if self._prev_arrow_pos == self_arrow_pos: return self._prev_arrow_pos = self_arrow_pos self_arrow_layout = self._arrow_layout self_arrow_layout.clear_widgets() self_arrow_img = self._arrow_img self._sctr = self._arrow_img self.clear_widgets(do_super=True) self_content.parent = None self_arrow_img.size_hint = (1, None) self_arrow_img.height = self_arrow_img.texture_size[1] self_arrow_img.pos = 0, 0 widget_list = [] arrow_list = [] parent = self_arrow_img.parent if parent: parent.remove_widget(self_arrow_img) if self_arrow_pos[0] == 'b' or self_arrow_pos[0] == 't': self.cols = 1 self.rows = 3 self_arrow_layout.orientation = 'horizontal' self_arrow_img.width = self.width / 3 self_arrow_layout.size_hint = (1, None) self_arrow_layout.height = self_arrow_img.height if self_arrow_pos[0] == 'b': if self_arrow_pos == 'bottom_mid': widget_list = (self_content, self_arrow_img) else: if self_arrow_pos == 'bottom_left': arrow_list = (self_arrow_img, Widget(), Widget()) elif self_arrow_pos == 'bottom_right': #add two dummy widgets arrow_list = (Widget(), Widget(), self_arrow_img) widget_list = (self_content, self_arrow_layout) else: sctr = Scatter(do_translation=False, rotation=180, do_rotation=False, do_scale=False, size_hint=(None, None), size=self_arrow_img.size) sctr.add_widget(self_arrow_img) if self_arrow_pos == 'top_mid': #add two dummy widgets arrow_list = (Widget(), sctr, Widget()) elif self_arrow_pos == 'top_left': arrow_list = (sctr, Widget(), Widget()) elif self_arrow_pos == 'top_right': arrow_list = (Widget(), Widget(), sctr) widget_list = (self_arrow_layout, self_content) elif self_arrow_pos[0] == 'l' or self_arrow_pos[0] == 'r': self.cols = 3 self.rows = 1 self_arrow_img.width = self.height / 3 self_arrow_layout.orientation = 'vertical' self_arrow_layout.cols = 1 self_arrow_layout.size_hint = (None, 1) self_arrow_layout.width = self_arrow_img.height rotation = -90 if self_arrow_pos[0] == 'l' else 90 self._sctr = sctr = Scatter(do_translation=False, rotation=rotation, do_rotation=False, do_scale=False, size_hint=(None, None), size=(self_arrow_img.size)) sctr.add_widget(self_arrow_img) if self_arrow_pos[-4:] == '_top': arrow_list = (Widget(size_hint=(1, .07)), sctr, Widget(size_hint=(1, .3))) elif self_arrow_pos[-4:] == '_mid': arrow_list = (Widget(), sctr, Widget()) Clock.schedule_once(self._update_arrow) elif self_arrow_pos[-7:] == '_bottom': arrow_list = (Widget(), Widget(), sctr) if self_arrow_pos[0] == 'l': widget_list = (self_arrow_layout, self_content) else: widget_list = (self_content, self_arrow_layout) # add widgets to arrow_layout add = self_arrow_layout.add_widget for widg in arrow_list: add(widg) # add widgets to self add = self.add_widget for widg in widget_list: add(widg) def _update_arrow(self, *dt): if self.arrow_pos in ('left_mid', 'right_mid'): self._sctr.center_y = self._arrow_layout.center_y
class FlappyBirdGame(Widget): mcnay = ObjectProperty(None) background = ObjectProperty(None) obstacles = ListProperty([]) score = NumericProperty(0) def __init__(self, **kwargs): super(FlappyBirdGame, self).__init__(**kwargs) self.mcnay.normal_velocity = [0, -4] self.mcnay.velocity = self.mcnay.normal_velocity self.background.velocity = [-2, 0] self.bind(size=self.size_callback) def remove_obstacle(self): self.remove_widget(self.obstacles[0]) self.obstacles = self.obstacles[1:] def new_obstacle(self, remove=True): if remove: self.remove_obstacle() new_obstacle = Obstacle() new_obstacle.height = self.height new_obstacle.x = self.width new_obstacle.update_position() new_obstacle.velocity = [-3, 0] self.add_widget(new_obstacle) self.obstacles = self.obstacles + [new_obstacle] def size_callback(self, instance, value): for obstacle in self.obstacles: obstacle.height = value[1] obstacle.update_position() self.background.size = value self.background.update_position() def update(self, dt): self.mcnay.update() self.background.update() # Loop through and update obstacles. Replace obstacles which went off the screen. for obstacle in self.obstacles: obstacle.update() if obstacle.x < self.mcnay.x and not obstacle.marked: obstacle.marked = True self.score += 1 self.new_obstacle(remove=False) if len(self.obstacles) == 0: self.new_obstacle(remove=False) elif self.obstacles[0].x < 0: self.remove_obstacle() # If obstacles is emply # See if the player collides with any obstacles for obstacle in self.obstacles: if self.mcnay.collide_widget( Widget(pos=(obstacle.x, obstacle.gap_top + 20), size=(obstacle.width, obstacle.height - obstacle.gap_top))): # This will be replaced later on sys.exit() if self.mcnay.collide_widget( Widget(pos=(obstacle.x, 0), size=(obstacle.width, obstacle.gap_top - obstacle.gap_size))): # This will also be replaced sys.exit()
class Rowinfo(BoxLayout, Database): color = ListProperty() def edit(self, root, icon, app): fields = [child.children[0].text for child in root.children[1:]][-2::-1] sem = root.children[-1].children[0].text tableName = "_" + str(self.parent.reg_no) conn = self.connect_database("fee_main.db") data = self.search_from_database(tableName, conn, "sem", sem, order_by="sem")[0] conn.close() sem, late = data[0], data[3] tableName = "_" + str(self.parent.reg_no) + "_" + str(sem) data = self.extractAllData("fee_main.db", tableName, order_by="id") adl = AddDataLayout() adl.prev_tid_list = [] adl.from_update = True adl.ids.sem.text = str(sem) adl.ids.sem.disabled = True adl.height = 60 * len(data) + 230 adl.ids.multipleDataContainer.height = 60 * len(data) for c, each in enumerate(data): if c == 0: w = adl.ids.multipleDataContainer.children[0] else: if (each[5] == "Late Fine"): adl.ids.lateCheckbox.active = True w = adl.ids.multipleDataContainer.children[0] adl.height = 60 * (len(data)) + 230 adl.ids.multipleDataContainer.height = 60 * (len(data)) else: w = MultipleDataLayout() adl.ids.multipleDataContainer.add_widget(w) w.ids.paid.text = str(each[1]) w.ids.date.text = each[2] w.ids.tid.text = each[3] w.ids.docName.text = each[3] + "." + each[4].split(".")[-1] if len( each[4].split(".")) > 1 else each[4] w.ids.rem.text = each[5] adl.prev_tid_list.append(each[3]) adl.open() def delete(self, app, root, icon): fields = [child.children[0].text for child in root.children[1:]][-1::-1] data = { "sem": fields[0], "tid": fields[5], "reg": self.parent.reg_no, "name": self.parent.name, "uname": self.parent.uname, } tableName = "_" + str(self.parent.reg_no) DeleteWarning( "fee", data, "fee_main.db", tableName, callback=app.root.current_screen.populate_screen, ).open() def open_feeinfo_popup(self, root, app): popup = FeeInfoPopup() popup.reg_no = self.parent.reg_no popup.app = app popup.sem = root.sem popup.ids.semLabel.text = "Semester[size=100][b]{}[/b][/size]".format( root.sem) popup.open()
class GridEntry(Button): coords = ListProperty([0, 0])
class PlayGround(Widget): bounds = ListProperty([]) objects = ListProperty([]) def __init__(self, **kw): super(PlayGround, self).__init__(**kw) self.init_physics() self.bind(size=self.update_bounds, pos=self.update_bounds) self.create_world() Clock.schedule_interval(self.update, 1 / 30.) def init_physics(self): self.space = space = phy.Space() space.iterations = 30 space.gravity = GRAVITY space.sleep_time_threshold = 0.5 space.collision_slop = 0.5 self.update_bounds() def update_bounds(self, *largs): space = self.space x0, y0 = self.pos x1 = self.right y1 = self.top if len(self.bounds): a, b, c, d = self.bounds self.space.remove(a) self.space.remove(b) self.space.remove(c) self.space.remove(d) a = phy.Segment(space.static_body, phy.Vec2d(x0, y0), phy.Vec2d(x1, y0), 10.0) b = phy.Segment(space.static_body, phy.Vec2d(x1, y0), phy.Vec2d(x1, y1), 10.0) c = phy.Segment(space.static_body, phy.Vec2d(x1, y1), phy.Vec2d(x0, y1), 10.0) d = phy.Segment(space.static_body, phy.Vec2d(x0, y1), phy.Vec2d(x0, y0), 10.0) self.space.add(a) self.space.add(b) self.space.add(c) self.space.add(d) self.cbounds = [a, b, c, d] def update(self, dt): ''' Update the worlds ''' self.space.step(1 / 30.) for obj in self.objects: obj.update() def on_touch_down(self, touch): shape = self.space.point_query_first(phy.Vec2d(touch.x, touch.y)) print shape def create_world(self): Box(self, 10000., pos=(300, 400), size=(200, 100), color=(1, 1, 0, 1)) Box(self, 10000., pos=(450, 550), size=(200, 100), color=(1, 0, 0, 1)) Box(self, 10000., pos=(250, 500), size=(50, 100), color=(1, 0, 1, 1)) Circle(self, 10000., pos=(100, 300), radius=30, color=(1, 0.5, 0.5, 1), elasticity=1.0) Circle(self, 10000., pos=(200, 500), radius=50, color=(0, 1, 0.5, 1))
class LearnSongsApp(App): """ Main program: show the list of songs by GUI """ status_text = StringProperty() # the first status text status_text2 = StringProperty() # the second status text current_sort = StringProperty() # the current sorting of song list sort_choices = ListProperty() # the sorting options of song list def __init__(self, **kwargs): super(LearnSongsApp, self).__init__(**kwargs) self.song_list = SongList() self.sort_choices = ["year", "artist"] self.current_sort = self.sort_choices[0] self.song_list.load_songs() def build(self): """ Build the Kivy GUI """ self.learn___ = "Songs to learn 2.0 by Chen Jianjian" # Name the GUI's name self.title = self.learn___ self.root = Builder.load_file('app.kv') # Connect to Kivy app self.create_widgets() # Create the songs button return self.root def change_sort(self, sorting_choice): """ change the sorting of the song list """ self.status_text = "Sorted by: {}".format(sorting_choice) self.song_list.sort(sorting_choice) self.root.ids.entriesBox.clear_widgets() self.create_widgets() sort_index = self.sort_choices.index(sorting_choice) self.current_sort = self.sort_choices[sort_index] def create_widgets(self): """ Create Songs' buttons from the csv file """ num_song = len(self.song_list.list_songs) # Count the number of songs learned_song = 0 for song in self.song_list.list_songs: # find the songs name = self.button_Text( song.title, song.artist, song.year, song.is_required) # showing the information in be the button) learned = song.is_required if learned == 'n': background_color = (1, 2, 1, 0.7 ) #if the song id learned show this color learned_song += 1 else: # If the song is not learned show blue color background_color = (1, 3, 4, 0.6) # clicking a song to learn temp_button = Button( text=name, id=str(song.title), background_color=background_color) # Add the song learned temp_button.bind( on_release=self.press_song) # show the message of the status self.root.ids.entriesBox.add_widget( temp_button) # add the song to the Kivy app self.status_text = 'To Learned: {} Learned: {}'.format( num_song - learned_song, learned_song) def button_Text(self, title, artist, year, learned): # show messages if learned == "n": display_text = "{} by {} {} (Learned)".format(title, artist, year) else: display_text = "{} by {} {}".format(title, artist, year) return display_text def press_song(self, button): # when you press the song button buttonText = button.text # Determine the text on the buttons selectedSong = Song() for song in self.song_list.list_songs: songDisplayText = self.button_Text(song.title, song.artist, song.year, song.is_required) # show text in Button if buttonText == songDisplayText: selectedSong = song break selectedSong.add_learned() self.root.ids.entriesBox.clear_widgets() # Apply to Kivy self.create_widgets() self.status_text2 = "You have learned {}".format( selectedSong.title) # Display the status text 2 def add_songs(self): """ add a song to learn """ # Check if have empty inputs if self.root.ids.song_title.text == "" or self.root.ids.song_artist.text == "" or self.root.ids.song_year.text == "": self.root.ids.status2.text = "All fields must be completed" return try: # Define song items inputted song_title = str(self.root.ids.song_title.text) song_artist = str(self.root.ids.song_artist.text) song_year = int(self.root.ids.song_year.text) is_required = "y" # Add the song to the song list self.song_list.add_to_list(song_title, song_artist, song_year, is_required) temp_button = Button(text=self.button_Text(song_title, song_artist, song_year, is_required)) temp_button.bind(on_release=self.press_song) # the new song button color temp_button.background_color = (1, 3, 4, 0.6) self.root.ids.entriesBox.add_widget(temp_button) # empty inputs self.root.ids.song_title.text = "" self.root.ids.song_artist.text = "" self.root.ids.song_year.text = "" except ValueError: # Display error when year input is not a number self.status_text2 = "Please enter a valid year" self.song_list.save_songs() def press_clear(self): """ Clear status text and inputs """ self.status_text = "" # Clear status_text self.status_text2 = "" # Clear status_text2 self.root.ids.song_title.text = '' # Clear title input self.root.ids.song_artist.text = '' # Clear artist input self.root.ids.song_year.text = '' # Clear year input
class PanelWprowadzDane(Screen): loadfile = ObjectProperty(None) savefile = ObjectProperty(None) aktywnasekcja = '' #text_input = ObjectProperty(None) max_plikow = 3 maszyna = [0] glowica = [0] pinola = [0] up = [0] a = {'Maszyna': maszyna, 'Glowica': glowica, 'Pinola': pinola, 'UP': up} def aktywne_okno(self, nazwa): self.aktywnasekcja = nazwa @staticmethod def pudelko_zdjec(lista_sciezek): pudelko = BoxLayout(orientation='vertical') pudelko.cols = 3 pudelko.row = 3 #check_panel = GridLayout(orientation='horizontal') cb = CheckBox(active=False) #check_panel.add_widget(cb) #pudelko.add_widget(check_panel) rozmiarlisty = len(lista_sciezek) pliki = [] if lista_sciezek[0] > 0: for i in range(lista_sciezek[0]): rozmiarlisty = rozmiarlisty - 2 pliki.append(lista_sciezek[rozmiarlisty]) print(i) for i in range(len(pliki)): print('tu jestem') plik = Image(source=pliki[i]) pudelko.add_widget(plik) else: CMMsFunc.stworz_okno_bledu('Powiadomienie', 'Brak zdjêæ').open() return pudelko def dismiss_popup(self): self._popup.dismiss() def show_picture(self, c): # decPic = self.a[key].encode('utf-8') #data = io.BytesIO(open(self.a[key], "rb").read()) # data = data.encode('utf-8') #content = CoreImage(self.a[key], ext="png").texture #content.reload() if c == 'Maszyna': #self.s = PanelPlikow(name='pliki_maszyna') self.p = self.pudelko_zdjec(self.maszyna) #self.s.add_widget(self.p) #self.manager.current = 'pliki_maszyna' self._popup = Popup(title="Plik", content=self.p, size_hint=(None, None), size=(600, 600)) self._popup.open() def show_load(self): #key = 'Maszyna' content = LoadDialog(load=self.load, cancel=self.dismiss_popup) self._popup = Popup(title="Load file", content=content, size_hint=(0.9, 0.9)) self._popup.open() #def show_save(self): #content = SaveDialog(save=self.save, cancel=self.dismiss_popup) # self._popup = Popup(title="Save file", content=content, # size_hint=(0.9, 0.9)) # self._popup.open() def load(self, path, filename): #with open(os.path.join(path, filename[0])) as stream: #self.text_input.text = stream.read() # to do odkomentowania póŸniej insertBLOB(121, 127, 1,'',os.path.join(path, filename[0])) zdj = convertToBinaryData(os.path.join(path, filename[0])) data = io.BytesIO(open(os.path.join(path, filename[0]), "rb").read()) content = CoreImage(data, ext="png").texture #content.reload() filen = os.path.join(path, filename[0]) #self.show_picture(filen) if self.aktywnasekcja == 'Maszyna': try: #Zwiêkszamy liczbê maszyna[0] z ka¿dym dodanym zdjêciem. NIe mo¿e byæ wiêcej zdjêæ ni¿ max_plikow if self.maszyna[0] < self.max_plikow: self.maszyna.append(os.path.join(path, filename[0])) self.maszyna.append( convertToBinaryData(os.path.join(path, filename[0]))) self.maszyna[0] = self.maszyna[0] + 1 CMMsFunc.stworz_okno_bledu( 'Powiadomienie', 'Plik dodany do pamiêci\n Do bazy za³adowany bêdzie po zatwierdzeniu\n wprowadzonych zmian' ).open() else: print("Nie uda³o siê") except: print('B³¹d') #CMMsFunc.stworz_okno_bledu('B£¥D', str(self.maszyna[1])).open() print(self.maszyna[1]) self.aktywnasekcja = '' self.dismiss_popup() #self.dismiss_popup() #def save(self, path, filename): # with open(os.path.join(path, filename), 'w') as stream: # stream.write(self.text_input.text) # self.dismiss_popup() lista_prod = ListProperty([]) glo_id = 0 pin_id = 0 upn_id = 0 lin_id = 0 cln_id = 0 opr_id = 0 str_id = 0 uio_id = 0 kln_id = 0 kmt_id = 0 polaczenie = CMMsFunc.polacz_z_bazadanych() kursor = CMMsFunc.stworz_kursor(polaczenie) def __init__(self, **kwargs): super(PanelWprowadzDane, self).__init__(**kwargs) self.lista_producentow() def lista_producentow(self): self.kursor.execute("SELECT Prd_PelnaNazwa FROM Producenci") wiersze = self.kursor.fetchall() for wiersz in wiersze: for kolumna in wiersz: self.lista_prod.append(kolumna) def wprowadz_dane_glowica(self, nazwa, producent, uwagi): if nazwa == "" or producent == "": CMMsFunc.stworz_okno_bledu( 'B£¥D', 'G£OWICA: \nPola Nazwa oraz Producent powinny byæ uzupe³nione' ).open() else: l = (nazwa, producent, uwagi) self.kursor.callproc('glowice_wprowadz_dane', l) self.polaczenie.commit() self.kursor.execute('select last_insert_id()') self.glo_id = self.kursor.fetchone()[0] self.ids.Glo_Nazwa.text = "" self.ids.Prd_GloNazwa.text = "" # if self.glo_id != 0: #CMMsFunc.stworz_okno_bledu('SUKCES',str(self.glo_id)).open() def wprowadz_dane_pinola(self, opis, wym_zew, wym_srub, adapter_glow, uwagi): if wym_zew != "" and wym_srub != "" and adapter_glow != "": l = [opis, wym_zew, wym_srub, adapter_glow, uwagi] self.kursor.callproc('pinole_wprowadz_dane', l) self.polaczenie.commit() for r in self.kursor.stored_results(): self.pin_id = r.fetchone() self.ids.Pin_Opis.text = "" self.ids.Pin_WymiarZewnetrzny.text = "" self.ids.Pin_WymiarsrubMontazu.text = "" self.ids.Pin_AdapterGlowicy.text = "" self.ids.Pin_Uwagi.text = "" else: CMMsFunc.stworz_okno_bledu( 'B£¥D', 'PINOLA: \nUzupe³nij dane dotycz¹ce Pinoli. Pola obowi¹zkowe to: \n Wymiar zewnêtrzny,\n Wymiar œrub monta¿u, \nAdapter g³owicy.' ).open() # if self.pin_id != 0: #CMMsFunc.stworz_okno_bledu('SUKCES',str(self.pin_id[0])).open() def wprowadz_dane_uklad_pneu(self, filtry_model, przeciwwaga_mdl, przeciwwaga_rodzaj, system_antywibracyjny, lozyska_pow_rodzaj, lozyska_pow_model, lozyska_pow_par, producent, uwagi): if filtry_model != '' and przeciwwaga_mdl != '' and przeciwwaga_rodzaj != '' and system_antywibracyjny != '' and lozyska_pow_rodzaj != '' and lozyska_pow_model != '' and lozyska_pow_par != '' and producent != '': l = [ filtry_model, przeciwwaga_mdl, przeciwwaga_rodzaj, system_antywibracyjny, lozyska_pow_rodzaj, lozyska_pow_model, lozyska_pow_par, producent, uwagi ] self.kursor.callproc('uklad_pneu_wprowadz_dane', l) self.polaczenie.commit() for r in self.kursor.stored_results(): self.upn_id = r.fetchone() else: CMMsFunc.stworz_okno_bledu( 'B£¥D', 'UK£AD PNEUMATYCZNY:\nUzupe³nij dane dotcz¹ce tej sekcji.\n Jedynie pole \'UWAGI\' mo¿e byæ puste' ).open() # if self.upn_id != 0: #CMMsFunc.stworz_okno_bledu('SUKCES',str(self.upn_id[0])).open() def wprowadz_dane_linialy(self, material, rozdzielczosc, rodzaj_sygnalu, rodzaj_sygnalu_szcz, sposob_montazu, producent, uwagi): if material != '' and rozdzielczosc != '' and rodzaj_sygnalu != '' and rodzaj_sygnalu_szcz != '' and sposob_montazu != '' and producent != '': l = [ material, rozdzielczosc, rodzaj_sygnalu, rodzaj_sygnalu_szcz, sposob_montazu, self.cln_id[0], producent, uwagi ] self.kursor.callproc('linialy_wprowadz_dane', l) self.polaczenie.commit() for r in self.kursor.stored_results(): self.lin_id = r.fetchone() else: CMMsFunc.stworz_okno_bledu( 'B£¥D', 'LINIA£Y:\nJedynie pole \'uwagi\' mo¿e pozostaæ nieuzupe³nione w tej sekcji' ).open() #if self.lin_id != 0: #CMMsFunc.stworz_okno_bledu('SUKCES',str(self.lin_id[0])).open() def wprowadz_dane_czytnik_linialu(self, rodzaj, sposob_montazu, uwagi): if rodzaj != '' and sposob_montazu != '': l = [rodzaj, sposob_montazu, uwagi] self.kursor.callproc('czytniki_linialu_wprowadz_dane', l) self.polaczenie.commit() for r in self.kursor.stored_results(): self.cln_id = r.fetchone() else: CMMsFunc.stworz_okno_bledu( 'B£¥D', 'Czytnik Linialu:\nJedynie pole \'uwagi\' mo¿e pozostaæ nieuzupe³nione w tej sekcji' ).open() #if self.cln_id != 0: #CMMsFunc.stworz_okno_bledu('SUKCES',str(self.cln_id[0])).open() def wprowadz_dane_oprogramowanie(self, rodzaj, wersja, uwagi): if rodzaj != '' and wersja != '': l = [rodzaj, wersja, uwagi] self.kursor.callproc('oprogramowanie_wprowadz_dane', l) self.polaczenie.commit() for r in self.kursor.stored_results(): self.opr_id = r.fetchone() else: CMMsFunc.stworz_okno_bledu( 'B£¥D', 'OPROGRAMOWANIE:\nJedynie pole \'uwagi\' mo¿e pozostaæ nieuzupe³nione w tej sekcji' ).open() # if self.opr_id != 0: #CMMsFunc.stworz_okno_bledu('SUKCES',str(self.opr_id[0])).open() def wprowadz_dane_sterowniki(self, producent, model, rodzaj_szatyster, rodzaj_interfejsu, uwagi, rodzaj_panelu): if producent != '' and model != '': l = [ producent, model, rodzaj_szatyster, rodzaj_interfejsu, uwagi, rodzaj_panelu ] self.kursor.callproc('sterowniki_wprowadz_dane', l) self.polaczenie.commit() for r in self.kursor.stored_results(): self.str_id = r.fetchone() else: CMMsFunc.stworz_okno_bledu( 'B£¥D', 'STEROWNIKI:\nPola: \'Model\' oraz \'Producent\'\ns¹ polami obowi¹zkowymi dla tej sekcji' ).open() #if self.str_id != 0: #CMMsFunc.stworz_okno_bledu('SUKCES',str(self.str_id[0])).open() def wprowadz_dane_napedy(self, model_silnika, parametry, rodzaj_napedu, uwagi): if model_silnika != '' and parametry != '' and rodzaj_napedu != '': l = [model_silnika, parametry, rodzaj_napedu, uwagi] self.kursor.callproc('napedy_wprowadz_dane', l) self.polaczenie.commit() for r in self.kursor.stored_results(): self.nap_id = r.fetchone() else: CMMsFunc.stworz_okno_bledu( 'B£¥D', 'NAPÊDY:\nJedynie pole \'uwagi\' mo¿e pozostaæ nieuzupe³nione w tej sekcji' ).open() #if self.nap_id != 0: #CMMsFunc.stworz_okno_bledu('SUKCES',str(self.nap_id[0])).open() def wprowadz_dane_urzadzeniaio(self, hamulec_rodzaj, hamulec_napiecie, krancowki_rodzaj, krancowki_zasilanie, kontrola_cis, inne_urzadzenia, uwagi): if hamulec_rodzaj != '' and hamulec_napiecie != '' and krancowki_rodzaj != '' and krancowki_zasilanie != '' and kontrola_cis != '' and uwagi != '': l = [ hamulec_rodzaj, hamulec_napiecie, krancowki_rodzaj, krancowki_zasilanie, kontrola_cis, inne_urzadzenia, uwagi ] self.kursor.callproc('urzadzeniaio_wprowadz_dane', l) self.polaczenie.commit() for r in self.kursor.stored_results(): self.uio_id = r.fetchone() else: CMMsFunc.stworz_okno_bledu( 'B£¥D', 'URZ¥DZENIA IO:\n Jedynie pole "Inne urz¹dzenia" mo¿e byæ puste. \nUzupe³nij pozosta³e pola.' ).open() #if self.uio_id != 0: #CMMsFunc.stworz_okno_bledu('SUKCES',str(self.uio_id[0])).open() def wprowadz_dane_klienci(self, pelna_nazwa, krotka_nazwa, nip, adres, region, kod_pocztowy, kraj, telefon, fax, mail, uwagi): if pelna_nazwa != '' and nip != '': l = [ pelna_nazwa, krotka_nazwa, nip, adres, region, kod_pocztowy, kraj, telefon, fax, mail, uwagi ] self.kursor.callproc('klienci_wprowadz_dane', l) self.polaczenie.commit() for r in self.kursor.stored_results(): self.kln_id = r.fetchone() else: CMMsFunc.stworz_okno_bledu( 'B£¥D', 'KLIENCI:\nUzupe³nij pe³n¹ nazwê klienta oraz NIP').open() #if self.kln_id != 0: #CMMsFunc.stworz_okno_bledu('SUKCES',str(self.uio_id[0])).open() def wprowadz_dane_kompensacja_temp(self, rodzaj_czujnikow, interfejs, uwagi): if rodzaj_czujnikow != '' and interfejs != '': l = [rodzaj_czujnikow, interfejs, uwagi] self.kursor.callproc('kompensacja_temp_wprowadz_dane', l) self.polaczenie.commit() for r in self.kursor.stored_results(): self.kmt_id = r.fetchone() else: CMMsFunc.stworz_okno_bledu( 'B£¥D', 'KOMPENSACJA TEMP:\nJedunie pole \'uwagi\' mo¿e byæ nieuzupe³nione w tej sekcji' ).open() def wprowadz_dane_maszyna(self, nazwa_producenta, model, zakresx, zakresy, zakresz, tab_znamionowa, opis, informacje): l = [ nazwa_producenta, model, zakresx, zakresy, zakresz, self.glo_id[0], self.pin_id[0], self.upn_id[0], self.opr_id[0], self.kln_id[0], self.lin_id[0], self.uio_id[0], self.str_id[0], '1', self.knt_id[0], tab_znamionowa, opis, informacje ] self.kursor.callproc('maszyny_wprowadz_dane', l) self.polaczenie.commit() CMMsFunc.stworz_okno_bledu( 'SUKCES', 'Dane zosta³y poprawnie wprowadzone').open()
class Splitter(BoxLayout): '''See module documentation. :Events: `on_press`: Fired when the splitter is pressed. `on_release`: Fired when the splitter is released. .. versionchanged:: 1.6.0 Added `on_press` and `on_release` events. ''' border = ListProperty([4, 4, 4, 4]) '''Border used for the :class:`~kivy.graphics.vertex_instructions.BorderImage` graphics instruction. This must be a list of four values: (top, right, bottom, left). Read the BorderImage instructions for more information about how to use it. :attr:`border` is a :class:`~kivy.properties.ListProperty` and defaults to (4, 4, 4, 4). ''' strip_cls = ObjectProperty(SplitterStrip) '''Specifies the class of the resize Strip. :attr:`strip_cls` is an :class:`kivy.properties.ObjectProperty` and defaults to :class:`~kivy.uix.splitter.SplitterStrip`, which is of type :class:`~kivy.uix.button.Button`. .. versionchanged:: 1.8.0 If you set a string, the :class:`~kivy.factory.Factory` will be used to resolve the class. ''' sizable_from = OptionProperty('left', options=( 'left', 'right', 'top', 'bottom')) '''Specifies whether the widget is resizable. Options are:: `left`, `right`, `top` or `bottom` :attr:`sizable_from` is an :class:`~kivy.properties.OptionProperty` and defaults to `left`. ''' strip_size = NumericProperty('10pt') '''Specifies the size of resize strip :attr:`strp_size` is a :class:`~kivy.properties.NumericProperty` defaults to `10pt` ''' min_size = NumericProperty('100pt') '''Specifies the minimum size beyond which the widget is not resizable. :attr:`min_size` is a :class:`~kivy.properties.NumericProperty` and defaults to `100pt`. ''' max_size = NumericProperty('500pt') '''Specifies the maximum size beyond which the widget is not resizable. :attr:`max_size` is a :class:`~kivy.properties.NumericProperty` and defaults to `500pt`. ''' _parent_proportion = NumericProperty(0.) '''(internal) Specifies the distance that the slider has travelled across its parent, used to automatically maintain a sensible position if the parent is resized. :attr:`_parent_proportion` is a :class:`~kivy.properties.NumericProperty` and defaults to 0. .. versionadded:: 1.9.0 ''' _bound_parent = ObjectProperty(None, allownone=True) '''(internal) References the widget whose size is currently being tracked by :attr:`_parent_proportion`. :attr:`_bound_parent` is a :class:`~kivy.properties.ObjectProperty` and defaults to None. .. versionadded:: 1.9.0 ''' keep_within_parent = BooleanProperty(False) '''If True, will limit the splitter to stay within its parent widget. :attr:`keep_within_parent` is a :class:`~kivy.properties.BooleanProperty` and defaults to False. .. versionadded:: 1.9.0 ''' rescale_with_parent = BooleanProperty(False) '''If True, will automatically change size to take up the same proportion of the parent widget when it is resized, while staying within :attr:`min_size` and :attr:`max_size`. As long as these attributes can be satisfied, this stops the :class:`Splitter` from exceeding the parent size during rescaling. :attr:`rescale_with_parent` is a :class:`~kivy.properties.BooleanProperty` and defaults to False. .. versionadded:: 1.9.0 ''' __events__ = ('on_press', 'on_release') def __init__(self, **kwargs): self._container = None self._strip = None super(Splitter, self).__init__(**kwargs) do_size = self._do_size fbind = self.fast_bind fbind('max_size', do_size) fbind('min_size', do_size) fbind('parent', self._rebind_parent) def on_sizable_from(self, instance, sizable_from): if not instance._container: return sup = super(Splitter, instance) _strp = instance._strip if _strp: # remove any previous binds _strp.unbind(on_touch_down=instance.strip_down) _strp.unbind(on_touch_move=instance.strip_move) _strp.unbind(on_touch_up=instance.strip_up) self.unbind(disabled=_strp.setter('disabled')) sup.remove_widget(instance._strip) else: cls = instance.strip_cls if isinstance(cls, string_types): cls = Factory.get(cls) instance._strip = _strp = cls() sz_frm = instance.sizable_from[0] if sz_frm in ('l', 'r'): _strp.size_hint = None, 1 _strp.width = instance.strip_size instance.orientation = 'horizontal' instance.unbind(strip_size=_strp.setter('width')) instance.bind(strip_size=_strp.setter('width')) else: _strp.size_hint = 1, None _strp.height = instance.strip_size instance.orientation = 'vertical' instance.unbind(strip_size=_strp.setter('height')) instance.bind(strip_size=_strp.setter('height')) index = 1 if sz_frm in ('r', 'b'): index = 0 sup.add_widget(_strp, index) _strp.bind(on_touch_down=instance.strip_down) _strp.bind(on_touch_move=instance.strip_move) _strp.bind(on_touch_up=instance.strip_up) _strp.disabled = self.disabled self.bind(disabled=_strp.setter('disabled')) def add_widget(self, widget, index=0): if self._container or not widget: return Exception('Splitter accepts only one Child') self._container = widget sz_frm = self.sizable_from[0] if sz_frm in ('l', 'r'): widget.size_hint_x = 1 else: widget.size_hint_y = 1 index = 0 if sz_frm in ('r', 'b'): index = 1 super(Splitter, self).add_widget(widget, index) self.on_sizable_from(self, self.sizable_from) def remove_widget(self, widget, *largs): super(Splitter, self).remove_widget(widget) if widget == self._container: self._container = None def clear_widgets(self): self.remove_widget(self._container) def strip_down(self, instance, touch): if not instance.collide_point(*touch.pos): return False touch.grab(self) self.dispatch('on_press') def on_press(self): pass def _rebind_parent(self, instance, new_parent): if self._bound_parent is not None: self._bound_parent.unbind(size=self.rescale_parent_proportion) if self.parent is not None: new_parent.bind(size=self.rescale_parent_proportion) self._bound_parent = new_parent self.rescale_parent_proportion() def rescale_parent_proportion(self, *args): if self.rescale_with_parent: parent_proportion = self._parent_proportion if self.sizable_from in ('top', 'bottom'): new_height = parent_proportion * self.parent.height self.height = max(self.min_size, min(new_height, self.max_size)) else: new_width = parent_proportion * self.parent.width self.width = max(self.min_size, min(new_width, self.max_size)) def _do_size(self, instance, value): if self.sizable_from[0] in ('l', 'r'): self.width = max(self.min_size, min(self.width, self.max_size)) else: self.height = max(self.min_size, min(self.height, self.max_size)) def strip_move(self, instance, touch): if touch.grab_current is not instance: return False max_size = self.max_size min_size = self.min_size sz_frm = self.sizable_from[0] if sz_frm in ('t', 'b'): diff_y = (touch.dy) if self.keep_within_parent: if sz_frm == 't' and (self.top + diff_y) > self.parent.top: diff_y = self.parent.top - self.top elif sz_frm == 'b' and (self.y + diff_y) < self.parent.y: diff_y = self.parent.y - self.y if sz_frm == 'b': diff_y *= -1 if self.size_hint_y: self.size_hint_y = None if self.height > 0: self.height += diff_y else: self.height = 1 height = self.height self.height = max(min_size, min(height, max_size)) self._parent_proportion = self.height / self.parent.height else: diff_x = (touch.dx) if self.keep_within_parent: if sz_frm == 'l' and (self.x + diff_x) < self.parent.x: diff_x = self.parent.x - self.x elif (sz_frm == 'r' and (self.right + diff_x) > self.parent.right): diff_x = self.parent.right - self.right if sz_frm == 'l': diff_x *= -1 if self.size_hint_x: self.size_hint_x = None if self.width > 0: self.width += diff_x else: self.width = 1 width = self.width self.width = max(min_size, min(width, max_size)) self._parent_proportion = self.width / self.parent.width def strip_up(self, instance, touch): if touch.grab_current is not instance: return if touch.is_double_tap: max_size = self.max_size min_size = self.min_size sz_frm = self.sizable_from[0] s = self.size if sz_frm in ('t', 'b'): if self.size_hint_y: self.size_hint_y = None if s[1] - min_size <= max_size - s[1]: self.height = max_size else: self.height = min_size else: if self.size_hint_x: self.size_hint_x = None if s[0] - min_size <= max_size - s[0]: self.width = max_size else: self.width = min_size touch.ungrab(instance) self.dispatch('on_release') def on_release(self): pass
class RV(BoxLayout): rv_data = ListProperty([]) rv_data_popup = ListProperty([]) start_point = NumericProperty(0) mode = StringProperty("") def __init__(self, **kwargs): super(RV, self).__init__(**kwargs) self.get_users() def get_users(self): polaczenie = CMMsFunc.polacz_z_bazadanych() kursor = CMMsFunc.stworz_kursor(polaczenie) '''This result retrieve from database''' self.rv_data.clear() self.rv_data_popup.clear() self.rv_data = [] self.rv_data_popup = [] kursor.execute( "SELECT Uzy_Id, Uzy_Login, Uzy_Imie, Uzy_Nazwisko, Uzy_Haslo, Uzy_ROla FROM Uzytkownicy ORDER BY Uzy_id ASC" ) rows = kursor.fetchall() # create data_items for row in rows: for col in row: #if len(str(col)) > 10: #self.rv_data.append(col[:10] + '...') #else: self.rv_data.append(col) kursor.execute( "SELECT Uzy_Id, Uzy_Login, Uzy_Imie, Uzy_Nazwisko, Uzy_Haslo, Uzy_ROla FROM Uzytkownicy ORDER BY Uzy_id ASC" ) rows_popup = kursor.fetchall() for row in rows_popup: for col in row: if len(str(col)) > 10: self.rv_data_popup.append(col[:10] + '...') else: self.rv_data_popup.append(col) for row in rows: for col in row: print(col) def add_record(self): self.mode = "Add" popup = CRUD(self) popup.open() def update_changes(self, obj): # if obj.mode == "Add": # insert record into Database Table #cur.execute("INSERT INTO Uzytkownicy(Uzy_Login,Uzy_Imie,Uzy_Nazwisko,Uzy_Haslo,Uzy_Rola) VALUES(?, ?, ?,?,?,?)", # (obj.col_data[1], obj.col_data[2], obj.col_data[3],obj.col_data[4],obj.col_data[5])) #else: # update Database Table self.kursor.execute( "UPDATE Uzytkownicy SET Uzy_Login = ?, Uzy_Imie = ?, Uzy_Nazwisko = ?, Uzy_Haslo = ?, Uzy_Rola = ? WHERE Uzy_Id = ?", (obj.col_data[1], obj.col_data[2], obj.col_data[3], obj.col_data[4], obj.col_data[5], obj.col_data[0])) con.commit() self.get_users()
class SweepGauge(BoxLayout): # these values match the dimensions of the svg elements used in this gauge. Builder.load_string(""" <RoundGauge>: anchor_x: 'center' anchor_y: 'center' value_size: self.height * 0.16 title_size: self.height * 0.08 SweepGauge: id: gauge FieldLabel: id: add_gauge halign: 'center' text: '+' color: (0.5, 0.5, 0.5, 1.0) font_size: self.height * 0.2 FieldLabel: id: value font_size: root.value_size halign: 'center' AnchorLayout: anchor_x: 'center' anchor_y: 'bottom' AutoShrinkFieldLabel: size_hint_y: 0.5 id: title shorten: False font_size: root.title_size halign: 'center' """) value = NumericProperty(0) color = ListProperty([1, 1, 1, 1]) gauge_mask = CoreImage('resource/gauge/gauge_mask.png') gauge_image = CoreImage('resource/gauge/round_gauge_270.png') gauge_shadow = CoreImage('resource/gauge/round_gauge_270_shadow.png') def __init__(self, **kwargs): super(SweepGauge, self).__init__(**kwargs) self.gauge_height = 110 self.gauge_width = 100 self.zoom_factor = 1.1 self.mask_rotations = [] size = self.height if self.height < self.width else self.width gauge_height = size / self.gauge_height x_center = self.pos[0] + self.width / 2 - self.gauge_width / 2 y_center = self.pos[1] + self.height / 2 - self.gauge_height / 2 with self.canvas: PushMatrix() self.dial_color = Color(rgba=self.color) self.gauge_translate = Translate(x_center, y_center, 0) self.gauge_scale = Scale(x=gauge_height, y=gauge_height) Rectangle(texture=SweepGauge.gauge_image.texture, pos=self.pos, size=self.size) PushMatrix() self.mask_rotations.append( Rotate(angle=-135, axis=(0, 0, 1), origin=(self.center[0], self.center[1]))) Rectangle(texture=SweepGauge.gauge_mask.texture) PopMatrix() PushMatrix() self.mask_rotations.append( Rotate(angle=-225, axis=(0, 0, 1), origin=(self.center[0], self.center[1]))) Rectangle(texture=SweepGauge.gauge_mask.texture) PopMatrix() PushMatrix() self.mask_rotations.append( Rotate(angle=-315, axis=(0, 0, 1), origin=(self.center[0], self.center[1]))) Rectangle(texture=SweepGauge.gauge_mask.texture) PopMatrix() PopMatrix() with self.canvas.after: PushMatrix() Color(1, 1, 1, 1) self.shadow_translate = Translate(x_center, y_center, 0) self.shadow_scale = Scale(x=gauge_height, y=gauge_height) Rectangle(texture=SweepGauge.gauge_shadow.texture) PopMatrix() self.bind(pos=self.update_all, size=self.update_all) def update_all(self, *args): size = self.height if self.height < self.width else self.width gauge_height = size / self.gauge_height * self.zoom_factor x_center = self.pos[0] + self.width / 2 - (self.gauge_width / 2) * gauge_height y_center = self.pos[1] + self.height / 2 - (self.gauge_height / 2) * gauge_height self.gauge_translate.x = x_center self.gauge_translate.y = y_center self.shadow_translate.x = x_center self.shadow_translate.y = y_center self.gauge_scale.x = gauge_height self.gauge_scale.y = gauge_height self.shadow_scale.x = gauge_height self.shadow_scale.y = gauge_height def on_value(self, instance, value): angle = (value * 270) / 100 self.mask_rotations[0].angle = -135 - angle self.mask_rotations[1].angle = -135 - angle if angle > 90 else -225 self.mask_rotations[2].angle = -135 - angle if angle > 180 else -315 def on_color(self, instance, value): self.dial_color.rgba = value
class DiagramElementsContainer(Widget): values = ListProperty() color = ListProperty() LABEL_SIZE = dp(100) def on_color(self, instance, value): if self.fill_color: Animation(rgba=value, duration=.5, t='in_out_cubic').start(self.fill_color) def __init__(self, **kwargs): self.fill_color = None self.normal_level_line = None self.normal_level_label = None self.half_level_line = None self.half_level_label = None super(DiagramElementsContainer, self).__init__(**kwargs) self.bind(values=self.update_elements, pos=self.update_elements, width=self.update_elements, height=self.update_elements) def fill_canvas(self): from kivy.graphics.context_instructions import Color from kivy.graphics.vertex_instructions import Line self.normal_level_label = Label(text="100% ", bold=True, halign='right', valign='bottom', size=(self.LABEL_SIZE, self.LABEL_SIZE), text_size=(self.LABEL_SIZE, self.LABEL_SIZE)) self.half_level_label = Label(text="50% ", bold=True, halign='right', valign='bottom', size=(self.LABEL_SIZE, self.LABEL_SIZE), text_size=(self.LABEL_SIZE, self.LABEL_SIZE)) self.add_widget(self.normal_level_label) self.add_widget(self.half_level_label) with self.canvas.before: self.fill_color = Color() with self.canvas.after: Color(1, 1, 1, 1) self.normal_level_line = Line(width=dp(2)) self.half_level_line = Line(width=dp(2)) def update_elements(self, *args, **kwargs): if not self.values: return if not self.fill_color: self.fill_canvas() max_y = float(max(self.values)) if max_y < 0.01: return normal_level_height = self.height * (1. / max_y) half_level_height = self.height * (.5 / max_y) normal_level_y = self.y + normal_level_height half_level_y = self.y + half_level_height if normal_level_height > self.height: if App.get_running_app().root_window: normal_level_y = App.get_running_app().root_window.height if half_level_height > self.height: if App.get_running_app().root_window: half_level_y = App.get_running_app().root_window.height self.normal_level_line.points = (self.x, normal_level_y, self.x + self.width, normal_level_y) self.normal_level_label.pos = (self.x + self.width - self.LABEL_SIZE, normal_level_y) self.half_level_line.points = (self.x, half_level_y, self.x + self.width, half_level_y) self.half_level_label.pos = (self.x + self.width - self.LABEL_SIZE, half_level_y)
class UserSelector(Button): """ Show and select connected users """ is_active = BooleanProperty(False) users_dropdown = ObjectProperty(None) usernames = ListProperty() selected_username = StringProperty() _connection = ObjectProperty(None) _update_event = ObjectProperty(None) _updating_users = BooleanProperty(False) _new_user_selected = BooleanProperty(False) _selecting_user = BooleanProperty(False) def __init__(self, **kwargs): super().__init__(**kwargs) self._app = App.get_running_app() self.users_dropdown = DropDown(on_select=self._select_user) print("constructor called") def _select_user(self, _, username): """ Select a user :param username: The username to select """ self.selected_username = username self._new_user_selected = True Logger.info(f"User selector:Selected partner: {username}") def _check_for_usernames_response(self): return self._connection.socket.recv(block=False) @staticmethod def _handle_usernames_response(response): """ parse the usernames from the server response :param response: The response the server sent :return: A list of the usernames the server sent """ usernames = response.get_content_as_text().split(", ") Logger.debug(f"User selector:Received usernames: {usernames}") return usernames def _update_dropdown(self, usernames): """ Update the list of the usernames the dropdown displays :param usernames: The usernames to display """ self.users_dropdown.clear_widgets() for username in usernames: self.users_dropdown.add_widget( Button(size_hint_y=None, size=self.size, text=username, on_release=lambda button: self.users_dropdown.select( button.text))) def _check_for_select_response(self): return self._connection.socket.recv(block=False) def _handle_select_response(self, response): pass def _finnish_selecting(self): self._app.partner = self.selected_username def _send_usernames_request(self): Logger.debug("User selector:Requesting usernames") self._connection.socket.send( Message(MESSAGE_TYPES["server interaction"], "get all connected usernames")) def _send_select_request(self): Logger.debug( f"User selector:Sending set partner: {self.selected_username}") self._connection.socket.send( Message(MESSAGE_TYPES["server interaction"], f"set partner\n{self.selected_username}")) def _update_users(self, _): try: if self._updating_users: usernames_response = self._check_for_usernames_response() if usernames_response is not None: usernames = UserSelector._handle_usernames_response( usernames_response) self._update_dropdown(usernames) self._updating_users = False elif self._selecting_user: select_response = self._check_for_select_response() if select_response is not None: self._handle_select_response(select_response) self._finnish_selecting() self._selecting_user = False elif self._new_user_selected: self._send_select_request() self._selecting_user = True self._new_user_selected = False else: self._send_usernames_request() self._updating_users = True except ConnectionClosed: # Unexpected close Logger.error("User selector:Unexpected close, closing!") self.close() except Exception as e: # TODO: be more specific print(e) Logger.error("User selector:Unexpected error, closing!", exc_info=True) self.close() def on_release(self): """ Open the dropdown """ Logger.debug("User selector:Attempting to open dropdown") if self.is_active: Logger.debug("User selector:Opening dropdown") self.users_dropdown.open(self) else: Logger.debug("User selector:Did not open dropdown " "since it is closed or had not started") def start(self, connection): """ Start receiving users and displaying them :param connection: The connection to get the users with """ Logger.info("User selector:Starting") self.is_active = True self._connection = connection self._update_event = Clock.schedule_interval( self._update_users, UPDATE_USERS_REFRESH_RATE) def close(self): """ Close the users getter Only call this after opening """ Logger.info("User selector:Closing") self.is_active = False if self._update_event is not None: self._update_event.cancel()
class Image(Widget): '''Image class, see module documentation for more information. ''' source = StringProperty(None) '''Filename / source of your image. :attr:`source` is a :class:`~kivy.properties.StringProperty` and defaults to None. ''' texture = ObjectProperty(None, allownone=True) '''Texture object of the image. The texture represents the original, loaded image texture. It is streched and positioned during rendering according to the :attr:`allow_stretch` and :attr:`keep_ratio` properties. Depending of the texture creation, the value will be a :class:`~kivy.graphics.texture.Texture` or a :class:`~kivy.graphics.texture.TextureRegion` object. :attr:`texture` is an :class:`~kivy.properties.ObjectProperty` and defaults to None. ''' texture_size = ListProperty([0, 0]) '''Texture size of the image. This represents the original, loaded image texture size. .. warning:: The texture size is set after the texture property. So if you listen to the change on :attr:`texture`, the property texture_size will not be up-to-date. Use self.texture.size instead. ''' def get_image_ratio(self): if self.texture: return self.texture.width / float(self.texture.height) return 1. mipmap = BooleanProperty(False) '''Indicate if you want OpenGL mipmapping to be applied to the texture. Read :ref:`mipmap` for more information. .. versionadded:: 1.0.7 :attr:`mipmap` is a :class:`~kivy.properties.BooleanProperty` and defaults to False. ''' image_ratio = AliasProperty(get_image_ratio, None, bind=('texture', )) '''Ratio of the image (width / float(height). :attr:`image_ratio` is an :class:`~kivy.properties.AliasProperty` and is read-only. ''' color = ListProperty([1, 1, 1, 1]) '''Image color, in the format (r, g, b, a). This attribute can be used to 'tint' an image. Be careful: if the source image is not gray/white, the color will not really work as expected. .. versionadded:: 1.0.6 :attr:`color` is a :class:`~kivy.properties.ListProperty` and defaults to [1, 1, 1, 1]. ''' allow_stretch = BooleanProperty(False) '''If True, the normalized image size will be maximized to fit in the image box. Otherwise, if the box is too tall, the image will not be stretched more than 1:1 pixels. .. versionadded:: 1.0.7 :attr:`allow_stretch` is a :class:`~kivy.properties.BooleanProperty` and defaults to False. ''' keep_ratio = BooleanProperty(True) '''If False along with allow_stretch being True, the normalized image size will be maximized to fit in the image box and ignores the aspect ratio of the image. Otherwise, if the box is too tall, the image will not be stretched more than 1:1 pixels. .. versionadded:: 1.0.8 :attr:`keep_ratio` is a :class:`~kivy.properties.BooleanProperty` and defaults to True. ''' keep_data = BooleanProperty(False) '''If True, the underlaying _coreimage will store the raw image data. This is useful when performing pixel based collision detection. .. versionadded:: 1.3.0 :attr:`keep_data` is a :class:`~kivy.properties.BooleanProperty` and defaults to False. ''' anim_delay = NumericProperty(.25) '''Delay the animation if the image is sequenced (like an animated gif). If anim_delay is set to -1, the animation will be stopped. .. versionadded:: 1.0.8 :attr:`anim_delay` is a :class:`~kivy.properties.NumericProperty` and defaults to 0.25 (4 FPS). ''' anim_loop = NumericProperty(0) '''Number of loops to play then stop animating. 0 means keep animating. .. versionadded:: 1.9.0 :attr:`anim_loop` is a :class:`~kivy.properties.NumericProperty` and defaults to 0. ''' nocache = BooleanProperty(False) '''If this property is set True, the image will not be added to the internal cache. The cache will simply ignore any calls trying to append the core image. .. versionadded:: 1.6.0 :attr:`nocache` is a :class:`~kivy.properties.BooleanProperty` and defaults to False. ''' def get_norm_image_size(self): if not self.texture: return self.size ratio = self.image_ratio w, h = self.size tw, th = self.texture.size # ensure that the width is always maximized to the containter width if self.allow_stretch: if not self.keep_ratio: return w, h iw = w else: iw = min(w, tw) # calculate the appropriate height ih = iw / ratio # if the height is too higher, take the height of the container # and calculate appropriate width. no need to test further. :) if ih > h: if self.allow_stretch: ih = h else: ih = min(h, th) iw = ih * ratio return iw, ih norm_image_size = AliasProperty(get_norm_image_size, None, bind=( 'texture', 'size', 'image_ratio', 'allow_stretch')) '''Normalized image size within the widget box. This size will always fit the widget size and will preserve the image ratio. :attr:`norm_image_size` is an :class:`~kivy.properties.AliasProperty` and is read-only. ''' def __init__(self, **kwargs): self._coreimage = None self._loops = 0 super(Image, self).__init__(**kwargs) fbind = self.fbind update = self.texture_update fbind('source', update) fbind('mipmap', update) if self.source: update() self.on_anim_delay(self, kwargs.get('anim_delay', .25)) def texture_update(self, *largs): if not self.source: self.texture = None else: filename = resource_find(self.source) self._loops = 0 if filename is None: return Logger.error('Image: Error reading file {filename}'. format(filename=self.source)) mipmap = self.mipmap if self._coreimage is not None: self._coreimage.unbind(on_texture=self._on_tex_change) try: if PY2: filename = filename.decode('utf-8') self._coreimage = ci = CoreImage(filename, mipmap=mipmap, anim_delay=self.anim_delay, keep_data=self.keep_data, nocache=self.nocache) except Exception as e: Logger.exception(e) self._coreimage = ci = None if ci: ci.bind(on_texture=self._on_tex_change) self.texture = ci.texture def on_anim_delay(self, instance, value): self._loop = 0 if self._coreimage is None: return self._coreimage.anim_delay = value if value < 0: self._coreimage.anim_reset(False) def on_texture(self, instance, value): if value is not None: self.texture_size = list(value.size) def _on_tex_change(self, *largs): # update texture from core image self.texture = self._coreimage.texture ci = self._coreimage if self.anim_loop and ci._anim_index == len(ci._image.textures) - 1: self._loops += 1 if self.anim_loop == self._loops: ci.anim_reset(False) self._loops = 0 def reload(self): '''Reload image from disk. This facilitates re-loading of images from disk in case the image content changes. .. versionadded:: 1.3.0 Usage:: im = Image(source = '1.jpg') # -- do something -- im.reload() # image will be re-loaded from disk ''' try: self._coreimage.remove_from_cache() except AttributeError: pass olsource = self.source self.source = '' self.source = olsource def on_nocache(self, *args): if self.nocache and self._coreimage: self._coreimage.remove_from_cache() self._coreimage._nocache = True
class EnvironmentWidget(RelativeLayout): base_color = ListProperty() temperature_value_color = ListProperty() temperature_label_color = ListProperty() humidity_value_color = ListProperty() humidity_label_color = ListProperty() quality_color_1 = ListProperty() quality_color_2 = ListProperty() quality_color_3 = ListProperty() quality_color_4 = ListProperty() quality_color_5 = ListProperty() VALUE_COLOR = "fresh" LABEL_COLOR = "base" QUALITY_COLOR = ["green", "green", "yellow", "yellow", "red"] temperature = StringProperty("--") humidity = StringProperty("--") def __init__(self, cfg, mqttc, **kwargs): self.base_color = RMColor.get_rgba("base") self._set_temperature(None) self._set_humidity(None) self.quality_color_1 = RMColor.get_rgba("reboot") self.quality_color_2 = RMColor.get_rgba("reboot") self.quality_color_3 = RMColor.get_rgba("reboot") self.quality_color_4 = RMColor.get_rgba("reboot") self.quality_color_5 = RMColor.get_rgba("reboot") super(EnvironmentWidget, self).__init__(**kwargs) self.cfg = cfg self.mqtt = mqttc mqtt.add_topic_callback(self.mqtt, self.cfg.get('Environment', "temperature"), self._on_temperature_update) mqtt.add_topic_callback(self.mqtt, self.cfg.get('Environment', "humidity"), self._on_humidity_update) mqtt.add_topic_callback(self.mqtt, self.cfg.get('Environment', "air_quality"), self._on_air_quality_update) def _on_temperature_update(self, _client, _userdata, message): payload = message.payload.decode("utf-8") self._set_temperature(payload) def _on_humidity_update(self, _client, _userdata, message): payload = message.payload.decode("utf-8") self._set_humidity(payload) def _on_air_quality_update(self, _client, _userdata, message): payload = message.payload.decode("utf-8") self._set_air_quality(payload) def _set_temperature(self, temperature): if temperature is None: self.temperature = "--" self.temperature_value_color = RMColor.get_rgba("reboot") self.temperature_label_color = RMColor.get_rgba("reboot") else: t = round(float(temperature)) self.temperature = "{:02d}".format(t) self.temperature_value_color = RMColor.get_rgba( EnvironmentWidget.VALUE_COLOR) self.temperature_label_color = RMColor.get_rgba( EnvironmentWidget.LABEL_COLOR) def _set_humidity(self, humidity): if humidity is None: self.humidity = "--" self.humidity_value_color = RMColor.get_rgba("reboot") self.humidity_label_color = RMColor.get_rgba("reboot") else: h = round(float(humidity)) self.humidity = "{:02d}".format(h) self.humidity_value_color = RMColor.get_rgba( EnvironmentWidget.VALUE_COLOR) self.humidity_label_color = RMColor.get_rgba( EnvironmentWidget.LABEL_COLOR) def _set_air_quality(self, air_quality): q = float(air_quality) off = RMColor.get_rgba("off") self.quality_color_1 = off if q < 1 else RMColor.get_rgba( EnvironmentWidget.QUALITY_COLOR[0]) self.quality_color_2 = off if q < 2 else RMColor.get_rgba( EnvironmentWidget.QUALITY_COLOR[1]) self.quality_color_3 = off if q < 3 else RMColor.get_rgba( EnvironmentWidget.QUALITY_COLOR[2]) self.quality_color_4 = off if q < 4 else RMColor.get_rgba( EnvironmentWidget.QUALITY_COLOR[3]) self.quality_color_5 = off if q < 5 else RMColor.get_rgba( EnvironmentWidget.QUALITY_COLOR[4])
class ItemDrawer(OneLineIconListItem): icon = StringProperty() text_color = ListProperty((0, 0, 0, 1))
class ButtonIcon(ButtonBase): icon = StringProperty('') text = StringProperty('') icon_align = OptionProperty("center", options=("center", "left", "right")) icon_size = ObjectProperty("20dp") __label_size_hint__ = ListProperty([1, .2]) __label_container__ = ObjectProperty(allownone=False) __orientation__ = OptionProperty("vertical", options=("vertical", "horizontal")) __widget_icon__ = ObjectProperty(None) def get_font_size_icon(self): if type(self.font_size) is str: self.font_size = dp(self.font_size.replace('dp', '')) if type(self.icon_size) is str: self.icon_size = dp(self.icon_size.replace('dp', '')) return self.font_size + self.icon_size font_size_icon = AliasProperty(get_font_size_icon, bind=["font_size", "icon_size"]) def __init__(self, **kargs): super(ButtonIcon, self).__init__(**kargs) def on_label_container(self, w, val): if self.text != "" and len(self.__label_container__.children) == 1: self.add_label() def on_text(self, w, val): if val != "" and self.__label_container__ and len( self.__label_container__.children) == 1: self.add_label() def add_label(self): label = Label(text=self.text, font_size=self.font_size, color=self.color, halign='center', valign='middle', size_hint=self.__label_size_hint__) self.bind(__label_size_hint__=label.setter('size_hint')) self.bind(size=label.setter('text_size')) self.bind(text=label.setter('text')) self.bind(color=label.setter('color')) self.bind(font_size=label.setter('font_size')) self.__label_container__.add_widget(label) if self.icon_align == "right": self.__label_container__.remove_widget(self.__widget_icon__) self.__label_container__.add_widget(self.__widget_icon__) def on_icon_align(self, w, val): if val == "center": self.__label_size_hint__ = (1, .2) self.__orientation__ = "vertical" elif val == "left" or val == "right": self.__orientation__ = "horizontal" self.__label_size_hint__ = (.8, 1) self.__widget_icon__.size_hint_x = .15 if val == "right": self.__label_container__.remove_widget(self.__widget_icon__) self.__label_container__.add_widget(self.__widget_icon__)
class Widget(WidgetBase): '''Widget class. See module documentation for more information. :Events: `on_touch_down`: Fired when a new touch event occurs `on_touch_move`: Fired when an existing touch moves `on_touch_up`: Fired when an existing touch disappears .. warning:: Adding a `__del__` method to a class derived from Widget with Python prior to 3.4 will disable automatic garbage collection for instances of that class. This is because the Widget class creates reference cycles, thereby `preventing garbage collection <https://docs.python.org/2/library/gc.html#gc.garbage>`_. .. versionchanged:: 1.0.9 Everything related to event properties has been moved to the :class:`~kivy.event.EventDispatcher`. Event properties can now be used when contructing a simple class without subclassing :class:`Widget`. .. versionchanged:: 1.5.0 The constructor now accepts on_* arguments to automatically bind callbacks to properties or events, as in the Kv language. ''' __metaclass__ = WidgetMetaclass __events__ = ('on_touch_down', 'on_touch_move', 'on_touch_up') _proxy_ref = None def __init__(self, **kwargs): # Before doing anything, ensure the windows exist. EventLoop.ensure_window() # Assign the default context of the widget creation. if not hasattr(self, '_context'): self._context = get_current_context() no_builder = '__no_builder' in kwargs if no_builder: del kwargs['__no_builder'] on_args = {k: v for k, v in kwargs.items() if k[:3] == 'on_'} for key in on_args: del kwargs[key] super(Widget, self).__init__(**kwargs) # Create the default canvas if it does not exist. if self.canvas is None: self.canvas = Canvas(opacity=self.opacity) # Apply all the styles. if not no_builder: Builder.apply(self, ignored_consts=self._kwargs_applied_init) # Bind all the events. if on_args: self.bind(**on_args) @property def proxy_ref(self): '''Return a proxy reference to the widget, i.e. without creating a reference to the widget. See `weakref.proxy <http://docs.python.org/2/library/weakref.html?highlight\ =proxy#weakref.proxy>`_ for more information. .. versionadded:: 1.7.2 ''' _proxy_ref = self._proxy_ref if _proxy_ref is not None: return _proxy_ref f = partial(_widget_destructor, self.uid) self._proxy_ref = _proxy_ref = WeakProxy(self, f) # Only f should be enough here, but it appears that is a very # specific case, the proxy destructor is not called if both f and # _proxy_ref are not together in a tuple. _widget_destructors[self.uid] = (f, _proxy_ref) return _proxy_ref def __hash__(self): return id(self) @property def __self__(self): return self # # Collision # def collide_point(self, x, y): ''' Check if a point (x, y) is inside the widget's axis aligned bounding box. :Parameters: `x`: numeric x position of the point (in window coordinates) `y`: numeric y position of the point (in window coordinates) :Returns: A bool. True if the point is inside the bounding box, False otherwise. .. code-block:: python >>> Widget(pos=(10, 10), size=(50, 50)).collide_point(40, 40) True ''' return self.x <= x <= self.right and self.y <= y <= self.top def collide_widget(self, wid): ''' Check if another widget collides with this widget. This function performs an axis-aligned bounding box intersection test by default. :Parameters: `wid`: :class:`Widget` class Widget to collide with. :Returns: bool. True if the other widget collides with this widget, False otherwise. .. code-block:: python >>> wid = Widget(size=(50, 50)) >>> wid2 = Widget(size=(50, 50), pos=(25, 25)) >>> wid.collide_widget(wid2) True >>> wid2.pos = (55, 55) >>> wid.collide_widget(wid2) False ''' if self.right < wid.x: return False if self.x > wid.right: return False if self.top < wid.y: return False if self.y > wid.top: return False return True # # Default event handlers # def on_touch_down(self, touch): '''Receive a touch down event. :Parameters: `touch`: :class:`~kivy.input.motionevent.MotionEvent` class Touch received. The touch is in parent coordinates. See :mod:`~kivy.uix.relativelayout` for a discussion on coordinate systems. :Returns: bool If True, the dispatching of the touch event will stop. If False, the event will continue to be dispatched to the rest of the widget tree. ''' if self.disabled and self.collide_point(*touch.pos): return True for child in self.children[:]: if child.dispatch('on_touch_down', touch): return True def on_touch_move(self, touch): '''Receive a touch move event. The touch is in parent coordinates. See :meth:`on_touch_down` for more information. ''' if self.disabled: return for child in self.children[:]: if child.dispatch('on_touch_move', touch): return True def on_touch_up(self, touch): '''Receive a touch up event. The touch is in parent coordinates. See :meth:`on_touch_down` for more information. ''' if self.disabled: return for child in self.children[:]: if child.dispatch('on_touch_up', touch): return True def on_disabled(self, instance, value): for child in self.children: child.disabled = value # # Tree management # def add_widget(self, widget, index=0, canvas=None): '''Add a new widget as a child of this widget. :Parameters: `widget`: :class:`Widget` Widget to add to our list of children. `index`: int, defaults to 0 Index to insert the widget in the list. Notice that the default of 0 means the widget is inserted at the beginning of the list and will thus be drawn on top of other sibling widgets. For a full discussion of the index and widget hierarchy, please see the :doc:`Widgets Programming Guide <guide/widgets>`. .. versionadded:: 1.0.5 `canvas`: str, defaults to None Canvas to add widget's canvas to. Can be 'before', 'after' or None for the default canvas. .. versionadded:: 1.9.0 .. code-block:: python >>> from kivy.uix.button import Button >>> from kivy.uix.slider import Slider >>> root = Widget() >>> root.add_widget(Button()) >>> slider = Slider() >>> root.add_widget(slider) ''' if not isinstance(widget, Widget): raise WidgetException( 'add_widget() can be used only with instances' ' of the Widget class.') widget = widget.__self__ if widget is self: raise WidgetException( 'Widget instances cannot be added to themselves.') parent = widget.parent # Check if the widget is already a child of another widget. if parent: raise WidgetException('Cannot add %r, it already has a parent %r' % (widget, parent)) widget.parent = parent = self # Child will be disabled if added to a disabled parent. if parent.disabled: widget.disabled = True canvas = self.canvas.before if canvas == 'before' else \ self.canvas.after if canvas == 'after' else self.canvas if index == 0 or len(self.children) == 0: self.children.insert(0, widget) canvas.add(widget.canvas) else: canvas = self.canvas children = self.children if index >= len(children): index = len(children) next_index = canvas.indexof(children[-1].canvas) else: next_child = children[index] next_index = canvas.indexof(next_child.canvas) if next_index == -1: next_index = canvas.length() else: next_index += 1 children.insert(index, widget) # We never want to insert widget _before_ canvas.before. if next_index == 0 and canvas.has_before: next_index = 1 canvas.insert(next_index, widget.canvas) def remove_widget(self, widget): '''Remove a widget from the children of this widget. :Parameters: `widget`: :class:`Widget` Widget to remove from our children list. .. code-block:: python >>> from kivy.uix.button import Button >>> root = Widget() >>> button = Button() >>> root.add_widget(button) >>> root.remove_widget(button) ''' if widget not in self.children: return self.children.remove(widget) if widget.canvas in self.canvas.children: self.canvas.remove(widget.canvas) elif widget.canvas in self.canvas.after.children: self.canvas.after.remove(widget.canvas) elif widget.canvas in self.canvas.before.children: self.canvas.before.remove(widget.canvas) widget.parent = None def clear_widgets(self, children=None): ''' Remove all (or the specified) :attr:`~Widget.children` of this widget. If the 'children' argument is specified, it should be a list (or filtered list) of children of the current widget. .. versionchanged:: 1.8.0 The `children` argument can be used to specify the children you want to remove. ''' if not children: children = self.children remove_widget = self.remove_widget for child in children[:]: remove_widget(child) def export_to_png(self, filename, *args): '''Saves an image of the widget and its children in png format at the specified filename. Works by removing the widget canvas from its parent, rendering to an :class:`~kivy.graphics.fbo.Fbo`, and calling :meth:`~kivy.graphics.texture.Texture.save`. .. note:: The image includes only this widget and its children. If you want to include widgets elsewhere in the tree, you must call :meth:`~Widget.export_to_png` from their common parent, or use :meth:`~kivy.core.window.WindowBase.screenshot` to capture the whole window. .. note:: The image will be saved in png format, you should include the extension in your filename. .. versionadded:: 1.9.0 ''' if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) if canvas_parent_index > -1: self.parent.canvas.remove(self.canvas) fbo = Fbo(size=self.size, with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Scale(1, -1, 1) Translate(-self.x, -self.y - self.height, 0) fbo.add(self.canvas) fbo.draw() fbo.texture.save(filename, flipped=False) fbo.remove(self.canvas) if self.parent is not None and canvas_parent_index > -1: self.parent.canvas.insert(canvas_parent_index, self.canvas) return True def get_root_window(self): '''Return the root window. :Returns: Instance of the root window. Can be a :class:`~kivy.core.window.WindowBase` or :class:`Widget`. ''' if self.parent: return self.parent.get_root_window() def get_parent_window(self): '''Return the parent window. :Returns: Instance of the parent window. Can be a :class:`~kivy.core.window.WindowBase` or :class:`Widget`. ''' if self.parent: return self.parent.get_parent_window() def _walk(self, restrict=False, loopback=False, index=None): # We pass index only when we are going on the parent # so don't yield the parent as well. if index is None: index = len(self.children) yield self for child in reversed(self.children[:index]): for walk_child in child._walk(restrict=True): yield walk_child # If we want to continue with our parent, just do it. if not restrict: parent = self.parent try: if parent is None or not isinstance(parent, Widget): raise ValueError index = parent.children.index(self) except ValueError: # Self is root, if we want to loopback from the first element: if not loopback: return # If we started with root (i.e. index==None), then we have to # start from root again, so we return self again. Otherwise, we # never returned it, so return it now starting with it. parent = self index = None for walk_child in parent._walk(loopback=loopback, index=index): yield walk_child def walk(self, restrict=False, loopback=False): ''' Iterator that walks the widget tree starting with this widget and goes forward returning widgets in the order in which layouts display them. :Parameters: `restrict`: bool, defaults to False If True, it will only iterate through the widget and its children (or children of its children etc.). Defaults to False. `loopback`: bool, defaults to False If True, when the last widget in the tree is reached, it'll loop back to the uppermost root and start walking until we hit this widget again. Naturally, it can only loop back when `restrict` is False. Defaults to False. :return: A generator that walks the tree, returning widgets in the forward layout order. For example, given a tree with the following structure: .. code-block:: kv GridLayout: Button BoxLayout: id: box Widget Button Widget walking this tree: .. code-block:: python >>> # Call walk on box with loopback True, and restrict False >>> [type(widget) for widget in box.walk(loopback=True)] [<class 'BoxLayout'>, <class 'Widget'>, <class 'Button'>, <class 'Widget'>, <class 'GridLayout'>, <class 'Button'>] >>> # Now with loopback False, and restrict False >>> [type(widget) for widget in box.walk()] [<class 'BoxLayout'>, <class 'Widget'>, <class 'Button'>, <class 'Widget'>] >>> # Now with restrict True >>> [type(widget) for widget in box.walk(restrict=True)] [<class 'BoxLayout'>, <class 'Widget'>, <class 'Button'>] .. versionadded:: 1.9.0 ''' gen = self._walk(restrict, loopback) yield next(gen) for node in gen: if node is self: return yield node def _walk_reverse(self, loopback=False, go_up=False): # process is walk up level, walk down its children tree, then walk up # next level etc. # default just walk down the children tree root = self index = 0 # we need to go up a level before walking tree if go_up: root = self.parent try: if root is None or not isinstance(root, Widget): raise ValueError index = root.children.index(self) + 1 except ValueError: if not loopback: return index = 0 go_up = False root = self # now walk children tree starting with last-most child for child in islice(root.children, index, None): for walk_child in child._walk_reverse(loopback=loopback): yield walk_child # we need to return ourself last, in all cases yield root # if going up, continue walking up the parent tree if go_up: for walk_child in root._walk_reverse(loopback=loopback, go_up=go_up): yield walk_child def walk_reverse(self, loopback=False): ''' Iterator that walks the widget tree backwards starting with the widget before this, and going backwards returning widgets in the reverse order in which layouts display them. This walks in the opposite direction of :meth:`walk`, so a list of the tree generated with :meth:`walk` will be in reverse order compared to the list generated with this, provided `loopback` is True. :Parameters: `loopback`: bool, defaults to False If True, when the uppermost root in the tree is reached, it'll loop back to the last widget and start walking back until after we hit widget again. Defaults to False. :return: A generator that walks the tree, returning widgets in the reverse layout order. For example, given a tree with the following structure: .. code-block:: kv GridLayout: Button BoxLayout: id: box Widget Button Widget walking this tree: .. code-block:: python >>> # Call walk on box with loopback True >>> [type(widget) for widget in box.walk_reverse(loopback=True)] [<class 'Button'>, <class 'GridLayout'>, <class 'Widget'>, <class 'Button'>, <class 'Widget'>, <class 'BoxLayout'>] >>> # Now with loopback False >>> [type(widget) for widget in box.walk_reverse()] [<class 'Button'>, <class 'GridLayout'>] >>> forward = [w for w in box.walk(loopback=True)] >>> backward = [w for w in box.walk_reverse(loopback=True)] >>> forward == backward[::-1] True .. versionadded:: 1.9.0 ''' for node in self._walk_reverse(loopback=loopback, go_up=True): yield node if node is self: return def to_widget(self, x, y, relative=False): '''Convert the given coordinate from window to local widget coordinates. See :mod:`~kivy.uix.relativelayout` for details on the coordinate systems. ''' if self.parent: x, y = self.parent.to_widget(x, y) return self.to_local(x, y, relative=relative) def to_window(self, x, y, initial=True, relative=False): '''Transform local coordinates to window coordinates. See :mod:`~kivy.uix.relativelayout` for details on the coordinate systems. ''' if not initial: x, y = self.to_parent(x, y, relative=relative) if self.parent: return self.parent.to_window(x, y, initial=False, relative=relative) return (x, y) def to_parent(self, x, y, relative=False): '''Transform local coordinates to parent coordinates. See :mod:`~kivy.uix.relativelayout` for details on the coordinate systems. :Parameters: `relative`: bool, defaults to False Change to True if you want to translate relative positions from a widget to its parent coordinates. ''' if relative: return (x + self.x, y + self.y) return (x, y) def to_local(self, x, y, relative=False): '''Transform parent coordinates to local coordinates. See :mod:`~kivy.uix.relativelayout` for details on the coordinate systems. :Parameters: `relative`: bool, defaults to False Change to True if you want to translate coordinates to relative widget coordinates. ''' if relative: return (x - self.x, y - self.y) return (x, y) def _apply_transform(self, m, pos=None): if self.parent: x, y = self.parent.to_widget(relative=True, *self.to_window(*(pos or self.pos))) m.translate(x, y, 0) m = self.parent._apply_transform(m) if self.parent else m return m def get_window_matrix(self, x=0, y=0): '''Calculate the transformation matrix to convert between window and widget coordinates. :Parameters: `x`: float, defaults to 0 Translates the matrix on the x axis. `y`: float, defaults to 0 Translates the matrix on the y axis. ''' m = Matrix() m.translate(x, y, 0) m = self._apply_transform(m) return m x = NumericProperty(0) '''X position of the widget. :attr:`x` is a :class:`~kivy.properties.NumericProperty` and defaults to 0. ''' y = NumericProperty(0) '''Y position of the widget. :attr:`y` is a :class:`~kivy.properties.NumericProperty` and defaults to 0. ''' width = NumericProperty(100) '''Width of the widget. :attr:`width` is a :class:`~kivy.properties.NumericProperty` and defaults to 100. .. warning:: Keep in mind that the `width` property is subject to layout logic and that this has not yet happened at the time of the widget's `__init__` method. ''' height = NumericProperty(100) '''Height of the widget. :attr:`height` is a :class:`~kivy.properties.NumericProperty` and defaults to 100. .. warning:: Keep in mind that the `height` property is subject to layout logic and that this has not yet happened at the time of the widget's `__init__` method. ''' pos = ReferenceListProperty(x, y) '''Position of the widget. :attr:`pos` is a :class:`~kivy.properties.ReferenceListProperty` of (:attr:`x`, :attr:`y`) properties. ''' size = ReferenceListProperty(width, height) '''Size of the widget. :attr:`size` is a :class:`~kivy.properties.ReferenceListProperty` of (:attr:`width`, :attr:`height`) properties. ''' def get_right(self): return self.x + self.width def set_right(self, value): self.x = value - self.width right = AliasProperty(get_right, set_right, bind=('x', 'width')) '''Right position of the widget. :attr:`right` is an :class:`~kivy.properties.AliasProperty` of (:attr:`x` + :attr:`width`). ''' def get_top(self): return self.y + self.height def set_top(self, value): self.y = value - self.height top = AliasProperty(get_top, set_top, bind=('y', 'height')) '''Top position of the widget. :attr:`top` is an :class:`~kivy.properties.AliasProperty` of (:attr:`y` + :attr:`height`). ''' def get_center_x(self): return self.x + self.width / 2. def set_center_x(self, value): self.x = value - self.width / 2. center_x = AliasProperty(get_center_x, set_center_x, bind=('x', 'width')) '''X center position of the widget. :attr:`center_x` is an :class:`~kivy.properties.AliasProperty` of (:attr:`x` + :attr:`width` / 2.). ''' def get_center_y(self): return self.y + self.height / 2. def set_center_y(self, value): self.y = value - self.height / 2. center_y = AliasProperty(get_center_y, set_center_y, bind=('y', 'height')) '''Y center position of the widget. :attr:`center_y` is an :class:`~kivy.properties.AliasProperty` of (:attr:`y` + :attr:`height` / 2.). ''' center = ReferenceListProperty(center_x, center_y) '''Center position of the widget. :attr:`center` is a :class:`~kivy.properties.ReferenceListProperty` of (:attr:`center_x`, :attr:`center_y`) properties. ''' cls = ListProperty([]) '''Class of the widget, used for styling. ''' id = StringProperty(None, allownone=True) '''Unique identifier of the widget in the tree. :attr:`id` is a :class:`~kivy.properties.StringProperty` and defaults to None. .. warning:: If the :attr:`id` is already used in the tree, an exception will be raised. ''' children = ListProperty([]) '''List of children of this widget. :attr:`children` is a :class:`~kivy.properties.ListProperty` and defaults to an empty list. Use :meth:`add_widget` and :meth:`remove_widget` for manipulating the children list. Don't manipulate the children list directly unless you know what you are doing. ''' parent = ObjectProperty(None, allownone=True, rebind=True) '''Parent of this widget. The parent of a widget is set when the widget is added to another widget and unset when the widget is removed from its parent. :attr:`parent` is an :class:`~kivy.properties.ObjectProperty` and defaults to None. ''' size_hint_x = NumericProperty(1, allownone=True) '''X size hint. Represents how much space the widget should use in the direction of the X axis relative to its parent's width. Only the :class:`~kivy.uix.layout.Layout` and :class:`~kivy.core.window.Window` classes make use of the hint. The size_hint is used by layouts for two purposes: - When the layout considers widgets on their own rather than in relation to its other children, the size_hint_x is a direct proportion of the parent width, normally between 0.0 and 1.0. For instance, a widget with ``size_hint_x=0.5`` in a vertical BoxLayout will take up half the BoxLayout's width, or a widget in a FloatLayout with ``size_hint_x=0.2`` will take up 20% of the FloatLayout width. If the size_hint is greater than 1, the widget will be wider than the parent. - When multiple widgets can share a row of a layout, such as in a horizontal BoxLayout, their widths will be their size_hint_x as a fraction of the sum of widget size_hints. For instance, if the size_hint_xs are (0.5, 1.0, 0.5), the first widget will have a width of 25% of the parent width. :attr:`size_hint_x` is a :class:`~kivy.properties.NumericProperty` and defaults to 1. ''' size_hint_y = NumericProperty(1, allownone=True) '''Y size hint. :attr:`size_hint_y` is a :class:`~kivy.properties.NumericProperty` and defaults to 1. See :attr:`size_hint_x` for more information, but with widths and heights swapped. ''' size_hint = ReferenceListProperty(size_hint_x, size_hint_y) '''Size hint. :attr:`size_hint` is a :class:`~kivy.properties.ReferenceListProperty` of (:attr:`size_hint_x`, :attr:`size_hint_y`) properties. See :attr:`size_hint_x` for more information. ''' pos_hint = ObjectProperty({}) '''Position hint. This property allows you to set the position of the widget inside its parent layout, in percent (similar to size_hint). For example, if you want to set the top of the widget to be at 90% height of its parent layout, you can write:: widget = Widget(pos_hint={'top': 0.9}) The keys 'x', 'right' and 'center_x' will use the parent width. The keys 'y', 'top' and 'center_y' will use the parent height. See :doc:`api-kivy.uix.floatlayout` for further reference. .. note:: :attr:`pos_hint` is not used by all layouts. Check the documentation of the layout in question to see if it supports pos_hint. :attr:`pos_hint` is an :class:`~kivy.properties.ObjectProperty` containing a dict. ''' size_hint_min_x = NumericProperty(None, allownone=True) '''When not None, the X-direction minimum size (in pixels, like :attr:`width`) when :attr:`size_hint_x` is also not None. When :attr:`size_hint_x` is not None, it is the minimum width that the widget will be set due to the :attr:`size_hint_x`. I.e. when a smaller size would be set, :attr:`size_hint_min_x` is the value used instead for the widget width. When None, or when :attr:`size_hint_x` is None, :attr:`size_hint_min_x` doesn't do anything. Only the :class:`~kivy.uix.layout.Layout` and :class:`~kivy.core.window.Window` classes make use of the hint. :attr:`size_hint_min_x` is a :class:`~kivy.properties.NumericProperty` and defaults to None. .. versionadded:: 1.9.2 ''' size_hint_min_y = NumericProperty(None, allownone=True) '''When not None, the Y-direction minimum size (in pixels, like :attr:`height`) when :attr:`size_hint_y` is also not None. When :attr:`size_hint_y` is not None, it is the minimum height that the widget will be set due to the :attr:`size_hint_y`. I.e. when a smaller size would be set, :attr:`size_hint_min_y` is the value used instead for the widget height. When None, or when :attr:`size_hint_y` is None, :attr:`size_hint_min_y` doesn't do anything. Only the :class:`~kivy.uix.layout.Layout` and :class:`~kivy.core.window.Window` classes make use of the hint. :attr:`size_hint_min_y` is a :class:`~kivy.properties.NumericProperty` and defaults to None. .. versionadded:: 1.9.2 ''' size_hint_min = ReferenceListProperty(size_hint_min_x, size_hint_min_y) '''Minimum size when using :attr:`size_hint`. :attr:`size_hint_min` is a :class:`~kivy.properties.ReferenceListProperty` of (:attr:`size_hint_min_x`, :attr:`size_hint_min_y`) properties. .. versionadded:: 1.9.2 ''' size_hint_max_x = NumericProperty(None, allownone=True) '''When not None, the X-direction maximum size (in pixels, like :attr:`width`) when :attr:`size_hint_x` is also not None. Similar to :attr:`size_hint_min_x`, except that it sets the maximum width. :attr:`size_hint_max_x` is a :class:`~kivy.properties.NumericProperty` and defaults to None. .. versionadded:: 1.9.2 ''' size_hint_max_y = NumericProperty(None, allownone=True) '''When not None, the Y-direction maximum size (in pixels, like :attr:`height`) when :attr:`size_hint_y` is also not None. Similar to :attr:`size_hint_min_y`, except that it sets the maximum height. :attr:`size_hint_max_y` is a :class:`~kivy.properties.NumericProperty` and defaults to None. .. versionadded:: 1.9.2 ''' size_hint_max = ReferenceListProperty(size_hint_max_x, size_hint_max_y) '''Maximum size when using :attr:`size_hint`. :attr:`size_hint_max` is a :class:`~kivy.properties.ReferenceListProperty` of (:attr:`size_hint_max_x`, :attr:`size_hint_max_y`) properties. .. versionadded:: 1.9.2 ''' ids = DictProperty({}) '''This is a dictionary of ids defined in your kv language. This will only be populated if you use ids in your kv language code. .. versionadded:: 1.7.0 :attr:`ids` is a :class:`~kivy.properties.DictProperty` and defaults to an empty dict {}. The :attr:`ids` are populated for each root level widget definition. For example: .. code-block:: kv # in kv <MyWidget@Widget>: id: my_widget Label: id: label_widget Widget: id: inner_widget Label: id: inner_label TextInput: id: text_input OtherWidget: id: other_widget <OtherWidget@Widget> id: other_widget Label: id: other_label TextInput: id: other_textinput Then, in python: .. code-block:: python >>> widget = MyWidget() >>> print(widget.ids) {'other_widget': <weakproxy at 041CFED0 to OtherWidget at 041BEC38>, 'inner_widget': <weakproxy at 04137EA0 to Widget at 04138228>, 'inner_label': <weakproxy at 04143540 to Label at 04138260>, 'label_widget': <weakproxy at 04137B70 to Label at 040F97A0>, 'text_input': <weakproxy at 041BB5D0 to TextInput at 041BEC00>} >>> print(widget.ids['other_widget'].ids) {'other_textinput': <weakproxy at 041DBB40 to TextInput at 041BEF48>, 'other_label': <weakproxy at 041DB570 to Label at 041BEEA0>} >>> print(widget.ids['label_widget'].ids) {} ''' opacity = NumericProperty(1.0) '''Opacity of the widget and all its children. .. versionadded:: 1.4.1 The opacity attribute controls the opacity of the widget and its children. Be careful, it's a cumulative attribute: the value is multiplied by the current global opacity and the result is applied to the current context color. For example, if the parent has an opacity of 0.5 and a child has an opacity of 0.2, the real opacity of the child will be 0.5 * 0.2 = 0.1. Then, the opacity is applied by the shader as: .. code-block:: python frag_color = color * vec4(1.0, 1.0, 1.0, opacity); :attr:`opacity` is a :class:`~kivy.properties.NumericProperty` and defaults to 1.0. ''' def on_opacity(self, instance, value): canvas = self.canvas if canvas is not None: canvas.opacity = value canvas = None '''Canvas of the widget. The canvas is a graphics object that contains all the drawing instructions for the graphical representation of the widget. There are no general properties for the Widget class, such as background color, to keep the design simple and lean. Some derived classes, such as Button, do add such convenience properties but generally the developer is responsible for implementing the graphics representation for a custom widget from the ground up. See the derived widget classes for patterns to follow and extend. See :class:`~kivy.graphics.Canvas` for more information about the usage. ''' disabled = BooleanProperty(False) '''Indicates whether this widget can interact with input or not.
class PrivateKeyScreen(Screen): """ Display the actions that work with private keys """ def __init__(self, NuBippyApp, **kwargs): super(PrivateKeyScreen, self).__init__(**kwargs) self.NuBippyApp = NuBippyApp self.passphrase = StringProperty() self.privateKey = StringProperty() self.entropy = ListProperty() self.newKey = BooleanProperty(False) self.isCompressed = True self.isBip = BooleanProperty(False) self.type = False self.prog_string = None # Link to the widgets # New Key page self.mainLayoutNK = self.ids.mainLayoutNK.__self__ self.newKeyAccordionItem = self.ids.newKeyAccordionItem.__self__ self.mainLabelNK = self.ids.mainLabelNK.__self__ self.passfieldLabelNK = self.ids.passfieldLabelNK.__self__ self.passfieldNK = self.ids.passfieldNK.__self__ self.feedbackNK = self.ids.feedbackNK.__self__ self.checkfieldLabelNK = self.ids.checkfieldLabelNK.__self__ self.checkfieldNK = self.ids.checkfieldNK.__self__ self.submitButtonNK = self.ids.submitButtonNK.__self__ self.encryptButtonNK = self.ids.encryptButtonNK.__self__ self.progressBarNK = self.ids.progressBarNK.__self__ self.image = self.ids.image.__self__ #Existing key page self.mainLayoutEK = self.ids.mainLayoutEK.__self__ self.existingKeyAccordionItem = self.ids.existingKeyAccordionItem.__self__ self.mainLabelEK = self.ids.mainLabelEK.__self__ self.privateKeyLabelEK = self.ids.privateKeyLabelEK.__self__ self.privateKeyInputEK = self.ids.privateKeyInputEK.__self__ self.passfieldLabelEK = self.ids.passfieldLabelEK.__self__ self.passfieldEK = self.ids.passfieldEK.__self__ self.feedbackEK = self.ids.feedbackEK.__self__ self.checkfieldLabelEK = self.ids.checkfieldLabelEK.__self__ self.checkfieldEK = self.ids.checkfieldEK.__self__ self.submitButtonEK = self.ids.submitButtonEK.__self__ self.actionButtonEK = self.ids.actionButtonEK.__self__ #remove the widgets that need adding after certain actions. #New Key Page self.mainLayoutNK.remove_widget(self.submitButtonNK) self.mainLayoutNK.remove_widget(self.encryptButtonNK) self.mainLayoutNK.remove_widget(self.progressBarNK) #Existing Key Page self.mainLayoutEK.remove_widget(self.passfieldLabelEK) self.mainLayoutEK.remove_widget(self.passfieldEK) self.mainLayoutEK.remove_widget(self.feedbackEK) self.mainLayoutEK.remove_widget(self.checkfieldLabelEK) self.mainLayoutEK.remove_widget(self.checkfieldEK) self.mainLayoutEK.remove_widget(self.actionButtonEK) self.NuBippyApp.set_info('Private Key') return def reset_ui(self, dt): """ return the UI to it's original state """ # reset the New Key page self.mainLayoutNK.clear_widgets() self.mainLabelNK.text = self.NuBippyApp.get_string('New_Key_Intro_Text') self.mainLayoutNK.add_widget(self.mainLabelNK) self.mainLayoutNK.add_widget(self.passfieldLabelNK) self.passfieldNK.text = '' self.mainLayoutNK.add_widget(self.passfieldNK) self.feedbackNK.text = '' self.mainLayoutNK.add_widget(self.feedbackNK) self.mainLayoutNK.add_widget(self.checkfieldLabelNK) self.checkfieldNK.text = '' self.mainLayoutNK.add_widget(self.checkfieldNK) # reset the existing key page self.mainLayoutEK.clear_widgets() self.mainLabelEK.text = self.NuBippyApp.get_string('Existing_Key_Intro_Text') self.mainLayoutEK.add_widget(self.mainLabelEK) self.mainLayoutEK.add_widget(self.privateKeyLabelEK) self.privateKeyInputEK.text = '' self.mainLayoutEK.add_widget(self.privateKeyInputEK) self.mainLayoutEK.add_widget(self.submitButtonEK) self.passfieldEK.text = '' self.checkfieldEK.text = '' #clear parameters self.passphrase = '' self.privateKey = '' self.entropy = [] self.newKey = False self.type = False self.isCompressed = True self.type = '' return def check_private_key(self, text): """ this method is fired when the submit button is pressed it checks the format of the entered text and ensures that it is a valid private key. returns the private key in """ # check if the entered text is a BIP encrypted key isBip, comment = key.isBip(text) if isBip is True: if comment == 'badchecksum': self.NuBippyApp.show_popup(self.NuBippyApp.get_string('Popup_Error'), self.NuBippyApp.get_string('Bip_Bad_Checksum')) self.privateKeyInputEK.text = '' return self.mainLabelEK.text = self.NuBippyApp.get_string('Bip_Key_Entered') self.privateKey = text self.privateKeyInputEK.text = '' self.type = 'BIP' self.passphrase_entry() self.NuBippyApp.set_info('Bip_Key_Entered_Info') return # check if it is a compressed or uncompressed WIF key isWif, comment = key.isWif(text) if isWif is True: if comment == 'badchecksum': self.NuBippyApp.show_popup(self.NuBippyApp.get_string('Popup_Error'), self.NuBippyApp.get_string('Wif_Bad_Checksum')) self.privateKeyInputEK.text = '' return if comment == 'compressed': self.mainLabelEK.text = self.NuBippyApp.get_string('Compressed_Wif_Key_Entered') self.isCompressed = True if comment == 'uncompressed': self.mainLabelEK.text = self.NuBippyApp.get_string('Uncompressed_Wif_Key_Entered') self.isCompressed = False self.privateKey = text self.type = 'WIF' self.passphrase_entry() self.NuBippyApp.set_info('Valid_Key_Entered_Info') return #check if it's a hex key if key.isHex(text) is True: self.mainLabelEK.text = self.NuBippyApp.get_string('Hex_Key_Entered') self.privateKey = text self.privateKeyInputEK.text = '' self.type = 'HEX' self.passphrase_entry() self.NuBippyApp.set_info('Valid_Key_Entered_Info') return #check if it's a base64 key if key.isBase64(text) is True: self.mainLabelEK.text = self.NuBippyApp.get_string('Base64_Key_Entered') self.privateKey = text self.privateKeyInputEK.text = '' self.type = 'B64' self.passphrase_entry() self.NuBippyApp.set_info('Valid_Key_Entered_Info') return #check if it's a base6 key if key.isBase6(text) is True: self.mainLabelEK.text = self.NuBippyApp.get_string('Base6_Key_Entered') self.privateKey = text self.privateKeyInputEK.text = '' self.type = 'B6' self.passphrase_entry() self.NuBippyApp.set_info('Valid_Key_Entered_Info') return #None of the above rules match so no key has been detected self.type = False self.NuBippyApp.show_popup(self.NuBippyApp.get_string('Popup_Error'), self.NuBippyApp.get_string('Not_Private_Key')) self.reset_ui(None) return def passphrase_entry(self): """ set up the UI ready for passphrase entry """ self.mainLayoutEK.remove_widget(self.privateKeyLabelEK) self.mainLayoutEK.remove_widget(self.privateKeyInputEK) self.mainLayoutEK.remove_widget(self.submitButtonEK) self.mainLayoutEK.add_widget(self.passfieldLabelEK) self.mainLayoutEK.add_widget(self.passfieldEK) self.mainLayoutEK.add_widget(self.feedbackEK) self.mainLayoutEK.add_widget(self.checkfieldLabelEK) self.mainLayoutEK.add_widget(self.checkfieldEK) self.passfieldEK.focus = True return def set_screen(self): """ set the info text based on which accordion item is collapsed """ if self.newKeyAccordionItem.collapse is True and self.type is not False: self.NuBippyApp.set_info('Private_Key_Screen_Info') else: self.NuBippyApp.set_info('Private_Key_New_Key_Screen_Info') return def check_passphrase(self, passfield, checkfield, feedback, layout, button): """ Check that the entered passphrase confirms to the basic rules ialso check that the confirmation matches the original """ layout.remove_widget(button) # get the text we need to compare passphrase = passfield.text checktext = checkfield.text # check for tabs in the passphrase or check string. #tabs don't do anything as standard so we check for them and move the focus accordingly if '\t' in passphrase: passfield.text = passphrase.replace('\t', '') checkfield.focus = True return if '\t' in checktext: checkfield.text = checktext.replace('\t', '') passfield.focus = True return #check the passphrase against the rules if len(passphrase) < 1: feedback.text = '' return if 7 > len(passphrase) > 0: feedback.color = (0.93725, 0.21176, 0.07843, 1) feedback.text = self.NuBippyApp.get_string('Passphrase_Too_Short') return elif passphrase != checktext: feedback.color = (1, 0.72157, 0, 1) feedback.text = self.NuBippyApp.get_string('Passphrases_Dont_Match') return else: feedback.text = '' if self.type == 'BIP': button.text = self.NuBippyApp.get_string('Decrypt') else: button.text = self.NuBippyApp.get_string('Encrypt') layout.add_widget(button) self.passphrase = passphrase return def submit_passphrase(self): """ Submit the passwords and move to the next screen """ # save the passphrase and clear the passphrase boxes self.passphrase = self.passfieldNK.text self.passfieldNK.text = '' self.checkfieldNK.text = '' # restructure the UI self.mainLayoutNK.remove_widget(self.passfieldLabelNK) self.mainLayoutNK.remove_widget(self.passfieldNK) self.mainLayoutNK.remove_widget(self.checkfieldLabelNK) self.mainLayoutNK.remove_widget(self.checkfieldNK) self.mainLayoutNK.remove_widget(self.submitButtonNK) self.mainLayoutNK.add_widget(self.progressBarNK) #Display instructions to the user self.mainLabelNK.text = self.NuBippyApp.get_string('Entropy_Explanation') self.entropy = [] self.bind(on_touch_move=self.draw_entropy) def draw_entropy(self, instance, value=False): """ This function is enabled when only a password has been entered. It allows the user to draw on the image shown to the right of the UI This is the method by which entropy is gathered for generation of key pairs """ with self.canvas: Color(1, 0.72157, 0) d = 5. if self.collide_point(value.x, value.y): Ellipse(pos=(value.x - d / 2, value.y - d / 2), size=(d, d), group='ellipses') self.entropy.append((int(value.x), int(value.y))) self.progressBarNK.value += 1 if self.progressBarNK.value == 800: self.unbind(on_touch_move=self.draw_entropy) self.progressBarNK.value = 0 self.mainLayoutNK.remove_widget(self.progressBarNK) self.canvas.remove_group('ellipses') self.mainLabelNK.text = self.NuBippyApp.get_string('Enough_Entropy') self.mainLayoutNK.add_widget(self.encryptButtonNK) self.newKey = True self.type = 'New' return def action_start(self, layout, label): """ Start the encryption process If we start encryption straight away, the UI doesn't have a chance to update """ # remove widgets and alert the user to the fact that BIP0038 encryption is starting layout.clear_widgets() if self.type == 'BIP': label.text = self.NuBippyApp.get_string('Starting_Decryption') else: label.text = self.NuBippyApp.get_string('Starting_Bip') layout.add_widget(label) # use clock to delay the start of the encryption otherwise the message above is never shown if self.type == 'BIP': Clock.schedule_once(self.decrypt, 0.5) else: Clock.schedule_once(self.encrypt, 0.5) return def encrypt(self, dt): """ Perform the actual encryption """ if self.newKey is True: BIP, bAddress, sAddress = gen.genBIPKey(self.passphrase, self.entropy, '', ) else: # otherwise, we encrypt the existing key BIP, bAddress, sAddress = gen.encBIPKey(self.privateKey, self.passphrase) resultsScreen = self.NuBippyApp.mainScreenManager.get_screen('Results') resultsScreen.display_bip(BIP, bAddress, sAddress) # clear the UI Clock.schedule_once(self.reset_ui, 5) return def decrypt(self, dt): """ Perform the decryption using the saved details """ WIF, bAddress, sAddress = gen.decBIPKey(self.privateKey, self.passphrase) resultsScreen = self.NuBippyApp.mainScreenManager.get_screen('Results') resultsScreen.display_wif(WIF, bAddress, sAddress) # clear the UI Clock.schedule_once(self.reset_ui, 5) return
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 CollectionsList(EventDispatcher): collections = ListProperty([]) popup = ObjectProperty(None, allownone=True) def __str__(self): return 'CollectionsList with {0} collections'.format( len(self.collections)) def __repr__(self): return self.__str__() def save(self, filen='default'): if filen == 'default': if platform() == 'android': default_filen = '/sdcard/noGo/collections_list.json' else: default_filen = '.' + '/collections/collections_list.json' filen = default_filen colstr = self.serialise() with open(filen, 'w') as fileh: fileh.write(colstr) def save_collection(self, colname): cols = filter(lambda j: j.name == colname, self.collections) if len(cols) > 0: cols[0].save() def serialise(self): coll_lists = [ SERIALISATION_VERSION, map(lambda j: j.get_filen(), self.collections) ] return json.dumps(coll_lists) def from_file(self, filen='default'): #default_filen = App.get_running_app().user_data_dir + '/collections_list.json' default_filen = './collections/collections_list.json' if filen == 'default': filen = default_filen with open(filen, 'r') as fileh: colstr = fileh.read() version, colpy = json.loads(colstr) colpy = jsonconvert(colpy) if version == 1: for entry in colpy: col = Collection() col.name = entry[0] col.defaultdir = entry[1] for game in entry[2]: col.games.append(CollectionSgf().from_dict(game, col)) self.collections.append(col) elif version == 2: if self.popup is not None: self.popup.progress = 0 self.popup.length = len(colpy) for entry in colpy: parts = entry.split('/') if len(parts) == 2: # print 'REBUILDING ENTRY' # print 'entry is',entry entry = './collections/' + parts[-1] # # print 'now is',entry try: col = Collection().from_file(entry) self.collections.append(col) if self.popup is not None: # print 'popup is',self.popup, self.popup.progress, self.popup.length self.popup.progress += 1 # time.sleep(1) except IOError: print 'Collection doesn\'t seem to exist. Skipping.' else: print 'Collection list version not recognised.' return self def new_collection(self, newname): if platform() == 'android': dirn = '/sdcard/noGo/collections/{0}'.format(newname) else: dirn = './games/{0}'.format(newname) print 'Making dir for new collection:', dirn try: mkdir(dirn) except OSError: print 'File exists! Add an error popup.' col = Collection(name=newname, defaultdir=dirn) col.save() self.collections = [col] + self.collections self.save() return col def delete_collection(self, name): matching_collections = filter(lambda j: j.name == name, self.collections) for col in matching_collections: self.collections.remove(col)
class ButtonBase(ButtonBehavior, Widget): #Para guardar datos en el boton y recuperarlas #despues en el evento. tag = ObjectProperty(None, allownone=True) #Colores del boton texto y fondo acepta hexadecimal y rgba bg_color = ObjectProperty([.5, .5, .5, 1]) color = ObjectProperty([1, 1, 1, 1]) font_size = ObjectProperty("20dp") border_size = NumericProperty('3dp') __container__ = ObjectProperty(None) __listchild__ = ListProperty([]) __shape_up__ = ObjectProperty(None) __shape_down__ = ObjectProperty(None) def __init__(self, **kargs): super(ButtonBase, self).__init__(**kargs) def on_color(self, w, val): if "#" in val: val = "".join(val) self.color = get_color_from_hex(val) else: self.color = val def on_border_size(self, w, v): if self.__container__: self.__container__.size = (self.__container__.parent.width - self.border_size, self.__container__.parent.height - self.border_size) def on___container__(self, root, val): self.__container__.bind(pos=self.on___container___pos) self.__container__.size = (self.__container__.parent.width - self.border_size, self.__container__.parent.height - self.border_size) for w in self.__listchild__: self.__container__.add_widget(w) self.draw_color() def on___listchild__(self, w, val): if self.__container__ != None: for w in self.__listchild__: self.__container__.add_widget(w) def add_widget(self, widget): if type(widget) is Decorators: super(ButtonBase, self).add_widget(widget) else: self.__listchild__.append(widget) def on___container___pos(self, root, val): if self.__shape_up__ == None: self.__shape_up__ = InstructionGroup(grup="__shape_up__ ") else: self.__container__.canvas.before.remove(self.__shape_up__) self.__shape_up__.clear() self.draw_color() def on_bg_color(self, root, val): if "#" in val: val = "".join(val) self.bg_color = get_color_from_hex(val) else: self.bg_color = val if get_hex_from_color(self.bg_color) <= "#33333333": self.color = (1, 1, 1, 1) else: self.color = (0, 0, 0, 1) if self.__shape_up__ == None: self.__shape_up__ = InstructionGroup(grup="__shape_up__ ") else: self.__container__.canvas.before.remove(self.__shape_up__) self.__shape_up__.clear() self.draw_color() def draw_color(self): if self.__container__ and self.__shape_up__: size = self.__container__.size color = Color(*self.bg_color) self.__shape_up__.add(color) self.__shape_up__.add( Rectangle(pos=self.__container__.pos, size=size)) self.__container__.canvas.before.add(self.__shape_up__) def collide_point(self, x, y): return (x > self.x and x < self.x + self.width) and (y > self.y and y < self.y + self.height) def on_press(self): size = self.__container__.size if self.__shape_down__ == None: self.__shape_down__ = InstructionGroup(group="__shape_down__") else: self.__container__.canvas.before.remove(self.__shape_down__) self.__shape_down__.clear() color = Color(0, 0, 0, .4) self.__shape_down__.add(color) self.__shape_down__.add( Rectangle(pos=self.__container__.pos, size=size)) self.__container__.canvas.before.add(self.__shape_down__) super(ButtonBase, self).on_press() def on_release(self): self.__container__.canvas.before.remove(self.__shape_down__) self.__shape_down__.clear() super(ButtonBase, self).on_release()
class Remote(App): "Remote" host = StringProperty() scan_results = ListProperty() current_screen = StringProperty() text_color = ColorProperty('#FFFFFF') background_color = ColorProperty('#000000FF') title_color = ColorProperty('#FFFFFFFF') title_font_size = NumericProperty() text_font_size = NumericProperty() def __init__(self, **kwargs): super(Remote, self).__init__(**kwargs) self.osc_server = None self.scan_client = None def on_start(self, **args): "stuff" self.current_screen = 'connect' self.osc_server = server = OSCThreadServer() self.osc_server.listen(address='0.0.0.0', port=PORT, default=True) server.bind(b'/found', callback=self.found) server.bind(b'/conf', callback=self.conf) sock = socket(AF_INET, SOCK_DGRAM) sock.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) sock.settimeout(1) self.scan_client = OSCClient( address='255.255.255.255', port=PEER_PORT, sock=sock, ) def found(self, *values): "when peer is found" print("peer found", values) frames = inspect.getouterframes(inspect.currentframe()) for frame, filename, line, function, lines, index in frames: if function == '_listen' and 'oscpy/server.py' in filename: break else: raise RuntimeError('answer() not called from a callback') host, _ = frame.f_locals.get('sender') self.scan_results.append({ 'name': values[0].decode('utf8'), 'host': host }) def conf( self, background_r, background_g, background_b, text_r, text_g, text_b, text_size, title_r, title_g, title_b, title_size, ): self.background_color = background_r, background_g, background_b self.text_color = text_r, text_g, text_b self.title_color = title_r, title_g, title_b self.title_font_size = title_size self.text_font_size = text_size def scan(self): "look for peers" self.scan_results = [] self.scan_client.send_message(b'/probe', []) def select_host(self, host): "select peer" self.host = host print(self.host) self.current_screen = 'remote' self.send('get_conf') def send(self, address, *values): "send to peer" print(address, values) print( self.osc_server.send_message(b'/%s' % address.encode('utf8'), values, ip_address=self.host, port=PEER_PORT))
class MDTooltip(ThemableBehavior, HoverBehavior, TouchBehavior): tooltip_bg_color = ColorProperty(None) """ Tooltip background color in ``rgba`` format. :attr:`tooltip_bg_color` is an :class:`~kivy.properties.ColorProperty` and defaults to `None`. """ tooltip_text_color = ColorProperty(None) """ Tooltip text color in ``rgba`` format. :attr:`tooltip_text_color` is an :class:`~kivy.properties.ColorProperty` and defaults to `None`. """ tooltip_text = StringProperty() """ Tooltip text. :attr:`tooltip_text` is an :class:`~kivy.properties.StringProperty` and defaults to `''`. """ tooltip_font_style = OptionProperty("Caption", options=theme_font_styles) """ Tooltip font style. Available options are: `'H1'`, `'H2'`, `'H3'`, `'H4'`, `'H5'`, `'H6'`, `'Subtitle1'`, `'Subtitle2'`, `'Body1'`, `'Body2'`, `'Button'`, `'Caption'`, `'Overline'`, `'Icon'`. :attr:`tooltip_font_style` is an :class:`~kivy.properties.OptionProperty` and defaults to `'Caption'`. """ tooltip_radius = ListProperty([ dp(7), ]) """ Corner radius values. :attr:`radius` is an :class:`~kivy.properties.ListProperty` and defaults to `[dp(7),]`. """ tooltip_display_delay = BoundedNumericProperty(0, min=0, max=4) """ Tooltip dsiplay delay. :attr:`tooltip_display_delay` is an :class:`~kivy.properties.BoundedNumericProperty` and defaults to `0`, min of `0` & max of `4`. This property only works on desktop. """ shift_y = NumericProperty() """ Y-offset of tooltip text. :attr:`shift_y` is an :class:`~kivy.properties.StringProperty` and defaults to `0`. """ _tooltip = None def __init__(self, **kwargs): super().__init__(**kwargs) self.register_event_type("on_show") self.register_event_type("on_dismiss") def delete_clock(self, widget, touch, *args): if self.collide_point(touch.x, touch.y) and touch.grab_current: try: Clock.unschedule(touch.ud["event"]) except KeyError: pass self.on_leave() def adjust_tooltip_position(self, x: float, y: float) -> tuple: """ Returns the coordinates of the tooltip that fit into the borders of the screen. """ # If the position of the tooltip is outside the right border # of the screen. if x + self._tooltip.width > Window.width: x = Window.width - (self._tooltip.width + dp(10)) else: # If the position of the tooltip is outside the left border # of the screen. if x < 0: x = "10dp" # If the tooltip position is below bottom the screen border. if y < 0: y = dp(10) # If the tooltip position is below top the screen border. else: if Window.height - self._tooltip.height < y: y = Window.height - (self._tooltip.height + dp(10)) return x, y def display_tooltip(self, interval: Union[int, float]) -> None: if not self._tooltip: return Window.add_widget(self._tooltip) pos = self.to_window(self.center_x, self.center_y) x = pos[0] - self._tooltip.width / 2 if not self.shift_y: y = pos[1] - self._tooltip.height / 2 - self.height / 2 - dp(20) else: y = pos[1] - self._tooltip.height / 2 - self.height + self.shift_y x, y = self.adjust_tooltip_position(x, y) self._tooltip.pos = (x, y) if DEVICE_TYPE == "desktop": Clock.schedule_once(self.animation_tooltip_show, self.tooltip_display_delay) else: Clock.schedule_once(self.animation_tooltip_show, 0) def animation_tooltip_show(self, interval: Union[int, float]) -> None: """Animation of opening tooltip on the screen.""" if self._tooltip: (Animation(_scale_x=1, _scale_y=1, d=0.1) + Animation(opacity=1, d=0.2)).start(self._tooltip) self.dispatch("on_show") def animation_tooltip_dismiss(self, interval: Union[int, float]) -> None: """ .. versionadded:: 1.0.0 Animation of closing tooltip on the screen. """ if self._tooltip: anim = Animation(_scale_x=0, _scale_y=0, d=0.1) + Animation( opacity=0, d=0.2) anim.bind(on_complete=self._on_dismiss_anim_complete) anim.start(self._tooltip) def remove_tooltip(self, *args) -> None: """Removes the tooltip widget from the screen.""" Window.remove_widget(self._tooltip) def on_long_touch(self, touch, *args) -> None: if DEVICE_TYPE != "desktop": self.on_enter(True) def on_enter(self, *args) -> None: """ See :attr:`~kivymd.uix.behaviors.hover_behavior.HoverBehavior.on_enter` method in :class:`~kivymd.uix.behaviors.hover_behavior.HoverBehavior` class. """ if not args and DEVICE_TYPE == "desktop": if self.tooltip_text: self._tooltip = MDTooltipViewClass( tooltip_bg_color=self.tooltip_bg_color, tooltip_text_color=self.tooltip_text_color, tooltip_text=self.tooltip_text, tooltip_font_style=self.tooltip_font_style, tooltip_radius=self.tooltip_radius, ) Clock.schedule_once(self.display_tooltip, -1) def on_leave(self) -> None: """ See :attr:`~kivymd.uix.behaviors.hover_behavior.HoverBehavior.on_leave` method in :class:`~kivymd.uix.behaviors.hover_behavior.HoverBehavior` class. """ if self._tooltip: Clock.schedule_once(self.animation_tooltip_dismiss) def on_show(self) -> None: """Default dismiss event handler.""" def on_dismiss(self) -> None: """ .. versionadded:: 1.0.0 Default dismiss event handler. """ def _on_dismiss_anim_complete(self, *args): self.dispatch("on_dismiss") self.remove_tooltip() self._tooltip = None
class MDFileManager(ThemableBehavior, MDRelativeLayout): icon = StringProperty("check") """ The icon that will be used on the directory selection button. :attr:`icon` is an :class:`~kivy.properties.StringProperty` and defaults to `check`. """ icon_folder = StringProperty(f"{images_path}folder.png") """ The icon that will be used for folder icons when using ``preview = True``. :attr:`icon` is an :class:`~kivy.properties.StringProperty` and defaults to `check`. """ exit_manager = ObjectProperty(lambda x: None) """ Function called when the user reaches directory tree root. :attr:`exit_manager` is an :class:`~kivy.properties.ObjectProperty` and defaults to `lambda x: None`. """ select_path = ObjectProperty(lambda x: None) """ Function, called when selecting a file/directory. :attr:`select_path` is an :class:`~kivy.properties.ObjectProperty` and defaults to `lambda x: None`. """ ext = ListProperty() """ List of file extensions to be displayed in the manager. For example, `['.py', '.kv']` - will filter out all files, except python scripts and Kv Language. :attr:`ext` is an :class:`~kivy.properties.ListProperty` and defaults to `[]`. """ search = OptionProperty("all", options=["all", "dirs", "files"]) """ It can take the values 'all' 'dirs' 'files' - display only directories or only files or both them. By default, it displays folders, and files. Available options are: `'all'`, `'dirs'`, `'files'`. :attr:`search` is an :class:`~kivy.properties.OptionProperty` and defaults to `all`. """ current_path = StringProperty(os.getcwd()) """ Current directory. :attr:`current_path` is an :class:`~kivy.properties.StringProperty` and defaults to `/`. """ use_access = BooleanProperty(True) """ Show access to files and directories. :attr:`use_access` is an :class:`~kivy.properties.BooleanProperty` and defaults to `True`. """ preview = BooleanProperty(False) """ Shows only image previews. :attr:`preview` is an :class:`~kivy.properties.BooleanProperty` and defaults to `False`. """ show_hidden_files = BooleanProperty(False) """ Shows hidden files. :attr:`show_hidden_files` is an :class:`~kivy.properties.BooleanProperty` and defaults to `False`. """ sort_by = OptionProperty( "name", options=["nothing", "name", "date", "size", "type"]) """ It can take the values 'nothing' 'name' 'date' 'size' 'type' - sorts files by option By default, sort by name. Available options are: `'nothing'`, `'name'`, `'date'`, `'size'`, `'type'`. :attr:`sort_by` is an :class:`~kivy.properties.OptionProperty` and defaults to `name`. """ sort_by_desc = BooleanProperty(False) """ Sort by descending. :attr:`sort_by_desc` is an :class:`~kivy.properties.BooleanProperty` and defaults to `False`. """ selector = OptionProperty("any", options=["any", "file", "folder", "multi"]) """ It can take the values 'any' 'file' 'folder' 'multi' By default, any. Available options are: `'any'`, `'file'`, `'folder'`, `'multi'`. :attr:`selector` is an :class:`~kivy.properties.OptionProperty` and defaults to `any`. """ selection = ListProperty() """ Contains the list of files that are currently selected. :attr:`selection` is a read-only :class:`~kivy.properties.ListProperty` and defaults to `[]`. """ _window_manager = None _window_manager_open = False def __init__(self, **kwargs): super().__init__(**kwargs) toolbar_label = self.ids.toolbar.children[1].children[0] toolbar_label.font_style = "Subtitle1" if (self.selector == "any" or self.selector == "multi" or self.selector == "folder"): self.add_widget( FloatButton( callback=self.select_directory_on_press_button, md_bg_color=self.theme_cls.primary_color, icon=self.icon, )) if self.preview: self.ext = [".png", ".jpg", ".jpeg"] self.disks = [] def show_disks(self) -> None: if platform == "win": self.disks = sorted( re.findall( r"[A-Z]+:.*$", os.popen("mountvol /").read(), re.MULTILINE, )) elif platform in ["linux", "android"]: self.disks = sorted( re.findall( r"on\s(/.*)\stype", os.popen("mount").read(), )) elif platform == "macosx": self.disks = sorted( re.findall( r"on\s(/.*)\s\(", os.popen("mount").read(), )) else: return self.current_path = "" manager_list = [] for disk in self.disks: access_string = self.get_access_string(disk) if "r" not in access_string: icon = "harddisk-remove" else: icon = "harddisk" manager_list.append({ "viewclass": "BodyManager", "path": disk, "icon": icon, "dir_or_file_name": disk, "events_callback": self.select_dir_or_file, "_selected": False, }) self.ids.rv.data = manager_list if not self._window_manager: self._window_manager = ModalView(size_hint=self.size_hint, auto_dismiss=False) self._window_manager.add_widget(self) if not self._window_manager_open: self._window_manager.open() self._window_manager_open = True def show(self, path: str) -> None: """ Forms the body of a directory tree. :param path: The path to the directory that will be opened in the file manager. """ self.current_path = path self.selection = [] dirs, files = self.get_content() manager_list = [] if dirs == [] and files == []: # selected directory pass elif not dirs and not files: # directory is unavailable return if self.preview: for name_dir in self.__sort_files(dirs): manager_list.append({ "viewclass": "BodyManagerWithPreview", "path": self.icon_folder, "realpath": os.path.join(path), "type": "folder", "name": name_dir, "events_callback": self.select_dir_or_file, "height": dp(150), "_selected": False, }) for name_file in self.__sort_files(files): if (os.path.splitext(os.path.join(path, name_file))[1] in self.ext): manager_list.append({ "viewclass": "BodyManagerWithPreview", "path": os.path.join(path, name_file), "name": name_file, "type": "files", "events_callback": self.select_dir_or_file, "height": dp(150), "_selected": False, }) else: for name in self.__sort_files(dirs): _path = os.path.join(path, name) access_string = self.get_access_string(_path) if "r" not in access_string: icon = "folder-lock" else: icon = "folder" manager_list.append({ "viewclass": "BodyManager", "path": _path, "icon": icon, "dir_or_file_name": name, "events_callback": self.select_dir_or_file, "_selected": False, }) for name in self.__sort_files(files): if self.ext and os.path.splitext(name)[1] not in self.ext: continue manager_list.append({ "viewclass": "BodyManager", "path": name, "icon": "file-outline", "dir_or_file_name": os.path.split(name)[1], "events_callback": self.select_dir_or_file, "_selected": False, }) self.ids.rv.data = manager_list if not self._window_manager: self._window_manager = ModalView(size_hint=self.size_hint, auto_dismiss=False) self._window_manager.add_widget(self) if not self._window_manager_open: self._window_manager.open() self._window_manager_open = True def get_access_string(self, path: str) -> str: access_string = "" if self.use_access: access_data = {"r": os.R_OK, "w": os.W_OK, "x": os.X_OK} for access in access_data.keys(): access_string += (access if os.access( path, access_data[access]) else "-") return access_string def get_content( self, ) -> Union[Tuple[List[str], List[str]], Tuple[None, None]]: """Returns a list of the type [[Folder List], [file list]].""" try: files = [] dirs = [] for content in os.listdir(self.current_path): if os.path.isdir(os.path.join(self.current_path, content)): if self.search == "all" or self.search == "dirs": if (not self.show_hidden_files) and ( content.startswith(".")): continue else: dirs.append(content) else: if self.search == "all" or self.search == "files": if len(self.ext) != 0: try: files.append( os.path.join(self.current_path, content)) except IndexError: pass else: if (not self.show_hidden_files and content.startswith(".")): continue else: files.append(content) return dirs, files except OSError: return None, None def close(self) -> None: """Closes the file manager window.""" self._window_manager.dismiss() self._window_manager_open = False def select_dir_or_file( self, path: str, widget: Union[BodyManagerWithPreview, Factory.BodyManager], ): """Called by tap on the name of the directory or file.""" if os.path.isfile(os.path.join(self.current_path, path)): if self.selector == "multi": file_path = os.path.join(self.current_path, path) if file_path in self.selection: widget._selected = False self.selection.remove(file_path) else: widget._selected = True self.selection.append(file_path) elif self.selector == "folder": return else: self.select_path(os.path.join(self.current_path, path)) else: self.current_path = path self.show(path) def back(self) -> None: """Returning to the branch down in the directory tree.""" path, end = os.path.split(self.current_path) if self.current_path and path == self.current_path: self.show_disks() else: if not end: self.close() self.exit_manager(1) else: self.show(path) def select_directory_on_press_button(self, *args) -> None: """Called when a click on a floating button.""" if self.selector == "multi": if len(self.selection) > 0: self.select_path(self.selection) else: if self.selector == "folder" or self.selector == "any": self.select_path(self.current_path) def __sort_files(self, files): def sort_by_name(files): files.sort(key=locale.strxfrm) files.sort(key=str.casefold) return files if self.sort_by == "name": sorted_files = sort_by_name(files) elif self.sort_by == "date": _files = sort_by_name(files) _sorted_files = [ os.path.join(self.current_path, f) for f in _files ] _sorted_files.sort(key=os.path.getmtime, reverse=True) sorted_files = [os.path.basename(f) for f in _sorted_files] elif self.sort_by == "size": _files = sort_by_name(files) _sorted_files = [ os.path.join(self.current_path, f) for f in _files ] _sorted_files.sort(key=os.path.getsize, reverse=True) sorted_files = [os.path.basename(f) for f in _sorted_files] elif self.sort_by == "type": _files = sort_by_name(files) sorted_files = sorted( _files, key=lambda f: (os.path.splitext(f)[1], os.path.splitext(f)[0]), ) else: sorted_files = files if self.sort_by_desc: sorted_files.reverse() return sorted_files