Esempio n. 1
0
class Projectile(Image):
    '''Lauch this piece of ammunition towards a target object (`target`),
    located at coordinates (`tx`, `ty`).

    When the projectile reaches its target, it disappears. Collision handling is done elsewhere.

    The `target` object is used to determine which collide_projectile method to check for collision
    in the on_progress method of the projectile.
    '''

    def shoot(self, tx, ty, target):
        self.target = target
        self.animation = Animation(x=tx, y=ty)
        self.animation.bind(on_start=self.on_start)
        self.animation.bind(on_progress=self.on_progress)
        self.animation.bind(on_complete=self.on_stop)
        self.animation.start(self)

    def on_start(self, instance, value):
        pass

    def on_progress(self, instance, value, progression):
        if self.target.collide_projectile(self):
            self.animation.stop(self)

    def on_stop(self, instance, value):
        self.parent.remove_widget(self)
Esempio n. 2
0
class AnimationTestCase(unittest.TestCase):
    def sleep(self, t):
        start = time()
        while time() < start + t:
            sleep(.01)
            Clock.tick()

    def setUp(self):
        self.a = Animation(x=100, d=1, t='out_bounce')
        self.w = Widget()

    def test_start_animation(self):
        self.a.start(self.w)
        self.sleep(1.5)
        self.assertAlmostEqual(self.w.x, 100)

    def test_animation_duration_0(self):
        a = Animation(x=100, d=0)
        a.start(self.w)
        self.sleep(.5)

    def test_stop_animation(self):
        self.a.start(self.w)
        self.sleep(.5)
        self.a.stop(self.w)
        self.assertNotAlmostEqual(self.w.x, 100)
        self.assertNotAlmostEqual(self.w.x, 0)

    def test_stop_all(self):
        self.a.start(self.w)
        self.sleep(.5)
        Animation.stop_all(self.w)

    def test_stop_all_2(self):
        self.a.start(self.w)
        self.sleep(.5)
        Animation.stop_all(self.w, 'x')

    def test_duration(self):
        self.assertEqual(self.a.duration, 1)

    def test_transition(self):
        self.assertEqual(self.a.transition, AnimationTransition.out_bounce)

    def test_animated_properties(self):
        self.assertEqual(self.a.animated_properties['x'], 100)

    def test_animated_instruction(self):
        instruction = Scale(3)
        self.a.start(instruction)
        self.assertEqual(self.a.animated_properties['x'], 100)
        self.assertAlmostEqual(instruction.x, 3)
        self.sleep(1.5)
        self.assertAlmostEqual(instruction.x, 100)
Esempio n. 3
0
class PlanillaScreen(Screen):

    def update_timepos(self, *args):
        timepos = self.pw.horario.get_timepos()
        Logger.debug("%s: update_timepos timepos=%s" % (APP, timepos))
        self.pw.timepos = timepos

    def on_enter(self, *args):
        self.update_timepos()
        Clock.schedule_interval(self.update_timepos, 60)
        self.anim = Animation(alpha=0.7, d=1) + Animation(alpha=0.2, d=1)
        self.anim.repeat = True
        self.anim.start(self.pw)

    def on_pre_leave(self, *args):
        Clock.unschedule(self.update_timepos)
        self.anim.stop(self.pw)
Esempio n. 4
0
    def on_touch_up(self, touch):
        if touch.grab_current is self:
            x, y = self.tpos
            diff_x = touch.x - x
            diff_y = touch.y - y
            space = 20
            if self.backgroundscreen:
                # if (diff_x  > space):
                #     self.backgroundscreen.center_x = touch.x
                # elif (diff_x < -space):
                #     self.backgroundscreen.center_x = touch.x
                if (diff_y > space):
                    self.backgroundscreen.y = touch.y
                    # 맵 변경이 일어남
                    app.game.door.door_down()
                    # up animation
                    self.backgroundscreen.opacity = 0
                    self.backgroundscreen.y = self.y
                    anim = Animation(center_y=self.center_y, duration=.2)
                    anim &= Animation(opacity=1, duration=.2)
                    if anim:
                        anim.stop(self)
                    anim.start(self.backgroundscreen)
                    self.backgroundcolor = random.random(
                    ), random.random(), random.random(), .5

                elif (diff_y < -space):
                    self.backgroundscreen.y = touch.y
                    app.game.door.door_up()

                    # down animation
                    self.backgroundscreen.opacity = 0
                    self.backgroundscreen.top = self.top
                    anim = Animation(center_y=self.center_y, duration=.2)
                    anim &= Animation(opacity=1, duration=.2)
                    if anim:
                        anim.stop(self)
                    anim.start(self.backgroundscreen)
                    self.backgroundcolor = random.random(
                    ), random.random(), random.random(), .5

                else:
                    self.backgroundscreen.center_x = self.center_x
                    self.backgroundscreen.center_y = self.center_y
            touch.ungrab(self)
Esempio n. 5
0
class Welcome(FloatLayout):
	blinking_text = ObjectProperty()
	
	def __init__(self):
		super(Welcome, self).__init__()
		self.anim = Animation(opacity=0, d=1)
		Clock.schedule_interval(self.blinking, 1)
		
	def blinking(self, dt):
		self.blinking_text.opacity = 1
		self.anim.start(self.blinking_text)
		
	def on_touch_down(self, touch):
		Clock.unschedule(self.blinking)
		self.anim.stop(self.blinking_text)
		parent = self.parent
		parent.clear_widgets()
		parent.add_widget(Principal())
Esempio n. 6
0
class AccordionListItem(Selectable, GridLayout):
    title = ObjectProperty(None)
    content = ObjectProperty(None)
    drag_opacity = NumericProperty(0.75)
    listview = ObjectProperty(None)
    shadow_color = ListProperty([])
    ix = NumericProperty(None)
    text = StringProperty('')
    why = BooleanProperty(False)
    collapse_alpha = NumericProperty(1.0)
    title_height_hint = NumericProperty(0.0)
    content_height_hint = NumericProperty(0.0)

    def __init__(self, **kwargs):
        self._anim_collapse = None
        self.register_event_type('on_release')
        super(AccordionListItem, self).__init__(**kwargs)

    def select(self, *args):
        if self._anim_collapse:
            self._anim_collapse.stop()
            self._anim_collapse = None

        self._anim_collapse = Animation(collapse_alpha=0.0,
                                        t='out_expo',
                                        d=0.25).start(self)

    def deselect(self, *args):
        if self._anim_collapse:
            self._anim_collapse.stop()
            self._anim_collapse = None

        self._anim_collapse = Animation(collapse_alpha=1.0,
                                        t='out_expo',
                                        d=0.25).start(self)

    def on_collapse_alpha(self, instance, value):
        instance.listview._do_layout()

    def on_touch_down(self, touch):
        if not self.collide_point(*touch.pos):
            return False
        else:
            return super(AccordionListItem, self).on_touch_down(touch)
Esempio n. 7
0
class AnimationTestCase(unittest.TestCase):

    def setUp(self):
        self.a = Animation(x=100, d=1, t='out_bounce')
        self.w = Widget()

    def test_start_animation(self):
        self.a.start(self.w)
        sleep(1)

    def test_stop_animation(self):
        self.a.start(self.w)
        sleep(.5)
        self.a.stop(self.w)

    def test_stop_all(self):
        self.a.start(self.w)
        sleep(.5)
        Animation.stop_all(self.w)
Esempio n. 8
0
class AnimationTestCase(unittest.TestCase):
    def sleep(self, t):
        start = time()
        while time() < start + t:
            sleep(0.01)
            Clock.tick()

    def setUp(self):
        self.a = Animation(x=100, d=1, t="out_bounce")
        self.w = Widget()

    def test_start_animation(self):
        self.a.start(self.w)
        self.sleep(1.5)
        self.assertAlmostEqual(self.w.x, 100)

    def test_stop_animation(self):
        self.a.start(self.w)
        self.sleep(0.5)
        self.a.stop(self.w)
        self.assertNotAlmostEqual(self.w.x, 100)
        self.assertNotAlmostEqual(self.w.x, 0)

    def test_stop_all(self):
        self.a.start(self.w)
        self.sleep(0.5)
        Animation.stop_all(self.w)

    def test_stop_all_2(self):
        self.a.start(self.w)
        self.sleep(0.5)
        Animation.stop_all(self.w, "x")

    def test_duration(self):
        self.assertEqual(self.a.duration, 1)

    def test_transition(self):
        self.assertEqual(self.a.transition, AnimationTransition.out_bounce)

    def test_animated_properties(self):
        self.assertEqual(self.a.animated_properties["x"], 100)
Esempio n. 9
0
class Ammo(Image):
    def shoot(self, tx, ty, target):
        self.target = target
        self.animation = Animation(x=tx, top=ty)
        self.animation.bind(on_start=self.on_start)
        self.animation.bind(on_progress=self.on_progress)
        self.animation.bind(on_complete=self.on_stop)
        self.animation.start(self)

    def on_start(self, instance, value):
        self.boom = Boom()
        self.boom.center = self.center
        self.parent.add_widget(self.boom)

    def on_progress(self, instance, value, progression):
        if progression >= .1:
            self.parent.remove_widget(self.boom)
        if self.target.collide_ammo(self):
            self.animation.stop(self)

    def on_stop(self, instance, value):
        self.parent.remove_widget(self)
Esempio n. 10
0
class ImageScreen(Screen):

    timepos = NumericProperty(0.5)
    alpha = NumericProperty(.8)

    def on_enter(self, *args):
        self.canvas.after.clear()
        with self.canvas.after:
            w = 10
            tp = self.app.horario.get_timepos()
            pos = (self.width - tp*self.width - w/2, 0)
            size = (w, self.height)
            self.tpc = Color(1, .1, .1, self.alpha)
            self.tp = Rectangle(pos=pos, size=size)
        Clock.schedule_interval(self.update_timepos, 60)
        self.anim = Animation(alpha=0.7, d=1) + Animation(alpha=0.2, d=1)
        self.anim.repeat = True
        self.anim.start(self)

    def load(self, path=''):
        assert path
        self.clear_widgets()
        img = AsyncImage(source=path, keep_ratio=False, allow_stretch=True)
        self.add_widget(img)

    def update_timepos(self, *args):
        tp = self.app.horario.get_timepos()
        Logger.debug("%s: update_img_timepos timepos=%s" % (APP, tp))
        self.tp.pos = (self.width - tp*self.width - 5, 0)

    def on_alpha(self, *args):
        self.tpc.a = self.alpha

    def on_pre_leave(self, *args):
        Clock.unschedule(self.update_timepos)
        self.anim.stop(self)
Esempio n. 11
0
class InterpreterGui(BoxLayout):
    output_window = ObjectProperty()
    code_input = ObjectProperty()
    scrollview = ObjectProperty()

    input_fail_alpha = NumericProperty(0.)

    lock_input = BooleanProperty(False)
    _lock_input = BooleanProperty(False)

    halting = BooleanProperty(False)
    '''True when the interpreter has been asked to stop but has not yet
    done so.'''

    interpreter_state = OptionProperty(
        'waiting',
        options=['waiting', 'interpreting', 'not_responding', 'restarting'])
    status_label_colour = StringProperty('0000ff')

    _output_label_queue = ListProperty([])

    dequeue_scheduled = ObjectProperty(None, allownone=True)
    clear_scheduled = ObjectProperty(None, allownone=True)

    awaiting_label_display_completion = BooleanProperty(False)

    def __init__(self, *args, **kwargs):
        super(InterpreterGui, self).__init__(*args, **kwargs)
        self.animation = Animation(input_fail_alpha=0.,
                                   t='out_expo',
                                   duration=0.5)

        self.interpreter = InterpreterWrapper(self)

        # Clock.schedule_interval(self._dequeue_output_label, 0.05)
        # Clock.schedule_interval(self._clear_output_label_queue, 1)

    def on_lock_input(self, instance, value):
        if value:
            self.input_focus_on_disable = self.code_input.focus
            self._lock_input = True
        else:
            self._lock_input = False
            self.code_input.focus = self.input_focus_on_disable
            self.ensure_no_ctrl_c_button()
            self.halting = False

    def ensure_ctrl_c_button(self):
        Clock.schedule_once(self._switch_to_ctrl_c_button, 0.4)

    def _switch_to_ctrl_c_button(self, *args):
        c = self.ids.carousel
        if c.index == 0:
            c.load_next()

    def ensure_no_ctrl_c_button(self):
        Clock.unschedule(self._switch_to_ctrl_c_button)
        c = self.ids.carousel
        if c.index == 1:
            c.load_previous()
        else:
            Animation.cancel_all(c)
            c._start_animation(new_offset=0)

    def on_interpreter_state(self, instance, value):
        if value == 'waiting':
            self.status_label_colour = '0000ff'
        elif value == 'interpreting':
            self.status_label_colour = '00ff00'
        elif value == 'not_responding':
            self.status_label_colour = 'ff0000'
        elif value == 'restarting':
            self.status_label_colour = 'ffA500'

    def interpret_line_from_code_input(self):
        text = self.code_input.text
        if text == '':
            self.flash_input_fail()
            return
        self.code_input.text = ''
        self.interpret_line(text)

    def flash_input_fail(self):
        self.animation.stop(self)
        self.input_fail_alpha = 1.
        self.animation.start(self)

    def interpret_line(self, text):
        index = self.interpreter.interpret_line(text)
        self.add_input_label(text, index)

    def add_input_label(self, text, index):
        l = InputLabel(text=text, index=index, root=self)
        self.output_window.add_widget(l)
        self.scrollview.scroll_to(l)

    def add_output_label(self, text, stream='stdout'):
        self._output_label_queue.append((text, stream))
        # self._dequeue_output_label(0)

    def _add_output_label(self, text, stream='stdout', scroll_to=True):
        l = OutputLabel(text=text, stream=stream)
        self.output_window.add_widget(l)
        if scroll_to:
            self.scrollview.scroll_to(l)
        return l

    def _dequeue_output_label(self, dt):
        if not self._output_label_queue:
            return

        # print('dequeueing', self._output_label_queue)

        t = time()
        i = 0
        while (time() - t) < 0.005:
            i += 1
            if not self._output_label_queue:
                break
            label_text = self._output_label_queue.pop(0)
            label = self._add_output_label(*label_text, scroll_to=False)
        print('Rendered {} labels in {}'.format(i, time() - t))
        Animation.stop_all(self.scrollview, 'scroll_x', 'scroll_y')
        self.scrollview.scroll_to(label)

        self.dequeue_scheduled.cancel()
        self.dequeue_scheduled = None

        if len(self._output_label_queue) == 0 and self.clear_scheduled:
            self.clear_scheduled.cancel()
            self.clear_scheduled = None
        elif len(self._output_label_queue) > 0:
            self.dequeue_scheduled = Clock.schedule_once(
                self._dequeue_output_label, 0.05)

        if (self.awaiting_label_display_completion
                and len(self._output_label_queue) == 0):
            self.awaiting_label_display_completion = False
            self._execution_complete()

    def _clear_output_label_queue(self, dt):
        labels = self._output_label_queue
        self._output_label_queue = []
        if labels:
            self.add_missing_labels_marker(labels=labels)

        if self.dequeue_scheduled:
            self.dequeue_scheduled.cancel()
            self.dequeue_scheduled = None

        if self.clear_scheduled:
            self.clear_scheduled.cancel()
            self.clear_scheduled = None

        if self.awaiting_label_display_completion:
            self.awaiting_label_display_completion = False
            self._execution_complete()

    def on__output_label_queue(self, instance, values):
        # print('olq', self.dequeue_scheduled, self.clear_scheduled)
        if self.dequeue_scheduled:
            return

        if not self.dequeue_scheduled:
            self.dequeue_scheduled = Clock.schedule_once(
                self._dequeue_output_label, 0)
        if not self.clear_scheduled:
            self.clear_scheduled = Clock.schedule_once(
                self._clear_output_label_queue, 1)

    def add_missing_labels_marker(self, num_labels=None, labels=None):
        if labels is not None:
            num_labels = len(labels)
        l = UserMessageLabel(
            text='{} lines omitted (too many to render)'.format(num_labels),
            background_colour=(1, 0.6, 0, 1))
        l.labels = labels
        self.output_window.add_widget(l)
        self.scrollview.scroll_to(l)

    def add_notification_label(self, text):
        self.add_break()
        l = NotificationLabel(text=text)
        self.output_window.add_widget(l)
        self.scrollview.scroll_to(l)
        self.add_break()

    def add_break(self):
        b = BreakMarker()
        self.output_window.add_widget(b)
        self.scrollview.scroll_to(b)

    def insert_previous_code(self, index, clear=False):
        if clear:
            self.code_input.text = ''
        code = self.interpreter.inputs[index]
        if self.code_input.text == '':
            self.code_input.text = code
        else:
            self.code_input.text += '\n' + code

    def send_sigint(self):
        self.halting = True
        self.interpreter.send_sigint()

    def restart_interpreter(self):
        self.interpreter.restart()

    def query_restart(self):
        popup = RestartPopup(interpreter_gui=self)
        popup.open()

    def execution_complete(self):
        '''Called when execution is complete so the TextInput should be
        unlocked etc., but first this is delayed until messages finish
        printing.
        '''
        if len(self._output_label_queue) == 0:
            self._execution_complete()
        else:
            self.awaiting_label_display_completion = True

    def _execution_complete(self):
        self.add_break()
        self.lock_input = False
        self.halting = False
        self.ensure_no_ctrl_c_button()
Esempio n. 12
0
class ProcessSelect(Widget):
    pid = NumericProperty(-1)

    chara = ObjectProperty(None)

    current_process_index = NumericProperty(-1)
    process_list = []

    dive_clock = None
    finished = BooleanProperty(False)

    columns = 20
    cell_interval = 120
    cell_size = (64, 64)

    # instruction groups
    cells = None
    overwrap = None
    lebels = None

    # properties about overwrap rectangle
    overwrap_pos_x = NumericProperty(0)
    overwrap_pos_y = NumericProperty(0)
    overwrap_pos = ReferenceListProperty(overwrap_pos_x, overwrap_pos_y)
    overwrap_size_w = NumericProperty(0)
    overwrap_size_h = NumericProperty(62)
    overwrap_size = ReferenceListProperty(overwrap_size_w, overwrap_size_h)
    overwrap_r = NumericProperty(0.03)
    overwrap_g = NumericProperty(0.8)
    overwrap_b = NumericProperty(1)
    overwrap_a = NumericProperty(0)
    overwrap_color = ReferenceListProperty(overwrap_r, overwrap_g, overwrap_b,
                                           overwrap_a)
    overwrap_color_anim = None

    def index_to_pos(self, i):
        """Calculate position from index"""
        posx = (i % self.columns) * self.cell_interval
        posy = int(i / self.columns) * self.cell_interval
        return posx, posy

    def pos_to_index(self, pos):
        i = int(pos[0] /
                self.cell_interval) + int(pos[1] / self.cell_interval) * 20

        if (pos[0] < 0 or pos[1] < 0
                or pos[0] > self.columns * self.cell_interval
                or pos[0] % self.cell_interval > self.cell_size[0]
                or pos[1] % self.cell_interval > self.cell_size[1]
                or i >= len(self.process_list)):
            i = -1  # case of no select or invalid select

        return i

    def start(self):
        """Initialize function."""
        try:
            self.process_list = Process.list()
            self.process_list.reverse()
        except:
            message("エラーが発生しました。管理者権限でこのゲームを実行してみてください。")
            return

        self.cells = InstructionGroup()
        self.overwrap = InstructionGroup()
        self.lebels = InstructionGroup()

        i = 0

        pid_of_this_program = os.getpid()

        for proc in self.process_list:
            # calculate position
            posx, posy = self.index_to_pos(i)

            # draw squares
            if proc["pid"] == pid_of_this_program:
                self.cells.add(Color(0.8, 0.8, 0.8))
            else:
                self.cells.add(Color(1, 1, 1))

            self.cells.add(Rectangle(pos=(posx, posy), size=self.cell_size))

            # draw text
            self.lebels.add(Color(0, 0, 0))
            self.lebels.add(
                draw_text_on_canvas(str(proc["pid"]), pos=(posx, posy)))

            i += 1

        self.canvas.add(self.cells)
        self.canvas.add(self.overwrap)
        self.canvas.add(self.lebels)

    def update(self, dt):
        """Frame update function."""

        coord = self.chara.coordinate

        if self.finished is True:
            return

        # calculate the index of selected process
        i = self.pos_to_index(coord)

        # if selected process changed
        if i != self.current_process_index:
            self.time_left = 1
            self.current_process_index = i

            # progress rectangle
            if i != -1:
                self.overwrap_color_anim = Animation(overwrap_a=1,
                                                     overwrap_size_w=62,
                                                     duration=2.)

                self.dive_clock = Clock.schedule_once(partial(self.dive, i),
                                                      2.)

                self.overwrap_color_anim.start(self)

                posx, posy = self.index_to_pos(i)

                self.overwrap_pos_x = posx + 1
                self.overwrap_pos_y = posy + 1
            else:
                self.overwrap_a = 0
                self.overwrap_size_w = 0
                self.overwrap_color_anim.stop(self)
                self.dive_clock.cancel()

        # draw overwrap
        self.overwrap.clear()
        self.overwrap.add(Color(*self.overwrap_color))
        self.overwrap.add(
            Rectangle(pos=self.overwrap_pos, size=self.overwrap_size))

    def dive(self, index, _):
        """Diving function."""
        self.pid = self.process_list[index]["pid"]
        try:
            mw = MemWorker(pid=self.pid)
            regs = list(mw.process.iter_region())
            mw.process.read_bytes(regs[0][0], bytes=1)
        except:
            posx, posy = self.index_to_pos(index)
            with self.canvas:
                Color(0.97, 0.1, 0)
                draw_text_on_canvas("ERROR",
                                    font_size=20,
                                    pos=(posx + 1, posy + 30))
        else:
            self.finished = True
            anim = Animation(opacity=0)

            def tmp(*args):
                self.canvas.clear()

            anim.bind(on_complete=tmp)
            anim.start(self)
