Beispiel #1
0
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
Beispiel #2
0
    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
Beispiel #4
0
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)
Beispiel #5
0
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[:]
Beispiel #7
0
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
Beispiel #8
0
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()
Beispiel #9
0
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.
Beispiel #10
0
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
Beispiel #11
0
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
Beispiel #12
0
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()
Beispiel #13
0
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()
Beispiel #14
0
class GridEntry(Button):
    coords = ListProperty([0, 0])
Beispiel #15
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))
Beispiel #16
0
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
Beispiel #17
0
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()
Beispiel #18
0
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
Beispiel #19
0
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()
Beispiel #20
0
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
Beispiel #21
0
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)
Beispiel #22
0
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()
Beispiel #23
0
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])
Beispiel #25
0
class ItemDrawer(OneLineIconListItem):
    icon = StringProperty()
    text_color = ListProperty((0, 0, 0, 1))
Beispiel #26
0
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__)
Beispiel #27
0
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.
Beispiel #28
0
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
Beispiel #29
0
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
Beispiel #30
0
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)
Beispiel #31
0
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()
Beispiel #32
0
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))
Beispiel #33
0
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
Beispiel #34
0
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