1 /*
2 Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY.
11
12 See the COPYING file for more details.
13 */
14
15 /**
16 * Terrain-palette in the editor.
17 */
18
19 #define GETTEXT_DOMAIN "wesnoth-editor"
20
21 #include "editor/palette/terrain_palettes.hpp"
22
23 #include "gettext.hpp"
24 #include "serialization/string_utils.hpp"
25
26 namespace {
27 static t_translation::terrain_code fg_terrain;
28 static t_translation::terrain_code bg_terrain;
29 }
30
31 namespace editor {
32
get_selected_bg_terrain()33 const t_translation::terrain_code& get_selected_bg_terrain() {
34 return bg_terrain;
35 }
36
get_selected_fg_terrain()37 const t_translation::terrain_code& get_selected_fg_terrain() {
38 return fg_terrain;
39 }
40
selected_fg_item() const41 const t_translation::terrain_code& terrain_palette::selected_fg_item() const { return fg_terrain; }
selected_bg_item() const42 const t_translation::terrain_code& terrain_palette::selected_bg_item() const { return bg_terrain; }
43
44
is_valid_terrain(const t_translation::terrain_code & c)45 static bool is_valid_terrain(const t_translation::terrain_code & c) {
46 return !(c == t_translation::VOID_TERRAIN || c == t_translation::FOGGED);
47 }
48
select_bg_item(const std::string & item_id)49 void terrain_palette::select_bg_item(const std::string& item_id) {
50 bg_terrain = item_map_[item_id];
51 editor_palette<t_translation::terrain_code>::select_bg_item(item_id);
52 }
53
select_fg_item(const std::string & item_id)54 void terrain_palette::select_fg_item(const std::string& item_id) {
55 fg_terrain = item_map_[item_id];
56 editor_palette<t_translation::terrain_code>::select_fg_item(item_id);
57 }
58
select_bg_item(const t_translation::terrain_code & terrain)59 void terrain_palette::select_bg_item(const t_translation::terrain_code& terrain) {
60 bg_terrain = terrain;
61 editor_palette<t_translation::terrain_code>::select_bg_item(get_id(terrain));
62 }
63
select_fg_item(const t_translation::terrain_code & terrain)64 void terrain_palette::select_fg_item(const t_translation::terrain_code& terrain) {
65 fg_terrain = terrain;
66 editor_palette<t_translation::terrain_code>::select_fg_item(get_id(terrain));
67 }
68
69
setup(const config & cfg)70 void terrain_palette::setup(const config& cfg)
71 {
72 // Get the available terrains temporary in items
73 t_translation::ter_list items = map().get_terrain_list();
74
75 //move "invalid" items to the end
76 std::stable_partition(items.begin(), items.end(), is_valid_terrain);
77
78 // Get the available groups and add them to the structure
79 std::set<std::string> group_names;
80 for(const config &group : cfg.child_range("terrain_group")) {
81 if(group_names.count(group["id"]) == 0) {
82 config group_cfg;
83 group_cfg["id"] = group["id"];
84 group_cfg["name"] = group["name"];
85
86 group_cfg["icon"] = group["icon"].str();
87 group_cfg["core"] = group["core"];
88 groups_.emplace_back(group_cfg);
89
90 group_names.insert(groups_.back().id);
91 }
92 }
93 for(const config &group : cfg.child_range("editor_group")) {
94 if(group_names.count(group["id"]) == 0) {
95 config group_cfg;
96 group_cfg["id"] = group["id"];
97 group_cfg["name"] = group["name"];
98
99 group_cfg["icon"] = "icons/terrain/terrain_" + group["icon"].str();
100 group_cfg["core"] = group["core"];
101 groups_.emplace_back(group_cfg);
102
103 group_names.insert(groups_.back().id);
104 }
105 }
106
107 std::map<std::string, item_group*> id_to_group;
108 for (item_group& group : groups_) {
109 id_to_group.emplace(group.id, &group);
110 }
111
112 // add the groups for all terrains to the map
113 for (const t_translation::terrain_code& t : items) {
114
115 const terrain_type& t_info = map().get_terrain_info(t);
116 DBG_ED << "Palette: processing terrain " << t_info.name()
117 << "(editor name: '" << t_info.editor_name() << "') "
118 << "(" << t_info.number() << ")"
119 << ": " << t_info.editor_group() << "\n";
120
121 // don't display terrains that were automatically created from base+overlay
122 if (t_info.is_combined()) continue;
123 // nor display terrains that have hide_in_editor=true
124 if (t_info.hide_in_editor()) continue;
125
126 // add the terrain to the requested groups
127 const std::vector<std::string>& keys = utils::split(t_info.editor_group());
128 bool core = false;
129
130 item_map_[get_id(t)] = t;
131
132 for (const std::string& k : keys) {
133 group_map_[k].push_back(get_id(t));
134 nmax_items_ = std::max<int>(nmax_items_, group_map_[k].size());
135 std::map<std::string, item_group*>::iterator i = id_to_group.find(k);
136 if (i != id_to_group.end()) {
137 if (i->second->core) {
138 core = true;
139 }
140 }
141 }
142
143 // A terrain is considered core iff it appears in at least
144 // one core terrain group
145 if (core) {
146 // Add the terrain to the default group
147 group_map_["all"].push_back(get_id(t));
148 nmax_items_ = std::max<int>(nmax_items_, group_map_["all"].size());
149 } else {
150 non_core_items_.insert(get_id(t));
151 }
152
153 }
154
155 // Set the default terrain
156 select_fg_item("regular_mountains");
157 select_bg_item("grassland");
158
159 // Set the default group
160 set_group("all");
161
162 if(active_group().empty()) {
163 ERR_ED << "No items found." << std::endl;
164 }
165 }
166
draw_item(const t_translation::terrain_code & terrain,surface & image,std::stringstream & tooltip_text)167 void terrain_palette::draw_item(const t_translation::terrain_code& terrain,
168 surface& image, std::stringstream& tooltip_text) {
169
170 const t_translation::terrain_code base_terrain = map().get_terrain_info(terrain).default_base();
171
172 //Draw default base for overlay terrains
173 if(base_terrain != t_translation::NONE_TERRAIN) {
174 const std::string base_filename = map().get_terrain_info(base_terrain).editor_image();
175 surface base_image(image::get_image(base_filename));
176
177 if(base_image == nullptr) {
178 tooltip_text << "BASE IMAGE NOT FOUND\n";
179 ERR_ED << "image for terrain : '" << base_filename << "' not found" << std::endl;
180 base_image = image::get_image(game_config::images::missing);
181 if(base_image == nullptr) {
182 ERR_ED << "Placeholder image not found" << std::endl;
183 return;
184 }
185 }
186
187 if(base_image->w != item_size_ || base_image->h != item_size_) {
188 base_image = scale_surface(base_image,
189 item_size_, item_size_);
190 }
191 }
192
193 const std::string filename = map().get_terrain_info(terrain).editor_image();
194 image = image::get_image(filename);
195 if(image == nullptr) {
196 tooltip_text << "IMAGE NOT FOUND\n";
197 ERR_ED << "image for terrain: '" << filename << "' not found" << std::endl;
198 image = image::get_image(game_config::images::missing);
199 if(image == nullptr) {
200 ERR_ED << "Placeholder image not found" << std::endl;
201 return;
202 }
203 }
204
205 if(image->w != item_size_ || image->h != item_size_) {
206 image = scale_surface(image, item_size_, item_size_);
207 }
208
209 tooltip_text << map().get_terrain_editor_string(terrain);
210 if(gui_.get_draw_terrain_codes()) {
211 tooltip_text << " " + font::unicode_em_dash + " " << terrain;
212 }
213 }
214
terrain_palette(editor_display & gui,const config & cfg,editor_toolkit & toolkit)215 terrain_palette::terrain_palette(editor_display &gui, const config& cfg, editor_toolkit &toolkit)
216 //TODO avoid magic numbers
217 : editor_palette<t_translation::terrain_code>(gui, cfg, 36, 4, toolkit)
218 {
219 }
220
get_id(const t_translation::terrain_code & terrain)221 const std::string& terrain_palette::get_id(const t_translation::terrain_code& terrain)
222 {
223 const terrain_type& t_info = map().get_terrain_info(terrain);
224 return t_info.id();
225 }
226
get_help_string()227 std::string terrain_palette::get_help_string()
228 {
229 std::ostringstream msg;
230 msg << _("FG: ") << map().get_terrain_editor_string(selected_fg_item()) << " | "
231 << _("BG: ") << map().get_terrain_editor_string(selected_bg_item());
232 return msg.str();
233 }
234
235
236 }
237