Esempio n. 13
0
class Ball(TickingWidget):
    """The ball that the solver moves through the maze.

    The ball has two collision-detection methods: the standard collide_point()
    for the area where the ball accepts touches, and collide_zoc() for the
    “zone of control”. The zone of coltrol grows when the ball is touched, and
    shrinks when the touch is released.

    When touched, the ball will move towards the touch at BALL_SPEED tiles per
    second (but maze walls will block it).
    """
    def __init__(self, parent, **kwargs):
        super(Ball, self).__init__(**kwargs)
        self.touch_uid = None
        self.target_pos = self.pos

        self.animation = None

        radius = self.radius = parent.cell_size * 0.3
        self.handle_radius = parent.cell_size * BALL_TOUCH_RADIUS
        self.zoc_radius = self.radius
        with self.canvas:
            Color(0, 0, 1, 0.5)
            Ellipse(pos=(-radius, -radius), size=(radius * 2, radius * 2))
            Color(0, 0, 0, 1)
            HollowCircle((0, 0), radius, 18)
            Color(0.5, 0.5, 0.5, 0.4)
            FilledCircle((0, 0), self.handle_radius)
            HollowCircle((0, 0), self.handle_radius, 18)
            self.scale_instruction = Scale(self.zoc_radius)
            Color(1, 1, 1, 0.2)
            FilledCircle((0, 0), 1)
            Color(0.5, 0.5, 0.5, 0.4)
            HollowCircle((0, 0), 1, 32)
        with self.canvas.before:
            PushMatrix()
            self.translation_instruction = Translate(0, 0, 0)
        with self.canvas.after:
            PopMatrix()

    def collide_point(self, x, y):
        px, py = self.pos
        return (px - x) ** 2 + (py - y) ** 2 < self.handle_radius ** 2

    def collide_zoc(self, x, y):
        px, py = self.pos
        return (px - x) ** 2 + (py - y) ** 2 < self.zoc_radius ** 2

    def tick(self, dt):
        if not self.parent:
            return
        # Try to cover the required distance. But if it's not done in 50
        # iterations, give up.
        remaining_distance = dt * BALL_SPEED * self.parent.cell_size
        for i in range(50):
            if remaining_distance <= 0.01 or self.pos == self.target_pos:
                break
            distance_covered = self.move_step(remaining_distance)
            if distance_covered == 0:
                break
            remaining_distance -= distance_covered
        if self.translation_instruction.xy != self.pos:
            # Update the canvas if the ball moved
            self.translation_instruction.xy = self.pos
            self.canvas.ask_update()
        if self.scale_instruction.scale != self.zoc_radius:
            # Update the canvas if the ZOC was resized
            self.scale_instruction.scale = self.zoc_radius
            self.canvas.ask_update()
        if not self.parent.ball_source.collide_point(*self.pos):
            # If the ball is outside the initial area, add time to the player's
            # clock
            self.parent.add_time(dt)
        if self.x < self.parent.cell_size:
            # IF the ball is in the goal area, the round ends
            self.parent.win()

    def move_step(self, remaining_distance):
        """Move a little towards the touch position, return distance covered

        `remaining_distance` is the maximum distance to move

        This implements one iteration of the moving, and is called enough times
        for the sum of the returned values is big enough.

        Both remaining_distance and the return value are in pixels, not tiles.
        """
        radius = self.radius
        pos = numpy.array(self.pos)
        # The distance we want to cover
        delta = self.target_pos - pos
        distance = numpy.sqrt(sum(delta ** 2))
        # Only move a little bit each time, so walls are checked correctly
        max_distance = min(remaining_distance, radius / 2)
        if distance > max_distance:
            delta = delta / distance * max_distance
            distance = max_distance
        pos += delta
        # From now, we will deal with tile coordinates instead of pixels
        tile_coord = numpy.array(self.parent.pixel_to_tile(pos))
        tile_radius = self.parent.pixel_to_tile((radius, radius))
        # Check the upper/lower & left/right points of the circle
        # if one of them is in a wall, "snap" the ball to that wall
        for axis in (0, 1):
            pt = [0, 0]
            pt[axis] = tile_radius[axis]
            if self.parent.wall_at_tile(tile_coord + pt):
                tile_coord[axis] = int(tile_coord[axis]) + 1 - pt[axis]
            if self.parent.wall_at_tile(tile_coord - pt):
                tile_coord[axis] = int(tile_coord[axis]) + pt[axis]
        # Get the closest grid intersection
        corner = numpy.array(tile_coord).round()
        # Get a point in the tile "behind" this clocest corner
        tile_behind_corner = 2 * corner - tile_coord
        # Check if there is a wall on that tile
        if self.parent.wall_at_tile(tile_behind_corner):
            vector_to_corner = corner - tile_coord
            # If part of the ball is inside a corner wall, push it back
            # XXX: This doesn't take into account that the ball can be slightly
            # elliptical in tile coordinates. (This isn't likely to matter,
            # though.)
            avg_radius = sum(tile_radius) / 2
            if sum(vector_to_corner ** 2) < avg_radius ** 2:
                distance_to_corner = numpy.sqrt(sum(vector_to_corner ** 2))
                direction_to_corner = vector_to_corner / distance_to_corner
                pushback_distance = avg_radius - distance_to_corner
                tile_coord -= direction_to_corner * pushback_distance
                pushed_back = True
        # Convert back to pixel coordinates
        self.pos = self.parent.tile_to_pixel(tile_coord)
        return distance

    def on_touch_down(self, touch, force=False):
        """Called for a new touch

        `force`: don't check that the touch is near the ball; assume it is.
        """
        if force or self.collide_point(touch.x, touch.y):
            if self.touch_uid:
                self.touch_uid = None
            self.touch_uid = touch.uid
            self.on_touch_move(touch)
            zoc_radius = self.parent.cell_size * BALL_ZOC_RADIUS
            if self.animation:
                self.animation.stop(self)
            self.animation = Animation(zoc_radius=zoc_radius, duration=0.5)
            self.animation.start(self)
            return True

    def on_touch_move(self, touch):
        if touch.uid == self.touch_uid:
            self.target_pos = touch.pos
            return True

    def on_touch_up(self, touch):
        if touch.uid == self.touch_uid:
            self.touch_uid = None
            self.target_pos = self.pos
            if self.animation:
                self.animation.stop(self)
            self.animation = Animation(zoc_radius=self.handle_radius,
                    t='in_cubic', duration=1)
            self.animation.start(self)
            return True
Esempio n. 14
0
class BoardTopLayer(RelativeLayout):
    is_locked = BooleanProperty(False)
    current_tile = ObjectProperty(None)
    board = ObjectProperty(None)

    def __init__(self, *args, **kwargs):
        super(BoardTopLayer, self).__init__(*args, **kwargs)
        self.show_anim = Animation(opacity=1, duration=0.2)
        self.hide_anim = Animation(opacity=0, duration=0.2)

    def on_touch_down(self, touch):
        if not self.is_locked:
            return False

        if self.collide_point(*touch.pos):
            touch.grab(self, exclusive=True)
            return True

        return False

    def on_touch_up(self, touch):
        if touch.grab_current is self:
            touch.ungrab(self)
            if self.collide_point(*touch.pos):
                self.hide_tile()
                return True

    def on_is_locked(self, instance, blocked):
        self.show_anim.stop(self)
        self.hide_anim.stop(self)

        if blocked:
            self.show_anim.start(self)
        else:
            self.hide_anim.start(self)

    def hide_tile(self):
        if self.current_tile is None:
            return

        self.is_locked = False
        self.remove_widget(self.current_tile)
        self._return_func(self.current_tile)

    def show_tile(self, tile, return_func):
        self._return_func = return_func
        self.current_tile = tile
        self.is_locked = True
        self.add_widget(tile)

        new_size = self.width * 0.75, self.height * 0.75
        new_pos = self.to_local(
            self.center_x - new_size[0] / 2,
            self.center_y - new_size[1] / 2,
        )
        tile.anim = Animation(
            x=new_pos[0],
            y=new_pos[0],
            width=new_size[0],
            height=new_size[1],
            transition='in_out_elastic',
        )
        tile.anim.start(tile)
Esempio n. 15
0
class Rotater(Scatter):
    def __init__(self, **kwargs):
        super(Rotater, self).__init__(**kwargs)
        self.size = (800, 800)
        self.pos = (270, 0)
        self.rotation = 0

        self.init_x = self.x
        self.init_y = self.y

        self.trans = ac.Trans.trans

        self.saxis = 0
        self.axis = 0

        self.dir = 0
        self.anim = None

        self.choice = None

    def on_touch_down(self, touch):
        ac.KEYFRAME = 0
        self.axis = touch.spos[0]
        self.saxis = touch.spos[0]
        self.anim = None
        self.rotation = 0
        self.dir = 0

        self.x = self.init_x
        self.y = self.init_y

    def on_touch_move(self, touch):
        if self.dir == 0:
            self.anim = None

        tmp_dir = 1 if self.axis > self.saxis else -1 if self.axis < self.saxis else 0
        if tmp_dir is not self.dir:
            self.anim = None
        self.dir = tmp_dir
        if self.anim is None:
            self.rotation = 0
            if self.dir == -1:
                self.anim = Animation(
                    x=self.init_x - 1500,
                    rotation=25,
                    transition=self.trans,
                    duration=1000,
                )
                self.anim.start(self)
            if self.dir == 1:
                self.anim = Animation(
                    x=self.init_x + 1500,
                    rotation=-25,
                    transition=self.trans,
                    duration=1000,
                )
                self.anim.start(self)

        difference = self.saxis - touch.spos[0]
        ac.KEYFRAME = abs(difference)

        self.axis = touch.spos[0]

    def on_touch_up(self, touch):

        if self.anim:
            self.anim.stop(self)
            if ac.KEYFRAME > 0.1:
                self.anim_down = Animation(
                    x=self.init_x + 1500 if self.dir == 1 else -1500,
                    y=self.init_y - 1500,
                    rotation=self.rotation + -90 if self.dir == 1 else 90,
                    transition=AnimationTransition.linear,
                    duration=1,
                )
                self.anim_down += Animation(
                    x=self.init_x,
                    y=self.init_y,
                    rotation=0,
                    transition=AnimationTransition.linear,
                    duration=0,
                )
                self.anim_down.start(self)

                if self.dir == 1:
                    self.choice(1)
                if self.dir == -1:
                    self.choice(2)
            else:
                self.rotation = 0
                self.anim_return = Animation(
                    x=self.init_x,
                    y=self.init_y,
                    transition=AnimationTransition.linear,
                    duration=0.2,
                )
                self.anim_return.start(self)

        ac.KEYFRAME = 0
        self.saxis = 0
        self.axis = 0
        self.dir = 0
Esempio n. 16
0
class Sprite(RelativeLayout):
    register = False
    size_ratio = 1.0

    def __init__(self, **kwargs):
        self.image_size = kwargs['size']
        RelativeLayout.__init__(self, size_hint=(None,None), **kwargs)

        self.grid = kwargs['grid']
        self.start_position = self.pos

        self.frozen = False
        self.alive = True
        self.animation = None
        self.safe_pos = self.pos
        self.path = []
        self.moving = False
        self.last_to_tuple = None
        self.move_duration = 0.25

        self.setup()
        self.init()

    def init(self):
        """ This method is called in initiliazation and on restart """
        self.before_init()

        self.frozen = False
        self.alive = True
        self.animation = None
        self.safe_pos = self.pos
        self.path = []
        self.moving = False
        self.last_to_tuple = None

        self.after_init()

    def before_init(self):
        pass

    def after_init(self):
        pass

    def setup(self):
        """ This method is called only in initiliazation """
        raise Exception('This method should be overridden')

    def save_pos(self):
        self.safe_pos = self.pos

    def load_pos(self):
        self.pos = self.safe_pos

    def hide(self):
        self.canvas.clear()

    def die(self):
        if not self.alive or self.parent.frozen:
            return
        print '%s died' % self.__class__.__name__
        self.alive = False
        self.stop() # hm?
        self.hide()
        self.on_death()
        return

    def on_death(self):
        pass

    def on_move_finish(self):
        pass

    def on_every_move(self):
        pass

    def freeze(self):
        self.frozen = True

    def face(self, direction):
        pass

    def continue_move(self):
        if not self.alive:
            return

        self.take_effect()

        if not self.path:
            self.moving = False
            if self.on_move_finish is not None:
                self.on_move_finish()
            self.on_move_finish = None
            self.on_every_move()
            return

        self.moving = True
        destination = self.path.pop()

        if destination.bomb is not None:
            # TODO maybe recalculate path?
            self.path = []
            self.moving = False
            return

        delta_x = abs(destination.pos[0] + self.parent.tile_size[0]/10 - self.pos[0])
        delta_y = abs(destination.pos[1] + self.parent.tile_size[1]/10 - self.pos[1])

        move_duration = self.move_duration

        if delta_x > delta_y:
            move_duration *= delta_x / self.parent.tile_size[0]
            if destination.pos[0] > self.pos[0]:
                self.face('right')
            elif destination.pos[0] < self.pos[0]:
                self.face('left')
        else:
            move_duration *= delta_y / self.parent.tile_size[1]
            if destination.pos[1] > self.pos[1]:
                self.face('top')
            elif destination.pos[1] < self.pos[1]:
                self.face('bottom')

        self.stop_move()

        offset = (self.parent.tile_size[0] - self.size[0])/4

        self.animation = Animation(
                pos=(
                    destination.pos[0] + self.parent.tile_size[0]/10 + offset, 
                    destination.pos[1] + self.parent.tile_size[1]/10 + offset
                ),
                duration=move_duration
        )
        self.animation.on_complete = lambda x: self.continue_move()
        self.animation.start(self)

    def move(self, to_tuple):
        if not self.alive:
            return

        from_tuple = self.grid.get_tile_indexes(*self.center_pos)

        if from_tuple == to_tuple:
            if not self.moving:
                self.grid.get_tile(*from_tuple).add_bomb(self)
                return
        if to_tuple == self.last_to_tuple:
            if self.is_bot():
                raise Exception('kokotina?')
            tile = self.grid.get_tile(*to_tuple)
            self.on_move_finish = lambda : tile.add_bomb(self)
            return

        path = self.grid.find_path(from_tuple, to_tuple)

        if not path:
            return

        self.on_move_finish = None
        self.last_to_tuple = to_tuple

        self.stop_move()
        self.path = path
        self.continue_move()

    def take_effect(self):
        tile = self.get_tile()
        effect = tile.get_effect()
        if effect is not None:
            effect.apply(self)

    def stop_move(self):
        if self.animation is not None:
            self.animation.on_complete = lambda x: self.nothing()
            self.animation.stop(self)

    def restart(self):
        self.before_restart()

        print 'restarting... hmm'
        self.stop()
        self.init()
        self.pos = self.start_position

        self.after_restart()

    def before_restart(self):
        pass

    def after_restart(self):
        pass

    def stop(self):
        self.before_stop()

        self.stop_move()

        self.after_stop()

    def before_stop(self):
        pass

    def after_stop(self):
        pass

    @property
    def center_pos(self):
        return self.center

    def get_tile(self):
        #print 'cp', self.center_pos
        pos_tuple = self.parent.grid.get_tile_indexes(*self.center_pos)
        #print 'pt', pos_tuple
        return self.parent.grid.get_tile(*pos_tuple)

    @property
    def name(self):
        return self.__class__.__name__

    def is_bot(self):
        return True

    def nothing(self):
        pass

    def collide(self, sprite):
        distance_x = abs(self.center_pos[0] - sprite.center_pos[0])
        if distance_x > self.parent.tile_size[0]*0.7:
            return False
        distance_y = abs(self.center_pos[1] - sprite.center_pos[1])
        if distance_y > self.parent.tile_size[1]*0.7:
            return False
        return True
Esempio n. 17
0
class MDFloatingActionButton(
    ThemableBehavior, CircularRippleBehavior, RoundElevationBehaviour, ButtonBehavior, AnchorLayout
):
    _bg_color_down = ListProperty([])
    background_color = ListProperty()
    background_color_down = ListProperty()
    background_color_disabled = ListProperty()
    theme_text_color = OptionProperty(None, allownone=True, options=["Primary", "Secondary", "Hint", "Error", "Custom"])
    text_color = ListProperty(None, allownone=True)

    def _get_bg_color_down(self):
        return self._bg_color_down

    def _set_bg_color_down(self, color, alpha=None):
        if len(color) == 2:
            self._bg_color_down = get_color_from_hex(colors[color[0]][color[1]])
            if alpha:
                self._bg_color_down[3] = alpha
        elif len(color) == 4:
            self._bg_color_down = color

    background_color_down = AliasProperty(_get_bg_color_down, _set_bg_color_down, bind=("_bg_color_down",))

    _bg_color_disabled = ListProperty([])

    def _get_bg_color_disabled(self):
        return self._bg_color_disabled

    def _set_bg_color_disabled(self, color, alpha=None):
        if len(color) == 2:
            self._bg_color_disabled = get_color_from_hex(colors[color[0]][color[1]])
            if alpha:
                self._bg_color_disabled[3] = alpha
        elif len(color) == 4:
            self._bg_color_disabled = color

    background_color_disabled = AliasProperty(
        _get_bg_color_disabled, _set_bg_color_disabled, bind=("_bg_color_disabled",)
    )
    icon = StringProperty("md-android")

    _elev_norm = NumericProperty(6)

    def _get_elev_norm(self):
        return self._elev_norm

    def _set_elev_norm(self, value):
        self._elev_norm = value if value <= 12 else 12
        self._elev_raised = (value + 6) if value + 6 <= 12 else 12
        self.elevation = self._elev_norm

    elevation_normal = AliasProperty(_get_elev_norm, _set_elev_norm, bind=("_elev_norm",))

    _elev_raised = NumericProperty(12)

    def _get_elev_raised(self):
        return self._elev_raised

    def _set_elev_raised(self, value):
        self._elev_raised = value if value + self._elev_norm <= 12 else 12

    elevation_raised = AliasProperty(_get_elev_raised, _set_elev_raised, bind=("_elev_raised",))

    def __init__(self, **kwargs):
        if self.elevation_raised == 0 and self.elevation_normal + 6 <= 12:
            self.elevation_raised = self.elevation_normal + 6
        elif self.elevation_raised == 0:
            self.elevation_raised = 12

        super(MDFloatingActionButton, self).__init__(**kwargs)

        self.elevation_press_anim = Animation(elevation=self.elevation_raised, duration=0.2, t="out_quad")
        self.elevation_release_anim = Animation(elevation=self.elevation_normal, duration=0.2, t="out_quad")

    def _set_ellipse(self, instance, value):
        ellipse = self.ellipse
        ripple_rad = self.ripple_rad

        ellipse.size = (ripple_rad, ripple_rad)
        ellipse.pos = (self.center_x - ripple_rad / 2.0, self.center_y - ripple_rad / 2.0)

    def on_disabled(self, instance, value):
        super(MDFloatingActionButton, self).on_disabled(instance, value)
        if self.disabled:
            self.elevation = 0
        else:
            self.elevation = self.elevation_normal

    def on_touch_down(self, touch):
        if not self.disabled:
            if touch.is_mouse_scrolling:
                return False
            if not self.collide_point(touch.x, touch.y):
                return False
            if self in touch.ud:
                return False
            self.elevation_press_anim.stop(self)
            self.elevation_press_anim.start(self)
        return super(MDFloatingActionButton, self).on_touch_down(touch)

    def on_touch_up(self, touch):
        if not self.disabled:
            if touch.grab_current is not self:
                return super(ButtonBehavior, self).on_touch_up(touch)
            self.elevation_release_anim.stop(self)
            self.elevation_release_anim.start(self)
        return super(MDFloatingActionButton, self).on_touch_up(touch)

    def on_elevation_normal(self, instance, value):
        self.elevation = value

    def on_elevation_raised(self, instance, value):
        if self.elevation_raised == 0 and self.elevation_normal + 6 <= 12:
            self.elevation_raised = self.elevation_normal + 6
        elif self.elevation_raised == 0:
            self.elevation_raised = 12
class RootLayout(BoxLayout, HoveringBehavior):
    dlls_loaded = BooleanProperty(False)
    listed_dlls = ListProperty()
    path = StringProperty()

    # mouse highlight
    _mouse_highlight_pos = ListProperty((0, 0))
    _highlight_alpha = NumericProperty()
    _mouse_highlight_anim = Animation()
    _can_highlight = BooleanProperty(False)

    # options
    mouse_highlight = BooleanProperty(Config.get('mouse_highlight', True))

    def __init__(self, **kw):
        super().__init__(**kw)

        self.bar = self.ids.bar

        # mouse highlight
        self.on_mouse_highlight(None, self.mouse_highlight)

        def callback(*__):
            if self.mouse_highlight:
                self._highlight_alpha = 0
                self._can_highlight = True
                self._show_highlight()
                Window.unbind(mouse_pos=callback)

        Window.bind(mouse_pos=callback)

        # sync
        def on_frame(*args):
            self.show_sync_popup()
            self.setup_updater()

        Clock.schedule_once(on_frame)

    # mouse highlight
    def _show_highlight(self, *__):
        self._mouse_highlight_anim.stop(self)
        self._mouse_highlight_anim = Animation(_highlight_alpha=1, d=.1)
        self._mouse_highlight_anim.start(self)

    def _hide_highlight(self, *__):
        self._mouse_highlight_anim.stop(self)
        self._mouse_highlight_anim = Animation(_highlight_alpha=0, d=.2)
        self._mouse_highlight_anim.start(self)

    def _update_highlight(self, __, pos):
        self._mouse_highlight_pos = pos[0] - 60, pos[1] - 60

    def on_mouse_highlight(self, __, is_on):
        if is_on:
            Window.bind(mouse_pos=self._update_highlight,
                        on_cursor_enter=self._show_highlight,
                        on_cursor_leave=self._hide_highlight)
            self._update_highlight(Window, Window.mouse_pos)
            self._show_highlight()
        else:
            Window.unbind(mouse_pos=self._update_highlight,
                          on_cursor_enter=self._show_highlight,
                          on_cursor_leave=self._hide_highlight)
            self._hide_highlight()
        Config.mouse_highlight = is_on

    def show_sync_popup(self):
        self.sync_popup = SyncPopup()
        self.sync_popup.open()

    @new_thread
    def setup_updater(self):
        self.updater = DllUpdater()
        self.dlls_loaded = self.updater.load_available_dlls()

        if self.dlls_loaded:
            self.ids.refresh_button.disabled = True
            OverdrawLabel(widget=self.ids.quickupdate_content,
                          icon='\uf12b',
                          text='Select a directory')

        else:
            self.ids.refresh_button.disabled = False
            OverdrawLabel(widget=self.ids.quickupdate_content,
                          icon='\uea6a',
                          text='Error when syncing')

        Clock.schedule_once(self.update_common_paths)

    def update_common_paths(self, *args):
        self.ids.game_collection_view.update_local_games()
        self.after_synced()

    def after_synced(self):
        self.sync_popup.dismiss()
        if not IS_ADMIN:
            self.run_as_admin_shown = self.run_as_admin_shown
            if hasattr(self, 'admin_btn'):
                self.admin_btn.ping()

    def switch_animations_enabled(self, _, value):
        Config.animations = value
        Notification(
            title_='Restart required',
            message=
            f'A [color={theme.PRIM}]restart[/color] may be required to [color={theme.PRIM}]{"enable" if value else "disable"}[/color] animations.'
        ).open()

    @property
    def run_as_admin_shown(self):
        return Config.get('run_as_admin_shown', True)

    @run_as_admin_shown.setter
    def run_as_admin_shown(self, value):
        if value:
            self.admin_btn = RunAsAdminButton()
            self.admin_btn.open()
        elif hasattr(self, 'admin_btn'):
            self.admin_btn.dismiss()
            del self.admin_btn

        Config.run_as_admin_shown = value

    @new_thread
    def load_directory(self):
        self.request_load_dlls(easygui.diropenbox())

    def request_load_dlls(self, path):
        if not path:
            return False

        path = os.path.abspath(path)

        self.launch_path = None
        self.path = path
        self.ids.path_info.text = path
        self.ids.selective_update_btn.disabled = True
        self.ids.update_all_btn.disabled = True

        if not os.path.isdir(path):
            return False

        notif = WorkingNotif(text='Searching for dlls')
        notif.open(animation=1)
        Clock.schedule_once(lambda *__: self._load_dlls(path, notif), .5)

    def _load_dlls(self, path, notif=None):
        try:
            self.ids.content_updater.remove_widget(self.launch_now_btn)
        except AttributeError:
            pass

        self.ids.quickupdate_content.overdrawer.dismiss()

        self.listed_dlls = []

        for relative_path in self.updater.local_dlls(path):
            if relative_path.split('\\')[-1] in self.updater.available_dlls:
                self.listed_dlls.append(relative_path)

        if not self.listed_dlls:
            ErrorPopup(
                title='No dlls found here!',
                message=
                f'We are sorry. We have not found any dlls to update here in\n[color={theme.PRIM}]{path}[/color].'
            ).open()

        else:
            self.ids.selective_update_btn.disabled = False
            self.ids.update_all_btn.disabled = False

            if Config.get('show_disclaimer', True):
                Clock.schedule_once(
                    lambda *args: Factory.DisclaimerPopup().open())
                Config.show_disclaimer = False

        self.goto_page(0)
        self.bar.ping()
        if notif:
            notif.dismiss()

    def load_selective(self):
        self.goto_page(5)

        self.ids.dll_view.dlls = self.listed_dlls

        last_selected = ConfLastDlls.get_list(self.path)

        if last_selected:
            self.ids.dll_view.select_by_text(last_selected)
        elif not self.ids.dll_view.selected_nodes:
            self.ids.dll_view.select_all()

    @new_thread
    def update_callback(self, from_selection=False):
        self.goto_page(0)
        self.ids.invert_selection_button.disabled = True
        OverdrawLabel(widget=self.ids.quickupdate_content,
                      icon='\ue896',
                      text='Updating dlls..')

        if from_selection:
            dlls = [
                item.get('text', '')
                for item in self.ids.dll_view.selected_nodes
            ]
            ConfLastDlls.set_list(self.path, dlls)
        else:
            dlls = self.listed_dlls

        Notification(
            title_=f'Updating {len(dlls)} dlls',
            message=
            f'This can take a [color={theme.PRIM}]while[/color] depending on your [color={theme.PRIM}]internet speed[/color].'
        ).open()

        try:
            self.updater.update_dlls(self.path, dlls)

        except Exception:
            ErrorPopup(
                title='Failed to update dlls!',
                message=
                f'Something happened and we are not sure what it was. Please contact our support from the settings.\n\n[color=f55]{format_exc()}[/color]'
            ).open()
            OverdrawLabel(widget=self.ids.quickupdate_content,
                          icon='\uea39',
                          text='Update failed')

        else:
            OverdrawLabel(widget=self.ids.quickupdate_content,
                          icon='\ue930',
                          text='Completed')

            if self.launch_path:
                self.launch_now_btn = LaunchNowButton()
                self.ids.content_updater.add_widget(self.launch_now_btn,
                                                    index=0)

        self.ids.dll_view.data = []

    def launch_updated(self):
        os.startfile(self.launch_path)

    def restore_callback(self):
        dlls = [
            item.get('text', '') for item in self.ids.dll_view.selected_nodes
        ]
        restored, not_restored = self.updater.restore_dlls(self.path, dlls)

        Factory.RestorePopup(restored=restored,
                             not_restored=not_restored).open()

    @silent_exc
    def clear_images_cache(self):
        shutil.rmtree(os.path.join(os.getcwd(), ImageCacher.CACHE_DIR))

    @silent_exc
    def clear_common_paths_cache(self):
        os.remove(GameCollection.COMMON_PATHS_CACHE_PATH)

    def goto_page(self, index):
        self.ids.content.page = index

    def game_path_button_callback(self):
        path = easygui.diropenbox()
        if not path:
            path = ''

        self.ids.game_add_form_dir.text_ = path

    def game_launch_path_button_callback(self):
        path = easygui.fileopenbox(filetypes=['*.exe', '*.url'],
                                   default=self.ids.game_add_form_dir.text +
                                   '\\*.exe')
        if not path:
            path = ''

        self.ids.game_add_form_launch.text_ = path

    def add_game_callback(self):
        game_name = self.ids.game_name_input.text
        game_patch_dir = self.ids.game_add_form_dir.text
        game_launch_path = (self.ids.game_add_form_launch.text
                            if self.ids.game_add_form_launch.text else
                            self.ids.url_input.text)

        if not (game_name and game_patch_dir and game_launch_path):
            return

        os.makedirs('.config', exist_ok=True)

        if not game_launch_path:
            game_launch_path = self.ids.game_add_form_launch.text

        data = {
            'path': game_patch_dir,
            'launchPath': game_launch_path,
        }

        store = JsonStore(GameCollection.CUSTOM_PATHS_PATH)
        store.put(game_name, **data)

        self.cancel_add_game_callback()
        self.ids.game_collection_view.update_custom_games()

    def cancel_add_game_callback(self):
        self.ids.game_name_input.text = ''
        self.ids.game_add_form_dir.text_ = ''
        self.ids.game_add_form_launch.text_ = ''
        self.ids.url_input.text = ''
        self.goto_page(1)

    @silent_exc
    def reset_custom_paths(self):
        os.remove(GameCollection.CUSTOM_PATHS_PATH)

    def uninstall_prompt(self):
        self.uninstall_popup = Factory.UninstallPopup()
        self.uninstall_popup.open()

    @silent_exc
    def export_logs(self):
        OUTPUT = os.path.expanduser('~\\Desktop\\XtremeUpdater_Logs.zip')
        SOURCE = os.path.abspath('logs\\')

        Logger.info(f"Trying to export logs from {SOURCE} to {OUTPUT}")

        try:
            shutil.make_archive(OUTPUT, 'zip', SOURCE)
        except:
            Logger.error(
                f"Failed to export logs from {SOURCE} to {OUTPUT}\n{format_exc()}"
            )
            raise
        else:
            Logger.info(
                f"Successfully exported logs from {SOURCE} to {OUTPUT}")

        Notification(
            title_='Logs exported',
            message=
            f'[color={theme.PRIM}]Logs[/color] were exported to [color={theme.PRIM}]{OUTPUT}[/color]',
            height=160).open()
