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