/* * Copyright (C) 2014-2018 Christopho, Solarus - http://www.solarus-games.org * * Solarus Quest Editor is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Solarus Quest Editor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "entities/tile.h" #include "ground_traits.h" #include "map_model.h" #include "quest.h" #include "tileset_model.h" #include namespace SolarusEditor { /** * @brief Creates a normal tile. * @param map The map containing the entity. * @param index Index of the entity in the map. */ Tile::Tile(MapModel& map, const EntityIndex& index) : Tile(map, index, EntityType::TILE) { } /** * @brief Constructor. * @param map The map containing the entity. * @param index Index of the entity in the map. * @param type Concrete type of entity: TILE or DYNAMIC_TILE. */ Tile::Tile(MapModel& map, const EntityIndex& index, EntityType type) : EntityModel(map, index, type) { set_resizable(true); set_has_preferred_layer(true); } /** * @brief Creates a normal tile from a dynamic one. * @param map The map. * @param tile_index index of the dynamic tile to clone. * @return The tile created. It is not on the map yet. */ EntityModelPtr Tile::create_from_dynamic_tile(MapModel& map, const EntityIndex& dynamic_tile_index) { Q_ASSERT(map.get_entity_type(dynamic_tile_index) == EntityType::DYNAMIC_TILE); EntityModelPtr tile = EntityModel::create(map, EntityType::TILE); tile->set_field("pattern", map.get_entity_field(dynamic_tile_index, "pattern")); tile->set_field("tileset", map.get_entity_field(dynamic_tile_index, "tileset")); tile->set_xy(map.get_entity_xy(dynamic_tile_index)); tile->set_size(map.get_entity_size(dynamic_tile_index)); return tile; } /** * @brief Returns the pattern id used by this tile. * @return The pattern id. */ QString Tile::get_pattern_id() const { return get_field("pattern").toString(); } /** * @brief Sets the pattern id used by this tile. * @param pattern_id The new pattern id. */ void Tile::set_pattern_id(const QString& pattern_id) { set_field("pattern", pattern_id); } /** * @brief Returns the tileset used by this tile. * @return The tileset. */ const TilesetModel* Tile::get_tileset() const { QString tileset_id = get_field("tileset").toString(); if (tileset_id.isEmpty()) { return get_map().get_tileset_model(); } return get_quest().get_tileset(tileset_id); } /** * @copydoc EntityModel::notify_field_changed */ void Tile::notify_field_changed(const QString& key, const QVariant& value) { EntityModel::notify_field_changed(key, value); if (key == "pattern" || key == "tileset") { update_pattern(); } } /** * @brief Updates the representation of the tile. * * This function should be called when the pattern changes. */ void Tile::update_pattern() { const TilesetModel* tileset = get_tileset(); if (tileset != nullptr) { int pattern_index = tileset->id_to_index(get_pattern_id()); if (pattern_index != -1) { // Update the resizing rules. set_base_size(tileset->get_pattern_frame(pattern_index).size()); set_resize_mode(get_pattern_resize_mode()); // Update the preferred initial layer. set_preferred_layer(tileset->get_pattern_default_layer(pattern_index)); // Update the traversable property. Ground ground = tileset->get_pattern_ground(pattern_index); set_traversable(GroundTraits::is_traversable(ground)); } } // Invalidate the cached image. pattern_image = QPixmap(); } /** * @brief Computes the resize mode for this tile from its pattern. * @return The appropriate resize mode. */ ResizeMode Tile::get_pattern_resize_mode() const { const TilesetModel* tileset = get_tileset(); if (tileset == nullptr) { return ResizeMode::MULTI_DIMENSION_ALL; } int pattern_index = tileset->id_to_index(get_pattern_id()); if (pattern_index == -1) { return ResizeMode::MULTI_DIMENSION_ALL; } switch (tileset->get_pattern_repeat_mode(pattern_index)) { case PatternRepeatMode::ALL: return ResizeMode::MULTI_DIMENSION_ALL; case PatternRepeatMode::HORIZONTAL: return ResizeMode::HORIZONTAL_ONLY; case PatternRepeatMode::VERTICAL: return ResizeMode::VERTICAL_ONLY; case PatternRepeatMode::NONE: return ResizeMode::NONE; } return ResizeMode::MULTI_DIMENSION_ALL; } /** * @copydoc EntityModel::draw */ void Tile::draw(QPainter& painter) const { if (pattern_image.isNull()) { // Lazily create the image. const TilesetModel* tileset = get_tileset(); if (tileset != nullptr) { int pattern_index = tileset->id_to_index(get_pattern_id()); if (pattern_index == -1) { // The pattern no longer exists: fallback to a generic tile icon. EntityModel::draw(painter); return; } int pattern_width = tileset->get_pattern_frame(pattern_index).width(); pattern_image = tileset->get_pattern_image(pattern_index).scaledToWidth(pattern_width); } } painter.drawTiledPixmap(0, 0, get_width(), get_height(), pattern_image); } /** * @copydoc EntityModel::notify_tileset_changed */ void Tile::notify_tileset_changed(const QString& tileset_id) { EntityModel::notify_tileset_changed(tileset_id); update_pattern(); } }