Esempio n. 19
0
class ZIScatter(Scatter):
    zoom_image = ObjectProperty(Widget())
    init_pos = ObjectProperty((75, 70))

    def __init__(self, **kwargs):
        super(ZIScatter, self).__init__(**kwargs)
        self.anim = Animation()  # Physics simple animation on touch up
        Clock.schedule_interval(self.clear_canvas, 0)
        Clock.schedule_interval(self.control_pos, 0)

    def clear_canvas(self, dt):
        self.canvas.clear()

    def is_leaving_its_box(self):
        #check if scatter is leaving its box
        s = self.scale
        x, y = self.pos
        w, h = self.size
        container = c = self.zoom_image
        #check every corner
        limitx = limity = False
        if (x > c.x or x + w * s < c.x + c.width):
            limitx = True
        if (y > c.y or y + h * s < c.y + c.height):
            limity = True
        return (limitx, limity)

    def fix_after_leaving_its_box(self):
        #check if scatter is leaving its box
        s = self.scale
        x, y = self.pos
        w, h = self.size
        container = c = self.zoom_image
        #check every corner
        limitx = limity = False
        if x > c.x:
            x = c.x
        if x + w * s < c.x + c.width:
            x = c.x + c.width - w * s
        if y > c.y:
            y = c.y
        if y + h * s < c.y + c.height:
            y = c.y + c.height - h * s
        self.pos = (x, y)

    def control_pos(self, dt):
        if self.scale <= 1.03:
            self.reset()
            pass
        #avoid scatter leaving its box while physics animation is going on (after touch up)
        if len(self._touches) > 0:
            return
        limitx, limity = self.is_leaving_its_box()
        if limitx == True or limity == True:
            self.anim.cancel(self)
            self.fix_after_leaving_its_box()

    def transform_with_touch(self, touch):
        init_pos = self.center
        init_scale = self.scale
        init_touch_len = len(self._touches)
        #super(ZIScatter, self).transform__with__touch(touch)

        # just do a simple one finger drag
        if len(self._touches
               ) == 1 and self.scale > 1.05:  #THIS IS NOT IN ORIGINAL SCATTER:
            # _last_touch_pos has last pos in correct parent space,
            # just like incoming touch
            dx = (touch.x - self._last_touch_pos[touch][0]) \
                    * self.do_translation_x
            dy = (touch.y - self._last_touch_pos[touch][1]) \
                    * self.do_translation_y
            self.apply_transform(Matrix().translate(dx, dy, 0))
            #return

        elif len(
                self._touches
        ) == 1 and self.scale < 1.05:  #THIS IS NOT IN ORIGINAL SCATTER:
            return

        else:  #TO AVOID RETURN IN ORIGINAL SCATTER
            # we have more than one touch...
            points = [Vector(self._last_touch_pos[t]) for t in self._touches]

            # we only want to transform if the touch is part of the two touches
            # furthest apart! So first we find anchor, the point to transform
            # around as the touch farthest away from touch
            anchor = max(points, key=lambda p: p.distance(touch.pos))

            # now we find the touch farthest away from anchor, if its not the
            # same as touch. Touch is not one of the two touches used to transform
            farthest = max(points, key=anchor.distance)
            if points.index(farthest) != self._touches.index(touch):
                return

            # ok, so we have touch, and anchor, so we can actually compute the
            # transformation
            old_line = Vector(*touch.ppos) - anchor
            new_line = Vector(*touch.pos) - anchor

            angle = radians(new_line.angle(old_line)) * self.do_rotation
            self.apply_transform(Matrix().rotate(angle, 0, 0, 1),
                                 anchor=anchor)

            if self.do_scale:
                scale = new_line.length() / old_line.length()
                new_scale = scale * self.scale
                if new_scale < self.scale_min or new_scale > self.scale_max:
                    scale = 1.0
                self.apply_transform(Matrix().scale(scale, scale, scale),
                                     anchor=anchor)

        #avoid scatter leaving its box
        limitx, limity = self.is_leaving_its_box()
        if limitx or limity:
            #cancel previous apply_transform
            if init_touch_len == 1:
                ddx = ddy = 0
                if limitx: ddx = -dx
                if limity: ddy = -dy
                self.apply_transform(Matrix().translate(ddx, ddy, 0))
            else:
                if self.do_scale:
                    #self.apply_transform(Matrix().scale(scale/init_scale, scale/init_scale, scale/init_scale),
                    #             anchor=anchor)
                    # control
                    #limitx, limity = self.is_leaving_its_box()
                    #if limitx or limity:
                    self.fix_after_leaving_its_box()

    def on_touch_down(self, touch):
        ret = super(ZIScatter, self).on_touch_down(touch)
        x, y = touch.x, touch.y
        #if not self.zoom_image.image.collide_point(x,y):
        #    # did not touch the mask area
        #    return True

        # if the touch isnt on the widget we do nothing
        if self.zoom_image.collide_point(x, y):
            if touch.is_double_tap:
                self.reset()

        #if not self.parent.image.collide_point(x,y):
        #    # did not touch the mask area
        #    touch.ud["outside"] = True
        #    return False

        return ret

    def on_touch_up(self, touch):
        if touch.grab_current is not self:
            return super(ZIScatter, self).on_touch_up(touch)
        """
        x, y = touch.x, touch.y
        # if the touch isnt on the widget we do nothing
        if self.zoom_image.collide_point(x, y):
            super(ZIScatter, self).on_touch_up(touch)
        """

        ###TAKEN FROM ORIGINAL SCATTER
        x, y = touch.x, touch.y
        # if the touch isnt on the widget we do nothing, just try children
        if self.zoom_image.collide_point(x, y):  #MODIFIED ORIGINAL SCATTER !!
            if not touch.grab_current == self:
                touch.push()
                touch.apply_transform_2d(self.to_local)
                if super(Scatter, self).on_touch_up(touch):
                    touch.pop()
                    return True
                touch.pop()

        # remove it from our saved touches
        if touch in self._touches and touch.grab_state:
            touch.ungrab(self)
            del self._last_touch_pos[touch]
            self._touches.remove(touch)

        # stop propagating if its within our bounds
        if self.collide_point(x, y):
            pass  #eturn True #MODIFIED ORIGINAL SCATTER !!

        # physics behaviour on touch up, fade speed down on the same direction
        return False

        duration = d = 1.5
        dx = touch.dx * 3 * d
        dy = touch.dy * 3 * d
        #print dx, dy
        adx = abs(dx)
        ady = abs(dy)
        if adx > 0 and ady > 0:
            #if adx > 400 :
            #if ady > 400 :
            V = Vector(self.center)
            Vd = Vector((dx, dy))
            destination = V + Vd

            anim = Animation(center=destination, d=d, t='out_expo', s=1 / 150.)
            self.anim.stop(self)
            self.anim = anim
            self.anim.start(self)
            self.previous_anim_dest = destination
        return False

    def reset(self):
        self.center = self.init_pos
        self.scale = 1
Esempio n. 20
0
    def on_main_button(self, button, main_screen, enermy_screen, dmg, attack_effect, gold_text, exp_text, lv_text):
        """ on_main_button turn """

        # Turn
        if self.game_status == GAME_STATUS_OPEN:
            # text code
            self.load_enermy()

            enermy_screen.center_x = enermy_screen.parent.center_x + 35
            anim = Animation(
                center_x=enermy_screen.parent.center_x, duration=.2)
            if anim:
                anim.stop(self)
            anim.start(enermy_screen)

            self._status_change(GAME_STATUS_BATTLE)
        elif self.game_status == GAME_STATUS_BATTLE:
            self._status_change(GAME_STATUS_TURN)

        elif self.game_status == GAME_STATUS_TURN:
            # print dir(app.sound['swing'])
            app.sound['swing'].play()

            # enermy
            left = Animation(
                center_x=enermy_screen.parent.center_x - 10, duration=.2)
            right = Animation(
                center_x=enermy_screen.parent.center_x, duration=.2)
            anim = left + right
            if anim:
                anim.stop(self)
            anim.start(enermy_screen)

            # player
            left = Animation(
                center_x=enermy_screen.parent.center_x - 10, duration=.2)
            right = Animation(
                center_x=enermy_screen.parent.center_x, duration=.2)
            anim = left + right
            if anim:
                anim.stop(self)
            anim.start(enermy_screen)

            # damage
            # 실제 공격데미지 만큼 커지면 재미있을 듯
            dmg_anim = Animation(
                center_y=dmg.parent.center_y + 100, duration=.4, t='out_circ')
            dmg_anim &= Animation(opacity=0, duration=.5)
            dmg_anim &= Animation(font_size=60, duration=.5)

            if dmg_anim:
                dmg.font_size = 30
                dmg.center_y = dmg.parent.center_y + 40
                dmg.opacity = 1
                dmg_anim.stop(self)
            dmg_anim.start(dmg)

            # attack_effect
            attack_effect_anim = Animation(
                center_y=dmg.parent.center_y + 100, duration=2.0, t='out_circ')
            attack_effect_anim &= Animation(opacity=0.0, duration=.5)
            attack_effect_anim &= Animation(size=(120, 120), duration=.5)

            if attack_effect_anim:
                attack_effect.size = (40, 40)
                attack_effect.center_y = attack_effect.parent.center_y
                attack_effect.opacity = 1.0
                attack_effect_anim.stop(self)
            attack_effect_anim.start(attack_effect)

            # check for fight
            if self.player.hp == 0 or self.enermy.hp == 0:
                return
            # take dmg each other
            if self.player.fight(self.enermy.ap):
                # if dead
                pass
            if self.enermy.fight(self.player.ap):
                # if dead
                self._status_change(GAME_STATUS_REWARD)
        elif self.game_status == GAME_STATUS_REWARD:
            app.sound['coin'].play()
            is_levelup = self.player.get_reward(self.enermy)

            # gold_text
            gold_anim = Animation(
                center_y=gold_text.parent.center_y + 100, duration=.2, t='out_circ')
            gold_anim &= Animation(opacity=0, duration=1.0)

            if gold_anim:
                gold_text.center_y = gold_text.parent.center_y + 40
                gold_text.opacity = 1
                gold_anim.stop(self)
            gold_anim.start(gold_text)

            # exp
            exp_anim = Animation(
                center_y=exp_text.parent.center_y + 130, duration=.2, t='out_circ')
            exp_anim &= Animation(opacity=0, duration=1.0)

            if exp_anim:
                exp_text.center_y = exp_text.parent.center_y + 40
                exp_text.opacity = 1
                exp_anim.stop(self)
            exp_anim.start(exp_text)

            if is_levelup:
                # lv
                lv_anim = Animation(
                    center_y=lv_text.parent.center_y + 150, duration=.2, t='out_circ')
                lv_anim &= Animation(opacity=0, duration=2.0)
                lv_anim &= Animation(font_size=100, duration=2.0)
                if lv_anim:
                    dmg.font_size = 25
                    lv_text.center_y = lv_text.parent.center_y + 40
                    lv_text.opacity = 1
                    lv_anim.stop(self)
                lv_anim.start(lv_text)

            # # reward
            # reward.center_y = reward.parent.center_y
            # reward.opacity=0
            # reward_anim = Animation(center_y=reward.parent.center_y+60, duration=1.0, t='out_circ')
            # reward_anim.bind(on_complete=self.wow)
            # # reward_anim &= Animation(opacity=1, duration=3.0)
            # reward_anim.start(reward)

            self._status_change(GAME_STATUS_OPEN)

        else:
            raise

        # Text button name change
        button.name = status_name(self.game_status)
Esempio n. 21
0
class PanelWidget(FloatLayout):
    """
    The implementation of the base panel widget.

    Other widgets could be inherited from ``Panel`` in order to get
    the standard visual decoration and show/hide transitions.

    """
    def __init__(self, **kwargs):
        """Initialize the widget and its state variables."""
        super(PanelWidget, self).__init__(**kwargs)
        self.bind(pos=self.redraw)
        self.bind(size=self.redraw)
        # hardcoded stuff
        self.color = (.1, .6, .6)
        self.border_width = 1
        self.corner_width = 1.5
        self.corner_len = 7
        self.opacity = .85
        # show/hide animations (hardcoded in half)
        self.hidden = True
        self.trans_duration_in = .6
        self.trans_duration_out = .3
        self.show_style = "out_elastic"
        self.hide_style = "in_back"
        scroll_x = self.pos[0]
        global_w = Window.size[0]
        hidden_x = global_w + 10
        self.x = hidden_x
        self.show_animation = Animation(x=scroll_x,
                                        duration=self.trans_duration_in,
                                        t=self.show_style)
        self.hide_animation = Animation(x=hidden_x,
                                        duration=self.trans_duration_out,
                                        t=self.hide_style)

    def toggle(self):
        """Toggle show/hide the panel with its contents."""
        if self.hidden:
            self.hide_animation.stop(self)
            self.show_animation.start(self)
        else:
            self.show_animation.stop(self)
            self.hide_animation.start(self)
        self.hidden = not self.hidden

    def redraw(self, *_args):
        """Redraw panel on the canvas."""
        saved_children = self.children[:]
        self.clear_widgets()
        self.canvas.clear()
        with self.canvas:
            # background
            Color(self.color[0] / 2, self.color[1] / 2, self.color[2] / 2,
                  self.opacity)
            Rectangle(pos=self.pos, size=self.size)
            # border
            Color(self.color[0], self.color[1], self.color[2], 1)
            pos_x, pos_y = self.pos
            width, height = self.size
            Line(points=[
                pos_x, pos_y, pos_x + width, pos_y, pos_x + width,
                pos_y + height, pos_x, pos_y + height, pos_x, pos_y
            ],
                 width=self.border_width,
                 cap='square',
                 joint='miter')
            # corners
            Color(1, 1, 1, .7)
            Line(points=[
                pos_x + self.corner_len, pos_y, pos_x, pos_y, pos_x,
                pos_y + self.corner_len
            ],
                 width=self.corner_width,
                 cap='square',
                 joint='miter')
            Line(points=[
                pos_x + width - self.corner_len, pos_y, pos_x + width, pos_y,
                pos_x + width, pos_y + self.corner_len
            ],
                 width=self.corner_width,
                 cap='square',
                 joint='miter')
            Line(points=[
                pos_x, pos_y + height - self.corner_len, pos_x, pos_y + height,
                pos_x + self.corner_len, pos_y + height
            ],
                 width=self.corner_width,
                 cap='square',
                 joint='miter')
            Line(points=[
                pos_x + width, pos_y + height - self.corner_len, pos_x + width,
                pos_y + height, pos_x + width - self.corner_len, pos_y + height
            ],
                 width=self.corner_width,
                 cap='square',
                 joint='miter')
        for widget in saved_children:
            self.add_widget(widget)
Esempio n. 22
0
class AnimationTestCase(unittest.TestCase):
    def sleep(self, t):
        start = time()
        while time() < start + t:
            sleep(.01)
            Clock.tick()

    def setUp(self):
        self.assertEqual(len(Animation._instances), 0)
        self.a = Animation(x=100, d=1, t='out_bounce')
        self.w = Widget()

    def tearDown(self):
        self.assertEqual(len(Animation._instances), 0)

    def test_start_animation(self):
        self.a.start(self.w)
        self.sleep(1.5)
        self.assertAlmostEqual(self.w.x, 100)

    def test_animation_duration_0(self):
        a = Animation(x=100, d=0)
        a.start(self.w)
        self.sleep(.5)

    def test_stop_animation(self):
        self.a.start(self.w)
        self.sleep(.5)
        self.a.stop(self.w)
        self.assertNotAlmostEqual(self.w.x, 100)
        self.assertNotAlmostEqual(self.w.x, 0)

    def test_stop_all(self):
        self.a.start(self.w)
        self.sleep(.5)
        Animation.stop_all(self.w)

    def test_stop_all_2(self):
        self.a.start(self.w)
        self.sleep(.5)
        Animation.stop_all(self.w, 'x')

    def test_duration(self):
        self.assertEqual(self.a.duration, 1)

    def test_transition(self):
        self.assertEqual(self.a.transition, AnimationTransition.out_bounce)

    def test_animated_properties(self):
        self.assertEqual(self.a.animated_properties['x'], 100)

    def test_animated_instruction(self):
        instruction = Scale(3)
        self.a.start(instruction)
        self.assertEqual(self.a.animated_properties['x'], 100)
        self.assertAlmostEqual(instruction.x, 3)
        self.sleep(1.5)
        self.assertAlmostEqual(instruction.x, 100)

    def test_weakref(self):
        widget = Widget()
        anim = Animation(x=100)
        anim.start(widget.proxy_ref)
        del widget
        gc.collect()
        try:
            self.sleep(1.)
        except ReferenceError:
            pass
Esempio n. 23
0
class BaseRaisedButton(CommonElevationBehavior, BaseButton):
    '''
    Abstract base class for raised buttons which elevate from material.
    Raised buttons are to be used sparingly to emphasise primary/important
    actions.

    Implements elevation behavior as well as the recommended down/disabled
    colors for raised buttons.
    '''
    def __init__(self, **kwargs):
        if self.elevation_raised == 0 and self.elevation_normal + 6 <= 12:
            self.elevation_raised = self.elevation_normal + 6
        elif self.elevation_raised == 0:
            self.elevation_raised = 12
        super(BaseRaisedButton, self).__init__(**kwargs)
        self.elevation_press_anim = Animation(elevation=self.elevation_raised,
                                              duration=.2, t='out_quad')
        self.elevation_release_anim = Animation(
            elevation=self.elevation_normal, duration=.2, t='out_quad')

    _elev_norm = NumericProperty(2)

    def _get_elev_norm(self):
        return self._elev_norm

    def _set_elev_norm(self, value):
        self._elev_norm = value if value <= 12 else 12
        self._elev_raised = (value + 6) if value + 6 <= 12 else 12
        self.elevation = self._elev_norm
        self.elevation_release_anim = Animation(elevation=value,
                                                duration=.2, t='out_quad')

    elevation_normal = AliasProperty(_get_elev_norm, _set_elev_norm,
                                     bind=('_elev_norm',))

    _elev_raised = NumericProperty(8)

    def _get_elev_raised(self):
        return self._elev_raised

    def _set_elev_raised(self, value):
        self._elev_raised = value if value + self._elev_norm <= 12 else 12
        self.elevation_press_anim = Animation(elevation=value,
                                              duration=.2, t='out_quad')

    elevation_raised = AliasProperty(_get_elev_raised, _set_elev_raised,
                                     bind=('_elev_raised',))

    def on_disabled(self, instance, value):
        if value:
            self.elevation = 0
        else:
            self.elevation = self.elevation_normal
        super(BaseRaisedButton, self).on_disabled(instance, value)
    
    def on_touch_down(self, touch):
        if not self.disabled:
            if touch.is_mouse_scrolling:
                return False
            if not self.collide_point(touch.x, touch.y):
                return False
            if self in touch.ud:
                return False
            self.elevation_press_anim.stop(self)
            self.elevation_press_anim.start(self)
        return super(BaseRaisedButton, self).on_touch_down(touch)

    def on_touch_up(self, touch):
        if not self.disabled:
            if touch.grab_current is not self:
                return super(ButtonBehavior, self).on_touch_up(touch)
            self.elevation_release_anim.stop(self)
            self.elevation_release_anim.start(self)
        return super(BaseRaisedButton, self).on_touch_up(touch)

    def _get_md_bg_color_down(self):
        t = self.theme_cls
        c = self.md_bg_color  # Default to no change on touch
        # Material design specifies using darker hue when on Dark theme
        if t.theme_style == 'Dark':
            if self.md_bg_color == t.primary_color:
                c = t.primary_dark
            elif self.md_bg_color == t.accent_color:
                c = t.accent_dark
        return c

    def _get_md_bg_color_disabled(self):
        if self.theme_cls.theme_style == 'Dark':
            c = (1., 1., 1., 0.12)
        else:
            c = (0., 0., 0., 0.12)
        return c
