Commits

Mark Steve Samson committed 3c713c0

Initial commit

Comments (0)

Files changed (10)

+*.pyc
+from kivy.app import App
+from kivy.uix.widget import Widget
+from kivy.properties import ObjectProperty
+from kivy.logger import Logger
+from kivy.utils import platform
+from kivy.core.window import Window
+
+from kivy.factory import Factory
+from plq.label import PLQLabel
+Factory.register('PLQLabel', PLQLabel)
+
+
+class Root(Widget):
+    screens = {}
+    screen = ObjectProperty()
+
+    def set_screen(self, name, screen_class=None, force_set=False, *args,
+                   **kwargs):
+        old_screen = self.screen
+        if hasattr(self.screen, 'transition_out'):
+            self.screen.transition_out().bind(
+                on_complete=lambda x, y: self.remove_widget(old_screen))
+        else:
+            self.remove_widget(self.screen)
+
+        screen = self.screens.get(name)
+        set_screen = False
+        if screen:
+            if force_set:
+                set_screen = True
+        else:
+            set_screen = True
+
+        if set_screen:
+            self.screen = self.screens[name] = screen_class(*args, **kwargs)
+        else:
+            self.screen = screen
+            for name, value in kwargs.items():
+                setattr(self.screen, name, value)
+
+        self.add_widget(self.screen)
+
+        if hasattr(self.screen, 'transition_in'):
+            self.screen.transition_in()
+
+
+class PLQ(App):
+    def build(self):
+        root = Root(size=(320, 480))
+
+        from plq.bg import BG
+        root.bg = BG(size=root.size)
+        root.add_widget(root.bg)
+
+        from kivy.lang import Builder
+        from plq.mainmenu import MainMenu
+        Builder.load_file('mainmenu.kv')
+        root.set_screen('mainmenu', MainMenu, size=root.size)
+
+        if platform() == 'ios':
+            from plq.scaler import Scaler
+            scaler = Scaler(size=root.size, scale=2)
+            scaler.add_widget(root)
+            Window.add_widget(scaler)
+        else:
+            Window.size = root.size
+            return root
+
+if __name__ == '__main__':
+    PLQ().run()
+<MainMenu>:
+    level_selector: level_selector
+    play_label: play_label
+    BoxLayout:
+        orientation: 'vertical'
+        pos: root.pos
+        size: root.size
+        Image:
+            size_hint: 1, 0.5
+            source: 'atlas://images/ui/logo'
+        PLQLabel:
+            id: play_label
+            size_hint: 1, .1
+            font_size: 32
+            text: 'Play'
+        RelativeLayout:
+            id: level_selector
+            levels: levels
+            size_hint: 1, .1
+            RelativeLayout:
+                id: levels
+            Image:
+                pos: -96, 0
+                source: 'atlas://images/ui/arrowleft'
+                on_touch_up: self.collide_point(*args[1].pos) and root.select_left()
+            Image:
+                pos: 96, 0
+                source: 'atlas://images/ui/arrowright'
+                on_touch_up: self.collide_point(*args[1].pos) and root.select_right()
+        PLQLabel:
+            size_hint: 1, .1
+            font_size: 24
+            text: 'Options'
+        PLQLabel:
+            size_hint: 1, .1
+            font_size: 24
+            text: 'About'
+        Widget:
+            size_hint: 1, .1

plq/__init__.py

Empty file added.
+from kivy.uix.relativelayout import RelativeLayout
+from kivy.uix.widget import Widget
+from kivy.uix.image import Image
+from kivy.graphics.context_instructions import Color
+from kivy.graphics.vertex_instructions import Rectangle
+from kivy.clock import Clock
+from kivy.properties import NumericProperty
+
+
+class BG(Widget):
+    speed = NumericProperty(1)
+
+    def __init__(self, *args, **kwargs):
+        super(BG, self).__init__(*args, **kwargs)
+
+        # Paint canvas white
+        with self.canvas:
+            Color(1, 1, 1)
+            Rectangle(pos=self.pos, size=self.size)
+
+        # Append BG tiles
+        self.bg_tiles = RelativeLayout(size=self.size)
+        bg_image = 'images/ui/bg.png'
+        for pos in [(-self.width, 0), (0, 0), (0, -self.height),
+                    (-self.width, -self.height)]:
+            self.bg_tiles.add_widget(Image(source=bg_image, pos=pos,
+                                           size=self.size))
+        self.add_widget(self.bg_tiles)
+
+        # Start BG animation
+        Clock.schedule_interval(self.scroll_bg, 0.01)
+
+    def scroll_bg(self, dt):
+        x, y = self.bg_tiles.pos
+        self.bg_tiles.pos = ((x % self.width) - self.speed,
+                             (y % self.height) + self.speed)
+from kivy.uix.label import Label
+
+
+class PLQLabel(Label):
+    def __init__(self, *args, **kwargs):
+        c = 0x33 / 256.
+        map(lambda d: kwargs.setdefault(*d), ({
+            'font_size': 24,
+            'font_name': 'fonts/Harabara.ttf',
+            'color': ([c] * 3) + [1],
+            'halign': 'center',
+            'markup': True,
+            }).items())
+        super(PLQLabel, self).__init__(*args, **kwargs)
+from collections import namedtuple
+
+Level = namedtuple('Level', 'id,name,logos,unlock_count')
+Logo = namedtuple('Logo', 'id,name,filename,answers')
+_levels = []
+
+
+def add_level(level_id, level_name, unlock_count, logo_infos):
+    global _levels
+    logos = set()
+    for logo_id, logo_info in enumerate(logo_infos):
+        logos.add(Logo(logo_id, *logo_info))
+    level = Level(level_id, level_name, logos, unlock_count)
+    _levels.append(level)
+    return level
+
+
+def get_levels():
+    return _levels
+
+
+level_1 = add_level(1, "Level 1", 0, [])
+level_2 = add_level(2, "Level 2", 25, [])
+level_3 = add_level(3, "Level 3", 43, []) 
+level_4 = add_level(4, "Level 4", 61, []) 
+level_5 = add_level(5, "Level 5", 80, [])

