Tweak android description
[erdslangetjie.git] / erdslangetjie / editor / editor.py
1 import sys
2 import os
3
4 from erdslangetjie.constants import TILE_SIZE
5
6 from kivy.app import App
7 from kivy.uix.widget import Widget
8 from kivy.uix.floatlayout import FloatLayout
9 from kivy.graphics import Color, Rectangle
10 from kivy.uix.label import Label
11 from kivy.uix.popup import Popup
12 from kivy.utils import platform
13 from kivy.config import Config
14
15 from erdslangetjie.data import filepath, load
16 from erdslangetjie.level import (Level, WALL, GATE, BUTTON,
17         FLOOR, ENTRY, EXIT)
18
19
20 if platform() != 'android':
21     Config.set('graphics', 'width', '1326')
22     Config.set('graphics', 'height', '760')
23
24
25 tool_map = {
26         'button': BUTTON,
27         'gate': GATE,
28         'wall': WALL,
29         'floor': FLOOR,
30         'add entry': ENTRY,
31         'add exit': EXIT
32         }
33
34
35 class EditorWindow(FloatLayout):
36
37     def __init__(self, level):
38         super(EditorWindow, self).__init__(size=(1326, 760))
39         if os.path.exists(filepath(level)):
40             level_data = load(level)
41             self.level = level
42         elif os.path.exists(filepath('levels/' + level)):
43             level_data = load('levels/' + level)
44             self.level = 'levels/' + level
45         else:
46             print 'Unable to find %s - treating this as a new level' % level
47             level_data = load('levels/blank.txt')
48             if 'levels/' in level:
49                 self.level = level
50             else:
51                 self.level = 'levels/' + level
52         self.level_obj = Level(level_data, self.level)
53         level_data.close()
54         self.level_obj.load_tiles()
55
56         self.tool = None
57         self.tool_widgets = []
58
59     def build(self):
60         self.clear_widgets()
61         tiles = self.level_obj.get_tiles()
62         bx, by = 0, 0
63         self.nodes = {}
64         for tile_line in tiles:
65             bx = 0
66             for tile in tile_line:
67                 self._draw_tile((bx, by), tile)
68                 bx += TILE_SIZE
69             by += TILE_SIZE
70
71         name = Label(text="Level: [color=00ffcc]%s[/color]" % self.level,
72                 markup=True, font_size=24, pos=(500, 360))
73         self.add_widget(name)
74
75         self.draw_toolbar()
76         self.draw_save_button()
77
78     def _draw_tile(self, tile_pos, tile):
79         if tile_pos in self.nodes:
80             self.remove_widget(self.nodes[tile_pos])
81         node = Widget(size=(TILE_SIZE, TILE_SIZE), pos=tile_pos)
82         node.bind(on_touch_down=self.change_node)
83         node.bind(on_touch_move=self.change_node)
84         with node.canvas:
85             Color(1, 1, 1)
86             Rectangle(pos=node.pos, size=node.size, texture=tile.texture)
87         self.add_widget(node)
88         self.nodes[tile_pos] = node
89
90     def draw_toolbar(self):
91         for widget in self.tool_widgets:
92             widget.unbind(on_ref_press=self.change_tool)
93             self.remove_widget(widget)
94         self.tool_widgets = []
95         y = 300
96         for tool in sorted(tool_map):
97             if self.tool == tool:
98                 color = '00cccc'
99             else:
100                 color = 'cccccc'
101             tool_label = Label(text='[color=%s][ref=%s]%s[/ref][/color]' %
102                     (color, tool, tool), markup=True, font_size=24,
103                     pos=(500, y))
104             y -= 50
105             tool_label.bind(on_ref_press=self.change_tool)
106             self.add_widget(tool_label)
107             self.tool_widgets.append(tool_label)
108
109     def draw_save_button(self):
110         save_label = Label(text='[color=ffffff][ref=save]Save[/ref][/color]',
111                 markup=True, font_size=24, pos=(500, -100))
112         save_label.bind(on_ref_press=self.do_save)
113         self.add_widget(save_label)
114
115     def do_save(self, label, ref):
116         try:
117             self.level_obj.validate()
118         except RuntimeError as err:
119             popup = Popup(title='Error',
120                     content=Label(text='Level not valid: %s' % err),
121                     size_hint=(.5, .5))
122             popup.open()
123             return
124         save_data = self.level_obj.get_level_data()
125         savefile = file(filepath(self.level), 'w')
126         savefile.write(save_data)
127         savefile.write('\n')
128         savefile.close()
129         popup = Popup(title='Success',
130                 content=Label(text='Level saved to %s' % self.level),
131                 size_hint=(.5, .5))
132         popup.open()
133
134     def change_tool(self, label, ref):
135         self.tool = ref
136         self.draw_toolbar()
137
138     def contained(self, node, pos):
139         if pos[0] < node.pos[0] or pos[0] > node.pos[0] + TILE_SIZE:
140             return False
141         if pos[1] < node.pos[1] or pos[1] > node.pos[1] + TILE_SIZE:
142             return False
143         return True
144
145     def change_node(self, node, touch):
146         if self.tool and self.contained(node, touch.pos):
147             tile_pos = (node.pos[0] / TILE_SIZE, node.pos[1] / TILE_SIZE)
148             action = tool_map[self.tool]
149             if self.level_obj.get_tile_type(tile_pos) != action:
150                 self.level_obj.set_tile_type(tile_pos, action)
151                 for map_pos, new_tile in self.level_obj.get_changed_tiles():
152                     node_pos = (map_pos[0] * TILE_SIZE, map_pos[1] * TILE_SIZE)
153                     self._draw_tile(node_pos, new_tile)
154
155
156 class EditorApp(App):
157
158     title = "Bane's Befuddlement Level Editor"
159
160     def __init__(self, level):
161         self.level = level
162         super(EditorApp, self).__init__()
163
164     def build(self):
165         editor = EditorWindow(self.level)
166         editor.build()
167         return editor
168
169
170 def main():
171     if len(sys.argv) > 1:
172         level = sys.argv[1]
173     else:
174         level = 'level1.txt'
175     EditorApp(level).run()
176
177
178 if __name__ == '__main__':
179     main()