Esempio n. 24
0
class Metronome(FloatLayout):
    needle_angle = NumericProperty(0)
    num_beats = NumericProperty(4)
    bpm = NumericProperty(200)
    top_prop = NumericProperty(0)

    def __init__(self, **kwargs):
        self.box = BoxLayout()
        self.beatbar = FloatLayout()
        self.buttonbar = BoxLayout()
        self.max_needle_angle = 30
        super().__init__(**kwargs)
        self.spb = 60 / self.bpm
        self.time_sig = 4

        self.sine_file = "./sine.wav"  # Written from NumPy array

        self.player = pyaudio.PyAudio()
        sine = wave.open(self.sine_file, "rb")
        self.sine_data = sine.readframes(2048)
        self.stream = self.player.open(
            format=self.player.get_format_from_width(sine.getsampwidth()),
            channels=sine.getnchannels(),
            rate=sine.getframerate(),
            output=True)

        self.stopped = True
        self.needle_animation = Animation()
        self.beatmarker_animation = Animation()
        Clock.schedule_once(self.hide)

    def hide(self, *args):
        self.top = 0

    def slide(self, state):
        if state == 'down' and self.top_prop == 0:
            self.top_prop = self.height + 50
        else:
            self.top_prop = 0

    def on_size(self, *args):
        target_ratio = 0.75
        width, height = self.size
        if width / height > target_ratio:
            self.box.height = height
            self.box.width = target_ratio * height
        else:
            self.box.width = width
            self.box.height = width / target_ratio
        self.size = self.box.size

    def on_bpm(self, instance, bpm):
        self.spb = 60 / self.bpm
        self.stop()

    def increment_bpm(self, val):
        if 40 <= self.bpm + val <= 300:
            self.bpm += val

    def play(self, *args):
        if self.stopped:
            self.stopped = False
            thread = Thread(target=self._play, daemon=True)
            thread.start()

    def _play(self):
        start = time.time()
        delta = self.spb
        goal = start + delta
        forward = True
        while not self.stopped:
            beat_num = (time.time() - start) // delta
            self.animate_needle(self.spb, forward)
            self.animate_beatmarker(0.1, beat_num)
            self.stream.write(self.sine_data)
            time.sleep(goal - time.time())
            forward = not forward
            goal += delta

    def stop(self):
        if not self.stopped:
            self.beatmarker_animation.stop(self)
            self.needle_animation.stop(self)
            self.stopped = True
            self.needle_angle = 0

    def animate_needle(self, duration, forward):
        self.needle_animation.stop(self)
        if forward:
            self.needle_angle = -self.max_needle_angle
            self.needle_animation = Animation(needle_angle=self.max_needle_angle, duration=duration)
        else:
            self.needle_angle = self.max_needle_angle
            self.needle_animation = Animation(needle_angle=-self.max_needle_angle, duration=duration)
        self.needle_animation.start(self)

    def animate_beatmarker(self, duration, beat_num):
        self.beatmarker_animation.stop(self)
        self.beatmarker_animation = Animation(duration=duration)
        beat_idx = int(beat_num % self.num_beats)
        beatmarker = self.beatbar.beatmarkers.children[beat_idx]
        self.beatmarker_animation.bind(on_progress=beatmarker.update_animation)
        self.beatmarker_animation.bind(on_complete=beatmarker.end_animation)
        self.beatmarker_animation.start(self)
Esempio n. 25
0
class MDFloatingTempActionButton(ThemableBehavior, CircularRippleBehavior,
                                 RoundElevationBehavior, ButtonBehavior,
                                 AnchorLayout):
    _bg_color_down = ListProperty([])
    background_color = ListProperty()
    background_color_down = ListProperty()
    background_color_disabled = ListProperty()
    theme_text_color = OptionProperty(
        None,
        allownone=True,
        options=['Primary', 'Secondary', 'Hint', 'Error', 'Custom'])
    text_color = ListProperty(None, allownone=True)

    def _get_bg_color_down(self):
        return self._bg_color_down

    def _set_bg_color_down(self, color, alpha=None):
        if len(color) == 2:
            self._bg_color_down = get_color_from_hex(
                colors[color[0]][color[1]])
            if alpha:
                self._bg_color_down[3] = alpha
        elif len(color) == 4:
            self._bg_color_down = color

    background_color_down = AliasProperty(_get_bg_color_down,
                                          _set_bg_color_down,
                                          bind=('_bg_color_down', ))

    _bg_color_disabled = ListProperty([])

    def _get_bg_color_disabled(self):
        return self._bg_color_disabled

    def _set_bg_color_disabled(self, color, alpha=None):
        if len(color) == 2:
            self._bg_color_disabled = get_color_from_hex(
                colors[color[0]][color[1]])
            if alpha:
                self._bg_color_disabled[3] = alpha
        elif len(color) == 4:
            self._bg_color_disabled = color

    background_color_disabled = AliasProperty(_get_bg_color_disabled,
                                              _set_bg_color_disabled,
                                              bind=('_bg_color_disabled', ))
    icon = StringProperty('android')

    _elev_norm = NumericProperty(6)

    def _get_elev_norm(self):
        return self._elev_norm

    def _set_elev_norm(self, value):
        self._elev_norm = value if value <= 12 else 12
        self._elev_raised = (value + 6) if value + 6 <= 12 else 12
        self.elevation = self._elev_norm

    elevation_normal = AliasProperty(_get_elev_norm,
                                     _set_elev_norm,
                                     bind=('_elev_norm', ))

    # _elev_raised = NumericProperty(12)
    _elev_raised = NumericProperty(6)

    def _get_elev_raised(self):
        return self._elev_raised

    def _set_elev_raised(self, value):
        self._elev_raised = value if value + self._elev_norm <= 12 else 12

    elevation_raised = AliasProperty(_get_elev_raised,
                                     _set_elev_raised,
                                     bind=('_elev_raised', ))

    def __init__(self, **kwargs):
        if self.elevation_raised == 0 and self.elevation_normal + 6 <= 12:
            self.elevation_raised = self.elevation_normal + 6
        elif self.elevation_raised == 0:
            self.elevation_raised = 12

        super(MDFloatingTempActionButton, self).__init__(**kwargs)

        self.elevation_press_anim = Animation(elevation=self.elevation_raised,
                                              duration=.2,
                                              t='out_quad')
        self.elevation_release_anim = Animation(
            elevation=self.elevation_normal, duration=.2, t='out_quad')

    def _set_ellipse(self, instance, value):
        ellipse = self.ellipse
        ripple_rad = self.ripple_rad

        ellipse.size = (ripple_rad, ripple_rad)
        ellipse.pos = (self.center_x - ripple_rad / 2.,
                       self.center_y - ripple_rad / 2.)

    def on_disabled(self, instance, value):
        super(MDFloatingTempActionButton, self).on_disabled(instance, value)
        if self.disabled:
            self.elevation = 0
        else:
            self.elevation = self.elevation_normal

    def on_touch_down(self, touch):
        if not self.disabled:
            if touch.is_mouse_scrolling:
                return False
            if not self.collide_point(touch.x, touch.y):
                return False
            if self in touch.ud:
                return False
            self.elevation_press_anim.stop(self)
            self.elevation_press_anim.start(self)
        return super(MDFloatingTempActionButton, self).on_touch_down(touch)

    def on_touch_up(self, touch):
        if not self.disabled:
            if touch.grab_current is not self:
                return super(ButtonBehavior, self).on_touch_up(touch)
            self.elevation_release_anim.stop(self)
            self.elevation_release_anim.start(self)
        return super(MDFloatingTempActionButton, self).on_touch_up(touch)

    def on_elevation_normal(self, instance, value):
        self.elevation = value

    def on_elevation_raised(self, instance, value):
        if self.elevation_raised == 0 and self.elevation_normal + 6 <= 12:
            self.elevation_raised = self.elevation_normal + 6
        elif self.elevation_raised == 0:
            self.elevation_raised = 12
class HoveringBehavior(EventDispatcher):
    hovering = BooleanProperty(False)
    hovering_attrs = DictProperty()
    anim_kw = DictProperty()
    _orig_attrs = {}
    _last_pos = (0, 0)

    def __init__(self, **kw):
        self.register_event_type('on_enter')
        self.register_event_type('on_leave')

        super().__init__(**kw)

        self.bind_hovering()

    def bind_hovering(self, *args):
        Window.bind(mouse_pos=self.on_mouse_pos)

    def unbind_hovering(self, *args):
        Window.unbind(mouse_pos=self.on_mouse_pos)

    def on_mouse_pos(self, __, pos):
        self._last_pos = pos

        if not self.get_root_window():
            return

        self.hovering = self.collide_point(*self.to_widget(*pos))

    def refresh_hovering(self):
        self.on_mouse_pos(None, self._last_pos)

    def on_hovering(self, __, hovering):
        self.dispatch('on_enter' if hovering else 'on_leave')

    def update_orig_attrs(self, *args):
        self._orig_attrs = {
            key: getattr(self, key)
            for key in self.hovering_attrs.keys()
        }

    def on_enter(self):
        if getattr(self, 'disabled', False):
            return

        if not self._orig_attrs:
            self.update_orig_attrs()

        try:
            self.on_leave_anim.stop(self)
        except AttributeError:
            pass

        self.on_enter_anim = Animation(**self.hovering_attrs, **self.anim_kw)
        self.on_enter_anim.start(self)

    def on_leave(self):
        try:
            self.on_enter_anim.stop(self)
        except AttributeError:
            pass

        self.on_leave_anim = Animation(**self._orig_attrs, **self.anim_kw)
        self.on_leave_anim.start(self)

    def on_hovering_attrs(self, *args):
        self.on_hovering(self, self.hovering)
Esempio n. 27
0
class ConnectionScreen(Screen):
    def __init__(self, **kwargs):
        super(ConnectionScreen, self).__init__(**kwargs)

        self.cancelConnect = False

        layout = FloatLayout()
        self.spinner = ProgressBar(
            max=1000,
            value=0,
            pos=[50, 600],
            size=[620, 50],
            size_hint_x=None,
            size_hint_y=None,
        )

        self.anim = Animation(value=0) + Animation(value=1000)
        self.anim.repeat = True
        self.anim.start(self.spinner)

        self.connectLabel = Label(
            text="Connecting to WiFi",
            font_size="60px",
            font_name="Raleway-Regular.ttf",
            color=[1, 1, 1, 1],
            size=[620, 100],
            pos=[50, 700],
            text_size=[620, 100],
            halign="center",
            size_hint_x=None,
            size_hint_y=None,
        )

        self.hintLabel = Label(
            text="Press F2 to skip",
            font_size="40px",
            font_name="Raleway-Regular.ttf",
            color=[1, 1, 1, 0.7],
            size=[620, 100],
            pos=[50, 500],
            text_size=[620, 100],
            halign="center",
            size_hint_x=None,
            size_hint_y=None,
        )

        layout.add_widget(self.spinner)
        layout.add_widget(self.connectLabel)
        layout.add_widget(self.hintLabel)
        self.add_widget(layout)

        return None

    def startConnect(self):
        _thread.start_new_thread(self.connect, ())

    def startUpdateConnection(self):
        _thread.start_new_thread(self.updateConnection, ())

    def updateConnection(self):
        try:
            print("Update connection to ", config["ssid"], ", ",
                  config["password"])
            self.connectLabel.text = "Updating network"
            self.hintLabel.opacity = 0.0

            out = check_output(["wpa_cli",
                                "list_networks"]).decode(sys.stdout.encoding)
            lines = out.splitlines()

            for i in range(len(lines)):
                if i > 1:
                    parts = lines[i].split("\t")
                    id = parts[0].strip()
                    print("Removing existing network ", id)
                    out = check_output(["wpa_cli", "remove_network",
                                        id]).decode(sys.stdout.encoding)
                    print(out)

            print("Adding a new network")
            out = check_output(["wpa_cli",
                                "add_network"]).decode(sys.stdout.encoding)
            parts = out.splitlines()
            id = parts[1]
            print(out)

            print("Setting SSID")
            out = check_output([
                "wpa_cli", "set_network", id, "ssid",
                '"' + config["ssid"] + '"'
            ]).decode(sys.stdout.encoding)
            print(out)

            print("Setting password")
            out = check_output([
                "wpa_cli", "set_network", id, "psk",
                '"' + config["password"] + '"'
            ]).decode(sys.stdout.encoding)
            print(out)

            print("Selecting network")
            out = check_output(["wpa_cli", "select_network",
                                id]).decode(sys.stdout.encoding)
            print(out)

            print("Enabling network")
            out = check_output(["wpa_cli", "enable_network",
                                id]).decode(sys.stdout.encoding)
            print(out)

            print("Saving configuration")
            out = check_output(["wpa_cli",
                                "save_config"]).decode(sys.stdout.encoding)
            print(out)

            self.connectLabel.text = "Restarting"
            time.sleep(3)

            print("Restarting")
            out = check_output(["sudo", "reboot",
                                "now"]).decode(sys.stdout.encoding)
            print(out)

            print("Reconfiguring supplicant")
            out = check_output(["wpa_cli",
                                "reconfigure"]).decode(sys.stdout.encoding)
            print(out)

            print("Restarting daemon")
            out = check_output(["sudo", "systemctl",
                                "daemon-reload"]).decode(sys.stdout.encoding)
            print(out)

            print("Stopping network")
            out = check_output(["sudo", "systemctl", "stop",
                                "dhcpcd"]).decode(sys.stdout.encoding)
            print(out)

            print("Starting network")
            out = check_output(["sudo", "systemctl", "start",
                                "dhcpcd"]).decode(sys.stdout.encoding)
            print(out)
        except:
            print(traceback.format_exc())

    def connect(self):
        global config
        self.connectLabel.text = "Connecting to WiFi"
        self.hintLabel.opacity = 0.5
        print("Connecting to ", config["ssid"], ", ", config["password"])
        time.sleep(3)

        if self.cancelConnect:
            self.anim.stop(self.spinner)
            self.spinner.value = 1000
            self.connectLabel.text = "Cancelled"
            time.sleep(3)
            self.parent.current = "settings"
            return

        connected = False
        for i in range(20):
            if self.cancelConnect:
                self.anim.stop(self.spinner)
                self.spinner.value = 1000
                self.connectLabel.text = "Cancelled"
                time.sleep(3)
                self.parent.current = "settings"
                break

            print("Connecting " + str(i + 1))
            out = check_output(["ifconfig",
                                "wlan0"]).decode(sys.stdout.encoding)
            if "inet " in out:
                connected = True
                break

            time.sleep(1)

        if not self.cancelConnect:
            if connected:
                self.anim.stop(self.spinner)
                self.spinner.value = 1000
                self.connectLabel.text = "Connected"
                time.sleep(3)
                if config["id"] == "":
                    print("Switching to Login")
                    self.parent.current = "login"
                else:
                    print("Switching to Main")
                    self.parent.current = "main"
            else:
                self.anim.stop(self.spinner)
                self.spinner.value = 1000
                self.connectLabel.text = "Failed to connect"
                time.sleep(3)
                self.parent.current = "settings"
Esempio n. 28
0
class InterpreterGui(ScatterLayout):
    c1 = NumericProperty()
    c2 = NumericProperty()
    c3 = NumericProperty()
    c4 = NumericProperty()
    fontSizer = NumericProperty()

    c1 = 1
    c2 = .3
    c3 = .4
    c4 = .85

    fontSizer = 24
    output_window = ObjectProperty()
    code_input = ObjectProperty()
    #scrollview = ObjectProperty()
    scatter = ObjectProperty()
    b = ObjectProperty()

    subprocesses = []
    off = False

    input_fail_alpha = NumericProperty(0.)

    lock_input = BooleanProperty(False)
    _lock_input = BooleanProperty(False)

    halting = BooleanProperty(False)
    '''True when the interpreter has been asked to stop but has not yet
    done so.'''

    interpreter_state = OptionProperty(
        'waiting',
        options=['waiting', 'interpreting', 'not_responding', 'restarting'])
    status_label_colour = StringProperty('b2ade6')

    _output_label_queue = ListProperty([])

    dequeue_scheduled = ObjectProperty(None, allownone=True)
    clear_scheduled = ObjectProperty(None, allownone=True)

    awaiting_label_display_completion = BooleanProperty(False)

    throttle_label_output = BooleanProperty()
    '''Whether to clear the output label queue regularly. If False, labels
    will always be displayed, but this *will* cause problems with
    e.g. a constantly printing while loop.
    '''

    interpreted_lines = ListProperty([])
    '''A list of the lines of code that have been executed so far.'''

    completion_threads = []
    '''The threads running jedi completion functions.'''

    most_recent_completion_time = 0.
    '''The most recent timestamp from a completion. New completions with
    older timestamps will be ignored.'''

    move_lock = False
    scale_lock_left = False
    scale_lock_right = False
    scale_lock_top = False
    scale_lock_bottom = False
    disp = 1
    outDisp = 3

    def __init__(self, *args, **kwargs):
        super(InterpreterGui, self).__init__(*args, **kwargs)
        self.animation = Animation(input_fail_alpha=0.,
                                   t='out_expo',
                                   duration=0.5)

        self.interpreter = InterpreterWrapper(
            'Interpreter',
            use_thread=True,
            throttle_output=App.get_running_app().setting__throttle_output,
            thread_name='interpreter')
        self.interpreter.bind(
            interpreter_state=self.setter('interpreter_state'))
        self.interpreter.bind(lock_input=self.setter('lock_input'))

        self.interpreter.bind(on_execution_complete=self.execution_complete)
        self.interpreter.bind(on_stdout=self.on_stdout)
        self.interpreter.bind(on_stderr=self.on_stderr)
        self.interpreter.bind(on_notification=self.on_notification)
        self.interpreter.bind(on_user_message=self.on_user_message)
        self.interpreter.bind(on_missing_labels=self.on_missing_labels)
        self.interpreter.bind(on_request_input=self.on_request_input)
        self.size_hint = .5, .5

        Clock.schedule_once(self.post_init_check, 0)

    def flip(self):
        if self.disp == 1:
            self.code_input.disabled = True
            self.output_window.disabled = True
            self.disp = 0
        else:
            self.code_input.disabled = False
            self.output_window.disabled = False
            self.disp = 1

    def post_init_check(self, *args):
        if App.get_running_app().ctypes_working:
            return
        self.add_user_message_label(
            ('Could not load ctypes on this device. Keyboard interrupt '
             'will not be available.'),
            background_colour=(1, 0.6, 0, 1))

    def on_lock_input(self, instance, value):
        if value:
            self.input_focus_on_disable = self.code_input.focus
            self._lock_input = True
        else:
            self._lock_input = False
            self.code_input.focus = self.input_focus_on_disable
            self.ensure_no_ctrl_c_button()
            self.halting = False

    def on_stdout(self, interpreter, text):
        kids = self.output_window.children
        if len(kids) > self.outDisp:
            self.output_window.remove_widget(kids[-2])
        self.add_output_label(text, 'stdout')

    def on_stderr(self, interpreter, text):
        kids = self.output_window.children
        if len(kids) > self.outDisp:
            self.output_window.remove_widget(kids[-2])
        self.add_output_label(text, 'stderr')

    def on_notification(self, interpreter, text):
        self.add_notification_label(text)

    def on_user_message(self, interpreter, text):
        self.add_user_message_label(text, background_colour=(1, 0.6, 0, 1))

    def on_request_input(self, interpreter, prompt):
        self.show_input_popup(prompt)

    def show_input_popup(self, prompt):
        # Window.softinput_mode = 'below_target'
        p = InputPopup(prompt=prompt, submit_func=self.send_input)
        p.open()

    def send_input(self, text):
        '''Send the given input to the Python interpreter.'''
        self.interpreter.send_input(text)

    def ensure_ctrl_c_button(self):
        if not App.get_running_app().ctypes_working:
            return
        Clock.schedule_once(self._switch_to_ctrl_c_button, 0.4)

    def _switch_to_ctrl_c_button(self, *args):
        c = self.ids.carousel
        if c.index == 0:
            c.load_next()

    def clear_output(self):
        for child in self.output_window.children[:-1]:
            self.output_window.remove_widget(child)

    def exec_file(self):
        App.get_running_app().root.switch_to('filechooser',
                                             open_method=self._exec_file,
                                             success_screen_name='interpreter',
                                             purpose='exec file')

    def _exec_file(self, filename):
        self.add_user_message_label('Executing {}...'.format(filename))
        self.ensure_ctrl_c_button()
        self.interpreter.exec_file(filename)

    def ensure_no_ctrl_c_button(self):
        Clock.unschedule(self._switch_to_ctrl_c_button)
        c = self.ids.carousel
        if c.index == 1:
            c.load_previous()
        else:
            Animation.cancel_all(c)
            c._start_animation(new_offset=0)

    def on_interpreter_state(self, instance, value):
        if value == 'waiting':
            self.status_label_colour = 'b2ade6'
        elif value == 'interpreting':
            self.status_label_colour = 'ade6b4'
        elif value == 'not_responding':
            self.status_label_colour = 'e6adad'
        elif value == 'restarting':
            self.status_label_colour = 'e6adad'

    def interpret_line_from_code_input(self):
        text = self.code_input.text
        if text == '':
            self.flash_input_fail()
            return
        self.code_input.text = ''
        self.interpret_line(text)

    def flash_input_fail(self):
        self.animation.stop(self)
        self.input_fail_alpha = 1.
        self.animation.start(self)

    def interpret_line(self, text):
        self.interpreted_lines.append(text)
        index = self.interpreter.interpret_line(text)
        self.add_input_label(text, index)
        self.ensure_ctrl_c_button()

    def add_user_message_label(self, text, **kwargs):
        l = UserMessageLabel(text=text, **kwargs)
        kids = self.output_window.children
        if len(kids) > self.outDisp:
            self.output_window.remove_widget(kids[-2])
        self.output_window.add_widget(l)
        #self.scrollview.scroll_to(l)

    def add_doc_label(self, text, **kwargs):
        l = DocLabel(text=text, **kwargs)
        kids = self.output_window.children
        if len(kids) > self.outDisp:
            self.output_window.remove_widget(kids[-2])
        self.output_window.add_widget(l)
        #self.scrollview.scroll_to(l)

    def add_input_label(self, text, index):
        kids = self.output_window.children
        if len(kids) > self.outDisp:
            self.output_window.remove_widget(kids[-2])
        l = InputLabel(text=text, index=index, root=self)
        self.output_window.add_widget(l)
        #self.scrollview.scroll_to(l)

    def add_output_label(self, text, stream='stdout'):
        kids = self.output_window.children
        if len(kids) > self.outDisp:
            self.output_window.remove_widget(kids[-2])
        self._output_label_queue.append((text, stream))
        # self._dequeue_output_label(0)

    def _add_output_label(self, text, stream='stdout', scroll_to=True):
        l = OutputLabel(text=text, stream=stream)
        kids = self.output_window.children
        if len(kids) > self.outDisp:
            self.output_window.remove_widget(kids[-2])
        self.output_window.add_widget(l)
        return l

    def _dequeue_output_label(self, dt):
        if not self._output_label_queue:
            return

        # print('dequeueing', self._output_label_queue)

        t = time()
        i = 0
        while (time() - t) < 0.005:
            i += 1
            if not self._output_label_queue:
                break
            label_text = self._output_label_queue.pop(0)
            label = self._add_output_label(*label_text, scroll_to=False)
        print('Rendered {} labels in {}'.format(i, time() - t))
        # Animation.stop_all(self.scrollview, 'scroll_x', 'scroll_y')
        # self.scrollview.scroll_to(label)

        self.dequeue_scheduled.cancel()
        self.dequeue_scheduled = None

        if len(self._output_label_queue) == 0 and self.clear_scheduled:
            self.clear_scheduled.cancel()
            self.clear_scheduled = None
        elif len(self._output_label_queue) > 0:
            self.dequeue_scheduled = Clock.schedule_once(
                self._dequeue_output_label, 0.05)

        if (self.awaiting_label_display_completion
                and len(self._output_label_queue) == 0):
            self.awaiting_label_display_completion = False
            self._execution_complete()

    def _clear_output_label_queue(self, dt):
        if not self.throttle_label_output:
            return
        labels = self._output_label_queue
        self._output_label_queue = []
        if labels:
            self.add_missing_labels_marker(labels=labels)

        if self.dequeue_scheduled:
            self.dequeue_scheduled.cancel()
            self.dequeue_scheduled = None

        if self.clear_scheduled:
            self.clear_scheduled.cancel()
            self.clear_scheduled = None

        if self.awaiting_label_display_completion:
            self.awaiting_label_display_completion = False
            self._execution_complete()

    def on__output_label_queue(self, instance, values):
        # print('olq', self.dequeue_scheduled, self.clear_scheduled)
        if self.dequeue_scheduled:
            return

        if not self.dequeue_scheduled:
            self.dequeue_scheduled = Clock.schedule_once(
                self._dequeue_output_label, 0)
        if not self.clear_scheduled:
            self.clear_scheduled = Clock.schedule_once(
                self._clear_output_label_queue, 1)

    def on_throttle_label_output(self, instance, value):
        self.interpreter.set_service_output_throttling(value)

    def on_missing_labels(self, instance, number):
        self.add_missing_labels_marker(num_labels=number)

    def add_missing_labels_marker(self, num_labels=None, labels=None):
        if labels is not None:
            num_labels = len(labels)
        self.add_user_message_label(
            '{} lines omitted (too many to render)'.format(num_labels),
            background_colour=(1, 0.6, 0, 1))
        # l.labels = labels

    def add_notification_label(self, text):
        self.add_break()
        l = NotificationLabel(text=text)
        self.output_window.add_widget(l)
        #self.scrollview.scroll_to(l)
        self.add_break()

    def add_break(self):
        b = BreakMarker()
        self.output_window.add_widget(b)
        #self.scrollview.scroll_to(b)

    def insert_previous_code(self, index, clear=False):
        if clear:
            self.code_input.text = ''
        code = self.interpreter.inputs[index]
        if self.code_input.text == '':
            self.code_input.text = code
        else:
            self.code_input.text += '\n' + code

    def send_sigint(self):
        self.halting = True
        self.interpreter.send_sigint()

    def restart_interpreter(self):
        self.interpreted_lines = []
        self.interpreter.restart()

    def query_restart(self):
        popup = RestartPopup(interpreter_gui=self)
        popup.open()

    def execution_complete(self, *args):
        '''Called when execution is complete so the TextInput should be
        unlocked etc., but first this is delayed until messages finish
        printing.
        '''
        if len(self._output_label_queue) == 0:
            self._execution_complete()
        else:
            self.awaiting_label_display_completion = True

    def _execution_complete(self):
        self.add_break()
        self.lock_input = False
        self.halting = False
        self.ensure_no_ctrl_c_button()

    def get_defs(self):
        previous_text = '\n'.join(self.interpreted_lines)
        num_previous_lines = len(previous_text.split('\n'))

        text = self.code_input.text
        row_index, line, col_index = self.code_input.currently_edited_line()

        get_defs('\n'.join([previous_text, text]),
                 self.show_defs,
                 line=row_index + num_previous_lines + 1,
                 col=col_index)

    def show_defs(self, defs, sigs, error=None):
        print('docs are', defs)
        if error is not None:
            self.add_doc_label(error)
            return
        if not defs and not sigs:
            self.add_doc_label('No definition found at cursor')
            return

        if defs:
            d = defs[0]
        else:
            d = sigs[0]
        if hasattr(d, 'params'):
            text = '{}({})\n{}'.format(
                d.desc_with_module,
                ', '.join([p.description for p in d.params]), d.doc)
        else:
            text = '{}\n{}'.format(d.desc_with_module, d.doc)

        self.add_doc_label(text)

    def on_touch_up(self, touch):
        self.move_lock = False
        self.scale_lock_left = False
        self.scale_lock_right = False
        self.scale_lock_top = False
        self.scale_lock_bottom = False
        self.size_hint = None, None
        if touch.grab_current is self:
            touch.ungrab(self)
            x = self.pos[0] / 10
            x = round(x, 0)
            x = x * 10
            y = self.pos[1] / 10
            y = round(y, 0)
            y = y * 10
            self.pos = x, y
            return super(InterpreterGui, self).on_touch_up(touch)

    # def transform_with_touch(self, touch):
    #     self.size_hint = None,None
    #     changed = False
    #     x = self.bbox[0][0]
    #     y = self.bbox[0][1]
    #     width = self.bbox[1][0]
    #     height = self.bbox[1][1]
    #     mid_x = x + width / 2
    #     mid_y = y + height / 2
    #     inner_width = width * 0.5
    #     inner_height = height * 0.5
    #     left = mid_x - (inner_width / 2)
    #     right = mid_x + (inner_width / 2)
    #     top = mid_y + (inner_height / 2)
    #     bottom = mid_y - (inner_height / 2)

    #         # just do a simple one finger drag
    #     if len(self._touches) == self.translation_touches:
    #         # _last_touch_pos has last pos in correct parent space,
    #         # just like incoming touch
    #         dx = (touch.x - self._last_touch_pos[touch][0]) \
    #              * self.do_translation_x
    #         dy = (touch.y - self._last_touch_pos[touch][1]) \
    #              * self.do_translation_y
    #         dx = dx / self.translation_touches
    #         dy = dy / self.translation_touches
    #         dx = dx
    #         dy = dy
    #         if (touch.x > left and touch.x < right and touch.y < top and touch.y > bottom or self.move_lock) and not self.scale_lock_left and not self.scale_lock_right and not self.scale_lock_top and not self.scale_lock_bottom:
    #             self.move_lock = True
    #             self.apply_transform(Matrix().translate(dx, dy, 0))
    #             changed = True

    #     change_x = touch.x - self.prev_x
    #     change_y = touch.y - self.prev_y
    #     anchor_sign = 1
    #     sign = 1
    #     if abs(change_x) >= 9 and not self.move_lock and not self.scale_lock_top and not self.scale_lock_bottom:
    #         if change_x < 0:
    #             sign = -1
    #         if (touch.x < left or self.scale_lock_left) and not self.scale_lock_right:
    #             self.scale_lock_left = True
    #             self.pos = (self.pos[0] + (sign * 10), self.pos[1])
    #             anchor_sign = -1
    #         elif (touch.x > right or self.scale_lock_right) and not self.scale_lock_left:
    #             self.scale_lock_right = True
    #         self.size[0] = self.size[0] + (sign * anchor_sign * 10)
    #         self.prev_x = touch.x
    #         changed = True
    #     if abs(change_y) >= 9 and not self.move_lock and not self.scale_lock_left and not self.scale_lock_right:
    #         if change_y < 0:
    #             sign = -1
    #         if (touch.y > top or self.scale_lock_top) and not self.scale_lock_bottom:
    #             self.scale_lock_top = True
    #         elif (touch.y < bottom or self.scale_lock_bottom) and not self.scale_lock_top:
    #             self.scale_lock_bottom = True
    #             self.pos = (self.pos[0], self.pos[1] + (sign * 10))
    #             anchor_sign = -1
    #         self.size[1] = self.size[1] + (sign * anchor_sign * 10)
    #         self.prev_y = touch.y
    #         changed = True
    #     return changed

    def on_touch_down(self, touch):
        parent = self.parent.parent
        me = self.parent
        parent.remove_widget(me)
        parent.add_widget(me)
        self.size_hint = None, None
        x, y = touch.x, touch.y
        self.prev_x = touch.x
        self.prev_y = touch.y
        # if the touch isnt on the widget we do nothing
        if not self.do_collide_after_children:
            if not self.collide_point(x, y):
                return False

        # let the child widgets handle the event if they want
        touch.push()
        touch.apply_transform_2d(self.to_local)
        if super(Scatter, self).on_touch_down(touch):
            # ensure children don't have to do it themselves
            if 'multitouch_sim' in touch.profile:
                touch.multitouch_sim = True
            touch.pop()
            self._bring_to_front(touch)
            return True
        touch.pop()

        # if our child didn't do anything, and if we don't have any active
        # interaction control, then don't accept the touch.
        if not self.do_translation_x and \
                not self.do_translation_y and \
                not self.do_rotation and \
                not self.do_scale:
            return False

        if self.do_collide_after_children:
            if not self.collide_point(x, y):
                return False

        if 'multitouch_sim' in touch.profile:
            touch.multitouch_sim = True
        # grab the touch so we get all it later move events for sure
        self._bring_to_front(touch)
        touch.grab(self)
        self._touches.append(touch)
        self._last_touch_pos[touch] = touch.pos
        return True

    def Save(self):
        lifeRaft = []
        lifeRaft.append(self.interpreted_lines)
        lifeRaft.append(self.code_input.text)
        return lifeRaft

    def Load(self, prior, curr):
        self.restart_interpreter()
        t.sleep(1)
        self.clear_output()
        t.sleep(10 / 1000)
        for i in prior:
            self.interpret_line(i)
            t.sleep(10 / 1000)
        self.code_input.text = curr
        self.clear_output()