plq/logoselect.py

+from math import ceil
+
+from kivy.animation import Animation
+from kivy.properties import NumericProperty, ObjectProperty
+from kivy.logger import Logger
+from kivy.uix.relativelayout import RelativeLayout
+from kivy.uix.gridlayout import GridLayout
+from kivy.uix.image import Image
+
+# TODO: Turn into an external module
+
+
+class LogoSelect(RelativeLayout):
+    level = ObjectProperty()
+
+    page = NumericProperty(0)
+    back_arrow = ObjectProperty()
+    logos = ObjectProperty()
+
+    def __init__(self, *args, **kwargs):
+        super(LogoSelect, self).__init__(*args, **kwargs)
+
+        # Back notifier
+        self.back_arrow = Image(source='atlas://images/ui/arrowup',
+                                width=self.width, top=self.size[1] - 20,
+                                center_x=self.center_x)
+        self.back_arrow.opacity = 0
+        self.add_widget(self.back_arrow)
+
+        # Set level
+        self.level = kwargs.get('level')
+
+    def transition_in(self):
+        self.y = -self.size[1]
+        anim = Animation(y=0, t='out_quint', duration=0.5)
+        anim.start(self)
+        return anim
+
+    def transition_out(self):
+        anim = Animation(y=-self.size[1], t='out_quint', duration=0.5)
+        anim.start(self)
+        return anim
+
+    def select_logo(self, instance, *args, **kwargs):
+        if instance.collide_point(*args[0].pos):
+            Logger.info("LOGO")
+
+    def on_touch_down(self, touch):
+        ud = touch.ud
+        ud['start_x'] = self.logos_grid.x
+        ud['start_y'] = self.logos_grid.y
+        ud['start_touch_x'] = touch.x
+        ud['start_touch_y'] = touch.y
+        touch.grab(self)
+
+    def on_touch_move(self, touch):
+        if touch.grab_current is not self:
+            return
+
+        ud = touch.ud
+        d = self.height / 4
+        dx = touch.x - ud['start_touch_x']
+        dy = touch.y - ud['start_touch_y']
+        if -dy > d or ud.get('pull'):
+            if not ud.get('pull'):
+                Animation(x=-self.page * self.width, t='out_quint',
+                          duration=0.5).start(self.logos_grid)
+                ud['pull'] = True
+            else:
+                self.logos_grid.y = ud['start_y'] + dy
+        else:
+            self.logos_grid.x = ud['start_x'] + dx
+
+        self.back_arrow.opacity = -dy / self.height
+
+    def on_touch_up(self, touch):
+        if touch.grab_current is not self:
+            return
+
+        # Check for page change
+        d = self.width / 3
+        dx = touch.x - touch.ud['start_touch_x']
+        if -dx > d and self.page < self.pages - 1:
+            self.page += 1
+        elif dx > d and self.page > 0:
+            self.page -= 1
+        else:
+            self.on_page(self, self.page)
+
+        # Check for back
+        dy = touch.ud['start_touch_y'] - touch.y
+        if dy > self.height / 2:
+            self.show_mainmenu()
+
+        Animation(y=0, t='out_quint').start(self.logos_grid)
+        Animation(opacity=0, t='out_quint').start(self.back_arrow)
+
+        touch.ungrab(self)
+
+    def on_level(self, instance, level):
+        # Create grid
+        self.pages = ceil(len(self.level.logos) / 9.)
+        w, h = self.size
+        if getattr(self, 'logos_grid', False):
+            self.page = 0
+            self.logos_grid.clear_widgets()
+        else:
+            self.logos_grid = GridLayout(pos=self.pos,
+                                         size=(w * self.pages, h),
+                                         col_default_width=w / 3 - 30,
+                                         col_force_default=True,
+                                         spacing=30,
+                                         padding=15,
+                                         rows=3)
+            self.add_widget(self.logos_grid)
+        for logo in self.level.logos:
+            logo_thumb = Image(
+                source='atlas://images/logos/thumbnail/%s' % logo.filename)
+            self.logos_grid.add_widget(logo_thumb)
+
+    def on_page(self, instance, page):
+        (Animation(x=-page * self.width, t='out_quint', duration=0.5)
+            .start(self.logos_grid))
+
+    def show_mainmenu(self):
+        root = self.parent
+        from plq.mainmenu import MainMenu
+        root.set_screen('mainmenu', MainMenu, size=root.size)
+from kivy.animation import Animation
+from kivy.properties import ObjectProperty, NumericProperty
+from kivy.uix.relativelayout import RelativeLayout
+from kivy.logger import Logger
+
+from plq.label import PLQLabel
+from plq.levels import get_levels
+
+
+class MainMenu(RelativeLayout):
+    level_selector = ObjectProperty()
+    level_selected = NumericProperty(0)
+    play_label = ObjectProperty()
+    levels = ObjectProperty()
+
+    def __init__(self, *args, **kwargs):
+        super(MainMenu, self).__init__(*args, **kwargs)
+
+        # Levels
+        self.levels = get_levels()
+
+        # Add levels
+        for i, level in enumerate(self.levels):
+            label = PLQLabel(text=level.name)
+            label.pos_hint = {'y': 0, 'x': i}
+            self.level_selector.levels.add_widget(label)
+
+        self.play_label.bind(on_touch_up=self.play_level)
+
+    def transition_in(self):
+        self.y = self.size[1] * 2
+        anim = Animation(y=0, t='out_quint', duration=0.5)
+        anim.start(self)
+        return anim
+
+    def transition_out(self):
+        anim = Animation(y=self.size[1], t='out_quint', duration=0.5)
+        anim.start(self)
+        return anim
+
+    def select_left(self):
+        if self.level_selected > 0:
+            self.level_selected -= 1
+
+    def select_right(self):
+        if self.level_selected < len(self.levels) - 1:
+            self.level_selected += 1
+
+    def on_level_selected(self, instance, level):
+        (Animation(x=-level * self.width,
+                   duration=0.5, t='in_out_quint')
+            .start(self.level_selector.levels))
+
+    def play_level(self, instance, *args):
+        if instance.collide_point(*args[0].pos):
+            level = self.levels[self.level_selected]
+            root = self.parent
+            from plq.logoselect import LogoSelect
+            root.set_screen('logoselect', LogoSelect, size=root.size,
+                            level=level)
+from kivy.uix.widget import Widget
+from kivy.properties import NumericProperty, ObjectProperty
+from kivy.base import EventLoop
+from kivy.lang import Builder
+
+
+class Scaler(Widget):
+    scale = NumericProperty(2)
+    container = ObjectProperty(None)
+
+    def __init__(self, **kwargs):
+        Builder.load_string('''
+<Scaler>:
+    container: container
+    canvas.before:
+        PushMatrix
+        Scale:
+            scale: root.scale
+
+    canvas.after:
+        PopMatrix
+
+    FloatLayout:
+        id: container
+        size: root.width / root.scale, root.height / root.scale
+''')
+
+        super(Scaler, self).__init__(**kwargs)
+        EventLoop.add_postproc_module(self)
+
+    def get_parent_window(self):
+        return self.container
+
+    def add_widget(self, widget):
+        if self.container is not None:
+            return self.container.add_widget(widget)
+        return super(Scaler, self).add_widget(widget)
+
+    def remove_widget(self, widget):
+        if self.container is not None:
+            return self.container.remove_widget(widget)
+        return super(Scaler, self).remove_widget(widget)
+
+    def process_to_local(self, x, y, relative=False):
+        if x is None:
+            return None, None
+        s = float(self.scale)
+        return x / s, y / s
+
+    def process(self, events):
+        transform = self.process_to_local
+        transformed = []
+        for etype, event in events:
+
+            # you might have a move and up event in the same process
+            # then avoid the double-transformation
+            if event in transformed:
+                continue
+            transformed.append(event)
+
+            event.sx, event.sy = transform(event.sx, event.sy)
+            if etype == 'begin':
+                event.osx, event.osy = transform(event.osx, event.osy)
+            else:
+                # update the delta
+                event.dsx = event.sx - event.psx
+                event.dsy = event.sy - event.psy
+
+        return events