1 /*
2  * Copyright (C) 2014-2018 Christopho, Solarus - http://www.solarus-games.org
3  *
4  * Solarus Quest Editor is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * Solarus Quest Editor is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 #ifndef SOLARUSEDITOR_ENTITY_MODEL_H
18 #define SOLARUSEDITOR_ENTITY_MODEL_H
19 
20 #include "entity_traits.h"
21 #include "resize_mode.h"
22 #include "sprite_model.h"
23 #include <QPointer>
24 
25 namespace SolarusEditor {
26 
27 class MapModel;
28 class Quest;
29 class QuestDatabase;
30 class TilesetModel;
31 
32 using SubtypeList = QList<QPair<QString, QString>>;
33 
34 /**
35  * @brief Model of a map entity.
36  *
37  * This class wraps an entity from the Solarus library and
38  * adds all useful information about how to represent and modify it in the
39  * editor.
40  * An EntityModel can represent an entity on the map or an entity that is not
41  * on the map yet.
42  *
43  * Each type of entity is a subclass of EntityModel.
44  */
45 class EntityModel {
46 
47 public:
48 
49   virtual ~EntityModel() = default;
50 
51   static EntityModelPtr create(
52       MapModel& map, EntityType type);
53   static EntityModelPtr create(
54       MapModel& map, const QString& entity_string);
55   static EntityModelPtr create(
56       MapModel& map, const EntityIndex& index);
57   static EntityModelPtr clone(
58       MapModel& map, const EntityIndex& index);
59   EntityModelPtr clone() const;
60 
61   const MapModel& get_map() const;
62   MapModel& get_map();
63   QString get_map_tileset_id() const;
64   const TilesetModel* get_map_tileset() const;
65   TilesetModel* get_map_tileset();
66   const Quest& get_quest() const;
67   const QuestDatabase& get_database() const;
68 
69   // Index on the map.
70   EntityIndex get_index() const;
71   bool is_on_map() const;
72   void added_to_map(const EntityIndex& index);
73   void about_to_be_removed_from_map();
74   void index_changed(const EntityIndex& index);
75 
76   EntityType get_type() const;
77   QString get_type_name() const;
78   bool is_dynamic() const;
79 
80   const Solarus::EntityData& get_entity() const;
81   Solarus::EntityData& get_entity();
82 
83   // Access data.
84   bool has_name() const;
85   QString get_name() const;
86   void set_name(const QString& name);
87   void ensure_valid_on_map();
88   void ensure_name_unique();
89   void ensure_default_destination_unique();
90   int get_layer() const;
91   void set_layer(int layer);
92   QPoint get_xy() const;
93   void set_xy(const QPoint& xy);
94   QPoint get_top_left() const;
95   void set_top_left(const QPoint& top_left);
96   QPoint get_bottom_right() const;
97   void set_bottom_right(const QPoint& bottom_right);
98   QPoint get_center() const;
99   void set_center(const QPoint& center);
100   bool has_origin_fields() const;
101   QPoint get_origin() const;
102   void set_origin(const QPoint& origin);
103   bool has_size_fields() const;
104   int get_width() const;
105   void set_width(int width);
106   int get_height() const;
107   void set_height(int height);
108   QSize get_size() const;
109   void set_size(const QSize& size);
110   QRect get_bounding_box() const;
111   bool get_has_preferred_layer() const;
112   int get_preferred_layer() const;
113   bool has_direction_field() const;
114   bool is_no_direction_allowed() const;
115   QString get_no_direction_text() const;
116   int get_num_directions() const;
117   int get_direction() const;
118   void set_direction(int direction);
119   bool is_enabled_at_start() const;
120   void set_enabled_at_start(bool enabled_at_start);
121   bool has_subtype_field() const;
122   SubtypeList get_existing_subtypes() const;
123   QString get_subtype() const;
124   void set_subtype(const QString& subtype);
125   bool has_field(const QString& key) const;
126   bool is_field_optional(const QString& key) const;
127   bool is_field_unset(const QString& key) const;
128   QVariant get_field(const QString& key) const;
129   void set_field(const QString& key, const QVariant& value);
130   int get_user_property_count() const;
131   QPair<QString, QString> get_user_property(int index) const;
132   bool set_user_property(int index, const QPair<QString, QString>& property);
133   bool add_user_property(const QPair<QString, QString>& property);
134   bool remove_user_property(int index);
135   static bool is_valid_user_property_key(const QString &key);
136   bool is_traversable() const;
137   QString to_string() const;
138 
139   // Resizing from the editor.
140   bool is_resizable() const;
141   ResizeMode get_resize_mode() const;
142   QSize get_base_size() const;
143   bool is_size_valid() const;
144   virtual bool is_size_valid(const QSize& size) const;
145   QSize get_closest_valid_size(const QSize& size) const;
146   virtual QSize get_valid_size() const;
147 
148   // Displaying in the editor.
149   virtual void draw(QPainter& painter) const;
150   virtual void notify_tileset_changed(const QString& tileset_id);
151 
152   void reload_sprite();
153 
154 protected:
155 
156   /**
157    * @brief Describes how to draw an entity as a sprite.
158    */
159   struct DrawSpriteInfo {
160 
161     bool enabled = true;  // false means not drawn as a sprite.
162     QString sprite_id;    // Only used if there is no "sprite" field.
163     QString animation;    // Animation for sprite_id (empty means default).
164     int direction = 0;    // Direction of the sprite.
165                           // Only used if there is no "direction" field.
166     int frame = 0;        // Index of the frame to show. If negative,
167                           // we count from the end (-1 is the last frame).
168     bool tiled = false;   // Tiled or only once at origin point.
169   };
170 
171   /**
172    * @brief Describes how to draw an entity as a shape.
173    *
174    * The shape is filled with a background color or a pixmap,
175    * or both if the pixmap is not tiled but centered,
176    * and may have a border with two black lines and a color between them.
177    * For now the shape is always rectangular.
178    */
179   struct DrawShapeInfo {
180 
181     bool enabled = false;  // false means not drawn as a shape.
182     QColor background_color;
183     QColor between_border_color;
184     QPixmap pixmap;
185     bool tiled_pixmap = false;  // Tiled or centered.
186   };
187 
188   /**
189    * @brief A rectangle region of an image file.
190    */
191   struct SubImage {
192     QString file_name;
193     QRect src_rect;  // An invalid rect means the whole image.
194     mutable QPixmap pixmap;
195   };
196 
197   /**
198    * @brief Describes how to draw an entity as a fixed image.
199    *
200    * If nothing is specified, the image will be a generic icon for the entity
201    * type.
202    */
203   struct DrawImageInfo {
204     SubImage image_no_direction;
205     QList<SubImage> images_by_direction;
206     double scale = 1.0;  // If 2.0, the image will have a resolution twice better.
207   };
208 
209   EntityModel(MapModel& map, const EntityIndex& index, EntityType type);
210 
211   void set_resizable(bool resizable);
212   void set_resize_mode(ResizeMode resize_mode);
213   void set_base_size(const QSize& base_size);
214 
215   void set_has_preferred_layer(bool has_preferred_layer);
216   void set_preferred_layer(int preferred_layer);
217 
218   void set_num_directions(int num_directions);
219   void set_no_direction_allowed(bool no_direction_allowed);
220   void set_no_direction_text(const QString& no_direction_text);
221 
222   void set_traversable(bool traversable);
223 
224   void set_existing_subtypes(const SubtypeList& subtypes);
225 
226   virtual void notify_name_changed(const QString& name);
227   virtual void notify_field_changed(const QString& key, const QVariant& value);
228   virtual void set_initial_values();
229 
230   const DrawSpriteInfo& get_draw_sprite_info() const;
231   void set_draw_sprite_info(const DrawSpriteInfo& draw_sprite_info);
232   const DrawShapeInfo& get_draw_shape_info() const;
233   void set_draw_shape_info(const DrawShapeInfo& draw_shape_info);
234   const DrawImageInfo& get_draw_image_info() const;
235   void set_draw_image_info(const DrawImageInfo& draw_shape_info);
236 
237   bool draw_as_sprite(QPainter& painter) const;
238   bool draw_as_sprite(QPainter& painter,
239                       const QString& sprite_id,
240                       const QString& animation,
241                       int direction,
242                       int frame) const;
243   bool draw_as_shape(QPainter& painter) const;
244   bool draw_as_image(QPainter& painter) const;
245   bool draw_as_image(QPainter& painter, const SubImage& image) const;
246   bool draw_as_icon(QPainter& painter) const;
247 
248 private:
249 
250   static EntityModelPtr create(
251       MapModel& map, const EntityIndex& index, EntityType type);
252   void set_entity(const Solarus::EntityData& entity);
253 
254   QPointer<MapModel> map;         /**< The map this entity belongs to
255                                    * (could be a reference but we want operator=). */
256   EntityIndex index;              /**< Index of this entity in the map.
257                                    * When invalid, the entity is not added to the map yet. */
258   Solarus::EntityData stub;       /**< Stub of entity, used before it gets added to the map. */
259   QString name;                   /**< Name of the entity. */
260   QPoint origin;                  /**< Origin point of the entity relative to its top-left corner. */
261   QSize size;                     /**< Size of the entity for the editor. */
262   QSize base_size;                /**< Reference size when resizing. */
263   ResizeMode resize_mode;         /**< How the entity can be resized. */
264   bool has_preferred_layer;       /**< Whether the entity has a preferred layer when added to the map. */
265   int preferred_layer;            /**< The preferred layer if has_preferred_layer is true. */
266   int num_directions;             /**< Number of possible directions (except the possible special one -1). */
267   bool no_direction_allowed;      /**< Whether the special no-value -1 is an allowed direction. */
268   QString no_direction_text;      /**< The text to show in a GUI for the special no-value -1 (if allowed). */
269   bool traversable;               /**< Whether this entity is assumed to be traversable. */
270   SubtypeList subtypes;           /**< Existing subtypes of this entity type. */
271 
272   // Displaying.
273   DrawSpriteInfo
274       draw_sprite_info;           /**< How to draw the entity
275                                    * when it is drawn as a sprite. */
276   mutable std::unique_ptr<SpriteModel>
277       sprite_model;               /**< Sprite to show when the entity is drawn
278                                    * as a sprite. */
279   mutable QPixmap sprite_image;   /**< Fixed image from the sprite. */
280   DrawShapeInfo draw_shape_info;  /**< Shape to use when the entity is drawn as
281                                    * a shape. */
282   DrawImageInfo draw_image_info;  /**< Subimage to use when the entity is
283                                    * drawn as a fixed image from a file. */
284   mutable QPixmap icon;           /**< Icon to use when the entity is drawn as
285                                    * an icon. */
286 };
287 
288 }
289 
290 #endif
291