Esempio n. 29
0
class AutoFontSizeTicker:
    """ mixin """
    # abstracts
    bind: callable
    font_size: float
    text: str
    texture_size: tuple
    width: float
    height: float

    # public attributes
    text_spacing: float = 9.0

    # internal attributes
    _font_size_anim: Optional[Animation] = None
    _font_anim_mode: int = 0
    _last_font_size: float

    _length_anim: Optional[Animation] = None
    _ori_text: str = ""
    _offset_anim: Optional[Animation] = None
    _ticker_text_offset: int = 0
    _ticker_text_length: int = 0
    _ticker_texture_width: float = 0.0

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.bind(text=self.text_resize)
        self.bind(width=self.text_resize)
        self.bind(height=self.text_resize)

    def font_size_adjustable(self):
        """ check if font size need/has to be adjustable. """
        if self.texture_size[0] + self.text_spacing < self.width \
                and self.texture_size[1] + self.text_spacing < self.height \
                and self.font_size < min(MAX_FONT_SIZE, self.height):
            return 1
        elif (self.texture_size[0] + self.text_spacing > self.width
              or self.texture_size[1] + self.text_spacing > self.height) \
                and self.font_size > MIN_FONT_SIZE:
            return -1
        return 0

    def text_resize(self, *_args):
        """ called on label text/size changed """
        print(f"text_resize texture_width={self.texture_size[0]}", _args,
              "  mem=",
              resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)
        # self._last_font_size = 0
        Clock.schedule_once(self._start_font_anim,
                            0.03)  # needed to update texture_size
        # self._start_font_anim()

    def _start_font_anim(self, *_args):
        """ delayed anim check """
        if not self.texture_size[0] or self._length_anim or self._offset_anim:
            print(
                f"      SKIP START FONT ANIM  texture_width={self.texture_size[0]}"
                f"  length_anim={self._length_anim}  ticker_anim={self._offset_anim}"
            )
            return
        self._stop_font_anim()
        print(
            f"font_anim: font={self.font_size:2.2f}  text={self.texture_size}  wid=({self.width}, {self.height})"
        )
        self._font_anim_mode = self.font_size_adjustable()
        if self._font_anim_mode == 1:
            reach_size = min(MAX_FONT_SIZE, self.height)
            print(f"     GROW   font size to {reach_size}")
        elif self._font_anim_mode == -1:
            reach_size = MIN_FONT_SIZE
            print(f"     SHRINK font size to {MIN_FONT_SIZE}")
        else:
            self._stop_font_anim()
            if self.font_size <= MIN_FONT_SIZE:
                self._start_length_anim()
            else:
                print("     SKIP   font size (stopped)")
            return

        self._font_size_anim = Animation(font_size=reach_size)
        self._font_size_anim.bind(on_progress=self._font_size_progress)
        # self._font_size_anim.bind(on_complete=self._start_length_anim)
        self._font_size_anim.start(self)

    def _stop_font_anim(self):
        if self._font_size_anim:
            self._font_size_anim.stop(self)
            self._font_size_anim = None
        self._font_anim_mode = 0

    def _font_size_progress(self, _anim: Animation, _self: Widget,
                            _progress: float):
        """ animation on_progress event handler. """
        print(
            f"   ON SIZE PROGRESS: font={self.font_size:2.2f}  texture={self.texture_size}"
        )
        if self._font_anim_mode and self._font_anim_mode != self.font_size_adjustable(
        ):
            print(
                f"     STOPPED {'GROW' if self._font_anim_mode == 1 else 'SHRINK'}"
            )
            self._stop_font_anim()
            if self._last_font_size:
                print(f"     correct font size to {self._last_font_size}")
                self.font_size = self._last_font_size
            self._start_length_anim()
        elif self.font_size <= MIN_FONT_SIZE:
            print(f"     SWITCH TO TICKER ANIM")
            self._stop_font_anim()
            self._start_length_anim()
        self._last_font_size = self.font_size

    def _start_length_anim(self, *_args):
        # self._stop_length_anim()
        print(
            f"length_anim: len={self._ticker_text_length}  text={self.text}  width={self.texture_size[0]}"
        )

        self._ticker_texture_width = self.width - self.text_spacing
        self._ori_text = self.text
        print(
            f"     START  text width={len(self.text)} at texture width={self.texture_size[0]}"
            f" -> {self._ticker_texture_width}")

        self._length_anim = Animation(
            _ticker_text_length=round((len(self.text) + 1) / 2))
        self._length_anim.bind(on_progress=self._ticker_length_progress)
        self._length_anim.start(self)

    def _start_offset_anim(self, *_args):
        print(
            f"offset_anim: offset={self._ticker_text_offset}  text={self.text}"
        )
        self._offset_anim = Animation(
            _ticker_text_offset=self._ticker_text_offset * 2, d=9.9)
        self._offset_anim.bind(on_progress=self._ticker_offset_progress)
        self._offset_anim.start(self)

    def _stop_length_anim(self):
        if self._length_anim:
            self.text = self._ori_text

            self._length_anim.stop(self)
            self._length_anim = None

            self._ticker_text_length = 0
            self._ticker_text_offset = 0
            self._ticker_texture_width = 0

        self._ori_text = ""

    def _ticker_length_progress(self, _anim: Animation, _self: Widget,
                                _progress: float):
        print(
            f"   ON LENGTH PROGRESS: len={self._ticker_text_length}  off={self._ticker_text_offset}  txt={self.text}"
        )
        if self.texture_size[
                0] + self.text_spacing < self._ticker_texture_width and not self._ticker_text_length:
            print(
                f"      FOUND  text width={len(self.text)} at texture width={self.texture_size[0]}"
            )
            self._ticker_text_length = len(self.text)
            self._ticker_text_offset = round(self._ticker_max_offset() / 2)
            self._length_anim.stop(self)

            self._start_offset_anim()
        else:
            self.text = self.text[1:-1]
            print(
                f"     SHRUNK text width={len(self.text)} at texture width={self.texture_size[0]}"
            )

    def _ticker_max_offset(self):
        return round(len(self._ori_text) + 1 - self._ticker_text_length)

    def _ticker_offset_progress(self, _anim: Animation, _self: Widget,
                                _progress: float):
        print(
            f"   ON OFFSET PROGRESS: len={self._ticker_text_length}  off={self._ticker_text_offset}  txt={self.text}"
        )
        beg = int(self._ticker_text_offset)
        end = beg + self._ticker_text_length
        self.text = self._ori_text[beg:end]
        if _progress >= 1.0:
            print(
                f"     {'BACKWARDS' if beg else 'FORWARDS'} {_progress}"
                f"  mem={resource.getrusage(resource.RUSAGE_SELF).ru_maxrss}")
            self._offset_anim.stop(self)
            self._offset_anim = Animation(
                _ticker_text_offset=0 if beg else self._ticker_max_offset(),
                d=9.9)
            self._offset_anim.bind(on_progress=self._ticker_offset_progress)
            self._offset_anim.start(self)
Esempio n. 30
0
class InterpreterGui(BoxLayout):
    subprocesses = []

    output_window = ObjectProperty()
    code_input = ObjectProperty()
    scrollview = ObjectProperty()

    input_fail_alpha = NumericProperty(0.)

    lock_input = BooleanProperty(False)
    _lock_input = BooleanProperty(False)

    halting = BooleanProperty(False)
    '''True when the interpreter has been asked to stop but has not yet
    done so.'''

    interpreter_state = OptionProperty(
        'waiting',
        options=['waiting', 'interpreting', 'not_responding', 'restarting'])
    status_label_colour = StringProperty('b2ade6')

    _output_label_queue = ListProperty([])

    dequeue_scheduled = ObjectProperty(None, allownone=True)
    clear_scheduled = ObjectProperty(None, allownone=True)

    awaiting_label_display_completion = BooleanProperty(False)

    throttle_label_output = BooleanProperty()
    '''Whether to clear the output label queue regularly. If False, labels
    will always be displayed, but this *will* cause problems with
    e.g. a constantly printing while loop.
    '''

    interpreted_lines = ListProperty([])
    '''A list of the lines of code that have been executed so far.'''

    completion_threads = []
    '''The threads running jedi completion functions.'''

    most_recent_completion_time = 0.
    '''The most recent timestamp from a completion. New completions with
    older timestamps will be ignored.'''
    def __init__(self, *args, **kwargs):
        super(InterpreterGui, self).__init__(*args, **kwargs)
        self.animation = Animation(input_fail_alpha=0.,
                                   t='out_expo',
                                   duration=0.5)

        self.interpreter = InterpreterWrapper(
            'Interpreter',
            use_thread=True,
            throttle_output=self.setting__throttle_output,
            thread_name='interpreter')
        self.interpreter.bind(
            interpreter_state=self.setter('interpreter_state'))
        self.interpreter.bind(lock_input=self.setter('lock_input'))

        self.interpreter.bind(on_execution_complete=self.execution_complete)
        self.interpreter.bind(on_stdout=self.on_stdout)
        self.interpreter.bind(on_stderr=self.on_stderr)
        self.interpreter.bind(on_notification=self.on_notification)
        self.interpreter.bind(on_user_message=self.on_user_message)
        self.interpreter.bind(on_missing_labels=self.on_missing_labels)
        self.interpreter.bind(on_request_input=self.on_request_input)

        # self.interpreter = DummyInterpreter()

        # Clock.schedule_interval(self._dequeue_output_label, 0.05)
        # Clock.schedule_interval(self._clear_output_label_queue, 1)

        Clock.schedule_once(self.post_init_check, 0)

    def post_init_check(self, *args):
        if self.ctypes_working:
            return
        self.add_user_message_label(
            ('Could not load ctypes on this device. Keyboard interrupt '
             'will not be available.'),
            background_colour=(1, 0.6, 0, 1))

    def on_lock_input(self, instance, value):
        if value:
            self.input_focus_on_disable = self.code_input.focus
            self._lock_input = True
        else:
            self._lock_input = False
            self.code_input.focus = self.input_focus_on_disable
            self.ensure_no_ctrl_c_button()
            self.halting = False

    def on_stdout(self, interpreter, text):
        self.add_output_label(text, 'stdout')

    def on_stderr(self, interpreter, text):
        self.add_output_label(text, 'stderr')

    def on_notification(self, interpreter, text):
        self.add_notification_label(text)

    def on_user_message(self, interpreter, text):
        self.add_user_message_label(text, background_colour=(1, 0.6, 0, 1))

    def on_request_input(self, interpreter, prompt):
        self.show_input_popup(prompt)

    def show_input_popup(self, prompt):
        # Window.softinput_mode = 'below_target'
        p = InputPopup(prompt=prompt, submit_func=self.send_input)
        p.open()

    def send_input(self, text):
        '''Send the given input to the Python interpreter.'''
        self.interpreter.send_input(text)

    def ensure_ctrl_c_button(self):
        if not self.ctypes_working:
            return
        Clock.schedule_once(self._switch_to_ctrl_c_button, 0.4)

    def _switch_to_ctrl_c_button(self, *args):
        c = self.ids.carousel
        if c.index == 0:
            c.load_next()

    def clear_output(self):
        for child in self.output_window.children[:-1]:
            self.output_window.remove_widget(child)

    def exec_file(self):
        self.root.switch_to('filechooser',
                            open_method=self._exec_file,
                            success_screen_name='interpreter',
                            purpose='exec file')

    def _exec_file(self, filename):
        self.add_user_message_label('Executing {}...'.format(filename))
        self.ensure_ctrl_c_button()
        self.interpreter.exec_file(filename)

    def ensure_no_ctrl_c_button(self):
        Clock.unschedule(self._switch_to_ctrl_c_button)
        c = self.ids.carousel
        if c.index == 1:
            c.load_previous()
        else:
            Animation.cancel_all(c)
            c._start_animation(new_offset=0)

    def on_interpreter_state(self, instance, value):
        if value == 'waiting':
            self.status_label_colour = 'b2ade6'
        elif value == 'interpreting':
            self.status_label_colour = 'ade6b4'
        elif value == 'not_responding':
            self.status_label_colour = 'e6adad'
        elif value == 'restarting':
            self.status_label_colour = 'e6adad'

    def interpret_line_from_code_input(self):
        text = self.code_input.text
        if text == '':
            self.flash_input_fail()
            return
        self.code_input.text = ''
        self.interpret_line(text)

    def flash_input_fail(self):
        self.animation.stop(self)
        self.input_fail_alpha = 1.
        self.animation.start(self)

    def interpret_line(self, text):
        self.interpreted_lines.append(text)
        index = self.interpreter.interpret_line(text)
        self.add_input_label(text, index)
        self.ensure_ctrl_c_button()

    def add_user_message_label(self, text, **kwargs):
        l = UserMessageLabel(text=text, **kwargs)
        self.output_window.add_widget(l)
        self.scrollview.scroll_to(l)

    def add_doc_label(self, text, **kwargs):
        l = DocLabel(text=text, **kwargs)
        self.output_window.add_widget(l)
        self.scrollview.scroll_to(l)

    def add_input_label(self, text, index):
        l = InputLabel(text=text, index=index, root=self)
        self.output_window.add_widget(l)
        self.scrollview.scroll_to(l)

    def add_output_label(self, text, stream='stdout'):
        self._output_label_queue.append((text, stream))
        # self._dequeue_output_label(0)

    def _add_output_label(self, text, stream='stdout', scroll_to=True):
        l = OutputLabel(text=text, stream=stream)
        self.output_window.add_widget(l)
        if scroll_to:
            self.scrollview.scroll_to(l)
        return l

    def _dequeue_output_label(self, dt):
        if not self._output_label_queue:
            return

        # print('dequeueing', self._output_label_queue)

        t = time()
        i = 0
        while (time() - t) < 0.005:
            i += 1
            if not self._output_label_queue:
                break
            label_text = self._output_label_queue.pop(0)
            label = self._add_output_label(*label_text, scroll_to=False)
        print('Rendered {} labels in {}'.format(i, time() - t))
        Animation.stop_all(self.scrollview, 'scroll_x', 'scroll_y')
        self.scrollview.scroll_to(label)

        self.dequeue_scheduled.cancel()
        self.dequeue_scheduled = None

        if len(self._output_label_queue) == 0 and self.clear_scheduled:
            self.clear_scheduled.cancel()
            self.clear_scheduled = None
        elif len(self._output_label_queue) > 0:
            self.dequeue_scheduled = Clock.schedule_once(
                self._dequeue_output_label, 0.05)

        if (self.awaiting_label_display_completion
                and len(self._output_label_queue) == 0):
            self.awaiting_label_display_completion = False
            self._execution_complete()

    def _clear_output_label_queue(self, dt):
        if not self.throttle_label_output:
            return
        labels = self._output_label_queue
        self._output_label_queue = []
        if labels:
            self.add_missing_labels_marker(labels=labels)

        if self.dequeue_scheduled:
            self.dequeue_scheduled.cancel()
            self.dequeue_scheduled = None

        if self.clear_scheduled:
            self.clear_scheduled.cancel()
            self.clear_scheduled = None

        if self.awaiting_label_display_completion:
            self.awaiting_label_display_completion = False
            self._execution_complete()

    def on__output_label_queue(self, instance, values):
        # print('olq', self.dequeue_scheduled, self.clear_scheduled)
        if self.dequeue_scheduled:
            return

        if not self.dequeue_scheduled:
            self.dequeue_scheduled = Clock.schedule_once(
                self._dequeue_output_label, 0)
        if not self.clear_scheduled:
            self.clear_scheduled = Clock.schedule_once(
                self._clear_output_label_queue, 1)

    def on_throttle_label_output(self, instance, value):
        self.interpreter.set_service_output_throttling(value)

    def on_missing_labels(self, instance, number):
        self.add_missing_labels_marker(num_labels=number)

    def add_missing_labels_marker(self, num_labels=None, labels=None):
        if labels is not None:
            num_labels = len(labels)
        self.add_user_message_label(
            '{} lines omitted (too many to render)'.format(num_labels),
            background_colour=(1, 0.6, 0, 1))
        # l.labels = labels

    def add_notification_label(self, text):
        self.add_break()
        l = NotificationLabel(text=text)
        self.output_window.add_widget(l)
        self.scrollview.scroll_to(l)
        self.add_break()

    def add_break(self):
        b = BreakMarker()
        self.output_window.add_widget(b)
        self.scrollview.scroll_to(b)

    def insert_previous_code(self, index, clear=False):
        if clear:
            self.code_input.text = ''
        code = self.interpreter.inputs[index]
        if self.code_input.text == '':
            self.code_input.text = code
        else:
            self.code_input.text += '\n' + code

    def send_sigint(self):
        self.halting = True
        self.interpreter.send_sigint()

    def restart_interpreter(self):
        self.interpreted_lines = []
        self.interpreter.restart()

    def query_restart(self):
        popup = RestartPopup(interpreter_gui=self)
        popup.open()

    def execution_complete(self, *args):
        '''Called when execution is complete so the TextInput should be
        unlocked etc., but first this is delayed until messages finish
        printing.
        '''
        if len(self._output_label_queue) == 0:
            self._execution_complete()
        else:
            self.awaiting_label_display_completion = True

    def _execution_complete(self):
        self.add_break()
        self.lock_input = False
        self.halting = False
        self.ensure_no_ctrl_c_button()

    def get_defs(self):
        previous_text = '\n'.join(self.interpreted_lines)
        num_previous_lines = len(previous_text.split('\n'))

        text = self.code_input.text
        row_index, line, col_index = self.code_input.currently_edited_line()

        get_defs('\n'.join([previous_text, text]),
                 self.show_defs,
                 line=row_index + num_previous_lines + 1,
                 col=col_index)

    def show_defs(self, defs, sigs, error=None):
        print('docs are', defs)
        if error is not None:
            self.add_doc_label(error)
            return
        if not defs and not sigs:
            self.add_doc_label('No definition found at cursor')
            return

        if defs:
            d = defs[0]
        else:
            d = sigs[0]
        if hasattr(d, 'params'):
            text = '{}({})\n{}'.format(
                d.desc_with_module,
                ', '.join([p.description for p in d.params]), d.doc)
        else:
            text = '{}\n{}'.format(d.desc_with_module, d.doc)

        self.add_doc_label(text)
