Less buggy Kivy 1.7 hackery
[erdslangetjie.git] / erdslangetjie / editor / editor.py
index 08c5f6b32bf987a7a81a4c7946540a7624a949fa..3cf3d6d9ca6de4da6adb28f52a9af7b924006d70 100644 (file)
@@ -1,23 +1,41 @@
 import sys
 import os
 import sys
 import os
-import kivy
 
 
-kivy.require('1.6.0')
+from erdslangetjie.constants import TILE_SIZE
 
 from kivy.app import App
 
 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.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.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):
 
 
 class EditorWindow(FloatLayout):
 
     def __init__(self, level):
-        super(EditorWindow, self).__init__(size=(648, 480))
+        super(EditorWindow, self).__init__(size=(1326, 760))
         if os.path.exists(filepath(level)):
             level_data = load(level)
             self.level = level
         if os.path.exists(filepath(level)):
             level_data = load(level)
             self.level = level
@@ -31,30 +49,114 @@ class EditorWindow(FloatLayout):
                 self.level = level
             else:
                 self.level = 'levels/' + level
                 self.level = level
             else:
                 self.level = 'levels/' + level
-        self.level_obj = Level(level_data)
+        self.level_obj = Level(level_data, self.level)
         level_data.close()
         self.level_obj.load_tiles()
 
         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()
     def build(self):
         self.clear_widgets()
         tiles = self.level_obj.get_tiles()
-        tile_size = 24
         bx, by = 0, 0
         bx, by = 0, 0
+        self.nodes = {}
         for tile_line in tiles:
             bx = 0
             for tile in tile_line:
         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:
+            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):
 
 
 
 class EditorApp(App):
 
+    title = "Bane's Befuddlement Level Editor"
+
     def __init__(self, level):
         self.level = level
         super(EditorApp, self).__init__()
     def __init__(self, level):
         self.level = level
         super(EditorApp, self).__init__()
@@ -70,10 +172,6 @@ def main():
         level = sys.argv[1]
     else:
         level = 'level1.txt'
         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()
 
 
     EditorApp(level).run()