1 #ifndef EDITOR_HPP_INCLUDED
2 #define EDITOR_HPP_INCLUDED
3 #ifndef NO_EDITOR
4 
5 #include <boost/function.hpp>
6 #include <boost/scoped_ptr.hpp>
7 #include <stack>
8 #include <vector>
9 
10 #include "external_text_editor.hpp"
11 #include "geometry.hpp"
12 #include "key.hpp"
13 #include "level.hpp"
14 #include "level_object.hpp"
15 #include "preferences.hpp"
16 #include "stats.hpp"
17 
18 static const int EDITOR_MENUBAR_HEIGHT = 40;
19 static const int EDITOR_SIDEBAR_WIDTH = 220;
20 
21 namespace gui {
22 class dialog;
23 }
24 
25 namespace editor_dialogs {
26 class character_editor_dialog;
27 class editor_layers_dialog;
28 class property_editor_dialog;
29 class segment_editor_dialog;
30 class tileset_editor_dialog;
31 class custom_object_dialog;
32 class hex_tileset_editor_dialog;
33 }
34 
35 class code_editor_dialog;
36 
37 class editor_menu_dialog;
38 class editor_mode_dialog;
39 
40 class editor
41 {
42 public:
43 	//A manager which should be scoped around creation of editors.
44 	struct manager {
45 		~manager();
46 	};
47 
48 	static editor* get_editor(const char* level_cfg);
49 	static void edit(const char* level_cfg, int xpos=-1, int ypos=-1);
50 	static std::string last_edited_level();
51 
52 	static int sidebar_width();
53 	static int codebar_height();
54 
55 	editor(const char* level_cfg);
56 	~editor();
57 
58 	void setup_for_editing();
59 	void edit_level();
60 
61 	void process();
62 	bool handle_event(const SDL_Event& event, bool swallowed);
63 	void handle_scrolling();
64 
xpos() const65 	int xpos() const { return xpos_; }
ypos() const66 	int ypos() const { return ypos_; }
67 
xres() const68 	int xres() const { return xres_; }
yres() const69 	int yres() const { return yres_; }
70 
71 	void set_pos(int x, int y);
72 
73 	typedef boost::intrusive_ptr<level> level_ptr;
74 	void set_playing_level(level_ptr lvl);
75 	void toggle_active_level();
76 
77 	void load_stats();
78 	void show_stats();
79 	void download_stats();
80 
81 	struct tileset {
82 		static void init(variant node);
83 		explicit tileset(variant node);
84 		std::string category;
85 		std::string type;
86 		int zorder;
87 		int x_speed;
88 		int y_speed;
89 		bool sloped;
90 		variant node_info;
91 
92 		boost::shared_ptr<tile_map> preview() const;
93 	private:
94 		mutable boost::shared_ptr<tile_map> preview_;
95 	};
96 
97 	struct enemy_type {
98 		enemy_type(const std::string& type, const std::string& category, variant frame_info);
99 		variant node;
100 		std::string category;
101 		std::string help;
102 
103 		const entity_ptr& preview_object() const;
104 		const boost::shared_ptr<const frame>& preview_frame() const;
105 
106 	private:
107 		mutable entity_ptr preview_object_;
108 		mutable boost::shared_ptr<const frame> preview_frame_;
109 		variant frame_info_;
110 	};
111 
112 	struct tile_selection {
emptyeditor::tile_selection113 		bool empty() const { return tiles.empty(); }
114 		std::vector<point> tiles;
115 	};
116 
selection() const117 	const tile_selection& selection() const { return tile_selection_; }
118 
119 	const std::vector<tileset>& all_tilesets() const;
get_tileset() const120 	int get_tileset() const { return cur_tileset_; }
121 	void set_tileset(int index);
122 
get_hex_tileset() const123 	int get_hex_tileset() const { return cur_hex_tileset_; }
124 	void set_hex_tileset(int index);
125 
126 	std::vector<enemy_type>& all_characters() const;
127 
get_object() const128 	int get_object() const { return cur_object_; }
129 	void set_object(int index);
130 
131 	enum EDIT_TOOL { TOOL_ADD_RECT, TOOL_SELECT_RECT, TOOL_MAGIC_WAND, TOOL_PENCIL, TOOL_PICKER, TOOL_ADD_OBJECT, TOOL_SELECT_OBJECT, TOOL_EDIT_SEGMENTS, TOOL_EDIT_HEXES, NUM_TOOLS };
132 	EDIT_TOOL tool() const;
133 	void change_tool(EDIT_TOOL tool);
134 
get_level()135 	level& get_level() { return *lvl_; }
get_level() const136 	const level& get_level() const { return *lvl_; }
137 
get_level_list() const138 	std::vector<level_ptr> get_level_list() const { return levels_; }
139 
140 	void save_level();
141 	void save_level_as(const std::string& filename);
142 	void quit();
143 	bool confirm_quit(bool allow_cancel=true);
144 	void zoom_in();
145 	void zoom_out();
zoom() const146 	int zoom() const { return zoom_; }
147 
148 	void undo_command();
149 	void redo_command();
150 
close()151 	void close() { done_ = true; }
152 
153 	void edit_level_properties();
154 	void create_new_module();
155 	void edit_module_properties();
156 	void create_new_object();
157 	void edit_shaders();
158 
159 	//make the selected objects part of a group
160 	void group_selection();
161 
face_right() const162 	bool face_right() const { return face_right_; }
163 
164 	//switch the current facing.
165 	void toggle_facing();
166 
167 	void toggle_upside_down();
168 
169 	void duplicate_selected_objects();
170 
171 	void run_script(const std::string& id);
172 
173 	//function which gets the expected layer at which a certain tile id appears.
174 	int get_tile_zorder(const std::string& tile_id) const;
175 	void add_tile_rect(int zorder, const std::string& tile_id, int x1, int y1, int x2, int y2);
176 
177 	enum EXECUTABLE_COMMAND_TYPE { COMMAND_TYPE_DEFAULT, COMMAND_TYPE_DRAG_OBJECT };
178 
179 	//function to execute a command which will go into the undo/redo list.
180 	//normally any time the editor mutates the level, it should be done
181 	//through this function
182 	void execute_command(boost::function<void()> command, boost::function<void()> undo, EXECUTABLE_COMMAND_TYPE type=COMMAND_TYPE_DEFAULT);
183 
184 	//functions to begin and end a group of commands. This is used when we
185 	//are going to execute a bunch of commands, and from the point of view of
186 	//undoing, they should be viewed as a single operation.
187 	//When end_command_group() is called, all calls to execute_command since
188 	//the corresponding call to begin_command_group() will be rolled up
189 	//into a single command.
190 	//
191 	//These functions are re-entrant.
192 	void begin_command_group();
193 	void end_command_group();
194 
195 	void draw_gui() const;
196 
197 	//We are currently playing a level we are editing, and we want
198 	//to reset it to its initial state.
199 	void reset_playing_level(bool keep_player=true);
200 
201 	void toggle_pause() const;
202 	void toggle_code();
203 
204 	bool has_keyboard_focus() const;
205 
206 	void start_adding_points(const std::string& field_name);
adding_points() const207 	const std::string& adding_points() const { return adding_points_; }
208 
level_state_id() const209 	int level_state_id() const { return level_changed_; }
210 
211 	void mutate_object_value(level_ptr lvl, entity_ptr e, const std::string& value, variant new_value);
212 
done() const213 	bool done() const { return done_; }
214 
215 private:
216 	editor(const editor&);
217 	void operator=(const editor&);
218 
219 	//Are we editing a level that is actually being played and in motion?
220 	bool editing_level_being_played() const;
221 
222 	void reset_dialog_positions();
223 
224 	void handle_mouse_button_down(const SDL_MouseButtonEvent& event);
225 	void handle_mouse_button_up(const SDL_MouseButtonEvent& event);
226 	void handle_key_press(const SDL_KeyboardEvent& key);
227 
228 	void handle_object_dragging(int mousex, int mousey);
229 	void handle_drawing_rect(int mousex, int mousey);
230 
231 	void process_ghost_objects();
232 	void remove_ghost_objects();
233 	void draw() const;
234 	void draw_selection(int xoffset, int yoffset) const;
235 
236 	void add_hex_tile_rect(int x1, int y1, int x2, int y2);
237 	void remove_hex_tile_rect(int x1, int y1, int x2, int y2);
238 
239 	void add_tile_rect(int x1, int y1, int x2, int y2);
240 	void remove_tile_rect(int x1, int y1, int x2, int y2);
241 	void select_tile_rect(int x1, int y1, int x2, int y2);
242 	void select_magic_wand(int xpos, int ypos);
243 
244 	void set_selection(const tile_selection& s);
245 
246 	void execute_shift_object(entity_ptr e, int dx, int dy);
247 
248 	void move_object(level_ptr lvl, entity_ptr e, int delta_x, int delta_y);
249 
editing_objects() const250 	bool editing_objects() const { return tool_ == TOOL_ADD_OBJECT || tool_ == TOOL_SELECT_OBJECT; }
editing_tiles() const251 	bool editing_tiles() const { return !editing_objects(); }
252 
253 	//functions which add and remove an object from a level, as well as
254 	//sending the object appropriate events.
255 	void add_multi_object_to_level(level_ptr lvl, entity_ptr e);
256 	void add_object_to_level(level_ptr lvl, entity_ptr e);
257 	void remove_object_from_level(level_ptr lvl, entity_ptr e);
258 
259 	void generate_mutate_commands(entity_ptr e, const std::string& attr, variant new_value,
260 	                              std::vector<boost::function<void()> >& undo,
261 	                              std::vector<boost::function<void()> >& redo);
262 
263 	void generate_remove_commands(entity_ptr e, std::vector<boost::function<void()> >& undo, std::vector<boost::function<void()> >& redo);
264 
265 	CKey key_;
266 
267 	level_ptr lvl_;
268 
269 	std::vector<level_ptr> levels_;
270 	int zoom_;
271 	int xpos_, ypos_;
272 	int anchorx_, anchory_;
273 
274 	// X and Y resolution of the editor, 0 means use default.
275 	int xres_, yres_;
276 
277 	//if we are dragging an entity around, this marks the position from
278 	//which the entity started the drag.
279 	int selected_entity_startx_, selected_entity_starty_;
280 	std::string filename_;
281 
282 	//If we are currently adding points to an object, this is non-empty
283 	//and has the name of the field we're adding points to. The object
284 	//being edited will always be lvl.editor_highlight()
285 	std::string adding_points_;
286 
287 	EDIT_TOOL tool_;
288 	bool done_;
289 	bool face_right_;
290 	bool upside_down_;
291 	int cur_tileset_;
292 	int cur_hex_tileset_;
293 
294 	int cur_object_;
295 
296 	tile_selection tile_selection_;
297 
298 	boost::scoped_ptr<editor_menu_dialog> editor_menu_dialog_;
299 	boost::scoped_ptr<editor_mode_dialog> editor_mode_dialog_;
300 	boost::scoped_ptr<editor_dialogs::character_editor_dialog> character_dialog_;
301 	boost::scoped_ptr<editor_dialogs::editor_layers_dialog> layers_dialog_;
302 	boost::scoped_ptr<editor_dialogs::property_editor_dialog> property_dialog_;
303 	boost::scoped_ptr<editor_dialogs::tileset_editor_dialog> tileset_dialog_;
304 	boost::scoped_ptr<editor_dialogs::hex_tileset_editor_dialog> hex_tileset_dialog_;
305 
306 	boost::scoped_ptr<editor_dialogs::segment_editor_dialog> segment_dialog_;
307 
308 	boost::scoped_ptr<code_editor_dialog> code_dialog_;
309 
310 	external_text_editor_ptr external_code_editor_;
311 
312 	void set_code_file();
313 
314 	gui::dialog* current_dialog_;
315 
316 	//if the mouse is currently down, drawing a rect.
317 	bool drawing_rect_, dragging_;
318 
319 	struct executable_command {
320 		boost::function<void()> redo_command;
321 		boost::function<void()> undo_command;
322 		EXECUTABLE_COMMAND_TYPE type;
323 	};
324 
325 	std::vector<executable_command> undo_, redo_;
326 
327 	//a temporary undo which is used for when we execute commands on
328 	//a temporary basis -- e.g. for a preview -- so we can later undo them.
329 	boost::scoped_ptr<executable_command> tmp_undo_;
330 
331 	//indexes into undo_ which records the beginning of the current 'group'
332 	//of commands. When begin_command_group() is called, a value is added
333 	//set to the size of undo_. When end_command_group() is called, all
334 	//commands with index > the top value are aggregated into a single command,
335 	//and the top value is popped.
336 	std::stack<int> undo_commands_groups_;
337 
338 	std::vector<entity_ptr> ghost_objects_;
339 
340 	int level_changed_;
341 	int selected_segment_;
342 
343 	int prev_mousex_, prev_mousey_;
344 };
345 
346 struct editor_resolution_manager : private preferences::editor_screen_size_scope
347 {
348 	static bool is_active();
349 	explicit editor_resolution_manager(int xres, int yres);
350 	~editor_resolution_manager();
351 
352 	int original_width_, original_height_;
353 };
354 
355 #endif // !NO_EDITOR
356 #endif
357