Esempio n. 31
0
class AlarmScreen(Screen):

    r = NumericProperty(100)    # Radio del círculo
    ra = NumericProperty(1.0)   # Alfa del círculo
    r2 = NumericProperty(100)   # Radio del círculo que marca pulsación
    r2a = NumericProperty(0)    # Alfa del círculo que marca pulsación
    cd = NumericProperty(0.0)   # Offset de los círculos que se desplazan
    ca = NumericProperty(1.0)   # Alfa de los círculos que se desplazan
    R = 0.08                    # Constante para calcular el tamaño
    motion_uid = None

    text = StringProperty('Alarma!')
    timetext = StringProperty('')
    inicio = datetime.now()  # Se actualiza en sonar_alarma

    def on_height(self, widget, height):
        self.r = height*self.R
        self.r2 = height*self.R

    def on_enter(self, *args):
        Logger.debug("%s: AlarmScreen.on_enter self.width=%s %s" % (
            APP, self.width, datetime.now()))
        if self.width < 100:
            width = 480  # No debería hacer falta, pero la primera vez falla
        else:
            width = self.width
        self.r2a = self.ca = self.cd = 0
        self.anim = Animation(cd=width/2, ca=1, d=1, t='in_quad') \
            + Animation(cd=0, ca=0, d=0)
        self.anim.repeat = True
        self.anim.start(self)

        self.app.reproducir_sonido_alarma()

        self.app.clock_callback = partial(
            self.app.cancelar_alarma,
            source='Clock', clock_date=datetime.now())
        Clock.schedule_once(self.app.clock_callback, self.app.ACS)  # segundos

        self.update_timetext()
        Clock.schedule_interval(self.update_timetext, 1)

    def on_pre_leave(self, *args):
        self.anim.stop(self)
        Logger.debug("%s: AlarmScreen.on_pre_leave %s" % (APP, datetime.now()))
        if platform == 'android':
            self.app.reset_window_flags()  # Permitir apagado automático
        Clock.unschedule(self.update_timetext)

    def on_touch_down(self, touch):
        if Vector(touch.pos).distance(
           Vector(self.center_x, self.height*0.2)) < 2*self.r:
            self.motion_uid = touch.uid
            self.r2a = .2
            self.r2 = self.height*self.R
            anim = Animation(
                r2=self.height*self.R*2.3, t='in_quad', d=0.3)
            anim.start(self)

    def on_touch_move(self, touch):
        if touch.uid == self.motion_uid:
            # Cancelar si de desplaza más de la mitad de la distancia al borde
            self.ra = 1-3.3*Vector(touch.pos).distance(
                Vector(self.center_x, self.height*0.2))/self.width
            self.r2a = 1 - self.ra * 0.8
            if self.ra < 0.05:
                self.ra = 1
                self.app.cancelar_alarma(source='user')

    def on_touch_up(self, touch):
        if touch.uid == self.motion_uid:
            self.ra = 1
            self.r2a = 0

    def update_timetext(self, *args):
        self.timetext = "%s - %s" % (self.inicio.strftime("%H:%M"),
                                     tdformat(self.inicio-datetime.now()))
