The Battle for Wesnoth  1.17.14+dev
editor_palettes.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2022
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #define GETTEXT_DOMAIN "wesnoth-editor"
17 
19 
20 #include "gettext.hpp"
21 #include "font/text_formatting.hpp"
22 #include "tooltips.hpp"
23 #include "overlay.hpp"
24 #include "filesystem.hpp"
25 #include "units/types.hpp"
26 
28 
29 namespace editor {
30 
31 template<class Item>
33 {
35  for (gui::widget& b : buttons_) {
36  h.push_back(&b);
37  }
38  return h;
39 }
40 
41 template<class Item>
43 {
44  auto pos = items.erase(items.begin() + i);
45 
46  std::vector<config> groups;
47  const std::vector<item_group>& item_groups = get_groups();
48 
49  for (std::size_t mci = 0; mci < item_groups.size(); ++mci) {
50  std::string groupname = item_groups[mci].name;
51  if (groupname.empty()) {
52  groupname = _("(Unknown Group)");
53  }
54  std::string img = item_groups[mci].icon + "_30";
55  if (mci == active_group_index()) {
56  std::string pressed_img = img + "-pressed.png";
57  if(!filesystem::get_binary_file_location("images", pressed_img).empty()) {
58  img = pressed_img;
59  } else {
60  img += ".png~CS(70,70,0)";
61  }
62  } else {
63  img += ".png";
64  }
65 
66  groups.emplace_back(
67  "label", groupname,
68  "icon", img
69  );
70  }
71 
72  items.insert(pos, groups.begin(), groups.end());
73 }
74 
75 template<class Item>
77 {
78  bool scrolled = false;
79  if(can_scroll_up()) {
80  // This should only be reachable with items_start_ being a multiple of columns_, but guard against underflow anyway.
81  if(items_start_ < columns_) {
82  items_start_ = 0;
83  } else {
84  items_start_ -= columns_;
85  }
86  scrolled = true;
87  set_dirty(true);
88  }
89  return scrolled;
90 }
91 
92 template<class Item>
94 {
95  return (items_start_ != 0);
96 }
97 
98 template<class Item>
100 {
101  return (items_start_ + buttons_.size() < num_items());
102 }
103 
104 template<class Item>
106 {
107  bool scrolled = false;
108  if(can_scroll_down()) {
109  items_start_ += columns_;
110  scrolled = true;
111  set_dirty(true);
112  }
113  return scrolled;
114 }
115 
116 template<class Item>
117 void editor_palette<Item>::set_group(const std::string& id)
118 {
119  assert(!id.empty());
120 
121  bool found = false;
122  for (const item_group& group : groups_) {
123  if (group.id == id) {
124  found = true;
125  std::shared_ptr<gui::button> palette_menu_button = gui_.find_menu_button("menu-editor-terrain");
126  if (palette_menu_button) {
127  //palette_menu_button->set_label(group.name);
128  palette_menu_button->set_tooltip_string(group.name);
129  palette_menu_button->set_overlay(group.icon);
130  }
131  }
132  }
133  assert(found);
134 
135  active_group_ = id;
136 
137  if(active_group().empty()) {
138  ERR_ED << "No items found in group with the id: '" << id << "'.";
139  }
140 }
141 
142 template<class Item>
144 {
145  assert(groups_.size() > index);
146  set_group(groups_[index].id);
147 }
148 
149 template<class Item>
151 {
152  assert(!active_group_.empty());
153 
154  for (std::size_t i = 0 ; i < groups_.size(); i++) {
155  if (groups_[i].id == active_group_)
156  return i;
157  }
158 
159  return static_cast<std::size_t>(-1);
160 }
161 
162 template<class Item>
163 void editor_palette<Item>::adjust_size(const SDL_Rect& target)
164 {
165  const int items_fitting = (target.h / item_space_) * columns_;
166  // This might be called while the palette is not visible onscreen.
167  // If that happens, no items will fit and we'll have a negative number here.
168  // Just skip it in that case.
169  //
170  // New items can be added via the add_item function, so this creates as
171  // many buttons as can fit, even if there aren't yet enough items to need
172  // that many buttons.
173  if(items_fitting > 0) {
174  const auto buttons_needed = static_cast<std::size_t>(items_fitting);
175  if(buttons_.size() != buttons_needed) {
176  buttons_.resize(buttons_needed, gui::tristate_button(this));
177  }
178  }
179 
180  // Update button locations and sizes. Needs to be done even if the number of buttons hasn't changed,
181  // because adjust_size() also handles moving left and right when the window's width is changed.
182  SDL_Rect dstrect;
183  dstrect.w = item_size_ + 2;
184  dstrect.h = item_size_ + 2;
185  for(std::size_t i = 0; i < buttons_.size(); ++i) {
186  dstrect.x = target.x + (i % columns_) * item_space_;
187  dstrect.y = target.y + (i / columns_) * item_space_;
188  buttons_[i].set_location(dstrect);
189  }
190 
191  set_location(target);
192  set_dirty(true);
193  gui_.set_help_string(get_help_string());
194 }
195 
196 template<class Item>
197 void editor_palette<Item>::select_fg_item(const std::string& item_id)
198 {
199  if (selected_fg_item_ != item_id) {
200  selected_fg_item_ = item_id;
201  set_dirty();
202  }
203  gui_.set_help_string(get_help_string());
204 }
205 
206 template<class Item>
207 void editor_palette<Item>::select_bg_item(const std::string& item_id)
208 {
209  if (selected_bg_item_ != item_id) {
210  selected_bg_item_ = item_id;
211  set_dirty();
212  }
213  gui_.set_help_string(get_help_string());
214 }
215 
216 template<class Item>
218 {
219  std::swap(selected_fg_item_, selected_bg_item_);
220  select_fg_item(selected_fg_item_);
221  select_bg_item(selected_bg_item_);
222  set_dirty();
223 }
224 
225 template<class Item>
227 {
228  return group_map_[active_group_].size();
229 }
230 
231 
232 template<class Item>
233 void editor_palette<Item>::hide(bool hidden)
234 {
235  widget::hide(hidden);
236 
237  if (!hidden) {
238  gui_.set_help_string(get_help_string());
239  } else {
240  gui_.clear_help_string();
241  }
242 
243  for (gui::widget& w : buttons_) {
244  w.hide(hidden);
245  }
246 }
247 
248 
249 template<class Item>
250 bool editor_palette<Item>::is_selected_fg_item(const std::string& id)
251 {
252  return selected_fg_item_ == id;
253 }
254 
255 template<class Item>
256 bool editor_palette<Item>::is_selected_bg_item(const std::string& id)
257 {
258  return selected_bg_item_ == id;
259 }
260 
261 template<class Item>
263 {
264  if (!dirty()) {
265  return;
266  }
267 
268  toolkit_.set_mouseover_overlay(gui_);
269 
270  std::shared_ptr<gui::button> palette_menu_button = gui_.find_menu_button("menu-editor-terrain");
271  if(palette_menu_button) {
272  t_string& name = groups_[active_group_index()].name;
273  std::string& icon = groups_[active_group_index()].icon;
274 
275  palette_menu_button->set_tooltip_string(name);
276  palette_menu_button->set_overlay(icon);
277  }
278 
279  // The hotkey system will automatically enable and disable the buttons when it runs, but it doesn't
280  // get triggered when handling mouse-wheel scrolling. Therefore duplicate that functionality here.
281  std::shared_ptr<gui::button> upscroll_button = gui_.find_action_button("upscroll-button-editor");
282  if(upscroll_button)
283  upscroll_button->enable(can_scroll_up());
284  std::shared_ptr<gui::button> downscroll_button = gui_.find_action_button("downscroll-button-editor");
285  if(downscroll_button)
286  downscroll_button->enable(can_scroll_down());
287 
288  for(std::size_t i = 0; i < buttons_.size(); ++i) {
289  const auto item_index = items_start_ + i;
290  gui::tristate_button& tile = buttons_[i];
291 
292  tile.hide(true);
293 
294  // If we've scrolled to the end of the list, or if there aren't many items, leave the button hidden
295  if(item_index >= num_items()) {
296  continue;
297  }
298 
299  const std::string item_id = active_group()[item_index];
300  //typedef std::map<std::string, Item> item_map_wurscht;
301  typename item_map::iterator item = item_map_.find(item_id);
302 
303  texture item_base, item_overlay;
304  std::stringstream tooltip_text;
305  setup_item((*item).second, item_base, item_overlay, tooltip_text);
306 
307  bool is_core = non_core_items_.find(get_id((*item).second)) == non_core_items_.end();
308  if (!is_core) {
309  tooltip_text << " "
311  << _("(non-core)") << "\n"
312  << _("Will not work in game without extra care.")
313  << "</span>";
314  }
315 
316  tile.set_tooltip_string(tooltip_text.str());
317  tile.set_item_image(item_base, item_overlay);
318  tile.set_item_id(item_id);
319 
320 // if (get_id((*item).second) == selected_bg_item_
321 // && get_id((*item).second) == selected_fg_item_) {
322 // tile.set_pressed(gui::tristate_button::BOTH);
323 // } else if (get_id((*item).second) == selected_bg_item_) {
324 // tile.set_pressed(gui::tristate_button::RIGHT);
325 // } else if (get_id((*item).second) == selected_fg_item_) {
326 // tile.set_pressed(gui::tristate_button::LEFT);
327 // } else {
328 // tile.set_pressed(gui::tristate_button::NONE);
329 // }
330 
331  if (is_selected_bg_item(get_id(item->second))
332  && is_selected_fg_item(get_id(item->second))) {
334  } else if (is_selected_bg_item(get_id(item->second))) {
336  } else if (is_selected_fg_item(get_id(item->second))) {
338  } else {
340  }
341 
342  tile.set_dirty(true);
343  tile.hide(false);
344  }
345 
346  set_dirty(false);
347 }
348 
349 template<class Item>
351 {
352  // This is unnecessary as every GUI1 widget is a TLD.
353  //for(std::size_t i = 0; i < buttons_.size(); ++i) {
354  // gui::tristate_button& tile = buttons_[i];
355  // tile.draw();
356  //}
357 }
358 
359 // Force compilation of the following template instantiations
361 template class editor_palette<const unit_type&>;
362 template class editor_palette<overlay>;
363 
364 } // end namespace editor
std::vector< events::sdl_handler * > sdl_handler_vector
Definition: events.hpp:190
virtual sdl_handler_vector handler_members() override
virtual void select_fg_item(const std::string &item_id) override
Select a foreground item.
Stores the info about the groups in a nice format.
virtual void select_bg_item(const std::string &item_id) override
std::size_t active_group_index()
void set_item_id(const std::string &id)
virtual bool scroll_down() override
Scroll the editor-palette down one step if possible.
void set_group(std::size_t index) override
virtual bool scroll_up() override
Scroll the editor-palette up one step if possible.
const std::vector< std::string > items
virtual bool is_selected_bg_item(const std::string &id)
#define h
std::string get_binary_file_location(const std::string &type, const std::string &filename)
Returns a complete path to the actual file of a given type or an empty string if the file isn&#39;t prese...
static std::string _(const char *str)
Definition: gettext.hpp:93
virtual bool can_scroll_up() override
void expand_palette_groups_menu(std::vector< config > &items, int i) override
Menu expanding for palette group list.
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition: texture.hpp:32
#define b
void set_pressed(PRESSED_STATE new_pressed_state)
virtual bool is_selected_fg_item(const std::string &id)
std::string span_color(const color_t &color)
Returns a Pango formatting string using the provided color_t object.
void set_dirty(bool dirty=true)
Definition: widget.cpp:180
virtual void hide(bool value=true)
Definition: widget.cpp:141
virtual bool can_scroll_down() override
virtual void layout() override
Called by draw_manager to validate layout before drawing.
Manage the empty-palette in the editor.
Definition: action.cpp:30
void swap(config &lhs, config &rhs)
Implement non-member swap function for std::swap (calls config::swap).
Definition: config.cpp:1456
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:215
std::size_t i
Definition: function.cpp:968
std::size_t num_items() override
Return the number of items in the currently-active group.
Declarations for File-IO.
int w
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:72
void set_tooltip_string(const std::string &str)
Definition: widget.cpp:246
static void setup_item(const std::string &item, window &window)
virtual void draw_contents() override
Called by widget::draw()
void adjust_size(const SDL_Rect &target) override
Update the size of this widget.
#define ERR_ED
void set_item_image(const texture &base, const texture &over=texture())
void hide(bool hidden) override
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:414
const color_t BAD_COLOR