Refactor
[erdslangetjie.git] / erdslangetjie / editor / editor.py
index c2d2745559801cada06ce3fe2f042c4edfbf9ca9..ef08b813e01f7c2d30c4dccbda827ba2bbe21df1 100644 (file)
@@ -1,23 +1,41 @@
 import sys
 import os
-import kivy
 
-kivy.require('1.6.0')
+from erdslangetjie.constants import TILE_SIZE
 
 from kivy.app import App
-from kivy.logger import Logger, LoggerHistory
 from kivy.uix.widget import Widget
 from kivy.uix.floatlayout import FloatLayout
 from kivy.graphics import Color, Rectangle
+from kivy.uix.label import Label
+from kivy.uix.popup import Popup
+from kivy.utils import platform
+from kivy.config import Config
 
 from erdslangetjie.data import filepath, load
-from erdslangetjie.level import Level
+from erdslangetjie.level import (Level, WALL, GATE, BUTTON,
+        FLOOR, ENTRY, EXIT)
+
+
+if platform() != 'android':
+    Config.set('graphics', 'width', '1326')
+    Config.set('graphics', 'height', '760')
+
+
+tool_map = {
+        'button': BUTTON,
+        'gate': GATE,
+        'wall': WALL,
+        'floor': FLOOR,
+        'add entry': ENTRY,
+        'add exit': EXIT
+        }
 
 
 class EditorWindow(FloatLayout):
 
     def __init__(self, level):
-        super(EditorWindow, self).__init__(size=(960, 960))
+        super(EditorWindow, self).__init__(size=(1326, 760))
         if os.path.exists(filepath(level)):
             level_data = load(level)
             self.level = level
@@ -31,26 +49,109 @@ class EditorWindow(FloatLayout):
                 self.level = level
             else:
                 self.level = 'levels/' + level
-        self.level_obj = Level()
-        self.level_obj.load(level_data)
+        self.level_obj = Level(level_data)
         level_data.close()
+        self.level_obj.load_tiles()
+
+        self.tool = None
+        self.tool_widgets = []
 
     def build(self):
         self.clear_widgets()
         tiles = self.level_obj.get_tiles()
-        tile_size = 24
         bx, by = 0, 0
+        self.nodes = {}
         for tile_line in tiles:
             bx = 0
             for tile in tile_line:
-                node = Widget(size=(tile_size, tile_size), pos=(bx, by))
-                with node.canvas:
-                    Color(1, 1, 1)
-                    Rectangle(pos=node.pos, size=node.size,
-                            texture=tile.texture)
-                self.add_widget(node)
-                bx += tile_size
-            by += tile_size
+                self._draw_tile((bx, by), tile)
+                bx += TILE_SIZE
+            by += TILE_SIZE
+
+        name = Label(text="Level: [color=00ffcc]%s[/color]" % self.level,
+                markup=True, font_size=24, pos=(500, 360))
+        self.add_widget(name)
+
+        self.draw_toolbar()
+        self.draw_save_button()
+
+    def _draw_tile(self, tile_pos, tile):
+        if tile_pos in self.nodes:
+            self.remove_widget(self.nodes[tile_pos])
+        node = Widget(size=(TILE_SIZE, TILE_SIZE), pos=tile_pos)
+        node.bind(on_touch_down=self.change_node)
+        node.bind(on_touch_move=self.change_node)
+        with node.canvas:
+            Color(1, 1, 1)
+            Rectangle(pos=node.pos, size=node.size, texture=tile.texture)
+        self.add_widget(node)
+        self.nodes[tile_pos] = node
+
+    def draw_toolbar(self):
+        for widget in self.tool_widgets:
+            widget.unbind(on_ref_press=self.change_tool)
+            self.remove_widget(widget)
+        self.tool_widgets = []
+        y = 300
+        for tool in sorted(tool_map):
+            if self.tool == tool:
+                color = '00cccc'
+            else:
+                color = 'cccccc'
+            tool_label = Label(text='[color=%s][ref=%s]%s[/ref][/color]' %
+                    (color, tool, tool), markup=True, font_size=24,
+                    pos=(500, y))
+            y -= 50
+            tool_label.bind(on_ref_press=self.change_tool)
+            self.add_widget(tool_label)
+            self.tool_widgets.append(tool_label)
+
+    def draw_save_button(self):
+        save_label = Label(text='[color=ffffff][ref=save]Save[/ref][/color]',
+                markup=True, font_size=24, pos=(500, -100))
+        save_label.bind(on_ref_press=self.do_save)
+        self.add_widget(save_label)
+
+    def do_save(self, label, ref):
+        try:
+            self.level_obj.validate()
+        except RuntimeError as err:
+            print err
+            popup = Popup(title='Error',
+                    content=Label(text='Level not valid: %s' % err),
+                    size_hint=(.5, .5))
+            popup.open()
+            return
+        save_data = self.level_obj.get_level_data()
+        savefile = file(filepath(self.level), 'w')
+        savefile.write(save_data)
+        savefile.write('\n')
+        savefile.close()
+        popup = Popup(title='Success',
+                content=Label(text='Level saved to %s' % self.level),
+                size_hint=(.5, .5))
+        popup.open()
+
+    def change_tool(self, label, ref):
+        self.tool = ref
+        self.draw_toolbar()
+
+    def contained(self, node, pos):
+        if pos[0] < node.pos[0] or pos[0] > node.pos[0] + TILE_SIZE:
+            return False
+        if pos[1] < node.pos[1] or pos[1] > node.pos[1] + TILE_SIZE:
+            return False
+        return True
+
+    def change_node(self, node, touch):
+        if self.tool and self.contained(node, touch.pos):
+            tile_pos = (node.pos[0] / TILE_SIZE, node.pos[1] / TILE_SIZE)
+            action = tool_map[self.tool]
+            if self.level_obj.get_tile_type(tile_pos) != action:
+                self.level_obj.set_tile_type(tile_pos, action)
+                for map_pos, new_tile in self.level_obj.get_changed_tiles():
+                    node_pos = (map_pos[0] * TILE_SIZE, map_pos[1] * TILE_SIZE)
+                    self._draw_tile(node_pos, new_tile)
 
 
 class EditorApp(App):
@@ -70,10 +171,6 @@ def main():
         level = sys.argv[1]
     else:
         level = 'level1.txt'
-    # Uncomment to silence excessive logging
-    #for hdlr in Logger.handlers[:]:
-    #    if not isinstance(hdlr, LoggerHistory):
-    #        Logger.removeHandler(hdlr)
     EditorApp(level).run()