Esempio n. 32
0
class GraphCanvas(Widget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._touches = []
        self.delay = RESIZE_DELAY
        self._mouse_pos_disabled = True

        self._init_animations()
        self.load_graph()

    def _init_animations(self):
        self.scale_animation = (
            Animation(size=(ANIMATION_WIDTH_2, ANIMATION_HEIGHT_2),
                      duration=SCALE_SPEED_OUT,
                      step=UPDATE_INTERVAL) +
            Animation(size=(ANIMATION_WIDTH, ANIMATION_HEIGHT),
                      duration=SCALE_SPEED_IN,
                      step=UPDATE_INTERVAL))
        self.scale_animation.repeat = True
        self.scale_animation.bind(on_progress=self._reposition_animated_node)

        self.rotate_animation = Clock.schedule_interval(
            self._rotate_node, UPDATE_INTERVAL)
        self.rotate_animation.cancel()

        self.edge_color_animation = Animation(a=0)
        self.edge_animation = Animation(width=ANIMATED_EDGE_WIDTH)
        self.edge_animation.bind(on_start=self._edge_animation_start,
                                 on_complete=self._reschedule_edge_animation)

        # Schedule events
        self.edge_move = Clock.schedule_interval(self._move_edge,
                                                 UPDATE_INTERVAL)
        self.edge_move.cancel()

        self.resize_event = Clock.schedule_once(self.update_canvas, self.delay)
        self.resize_event.cancel()

        self.layout_stepper = Clock.schedule_interval(self.step_layout,
                                                      UPDATE_INTERVAL)
        self.layout_stepper.cancel()

    def load_graph(self):
        """Set initial graph.
        """
        self._selecting_nnodes = True
        NewGameDialogue(self).open()

    def setup_canvas(self):
        """Populate the canvas with the initial instructions.
        """
        self._selecting_nnodes = False

        self.G = Graph.Star(self.nnodes, mode="out")
        self._unscaled_layout = Layout([(0.0, 0.0),
                                        *circle_points(self.nnodes - 1)])

        self.scale = INIT_SCALE
        self.offset_x, self.offset_y = INIT_OFFSET

        self._selected_edge = self._selected_node = None
        self._source_node = self._target_edge = None

        self.canvas.clear()

        with self.canvas.before:
            self.background_color = Color(*BACKGROUND_COLOR)
            self._background = Rectangle(size=self.size, pos=self.pos)

        with self.canvas:
            self.animated_edge_color = Color(*HIGHLIGHTED_EDGE)
            self.animated_edge_color.a = 0
            self.animated_edge = Line(width=1.1)

        # Edge instructions before Node instructions so they're drawn underneath nodes.
        self._edge_instructions = CanvasBase()
        with self._edge_instructions:
            self.edges = {
                edge.tuple: Edge(edge.tuple, self)
                for edge in self.G.es
            }
        self.canvas.add(self._edge_instructions)

        # Animated node drawn above edges but below other nodes.
        with self.canvas:
            PushMatrix()
            self.rotation_instruction = Rotate()
            self.animated_node_color = Color(*ANIMATED_NODE_COLOR)
            self.animated_node_color.a = 0
            self.animated_node = Rectangle(size=(ANIMATION_WIDTH,
                                                 ANIMATION_HEIGHT),
                                           source=ANIMATED_NODE_SOURCE)
            PopMatrix()

        self._node_instructions = CanvasBase()
        with self._node_instructions:
            self.nodes = [Node(vertex.index, self) for vertex in self.G.vs]
        self.canvas.add(self._node_instructions)

        # TODO: Refactor so we only need to do this once
        self.bind(size=self._delayed_resize, pos=self._delayed_resize)
        Window.bind(mouse_pos=self.on_mouse_pos)

        self.step_layout()
        self.layout_stepper()

        self._mouse_pos_disabled = False

    def reset(self):
        self._mouse_pos_disabled = True

        # Stop all animations
        self.layout_stepper.cancel()
        self.edge_move.cancel()

        self.scale_animation.stop(self.animated_node)
        self.rotate_animation.cancel()

        self.edge_color_animation.stop(self.animated_edge_color)
        self.edge_animation.stop(self.animated_edge)

        self.canvas.clear()
        self.load_graph()

    @property
    def selected_edge(self):
        """While there is no source node, the selected edge is just the edge that is currently colliding with the mouse.
        """
        return self._selected_edge

    @selected_edge.setter
    def selected_edge(self, edge):
        if self.selected_edge is not None:
            self.selected_edge.is_tail_selected = None

        self._selected_edge = edge

    @property
    def selected_node(self):
        """This is the end of selected edge that is closest to the mouse position.
        """
        return self._selected_node

    @selected_node.setter
    def selected_node(self, node):
        edges = self.edges
        G = self.G

        if self._selected_node is not None:
            # Reset node and out-edges to their default colors
            self._selected_node.color.rgba = NODE_COLOR

            for edge in G.vs[self._selected_node.index].out_edges():
                e = edges[edge.tuple]
                if e is not self.selected_edge:
                    e.color.rgba = EDGE_COLOR
                    e.head_color.rgba = HEAD_COLOR

        self._selected_node = node
        if node is not None:
            # Highlight this node and adjacent out-edges
            node.color.rgba = HIGHLIGHTED_NODE

            for edge in G.vs[node.index].out_edges():
                e = edges[edge.tuple]
                if e is not self.selected_edge:
                    e.color.rgba = HIGHLIGHTED_EDGE
                    e.head_color.rgba = HIGHLIGHTED_HEAD

            self._selected_node_x, self._selected_node_y = self._unscaled_layout[
                node.index]
            self.animated_node_color.a = 1
            self.rotate_animation()
            self.scale_animation.start(self.animated_node)

        else:
            self.animated_node_color.a = 0
            self.rotate_animation.cancel()
            self.scale_animation.stop(self.animated_node)

    @property
    def source_node(self):
        """Source node is set to selected node when the selected node is clicked.
        """
        return self._source_node

    @source_node.setter
    def source_node(self, node):
        if self.source_node is not None:
            self.animated_node_color.rgba = HIGHLIGHTED_EDGE

        self._source_node = node

        if node is not None:
            self.animated_node_color.rgba = HIGHLIGHTED_NODE

    @property
    def target_edge(self):
        """The target edge is the edge we move along.
        """
        return self._target_edge

    @target_edge.setter
    def target_edge(self, edge):
        if self.target_edge is not None:
            self.target_edge.color.rgba = HIGHLIGHTED_EDGE
            self.target_edge.head_color.rgba = HIGHLIGHTED_HEAD

            self._keep_animating = False
            self.edge_animation.stop(self.animated_edge)

        self._target_edge = edge

        if edge is not None:
            edge.color.rgba = HIGHLIGHTED_NODE
            edge.head_color.rgba = WHITE
            self._keep_animating = True
            self.edge_animation.start(self.animated_edge)

    def _transform_coords(self, coord):
        """Transform vertex coordinates to canvas coordinates.
        """
        return (
            (coord[0] * self.scale + self.offset_x) * self.width,
            (coord[1] * self.scale + self.offset_y) * self.height,
        )

    def _invert_coords(self, x, y):
        """Transform canvas coordinates to vertex coordinates.
        """
        return (x / self.width - self.offset_x) / self.scale, (
            y / self.height - self.offset_y) / self.scale

    def _rotate_node(self, dt):
        """This rotates `animated_node` when called. `dt` does nothing, but is required for kivy's scheduler.
        """
        self.rotation_instruction.origin = self.layout[
            self.selected_node.index]
        self.rotation_instruction.angle = (self.rotation_instruction.angle +
                                           ROTATE_INCREMENT) % 360

    def _reposition_animated_node(self, *args):
        x, y = self.layout[self.selected_node.index]
        w, h = self.animated_node.size
        self.animated_node.pos = x - w // 2, y - h // 2

    def _delayed_resize(self, *args):
        self.resize_event.cancel()
        self.resize_event()

        self._background.size = self.size
        self._background.pos = self.pos

    def _edge_animation_start(self, *args):
        self.animated_edge.width = 1.1

        self.animated_edge_color.a = 1
        self.edge_color_animation.start(self.animated_edge_color)

    def _reschedule_edge_animation(self, *args):
        self.edge_color_animation.stop(self.animated_edge_color)
        self.animated_edge_color.a = 0
        self.animated_edge.width = 1.1

        if self._keep_animating:
            # Just calling edge_animation.start won't work as we're still animating, we must schedule the restart.
            Clock.schedule_once(
                lambda dt: self.edge_animation.start(self.animated_edge))

    def _lerp_edge(self):
        """Generator that updates the selected edge position.
        """
        # Before we reset the edge colors grab the information we need to lerp:
        selected_edge = self.selected_edge
        is_tail_selected = selected_edge.is_tail_selected
        sx, sy, tx, ty = selected_edge.points

        start_x, start_y, stop_x, stop_y = self.target_edge.points
        new_end = self.target_edge.edge[1]

        # Reset the colors:
        self.source_node = self.target_edge = self.selected_edge = None  # WARNING: The order of these assignments is important.

        self.layout_stepper.cancel(
        )  # Need to turn off the layout_stepper while lerping
        self._mouse_pos_disabled = True

        yield

        for i in range(MOVE_STEPS):
            k = i / MOVE_STEPS
            x = start_x * (1 - k) + stop_x * k
            y = start_y * (1 - k) + stop_y * k
            selected_edge.update_points(*((x, y, tx,
                                           ty) if is_tail_selected else (sx,
                                                                         sy, x,
                                                                         y)))
            yield

        return selected_edge, is_tail_selected, new_end  # _move_edge needs this information to update the underlying graph

    def _move_edge(self, dt):
        """Lerp the selected edge to it's new position and update the underlying graph when finished.
        """
        try:
            next(self._edge_lerp)

        except StopIteration as e:
            selected_edge, is_tail_selected, new_end = e.value

            self.edge_move.cancel()
            self.G.delete_edges((selected_edge.edge, ))
            del self.edges[selected_edge.edge]

            source, target = selected_edge.edge
            if is_tail_selected:
                selected_edge.edge = self.G.add_edge(new_end, target).tuple
                self.edges[new_end, target] = selected_edge
            else:
                selected_edge.edge = self.G.add_edge(source, new_end).tuple
                self.edges[source, new_end] = selected_edge

            self.layout_stepper()
            self._mouse_pos_disabled = False

    def move_edge(self):
        self._edge_lerp = self._lerp_edge()
        next(
            self._edge_lerp
        )  # Prime the generator -- If we don't do this immediately it's possible to lose the
        # selected edge information before the scheduler calls `_move_edge`
        self.edge_move()

    def on_touch_move(self, touch):
        """Zoom if multitouch, else if a node is selected, drag it, else move the entire graph.
        """
        if touch.grab_current is not self or touch.button == 'right':
            return

        if self._selecting_nnodes:
            return

        if len(self._touches) > 1:
            self.transform_on_touch(touch)

        elif self.selected_edge is not None:
            px, py = self._invert_coords(touch.px, touch.py)
            x, y = self._invert_coords(touch.x, touch.y)
            self._selected_node_x += x - px
            self._selected_node_y += y - py

        else:
            self.offset_x += touch.dx / self.width
            self.offset_y += touch.dy / self.height

        self.update_canvas()
        return True

    def transform_on_touch(self, touch):
        """Rescales the canvas.
        """
        ax, ay = self._touches[-2].pos  # Anchor coords
        x, y = self._invert_coords(ax, ay)

        cx = (touch.x - ax) / self.width
        cy = (touch.y - ay) / self.height
        current_length = hypot(cx, cy)

        px = (touch.px - ax) / self.width
        py = (touch.py - ay) / self.height
        previous_length = hypot(px, py)

        self.scale = max(self.scale + current_length - previous_length,
                         MIN_SCALE)

        # Make sure the anchor is a fixed point:
        # Note we can't use `ax, ay` as `self.scale` has changed.
        x, y = self._transform_coords((x, y))

        self.offset_x += (ax - x) / self.width
        self.offset_y += (ay - y) / self.height

    def on_touch_down(self, touch):
        if touch.is_mouse_scrolling:  # REMOVE THIS: For testing only
            self.reset()
            return True

        if self._selecting_nnodes:
            return

        if not self.collide_point(*touch.pos):
            return

        touch.grab(self)
        self._touches.append(touch)
        self._mouse_pos_disabled = True

        # Change the color of multitouch dots to match our color scheme:
        if touch.button == 'right':
            touch.multitouch_sim = True
            with Window.canvas.after:
                touch.ud._drawelement = (
                    Color(*HIGHLIGHTED_EDGE),
                    Ellipse(size=(20, 20),
                            segments=15,
                            pos=(touch.x - 10, touch.y - 10)),
                )

        return True

    def on_touch_up(self, touch):
        if touch.grab_current is not self:
            return

        touch.ungrab(self)
        self._touches.remove(touch)
        self._mouse_pos_disabled = False

        if touch.time_end - touch.time_start > TOUCH_INTERVAL:
            return

        if self.source_node is not None:
            if self.target_edge is not None:
                self.move_edge()
            else:
                self.source_node = None
                # Recheck collision with edge:
                collides, is_tail_selected = self.selected_edge.collides(
                    touch.x, touch.y)
                if collides:
                    self.selected_edge.is_tail_selected = is_tail_selected
                else:
                    self.selected_edge = None

        elif self.selected_node is not None:
            self.source_node = self.selected_node

    def on_mouse_pos(self, *args):
        mx, my = args[-1]

        if self._mouse_pos_disabled or not self.collide_point(mx, my):
            return

        # If source node is set, check collision with an adjacent out-edge.
        if self.source_node is not None:
            if self.target_edge is None:
                for edge in self.G.vs[self.source_node.index].out_edges():
                    target = self.edges[edge.tuple]
                    if target is not self.selected_edge and target.collides(
                            mx, my)[0]:
                        self.target_edge = target
                        break
            else:
                if not self.target_edge.collides(mx, my)[0]:
                    self.target_edge = None

        # If an edge is selected, just check collision with that edge.
        elif self.selected_edge is not None:
            collides, is_tail_selected = self.selected_edge.collides(mx, my)
            if collides:
                self.selected_edge.is_tail_selected = is_tail_selected
            else:
                self.selected_edge = None

        # Check collision with all edges.
        else:
            for edge in self.edges.values():
                collides, is_tail_selected = edge.collides(mx, my)
                if collides:
                    self.selected_edge = edge  # This should be set before `edge.is_tail_selected`
                    edge.is_tail_selected = is_tail_selected
                    break
            else:
                self.selected_edge = None

    def update_canvas(self, dt=0):
        """Update coordinates of all elements. `dt` is a dummy arg required for kivy's scheduler.
        """
        if self.resize_event.is_triggered:  # We use a delayed resize, this will make sure we're done resizing before we update.
            return

        for edge in self.edges.values():
            edge.update()

        if self.target_edge is not None:
            self.animated_edge.points = self.target_edge.points

        for node in self.nodes:
            node.update()

    def step_layout(self, dt=0):
        """Iterate the graph layout algorithm. `dt` is a dummy arg required for kivy's scheduler.
        """
        self._unscaled_layout = self.G.layout_graphopt(
            niter=1,
            seed=self._unscaled_layout,
            max_sa_movement=.1,
            node_charge=.00001)

        # Keep the selected node fixed:
        if self.selected_node is not None:
            self._unscaled_layout[
                self.selected_node.
                index] = self._selected_node_x, self._selected_node_y

        self.layout = self._unscaled_layout.copy()
        self.layout.transform(self._transform_coords)

        self.update_canvas()
Esempio n. 33
0
class FloatingActionButton(ThemeBehaviour, CircularRippleBehavior,
                           ElevationBehaviour, ButtonBehavior, AnchorLayout):

    _bg_color_down = ListProperty([])

    def _get_bg_color_down(self):
        return self._bg_color_down

    def _set_bg_color_down(self, color, alpha=None):
        if len(color) == 2:
            self._bg_color_down = get_rgba_color(color, control_alpha=alpha)
        elif len(color) == 4:
            self._bg_color_down = color

    background_color_down = AliasProperty(_get_bg_color_down,
                                          _set_bg_color_down,
                                          bind=('_bg_color_down', ))

    _bg_color_disabled = ListProperty([])

    def _get_bg_color_disabled(self):
        return self._bg_color_disabled

    def _set_bg_color_disabled(self, color, alpha=None):
        if len(color) == 2:
            self._bg_color_disabled = get_rgba_color(color,
                                                     control_alpha=alpha)
        elif len(color) == 4:
            self._bg_color_disabled = color

    background_color_disabled = AliasProperty(_get_bg_color_disabled,
                                              _set_bg_color_disabled,
                                              bind=('_bg_color_disabled', ))

    theme_style = OptionProperty(None,
                                 options=['Light', 'Dark', 'Custom'],
                                 allownone=True)

    icon_color = ListProperty(None, allownone=True)

    elevation_normal = BoundedNumericProperty(2, min=0, max=12)
    elevation_raised = BoundedNumericProperty(0, min=0, max=12)

    icon = StringProperty('md-android')

    def __init__(self, **kwargs):
        self.elevation = self.elevation_normal

        if self.elevation_raised == 0 and self.elevation_normal + 6 <= 12:
            self.elevation_raised = self.elevation_normal + 6
        elif self.elevation_raised == 0:
            self.elevation_raised = 12

        super(FloatingActionButton, self).__init__(**kwargs)
        self.background_color = self._theme_cls.primary_color
        self.background_color_down = self._theme_cls.primary_dark
        self.background_color_disabled = self._theme_cls.disabled_bg_color()

        self.elevation_press_anim = Animation(elevation=self.elevation_raised,
                                              duration=.2,
                                              t='out_quad')
        self.elevation_release_anim = Animation(
            elevation=self.elevation_normal, duration=.2, t='out_quad')

    def _set_ellipse(self, instance, value):
        ellipse = self.ellipse
        ripple_rad = self.ripple_rad

        ellipse.size = (ripple_rad, ripple_rad)
        ellipse.pos = (self.center_x - ripple_rad / 2.,
                       self.center_y - ripple_rad / 2.)

    def on_disabled(self, instance, value):
        super(FloatingActionButton, self).on_disabled(instance, value)
        if self.disabled:
            self.elevation = 0
        else:
            self.elevation = self.elevation_normal

    def on_touch_down(self, touch):
        if not self.disabled:
            if touch.is_mouse_scrolling:
                return False
            if not self.collide_point(touch.x, touch.y):
                return False
            if self in touch.ud:
                return False
            self.elevation_press_anim.stop(self)
            self.elevation_press_anim.start(self)
        return super(FloatingActionButton, self).on_touch_down(touch)

    def on_touch_up(self, touch):
        if not self.disabled:
            if touch.grab_current is not self:
                return super(ButtonBehavior, self).on_touch_up(touch)
            self.elevation_release_anim.stop(self)
            self.elevation_release_anim.start(self)
        return super(FloatingActionButton, self).on_touch_up(touch)

    def on_elevation_normal(self, instance, value):
        self.elevation = value

    def on_elevation_raised(self, instance, value):
        if self.elevation_raised == 0 and self.elevation_normal + 6 <= 12:
            self.elevation_raised = self.elevation_normal + 6
        elif self.elevation_raised == 0:
            self.elevation_raised = 12
Esempio n. 34
0
class Pomodoro(BoxLayout):
    time_period = NumericProperty()
    rotation = NumericProperty(0)
    sprint_count = NumericProperty(0)

    time_display = StringProperty()
    time_minute = StringProperty()
    time_second = StringProperty()
    state = StringProperty()
    start = StringProperty()
    stop = StringProperty()

    logs = ListProperty([])

    server_url = StringProperty()
    #"http://172.18.140.79:8000/api/v1.0/put/pomodoro"
    server_user = StringProperty("barbaros")

    server_send = BooleanProperty(False)
    count_start = BooleanProperty(False)
    connect_server = BooleanProperty(False)

    buttons = ListProperty()

    def __init__(self, *args, **kwargs):
        super(Pomodoro, self).__init__(*args, **kwargs)
        self.buttons = get_buttons(self, [])
        self.animation = None
        self.clock = SoundLoader.load('assets/clock.wav')
        self.alarm = SoundLoader.load('assets/alarm.wav')
        self.load_log_dates()
        #self.load_logs()
        try:
            last_session = DB.store_get('last_session')
        except KeyError:
            last_session = ""
        if last_session:
            self.set_restart_session(last_session)
        else:
            self.set_to_workstate()

        if ACTIVE_STYLE == "style1":
            self.sm.current = 'start'

    def show_log(self, index):
        """
        show_log, to display specified log with more
        information and full log content.
        """
        data = self.logs[index]
        self.switch_screen('logdetail_screen', side='down')
        floatlayout = self.sm.current_screen.children[0]
        floatlayout.log_detail.text = data['content']
        floatlayout.date_distance.text = "[color=%s]%s - %s[/color]"%(
                                        floatlayout.date_distance.color_data,
                                        data['date_from'].split(' ')[1],
                                        data['date_to'].split(' ')[1])

    def db_check(self):
        """
        db_check, json data can be damaged as objects on it
        to make it back to json serializable dict function called.
        """
        keys = DB.keys()
        for k in keys:
            value = DB.store_get(k)
            if type(value) == list:
                for v in value:
                    if type(v) == dict:
                        if 'date_from' in v:
                            v['date_from'] = str(v['date_from'])
                        if 'date_to' in v:
                            v['date_to'] = str(v['date_to'])

    def load_log_dates(self):
        """
        load_log_dates, is for picking log days only and
        serving as sorted reversely.
        """
        days = list(set(filter(lambda x: len(x.split("-"))==3, DB.keys())))
        days.sort(reverse=True)
        self.log_spinner.values = days

    def load_logs(self, date=""):
        """
        load_logs, according to the given date required
        data set is taken and serves to app.
        """
        logs = []
        days = filter(lambda x: len(x.split("-"))==3, DB.keys())
        for day in days:
            data = DB.store_get(day)
            DB.store_sync()
            for log in data:
                if type(log['date_from']) != datetime:
                    log['date_from'] = datetime.strptime(log['date_from'],
                                                "%Y-%m-%d %H:%M:%S")
                if type(log['date_to']) != datetime:
                    log['date_to'] = datetime.strptime(log['date_to'],
                                                "%Y-%m-%d %H:%M:%S")
            if day == date:
                logs.extend(data)
        logs.sort(key=lambda x: x['date_from'], reverse=True)
        counter = 0
        for log in logs:
            log['index'] = logs.index(log)
        self.logs = logs
        self.db_check()

    def set_restart_session(self, dct):
        """
        To restore previously stored, because of restart
        operation, data. Not to reach the same session
        after restoring operation the data must be deleted.
        """
        self.message.text = dct['message_text']
        self.message.disabled = dct['message_disabled']
        self.server_url = dct['server_url']
        self.count_start = dct['count_start']
        self.state = dct['state']
        self.time_period = dct['time_period']
        self.start = dct['start']
        self.stop = dct['stop']

        state = self.state
        if self.state in ("paused", "work"):
            self.set_to_workstate(period=self.time_period)
        else:
            self.set_to_breakstate(period=self.time_period)

        if self.count_start:
            if self.state == "break":
                self.message.disabled = False
                self.message.focus = True
                if ACTIVE_STYLE == "style3":
                    self.message.background_color = get_color_from_hex(
                        "ffffff")
            else:
                self.start_animation()
        else:
            self.disable_buttons()
        if state == "paused":
            self.pause_but.disabled = True

        DB.store_delete('last_session')
        self.db_check()
        DB.store_sync()

    def disable_buttons(self):
        """
        play, stop and pause buttons disability attr. handler.
        """
        buttons = [self.play_but,
                   self.stop_but,
                   self.pause_but]
        for but in buttons:
            but.disabled = False

    def start_animation(self):
        """
        starts animation for rotation, if state is on 'work'
        then start date should be taken to log pomodoro.
        other then stop date must be reset in each starting animation action.
        """
        if self.state == "work":
            self.count_start = True
            self.start = str(datetime.now()).rsplit('.', 1)[0]

        elif self.state == "paused" and ACTIVE_STYLE in ("style2", "style3"):
            self.pause_but.disabled = False
            self.state = "work"
            self.count_start = True
        self.disable_buttons()
        self.stop = ""
        if self.state == "break":
            self.pause_but.disabled = True
            self.pause_but.inactive = True
            self.play_but.disabled = True
            self.play_but.inactive = True

        if not self.server_send:
            self.send_data()
        Clock.schedule_once(lambda dt: self.decrease_minutes(), 1)
        if ACTIVE_STYLE == "style1":
            self.start_button.disabled = True
        if ACTIVE_STYLE in ("style2", "style3"):
            self.play_but.disabled = True
            self.message.disabled = True
            self.message.focus = False
            if ACTIVE_STYLE == "style3":
                self.message.background = (0.078, 0.090, 0.094, 1)

    def decrease_minutes(self):
        """
        until the rotation count reaches the end
        minutes and rotation should be continue.
        At the end pomodoro stop date must be taken too
        sounds should also be handled.
        """
        if not self.count_start:
            pass
        elif self.time_period < 1:
            self.rotation = 0
            self.reset_time()
        else:
            self.clock.stop()
            self.clock.play()

            self.rotation += self.perrotation
            self.time_period -= 1
            self.time_display = strftime('%M:%S', gmtime(self.time_period))
            self.time_minute, self.time_second = self.time_display.split(':')
            if not self.server_send:
                self.send_data()
            if ACTIVE_STYLE == "style1":
                if self.animation:
                    self.animation.stop(self)
                self.animation = Animation(rotation=self.rotation, d=1)
                self.animation.start(self)

            if self.state == "work" and self.time_period < 1:
                self.stop = str(datetime.now()).rsplit('.', 1)[0]

            Clock.schedule_once(lambda dt: self.decrease_minutes(), 1)

    def send_data(self, state=""):
        """
        To update server side info, if requested.
        """
        result = True
        if self.server_url and self.server_user:
            state_time = {"work": 1500, "break": 300, "stop": 1800}
            total_time = state_time[state] if state else state_time[self.state]
            result = REQ_GET(self.server_url,
                             params={"user": self.server_user,
                                     "total": total_time,
                                     "now": self.time_period,
                                     "state": self.state},
                             timeout=1,)
            self.server_send = result
        return result

    def pause_animation(self):
        """
        To pause the timer. in this change of state
        if server side visuality wanted, updater should be called.
        """
        self.count_start = False
        self.clock.stop()
        self.alarm.stop()
        state = self.state
        self.state = 'paused'
        self.disable_buttons()
        self.pause_but.disabled = True
        if self.server_url and self.server_user:
            while True:
                res_result = self.send_data(state=state)
                if res_result.status_code == 200:
                    break
        self.server_send = False

    def stop_animation(self):
        """
        To stop the timer. in this change of state
        if server side visuality wanted, updater should be called.
        """
        self.count_start = False
        self.clock.stop()
        self.alarm.stop()
        if self.server_url and self.server_user:
            self.state = "stop"
            while True:
                res_result = self.send_data()
                if res_result.status_code == 200:
                    break
        self.set_to_workstate()
        self.message.text = ""
        if ACTIVE_STYLE == "style3":
            self.message.background_color = (0.078, 0.090, 0.094, 1)
        self.message.disabled = True
        self.disable_buttons()
        self.server_send = False

    def switch_screen(self, screen, side=None):
        """
        action screens rotation handling
        """
        direction = 'up'
        if ACTIVE_STYLE in ("style2", "style3") and \
                self.sm.current == self.sm.settings_screen.name:
            direction = 'down'
        if side:
            direction = side
        self.sm.transition = SlideTransition(direction=direction)
        self.sm.current = screen
        self.buttons = get_buttons(self, [])

    def set_clock(self):
        """
        rotation for per second calculation.
        """
        if self.time_period:
            self.perrotation = Vector(1, 1).angle(
                Vector(1, 1).rotate(360 / float(self.time_period)))

    def set_to_workstate(self, period=None):
        """
        the state of pomodoro taken to 'work' time periods and
        required settings handled. for per work pomodoro
        counter counts this state until break state triggered
        """
        self.state = "work"
        self.time_period = WORK_TIME_PERIOD if period == None else period
        self.time_display = strftime('%M:%S', gmtime(self.time_period))
        self.time_minute, self.time_second = self.time_display.split(':')
        self.sprint_count += 1
        self.set_clock()
        if ACTIVE_STYLE == "style1":
            self.switch_screen('start')

    def set_to_breakstate(self, period=None):
        """
        Break pomodoro action handled, the time calculated by
        the work state counter then it resets
        """
        self.state = "break"
        self.time_period = (
            BREAK_TIME_PERIOD * self.sprint_count) if period == None else period
        self.sprint_count = 0
        self.time_display = strftime('%M:%S', gmtime(self.time_period))
        self.time_minute, self.time_second = self.time_display.split(':')
        self.set_clock()
        if ACTIVE_STYLE == "style1":
            self.switch_screen('start')

    def reset_time(self):
        """
        triggered when the timer reaches the end, animation, clock sound,
        disability of button switched to other state of each.
        pomodoro state changes according to the current one.
        If the current state is 'break' then 'work' state trigger triggered
        """
        if self.animation:
            self.animation.stop(self)
        self.rotation = 0
        self.clock.stop()
        self.alarm.play()
        if ACTIVE_STYLE == "style1":
            self.start_button.disabled = False
        elif ACTIVE_STYLE in ("style2", "style3"):
            self.disable_buttons()
            if self.state == "work":
                self.state = "break"
                self.set_to_breakstate()

                self.message.disabled = False
                self.message.focus = True
                if ACTIVE_STYLE == "style3":
                    self.message.background_color = get_color_from_hex(
                        "ffffff")

                self.play_but.disabled = True
                self.pause_but.disabled = True
                self.play_but.inactive = True
                self.pause_but.inactive = True
            elif self.state == "break":
                self.set_to_workstate()
                self.message.text = ""
        if ACTIVE_STYLE == "style1":
            if self.state == "break":
                self.switch_screen('start')
                self.set_to_workstate()
            else:
                self.switch_screen('info')

    def set_volume(self, state):
        """
        Volume operation handled except alarm sound.
        """
        on_off = 0 if state == "down" else 1
        if self.clock:
            self.clock.volume = on_off

    def keep_info(self, text=None):
        """
        after each pomodoro in 'work' state an information is taken
        from user and to log that with other necessary informations
        collection is written in a file.
        """
        if not text:
            text = self.message.text.strip()

        if text:
            if ACTIVE_STYLE == "style3":
                self.message.background_color = (0.078, 0.090, 0.094, 1)

            data = dict(date_from=self.start,
                        date_to=self.stop,
                        content=text,
                        is_sent=False)
            if ACTIVE_STYLE == "style1":
                self.message.text = ""
            current_day = self.start.rsplit(" ", 1)[0]
            try:
                existing_data = DB.store_get(current_day)
            except KeyError:
                existing_data = []
            existing_data.append(data)
            DB.store_put(current_day, existing_data)
            self.db_check()
            self.load_log_dates()
            DB.store_sync()
            if ACTIVE_STYLE == "style1":
                self.switch_screen('action')
            elif ACTIVE_STYLE in ("style2", "style3"):
                self.start_animation()

    def update_connect_server(self):
        self.connect_server = not self.connect_server
        if self.connect_server:
            self.switch_screen(server_screen, side='right')

    def set_server_user(self):
        pass

    def set_server_url(self):
        pass

    def on_mouse_pos(self, *args):
        """
        hover action handling, for capable buttons.
        """
        mouse_position = args[1]

        if self.sm.current == 'log_screen':
            #items = self.sm.children[0].children[0].logs.children[0].children[0].children
            pass
        else:
            buttons = filter(lambda x:
                             x.pos[0] <= mouse_position[0] <= x.ranged[0] and
                             x.pos[1] <= mouse_position[1] <= x.ranged[1],
                             self.buttons)
            button = None
            if buttons and 149 > mouse_position[1] > 1 and \
                    299 > mouse_position[0] > 1:
                button = buttons[0]
            for but in self.buttons:
                if but != button:
                    but.inactive = True
                else:
                    but.inactive = False

    def change_theme(self):
        theme = DB.store_get("theme")
        if theme == 'style3':
            theme = 'style2'
            self.toggle_source.source = "assets/icons/switches_to_dark.png"
        else:
            theme = 'style3'
            self.toggle_source.source = "assets/icons/switches_to_light.png"
        DB.store_put('theme', theme)
        self.db_check()
        DB.store_sync()
        Clock.schedule_once(lambda dt: self.restart(), .5)

    def to_dict(self):
        """
        To store required data from restoring app and
        loosing all, values packed in a dict.
        """
        return {'state': self.state,
                'count_start': self.count_start,
                'server_url': self.server_url,
                'server_user': self.server_user,
                'message_text': self.message.text,
                'message_disabled': self.message.disabled,
                'time_period': self.time_period,
                'start': str(self.start),
                'stop': str(self.stop)}

    def restart(self):
        """
        Restoring current values to specified file on
        config.py and restart operation of app handled.
        """
        DB.store_put('last_session', self.to_dict())
        self.db_check()
        DB.store_sync()
        args = sys.argv[:]
        args.insert(0, sys.executable)
        os.execv(sys.executable, args)

    def log_converter(self, row_index, item):
        data = {
            'log': item['content'],
            'date': str(item['date_from'].split(" ")[1].strip()),
            'index': item['index']
        }
        return data
Esempio n. 35
0
anim.start(widget)

# animaçoes em paralelo, duas animacoes ao mesmo tempo
anim = Animation(pos=(80, 10))
anim &= Animation(size=(800, 800), duration=2.)
anim.start(widget)

# animacao em que se repete ao terminar
anim = Animation(x=50) + Animation(size=(80, 80), duration=2.)
anim.repeat = True
anim.start(widget)
Animation.cancel_all(widget, 'x')  #cancelar todas animacoes

# CARACTERISTICAS
anim.start(widget)  #inicia uma animacao
anim.stop(widget)  #para uma animacao
anim.cancel(widget)  #apara a animacaoe evento on_complete noa sera executado
Animation.stop_all(widget, 'x')  #para e afeta todas a s animacoes
Animation.cancel_all(widget, 'y')  #para e afeta todas a s animacoes
stop_property(widget, 'x')  #para e remove a propriedade da animacao do widget
cancel_property(widget,
                'y')  #para e remove a propriedade da animacao do widget
anim.duration = 2.0  # tempo duracao de animacao
anim.transition = 'in_quad'  # funcao de transicao, pode ser da propeia classe que vc criou
anim.step = 1.0 / 30.0  # 30 FPS na animacao
anim.have_properties_to_animate  #retona true se widget tem uma animacao

#EVENTOS
anim.on_start  #dispara quando a niamacaoe iniciada
anim.on_complete  #dispara quandoa  animacao termina
anim.on_progress  #dispara euqnato a animcao seta sendo executada
Esempio n. 36
0
class MetronomeWidget(Widget):
    def __init__(self, dur, pulsing):
        Widget.__init__(self)
        self.dur = dur
        self.mode = 'Moving Block'
        self.pulsing = pulsing
        self.pulse_schedule = None
        self.text_feedback_label = Label(text='Welcome to Intuitive Metronome (IM)!', font_size=26,
                                         bold=True, pos=(350, 300), color=TEXT_COLOR)
        self.text_feedback = 'Welcome to Intuitive Metronome (IM)!'
        self.add_widget(self.text_feedback_label)
        with self.canvas:
            Color(BLOCK_COLOR[0], BLOCK_COLOR[1], BLOCK_COLOR[2], BLOCK_COLOR[3])
            self.block = Rectangle(size_hint=(None, None))
        self.accomp_file = None
        self.accomp_playing = False

        # Leap Variables
        self.controller = Leap.Controller()
        self.data, self.fs = sf.read('click.wav', dtype='float32')
        self.animation = None
        self.click_schedule = None
        self.controller = Leap.Controller()
        self.state = 'stop'
        self.is_running = False
        self.stop_time = None
        self.my_recording = []
        self.gave_recording_feedback = False
        Clock.schedule_interval(self.update_label, 0.5)
        Clock.schedule_interval(self.on_update, 1)

    def update_label(self, *args):
        self.text_feedback_label.text = self.text_feedback

    def play_click(self, dt=None):
        sd.play(self.data, self.fs)

    def blink_square(self, dt=None):
        with self.canvas:
            Color(BLOCK_COLOR[0], BLOCK_COLOR[1], BLOCK_COLOR[2], BLOCK_COLOR[3])
            flash = Rectangle(size=(900, 700))

        def reset_blink(*args):
            self.canvas.remove(flash)

        Clock.schedule_once(reset_blink, self.dur*0.5)

    def process_leap(self):
        frame = self.controller.frame()
        self.hand = frame.hands[0]
        if self.state == 'start':
            if self.hand.grab_strength == 1:
                self.state = 'stop'
        elif self.state == 'stop':
            print('Looking for pinch to start: pinch strength is ', self.hand.pinch_strength)
            self.text_feedback = 'Looking for pinch to start: pinch strength is %s' % round(self.hand.pinch_strength, 2)
            if self.hand.pinch_strength == 1:
                self.state = 'start'

    def on_update(self, *args):
        if (self.stop_time is None) or (time.time() - self.stop_time > 3):
            if self.gave_recording_feedback:
                pass
            else:
                self.process_leap()
            if self.state == 'start' and not self.is_running:
                print('Metronome has started. It is listening for input tempo.')
                if self.accomp_file:
                    self.text_feedback = 'Listening for input tempo. May take awhile to load MIDI file.'
                else:
                    self.text_feedback = 'Metronome has started. It is listening for input tempo.'

                if not self.gave_recording_feedback:
                    self.gave_recording_feedback = True
                else:
                    t_avg, bpm = record_process_signal()
                    self.gave_recording_feedback = False
                    #t_avg, bpm = 0.46, 128
                    if self.accomp_file and not self.accomp_playing:
                        #self.text_feedback = 'Playing MIDI file at your tempo, %s BPM.' % bpm
                        self.py_game = run_midi_player(self.accomp_file, bpm, 'Piano', self.controller)
                        self.accomp_playing = True

                    Animation.cancel_all(self)
                    self.dur = float(round(t_avg, 2))
                    if self.pulsing:
                        if self.block:
                            self.canvas.remove(self.block)
                            self.block = None
                        self.pulse_schedule = Clock.schedule_interval(self.blink_square, self.dur)
                    else:
                        self.animation = Animation(pos=(700, 0), duration=0.98 * self.dur) \
                                         + Animation(pos=(0, 0), duration=0.98 * self.dur)
                        self.animation.repeat = True
                        if self.block is None:
                            with self.canvas:
                                Color(BLOCK_COLOR[0], BLOCK_COLOR[1], BLOCK_COLOR[2], BLOCK_COLOR[3])
                                self.block = Rectangle(size_hint=(None, None))
                        self.animation.start(self.block)

                    self.click_schedule = Clock.schedule_interval(self.play_click, self.dur)
                    self.is_running = True
                    if self.accomp_playing:
                        self.text_feedback = 'Playing MIDI file at your tempo, %s BPM. To stop, make a fist - %s' % (round(bpm), round(self.hand.grab_strength, 2))
                    else:
                        self.text_feedback = 'Metronome is running. To stop, make a fist! Fist strength: %s' % round(self.hand.grab_strength, 2)
                    print('Metronome is running. To stop, make a fist! Fist strength: %s' % round(self.hand.grab_strength, 2))
            elif self.state == 'stop' and self.is_running:
                print('Metronome has stopped')
                self.text_feedback = 'Metronome has stopped.'
                if self.accomp_playing:
                    self.py_game.mixer.music.stop()
                    self.accomp_playing = False
                    self.accomp_file = None

                if self.pulsing:
                    if self.pulse_schedule:
                        self.pulse_schedule.cancel()
                else:
                    if self.animation:
                        self.animation.stop(self.block)
                        self.animation.repeat = False
                if self.click_schedule:
                    self.click_schedule.cancel()
                self.is_running = False
                self.stop_time = time.time()
        else:
            print('Cycle ended! Short waiting before the next cycle!')
class AnimationTestCase(unittest.TestCase):
    def sleep(self, t):
        start = time()
        while time() < start + t:
            sleep(.01)
            Clock.tick()

    def setUp(self):
        self.a = Animation(x=100, d=1, t='out_bounce')
        self.w = Widget()

    def test_start_animation(self):
        self.a.start(self.w)
        self.sleep(1.5)
        self.assertAlmostEqual(self.w.x, 100)

    def test_animation_duration_0(self):
        a = Animation(x=100, d=0)
        a.start(self.w)
        self.sleep(.5)

    def test_stop_animation(self):
        self.a.start(self.w)
        self.sleep(.5)
        self.a.stop(self.w)
        self.assertNotAlmostEqual(self.w.x, 100)
        self.assertNotAlmostEqual(self.w.x, 0)

    def test_stop_all(self):
        self.a.start(self.w)
        self.sleep(.5)
        Animation.stop_all(self.w)

    def test_stop_all_2(self):
        self.a.start(self.w)
        self.sleep(.5)
        Animation.stop_all(self.w, 'x')

    def test_duration(self):
        self.assertEqual(self.a.duration, 1)

    def test_transition(self):
        self.assertEqual(self.a.transition, AnimationTransition.out_bounce)

    def test_animated_properties(self):
        self.assertEqual(self.a.animated_properties['x'], 100)

    def test_animated_instruction(self):
        instruction = Scale(3)
        self.a.start(instruction)
        self.assertEqual(self.a.animated_properties['x'], 100)
        self.assertAlmostEqual(instruction.x, 3)
        self.sleep(1.5)
        self.assertAlmostEqual(instruction.x, 100)

    def test_weakref(self):
        widget = Widget()
        anim = Animation(x=100)
        anim.start(widget.proxy_ref)
        del widget
        try:
            self.sleep(1.)
        except ReferenceError:
            pass
Esempio n. 38
0
class ButtonBase(Button):
    """Basic button widget."""

    warn = BooleanProperty(False)
    target_background = ListProperty()
    target_text = ListProperty()
    background_animation = ObjectProperty()
    text_animation = ObjectProperty()
    last_disabled = False
    menu = BooleanProperty(False)
    toggle = BooleanProperty(False)

    button_update = BooleanProperty()

    def __init__(self, **kwargs):
        self.background_animation = Animation()
        self.text_animation = Animation()
        app = App.get_running_app()
        self.background_color = app.theme.button_up
        self.target_background = self.background_color
        self.color = app.theme.button_text
        self.target_text = self.color
        super(ButtonBase, self).__init__(**kwargs)

    def on_button_update(self, *_):
        Clock.schedule_once(self.set_color_instant)

    def set_color_instant(self, *_):
        self.set_color(instant=True)


    def set_color(self, instant=False):
        app = App.get_running_app()
        if self.disabled:
            self.set_text(app.theme.button_disabled_text, instant=instant)
            self.set_background(app.theme.button_disabled, instant=instant)
        else:
            self.set_text(app.theme.button_text, instant=instant)
            if self.menu:
                if self.state == 'down':
                    self.set_background(app.theme.button_menu_down, instant=True)
                else:
                    self.set_background(app.theme.button_menu_up, instant=instant)
            elif self.toggle:
                if self.state == 'down':
                    self.set_background(app.theme.button_toggle_true, instant=instant)
                else:
                    self.set_background(app.theme.button_toggle_false, instant=instant)

            elif self.warn:
                if self.state == 'down':
                    self.set_background(app.theme.button_warn_down, instant=True)
                else:
                    self.set_background(app.theme.button_warn_up, instant=instant)
            else:
                if self.state == 'down':
                    self.set_background(app.theme.button_down, instant=True)
                else:
                    self.set_background(app.theme.button_up, instant=instant)

    def on_disabled(self, *_):
        self.set_color()

    def on_menu(self, *_):
        self.set_color(instant=True)

    def on_toggle(self, *_):
        self.set_color(instant=True)

    def on_warn(self, *_):
        self.set_color(instant=True)

    def on_state(self, *_):
        self.set_color()

    def set_background(self, color, instant=False):
        if self.target_background == color:
            return
        app = App.get_running_app()
        self.background_animation.stop(self)
        if app.animations and not instant:
            self.background_animation = Animation(background_color=color, duration=app.animation_length)
            self.background_animation.start(self)
        else:
            self.background_color = color
        self.target_background = color

    def set_text(self, color, instant=False):
        if self.target_text == color:
            return
        app = App.get_running_app()
        self.text_animation.stop(self)
        if app.animations and not instant:
            self.text_animation = Animation(color=color, duration=app.animation_length)
            self.text_animation.start(self)
        else:
            self.color = color
        self.target_text = color
Esempio n. 39
0
class FloatingActionButton(ThemeBehaviour, CircularRippleBehavior, ElevationBehaviour, ButtonBehavior, AnchorLayout):

	_bg_color_down = ListProperty([])
	def _get_bg_color_down(self):
		return self._bg_color_down

	def _set_bg_color_down(self, color, alpha=None):
		if len(color) == 2:
			self._bg_color_down = get_rgba_color(color, control_alpha=alpha)
		elif len(color) == 4:
			self._bg_color_down = color

	background_color_down = AliasProperty(_get_bg_color_down, _set_bg_color_down,
										  bind=('_bg_color_down', ))

	_bg_color_disabled = ListProperty([])
	def _get_bg_color_disabled(self):
		return self._bg_color_disabled

	def _set_bg_color_disabled(self, color, alpha=None):
		if len(color) == 2:
			self._bg_color_disabled = get_rgba_color(color, control_alpha=alpha)
		elif len(color) == 4:
			self._bg_color_disabled = color
	background_color_disabled = AliasProperty(_get_bg_color_disabled, _set_bg_color_disabled,
											  bind=('_bg_color_disabled', ))

	theme_style = OptionProperty(None, options=['Light', 'Dark', 'Custom'], allownone=True)

	icon_color = ListProperty(None, allownone=True)


	elevation_normal = BoundedNumericProperty(2, min=0, max=12)
	elevation_raised = BoundedNumericProperty(0, min=0, max=12)

	icon = StringProperty('md-android')

	def __init__(self, **kwargs):
		self.elevation = self.elevation_normal

		if self.elevation_raised == 0 and self.elevation_normal + 6 <= 12:
			self.elevation_raised = self.elevation_normal + 6
		elif self.elevation_raised == 0:
			self.elevation_raised = 12

		super(FloatingActionButton, self).__init__(**kwargs)
		self.background_color = self._theme_cls.primary_color
		self.background_color_down = self._theme_cls.primary_dark
		self.background_color_disabled = self._theme_cls.disabled_bg_color()


		self.elevation_press_anim = Animation(elevation=self.elevation_raised, duration=.2, t='out_quad')
		self.elevation_release_anim = Animation(elevation=self.elevation_normal, duration=.2, t='out_quad')

	def _set_ellipse(self, instance, value):
		ellipse = self.ellipse
		ripple_rad = self.ripple_rad

		ellipse.size = (ripple_rad, ripple_rad)
		ellipse.pos = (self.center_x - ripple_rad / 2.,
					   self.center_y - ripple_rad / 2.)

	def on_disabled(self, instance, value):
		super(FloatingActionButton, self).on_disabled(instance, value)
		if self.disabled:
			self.elevation = 0
		else:
			self.elevation = self.elevation_normal

	def on_touch_down(self, touch):
		if not self.disabled:
			if touch.is_mouse_scrolling:
				return False
			if not self.collide_point(touch.x, touch.y):
				return False
			if self in touch.ud:
				return False
			self.elevation_press_anim.stop(self)
			self.elevation_press_anim.start(self)
		return super(FloatingActionButton, self).on_touch_down(touch)

	def on_touch_up(self, touch):
		if not self.disabled:
			if touch.grab_current is not self:
				return super(ButtonBehavior, self).on_touch_up(touch)
			self.elevation_release_anim.stop(self)
			self.elevation_release_anim.start(self)
		return super(FloatingActionButton, self).on_touch_up(touch)

	def on_elevation_normal(self, instance, value):
		self.elevation = value

	def on_elevation_raised(self, instance, value):
		if self.elevation_raised == 0 and self.elevation_normal + 6 <= 12:
			self.elevation_raised = self.elevation_normal + 6
		elif self.elevation_raised == 0:
			self.elevation_raised = 12
Esempio n. 40
0
class Ball(TickingWidget):
    """The ball that the solver moves through the maze.

    The ball has two collision-detection methods: the standard collide_point()
    for the area where the ball accepts touches, and collide_zoc() for the
    “zone of control”. The zone of coltrol grows when the ball is touched, and
    shrinks when the touch is released.

    When touched, the ball will move towards the touch at BALL_SPEED tiles per
    second (but maze walls will block it).
    """
    def __init__(self, parent, **kwargs):
        super(Ball, self).__init__(**kwargs)
        self.touch_uid = None
        self.target_pos = self.pos

        self.animation = None

        radius = self.radius = parent.cell_size * 0.3
        self.handle_radius = parent.cell_size * BALL_TOUCH_RADIUS
        self.zoc_radius = self.radius
        with self.canvas:
            Color(0, 0, 1, 0.5)
            Ellipse(pos=(-radius, -radius), size=(radius * 2, radius * 2))
            Color(0, 0, 0, 1)
            HollowCircle((0, 0), radius, 18)
            Color(0.5, 0.5, 0.5, 0.4)
            FilledCircle((0, 0), self.handle_radius)
            HollowCircle((0, 0), self.handle_radius, 18)
            self.scale_instruction = Scale(self.zoc_radius)
            Color(1, 1, 1, 0.2)
            FilledCircle((0, 0), 1)
            Color(0.5, 0.5, 0.5, 0.4)
            HollowCircle((0, 0), 1, 32)
        with self.canvas.before:
            PushMatrix()
            self.translation_instruction = Translate(0, 0, 0)
        with self.canvas.after:
            PopMatrix()

    def collide_point(self, x, y):
        px, py = self.pos
        return (px - x)**2 + (py - y)**2 < self.handle_radius**2

    def collide_zoc(self, x, y):
        px, py = self.pos
        return (px - x)**2 + (py - y)**2 < self.zoc_radius**2

    def tick(self, dt):
        if not self.parent:
            return
        # Try to cover the required distance. But if it's not done in 50
        # iterations, give up.
        remaining_distance = dt * BALL_SPEED * self.parent.cell_size
        for i in range(50):
            if remaining_distance <= 0.01 or self.pos == self.target_pos:
                break
            distance_covered = self.move_step(remaining_distance)
            if distance_covered == 0:
                break
            remaining_distance -= distance_covered
        if self.translation_instruction.xy != self.pos:
            # Update the canvas if the ball moved
            self.translation_instruction.xy = self.pos
            self.canvas.ask_update()
        if self.scale_instruction.scale != self.zoc_radius:
            # Update the canvas if the ZOC was resized
            self.scale_instruction.scale = self.zoc_radius
            self.canvas.ask_update()
        if not self.parent.ball_source.collide_point(*self.pos):
            # If the ball is outside the initial area, add time to the player's
            # clock
            self.parent.add_time(dt)
        if self.x < self.parent.cell_size:
            # IF the ball is in the goal area, the round ends
            self.parent.win()

    def move_step(self, remaining_distance):
        """Move a little towards the touch position, return distance covered

        `remaining_distance` is the maximum distance to move

        This implements one iteration of the moving, and is called enough times
        for the sum of the returned values is big enough.

        Both remaining_distance and the return value are in pixels, not tiles.
        """
        radius = self.radius
        pos = numpy.array(self.pos)
        # The distance we want to cover
        delta = self.target_pos - pos
        distance = numpy.sqrt(sum(delta**2))
        # Only move a little bit each time, so walls are checked correctly
        max_distance = min(remaining_distance, radius / 2)
        if distance > max_distance:
            delta = delta / distance * max_distance
            distance = max_distance
        pos += delta
        # From now, we will deal with tile coordinates instead of pixels
        tile_coord = numpy.array(self.parent.pixel_to_tile(pos))
        tile_radius = self.parent.pixel_to_tile((radius, radius))
        # Check the upper/lower & left/right points of the circle
        # if one of them is in a wall, "snap" the ball to that wall
        for axis in (0, 1):
            pt = [0, 0]
            pt[axis] = tile_radius[axis]
            if self.parent.wall_at_tile(tile_coord + pt):
                tile_coord[axis] = int(tile_coord[axis]) + 1 - pt[axis]
            if self.parent.wall_at_tile(tile_coord - pt):
                tile_coord[axis] = int(tile_coord[axis]) + pt[axis]
        # Get the closest grid intersection
        corner = numpy.array(tile_coord).round()
        # Get a point in the tile "behind" this clocest corner
        tile_behind_corner = 2 * corner - tile_coord
        # Check if there is a wall on that tile
        if self.parent.wall_at_tile(tile_behind_corner):
            vector_to_corner = corner - tile_coord
            # If part of the ball is inside a corner wall, push it back
            # XXX: This doesn't take into account that the ball can be slightly
            # elliptical in tile coordinates. (This isn't likely to matter,
            # though.)
            avg_radius = sum(tile_radius) / 2
            if sum(vector_to_corner**2) < avg_radius**2:
                distance_to_corner = numpy.sqrt(sum(vector_to_corner**2))
                direction_to_corner = vector_to_corner / distance_to_corner
                pushback_distance = avg_radius - distance_to_corner
                tile_coord -= direction_to_corner * pushback_distance
                pushed_back = True
        # Convert back to pixel coordinates
        self.pos = self.parent.tile_to_pixel(tile_coord)
        return distance

    def on_touch_down(self, touch, force=False):
        """Called for a new touch

        `force`: don't check that the touch is near the ball; assume it is.
        """
        if force or self.collide_point(touch.x, touch.y):
            if self.touch_uid:
                self.touch_uid = None
            self.touch_uid = touch.uid
            self.on_touch_move(touch)
            zoc_radius = self.parent.cell_size * BALL_ZOC_RADIUS
            if self.animation:
                self.animation.stop(self)
            self.animation = Animation(zoc_radius=zoc_radius, duration=0.5)
            self.animation.start(self)
            return True

    def on_touch_move(self, touch):
        if touch.uid == self.touch_uid:
            self.target_pos = touch.pos
            return True

    def on_touch_up(self, touch):
        if touch.uid == self.touch_uid:
            self.touch_uid = None
            self.target_pos = self.pos
            if self.animation:
                self.animation.stop(self)
            self.animation = Animation(zoc_radius=self.handle_radius,
                                       t='in_cubic',
                                       duration=1)
            self.animation.start(self)
            return True
Esempio n. 41
0
    def update(self, dt):
        """ 게임업데이트 """

        if not self.is_start:
            self.txupdate(dt)
            # tip label
            if self.tip_label.opacity <= 1.0:
                self.tip_label.opacity += 0.005

            return

        self.txupdate(dt)

        self.is_ycoll = False

        # Character's Move
        for brick in self.bricks:

            # meet Block
            if self.character.collide_widget(brick):
                z = Vector(self.character.center) - Vector(brick.center)

                if -0.70 < z.normalize()[0] < 0.70:
                    # down
                    if self.character_y_collision(brick):
                        self.is_jumping = False
                        self.is_ycoll = True
                else:
                    self.character_x_collision(brick)

        self.character.move()

        # y 충돌이면 떨어지지 않는다. // 표면보다 같거나 낮으면 떨어지지 않는다.
        if not self.is_ycoll and not self.character.y <= self.y:
            self.character.y -= 5.0

        # floor
        if self.character.y <= self.y and self.is_jumping:
            self.is_jumping = False
            self.character.y = self.y

        # next stage
        if self.character.center_x > self.width or self.character.center_x < 0:
            self.clear_stage()

        # monster
        for monster in self.monsters:
            if self.character.collide_widget(monster):

                if monster.status == 1:  # Food
                    anim = Animation(
                        size=[self.character.player_image.width * 1.2, self.character.player_image.height * 1.2], duration=.2)
                    if anim:
                        anim.stop(self.character.player_image)
                        anim.start(self.character.player_image)
                    # remove monster
                    self.remove_widget(monster)
                    self.monsters.remove(monster)
                    self.score += 1

                elif monster.status == 2:  # Enemy
                    monster.source_dir = "data/mouse_dead.png"
                    monster.status = 3

                    left = Animation(
                        center_x=monster.center_x + 10, duration=.2)
                    right = Animation(center_x=monster.center_x, duration=.2)
                    anim = left + right
                    if anim:
                        anim.stop(self)
                    anim.start(monster)
                    self.score += 2

                elif monster.status == 9:  # Boss
                    monster.source_dir = "data/spider_dead.png"
                    monster.status = 3
                    self.score += 3

                elif monster.status == 10:  # Girl
                    self.character.velocity = [0, 0]
                    self.character.y += 6
                    monster.y += 1
                    if self.center[1] < self.character.y:
                        self.clear_stage()

                # Letter
                elif monster.status in [12, 13, 14, 15, 16, 17, 18, 19, 20, 21]:
                    left = Animation(
                        center_y=monster.center_y + 400, duration=.2)
                    right = Animation(center_y=monster.center_y, duration=.2)
                    anim = left + right
                    if anim:
                        anim.stop(self)
                    anim.start(monster)
                    monster.status = 3
                    self.score += 1

                # Hurt
                elif monster.status in [30, 31, 32, 33, 34]:
                    left = Animation(
                        center_y=monster.center_y + 400, duration=.2)
                    right = Animation(center_y=monster.center_y, duration=.2)
                    anim = left + right
                    if anim:
                        anim.stop(self)
                    anim.start(monster)
                    monster.source_dir = monster.source_dir.replace(
                        "_hurt", "")
                    monster.status = 3
                    self.score += 2

                # 3. MESSAGE
                elif monster.status == 3:
                    pass
                # 4. JUMP - SONIC
                elif monster.status == 4:
                    self.character_jump(2)  # jump time x 2
                # 5. Gold Ring - SONIC
                elif monster.status == 5:
                    self.remove_widget(monster)
                    self.monsters.remove(monster)
                    self.score += 1
                # 6. speed up
                elif monster.status == 23:
                    self.remove_widget(monster)
                    self.monsters.remove(monster)
                    self.score += 1
                    self.character.velocity = [
                        self.character.velocity[0] * 2, 0]

                # 6,7. FLAGS - MARIO
                elif monster.status == 6:
                    self.character.velocity = [0, 0]
                    self.score += 1
                    monster.status = 3

                elif monster.status == 22:
                    self.character.velocity = [
                        self.block_size / self.speed_ratio, 0]

                # 8. Gold coin - MARIO
                elif monster.status in [8, 24]:
                    self.remove_widget(monster)
                    self.monsters.remove(monster)
                    self.score += 1
                self.is_jumping = False

        # trap
        for trap in self.traps:
            if self.character.collide_widget(trap):
                self.failed_stage()
Esempio n. 42
0
class AlarmScreen(Screen):

    r = NumericProperty(100)  # Radio del círculo
    ra = NumericProperty(1.0)  # Alfa del círculo
    r2 = NumericProperty(100)  # Radio del círculo que marca pulsación
    r2a = NumericProperty(0)  # Alfa del círculo que marca pulsación
    cd = NumericProperty(0.0)  # Offset de los círculos que se desplazan
    ca = NumericProperty(1.0)  # Alfa de los círculos que se desplazan
    R = 0.08  # Constante para calcular el tamaño
    motion_uid = None

    text = StringProperty('Alarma!')
    timetext = StringProperty('')
    inicio = datetime.now()  # Se actualiza en sonar_alarma

    def on_height(self, widget, height):
        self.r = height * self.R
        self.r2 = height * self.R

    def on_enter(self, *args):
        Logger.debug("%s: AlarmScreen.on_enter self.width=%s %s" %
                     (APP, self.width, datetime.now()))
        if self.width < 100:
            width = 480  # No debería hacer falta, pero la primera vez falla
        else:
            width = self.width
        self.r2a = self.ca = self.cd = 0
        self.anim = Animation(cd=width / 2, ca=1, d=1, t='in_quad') \
            + Animation(cd=0, ca=0, d=0)
        self.anim.repeat = True
        self.anim.start(self)

        self.app.reproducir_sonido_alarma()

        self.app.clock_callback = partial(self.app.cancelar_alarma,
                                          source='Clock',
                                          clock_date=datetime.now())
        Clock.schedule_once(self.app.clock_callback, self.app.ACS)  # segundos

        self.update_timetext()
        Clock.schedule_interval(self.update_timetext, 1)

    def on_pre_leave(self, *args):
        self.anim.stop(self)
        Logger.debug("%s: AlarmScreen.on_pre_leave %s" % (APP, datetime.now()))
        if platform == 'android':
            self.app.reset_window_flags()  # Permitir apagado automático
        Clock.unschedule(self.update_timetext)

    def on_touch_down(self, touch):
        if Vector(touch.pos).distance(Vector(self.center_x,
                                             self.height * 0.2)) < 2 * self.r:
            self.motion_uid = touch.uid
            self.r2a = .2
            self.r2 = self.height * self.R
            anim = Animation(r2=self.height * self.R * 2.3, t='in_quad', d=0.3)
            anim.start(self)

    def on_touch_move(self, touch):
        if touch.uid == self.motion_uid:
            # Cancelar si de desplaza más de la mitad de la distancia al borde
            self.ra = 1 - 3.3 * Vector(touch.pos).distance(
                Vector(self.center_x, self.height * 0.2)) / self.width
            self.r2a = 1 - self.ra * 0.8
            if self.ra < 0.05:
                self.ra = 1
                self.app.cancelar_alarma(source='user')

    def on_touch_up(self, touch):
        if touch.uid == self.motion_uid:
            self.ra = 1
            self.r2a = 0

    def update_timetext(self, *args):
        self.timetext = "%s - %s" % (self.inicio.strftime("%H:%M"),
                                     tdformat(self.inicio - datetime.now()))
Esempio n. 43
0
class BaseRaisedButton(CommonElevationBehavior, BaseButton):
    '''
    Abstract base class for raised buttons which elevate from material.
    Raised buttons are to be used sparingly to emphasise primary/important
    actions.

    Implements elevation behavior as well as the recommended down/disabled
    colors for raised buttons.
    '''
    def __init__(self, **kwargs):
        if self.elevation_raised == 0 and self.elevation_normal + 6 <= 12:
            self.elevation_raised = self.elevation_normal + 6
        elif self.elevation_raised == 0:
            self.elevation_raised = 12
        super(BaseRaisedButton, self).__init__(**kwargs)
        self.elevation_press_anim = Animation(elevation=self.elevation_raised,
                                              duration=.2,
                                              t='out_quad')
        self.elevation_release_anim = Animation(
            elevation=self.elevation_normal, duration=.2, t='out_quad')

    _elev_norm = NumericProperty(2)

    def _get_elev_norm(self):
        return self._elev_norm

    def _set_elev_norm(self, value):
        self._elev_norm = value if value <= 12 else 12
        self._elev_raised = (value + 6) if value + 6 <= 12 else 12
        self.elevation = self._elev_norm
        self.elevation_release_anim = Animation(elevation=value,
                                                duration=.2,
                                                t='out_quad')

    elevation_normal = AliasProperty(_get_elev_norm,
                                     _set_elev_norm,
                                     bind=('_elev_norm', ))
    _elev_raised = NumericProperty(8)

    def _get_elev_raised(self):
        return self._elev_raised

    def _set_elev_raised(self, value):
        self._elev_raised = value if value + self._elev_norm <= 12 else 12
        self.elevation_press_anim = Animation(elevation=value,
                                              duration=.2,
                                              t='out_quad')

    elevation_raised = AliasProperty(_get_elev_raised,
                                     _set_elev_raised,
                                     bind=('_elev_raised', ))

    def on_disabled(self, instance, value):
        if self.disabled:
            self.elevation = 0
        else:
            self.elevation = self.elevation_normal
        super(BaseRaisedButton, self).on_disabled(instance, value)

    def on_touch_down(self, touch):
        if not self.disabled:
            if touch.is_mouse_scrolling:
                return False
            if not self.collide_point(touch.x, touch.y):
                return False
            if self in touch.ud:
                return False
            self.elevation_press_anim.stop(self)
            self.elevation_press_anim.start(self)
        return super(BaseRaisedButton, self).on_touch_down(touch)

    def on_touch_up(self, touch):
        if not self.disabled:
            if touch.grab_current is not self:
                return super(ButtonBehavior, self).on_touch_up(touch)
            self.elevation_release_anim.stop(self)
            self.elevation_release_anim.start(self)
        return super(BaseRaisedButton, self).on_touch_up(touch)

    def _get_md_bg_color_down(self):
        t = self.theme_cls
        c = self.md_bg_color  # Default to no change on touch
        # Material design specifies using darker hue when on Dark theme
        if t.theme_style == 'Dark':
            if self.md_bg_color == t.primary_color:
                c = t.primary_dark
            elif self.md_bg_color == t.accent_color:
                c = t.accent_dark
        return c

    def _get_md_bg_color_disabled(self):
        if self.theme_cls.theme_style == 'Dark':
            c = (1., 1., 1., 0.12)
        else:
            c = (0., 0., 0., 0.12)
        return c
class Picture(Scatter):
    '''Picture is the class that will show the image with a white border and a
    shadow. They are nothing here because almost everything is inside the
    picture.kv. Check the rule named <Picture> inside the file, and you'll see
    how the Picture() is really constructed and used.

    The source property will be the filename to show.
    '''
        
    source = StringProperty(None)
    image_type = StringProperty(None)
    selected = BooleanProperty(None)
    full = BooleanProperty(None)
    
    def __init__(self,post,sourcepos,**kw):
        self.downloader=None
        self.post= post 
        self.download('preview')
        Scatter.__init__(self,**kw)
        self.back_animation=Animation(pos=sourcepos,scale=1.2, rotation=0.0)
        self.center_animation=Animation(pos=(0,0),scale=10.0, rotation=0.0)        
        self.next_animation=Animation(pos=(2000,sourcepos[1]),scale=0.1)
        self.prev_animation=Animation(pos=(-1000,sourcepos[1]),scale=0.1)
        self.touches=set()
        
    def do_unfocus(self):
        self.back_animation.start(self)
    
    def on_scale(self,instance,value):
        if value <= 2.0:
            self.download('preview') 
        elif value <=10.0:
            self.download('sample') 
        else:
            self.download('full') 
        
    def on_touch_down(self, touch):
        if not self.collide_point(touch.x, touch.y):
            return
        self.touches.add(touch.uid)
        if not self.selected:
            self.selected= True
        
        if touch.is_double_tap:
            self.full=True
            self.center_animation.start(self)            
            return True
        self.back_animation.stop(self)
        return Scatter.on_touch_down(self, touch)
    
    def on_touch_up(self, touch):
        try:
            self.touches.remove(touch.uid)
            if not self.touches and not self.selected: 
                self.back_animation.start(self)
        except:
            pass
        return Scatter.on_touch_up(self, touch)
    
    def on_selected(self,instance,value):
        if not value and not self.touches:
            self.back_animation.start(self)
    
    def download(self, image_type, path=None, pre=None):
        post= self.post
        if self.image_type == image_type:
            return 
        
        self.image_type=image_type
        
        
        if pre == None:
            pre= ''
        
        if path == None:
            path= ""
        else:
            if not os.path.exists(path):
                os.mkdir(path)
                
        dir= os.path.join(path, post.domain)
        if not os.path.exists(dir):
            os.mkdir(dir)
            
        dir= os.path.join(dir, image_type)
        if not os.path.exists(dir):
            os.mkdir(dir)
        
        dest = os.path.join(dir, post.name(image_type))
        
        if os.path.isfile(dest):
            
            if image_type != 'full':
                self.source = dest
                return
            
            if self.downloader is not None:
                pass
            
            if self.post.local_files[image_type]:
                Logger.warn( "Caching found of %d."%(self.post.index,))
                self.source = dest
                return           
            
            with open(dest, 'rb') as f:
                bin = f.read()
    
            if post.md5 == hashlib.md5(bin).hexdigest():
                Logger.warn( "md5 correct found of %d: %s."%(self.post.index,dest))
                self.post.local_files[image_type]=True
                self.source = dest
                return 

        if self.downloader is not None:
            pass
        url = post.get_url(image_type)
        if not url:
            Logger.warn('invalid')
            return
        Logger.warn('downloading ')
        self.downloader= Downloader(url,dest,self.download_complete, self.download_progress)
        self.downloader.start()
        
    def download_progress(self, count, blockSize, totalSize,*k):
        progress = int(count * blockSize * 100 / totalSize)
        progress = min(100, progress)
        if count * blockSize == totalSize:
            Logger.warn("Total ok!")
        Logger.warn( '%s%%' % (progress,))
    
    def download_complete(self,dl,*k):
        self.source = dl.dest
        self.downloader=None