The Battle for Wesnoth  1.17.8+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 "floating_label.hpp"
23 #include "tooltips.hpp"
24 #include "overlay.hpp"
25 #include "filesystem.hpp"
26 #include "units/types.hpp"
27 
29 
30 namespace editor {
31 
32 template<class Item>
34 {
36  for (gui::widget& b : buttons_) {
37  h.push_back(&b);
38  }
39  return h;
40 }
41 
42 template<class Item>
44 {
45  auto pos = items.erase(items.begin() + i);
46 
47  std::vector<config> groups;
48  const std::vector<item_group>& item_groups = get_groups();
49 
50  for (std::size_t mci = 0; mci < item_groups.size(); ++mci) {
51  std::string groupname = item_groups[mci].name;
52  if (groupname.empty()) {
53  groupname = _("(Unknown Group)");
54  }
55  std::string img = item_groups[mci].icon + "_30";
56  if (mci == active_group_index()) {
57  std::string pressed_img = img + "-pressed.png";
58  if(!filesystem::get_binary_file_location("images", pressed_img).empty()) {
59  img = pressed_img;
60  } else {
61  img += ".png~CS(70,70,0)";
62  }
63  } else {
64  img += ".png";
65  }
66 
67  groups.emplace_back(
68  "label", groupname,
69  "icon", img
70  );
71  }
72 
73  items.insert(pos, groups.begin(), groups.end());
74 }
75 
76 template<class Item>
78 {
79  bool scrolled = false;
80  if(can_scroll_up()) {
81  // This should only be reachable with items_start_ being a multiple of columns_, but guard against underflow anyway.
82  if(items_start_ < columns_) {
83  items_start_ = 0;
84  } else {
85  items_start_ -= columns_;
86  }
87  scrolled = true;
88  set_dirty(true);
89  }
90  return scrolled;
91 }
92 
93 template<class Item>
95 {
96  return (items_start_ != 0);
97 }
98 
99 template<class Item>
101 {
102  return (items_start_ + buttons_.size() < num_items());
103 }
104 
105 template<class Item>
107 {
108  bool scrolled = false;
109  if(can_scroll_down()) {
110  items_start_ += columns_;
111  scrolled = true;
112  set_dirty(true);
113  }
114  return scrolled;
115 }
116 
117 template<class Item>
118 void editor_palette<Item>::set_group(const std::string& id)
119 {
120  assert(!id.empty());
121 
122  bool found = false;
123  for (const item_group& group : groups_) {
124  if (group.id == id) {
125  found = true;
126  std::shared_ptr<gui::button> palette_menu_button = gui_.find_menu_button("menu-editor-terrain");
127  if (palette_menu_button) {
128  //palette_menu_button->set_label(group.name);
129  palette_menu_button->set_tooltip_string(group.name);
130  palette_menu_button->set_overlay(group.icon);
131  }
132  }
133  }
134  assert(found);
135 
136  active_group_ = id;
137 
138  if(active_group().empty()) {
139  ERR_ED << "No items found in group with the id: '" << id << "'.";
140  }
141 }
142 
143 template<class Item>
145 {
146  assert(groups_.size() > index);
147  set_group(groups_[index].id);
148 }
149 
150 template<class Item>
152 {
153  assert(!active_group_.empty());
154 
155  for (std::size_t i = 0 ; i < groups_.size(); i++) {
156  if (groups_[i].id == active_group_)
157  return i;
158  }
159 
160  return static_cast<std::size_t>(-1);
161 }
162 
163 template<class Item>
164 void editor_palette<Item>::adjust_size(const SDL_Rect& target)
165 {
166  const int items_fitting = (target.h / item_space_) * columns_;
167  // This might be called while the palette is not visible onscreen.
168  // If that happens, no items will fit and we'll have a negative number here.
169  // Just skip it in that case.
170  //
171  // New items can be added via the add_item function, so this creates as
172  // many buttons as can fit, even if there aren't yet enough items to need
173  // that many buttons.
174  if(items_fitting > 0) {
175  const auto buttons_needed = static_cast<std::size_t>(items_fitting);
176  if(buttons_.size() != buttons_needed) {
177  buttons_.resize(buttons_needed, gui::tristate_button(this));
178  }
179  }
180 
181  // Update button locations and sizes. Needs to be done even if the number of buttons hasn't changed,
182  // because adjust_size() also handles moving left and right when the window's width is changed.
183  SDL_Rect dstrect;
184  dstrect.w = item_size_ + 2;
185  dstrect.h = item_size_ + 2;
186  for(std::size_t i = 0; i < buttons_.size(); ++i) {
187  dstrect.x = target.x + (i % columns_) * item_space_;
188  dstrect.y = target.y + (i / columns_) * item_space_;
189  buttons_[i].set_location(dstrect);
190  }
191 
192  set_location(target);
193  set_dirty(true);
195  font::set_help_string(get_help_string());
196 }
197 
198 template<class Item>
199 void editor_palette<Item>::select_fg_item(const std::string& item_id)
200 {
201  if (selected_fg_item_ != item_id) {
202  selected_fg_item_ = item_id;
203  set_dirty();
204  }
206  font::set_help_string(get_help_string());
207 }
208 
209 template<class Item>
210 void editor_palette<Item>::select_bg_item(const std::string& item_id)
211 {
212  if (selected_bg_item_ != item_id) {
213  selected_bg_item_ = item_id;
214  set_dirty();
215  }
217  font::set_help_string(get_help_string());
218 }
219 
220 template<class Item>
222 {
223  std::swap(selected_fg_item_, selected_bg_item_);
224  select_fg_item(selected_fg_item_);
225  select_bg_item(selected_bg_item_);
226  set_dirty();
227 }
228 
229 template<class Item>
231 {
232  return group_map_[active_group_].size();
233 }
234 
235 
236 template<class Item>
237 void editor_palette<Item>::hide(bool hidden)
238 {
239  widget::hide(hidden);
240 
241  if (!hidden) {
242  font::set_help_string(get_help_string());
243  } else {
245  }
246 
247  for (gui::widget& w : buttons_) {
248  w.hide(hidden);
249  }
250 }
251 
252 
253 template<class Item>
254 bool editor_palette<Item>::is_selected_fg_item(const std::string& id)
255 {
256  return selected_fg_item_ == id;
257 }
258 
259 template<class Item>
260 bool editor_palette<Item>::is_selected_bg_item(const std::string& id)
261 {
262  return selected_bg_item_ == id;
263 }
264 
265 template<class Item>
267 {
268  if (!dirty()) {
269  return;
270  }
271 
272  toolkit_.set_mouseover_overlay(gui_);
273 
274  std::shared_ptr<gui::button> palette_menu_button = gui_.find_menu_button("menu-editor-terrain");
275  if(palette_menu_button) {
276  t_string& name = groups_[active_group_index()].name;
277  std::string& icon = groups_[active_group_index()].icon;
278 
279  palette_menu_button->set_tooltip_string(name);
280  palette_menu_button->set_overlay(icon);
281  }
282 
283  // The hotkey system will automatically enable and disable the buttons when it runs, but it doesn't
284  // get triggered when handling mouse-wheel scrolling. Therefore duplicate that functionality here.
285  std::shared_ptr<gui::button> upscroll_button = gui_.find_action_button("upscroll-button-editor");
286  if(upscroll_button)
287  upscroll_button->enable(can_scroll_up());
288  std::shared_ptr<gui::button> downscroll_button = gui_.find_action_button("downscroll-button-editor");
289  if(downscroll_button)
290  downscroll_button->enable(can_scroll_down());
291 
292  for(std::size_t i = 0; i < buttons_.size(); ++i) {
293  const auto item_index = items_start_ + i;
294  gui::tristate_button& tile = buttons_[i];
295 
296  tile.hide(true);
297 
298  // If we've scrolled to the end of the list, or if there aren't many items, leave the button hidden
299  if(item_index >= num_items()) {
300  continue;
301  }
302 
303  const std::string item_id = active_group()[item_index];
304  //typedef std::map<std::string, Item> item_map_wurscht;
305  typename item_map::iterator item = item_map_.find(item_id);
306 
307  texture item_base, item_overlay;
308  std::stringstream tooltip_text;
309  setup_item((*item).second, item_base, item_overlay, tooltip_text);
310 
311  bool is_core = non_core_items_.find(get_id((*item).second)) == non_core_items_.end();
312  if (!is_core) {
313  tooltip_text << " "
315  << _("(non-core)") << "\n"
316  << _("Will not work in game without extra care.")
317  << "</span>";
318  }
319 
320  tile.set_tooltip_string(tooltip_text.str());
321  tile.set_item_image(item_base, item_overlay);
322  tile.set_item_id(item_id);
323 
324 // if (get_id((*item).second) == selected_bg_item_
325 // && get_id((*item).second) == selected_fg_item_) {
326 // tile.set_pressed(gui::tristate_button::BOTH);
327 // } else if (get_id((*item).second) == selected_bg_item_) {
328 // tile.set_pressed(gui::tristate_button::RIGHT);
329 // } else if (get_id((*item).second) == selected_fg_item_) {
330 // tile.set_pressed(gui::tristate_button::LEFT);
331 // } else {
332 // tile.set_pressed(gui::tristate_button::NONE);
333 // }
334 
335  if (is_selected_bg_item(get_id(item->second))
336  && is_selected_fg_item(get_id(item->second))) {
338  } else if (is_selected_bg_item(get_id(item->second))) {
340  } else if (is_selected_fg_item(get_id(item->second))) {
342  } else {
344  }
345 
346  tile.set_dirty(true);
347  tile.hide(false);
348  }
349 
350  set_dirty(false);
351 }
352 
353 template<class Item>
355 {
356  // This is unnecessary as every GUI1 widget is a TLD.
357  //for(std::size_t i = 0; i < buttons_.size(); ++i) {
358  // gui::tristate_button& tile = buttons_[i];
359  // tile.draw();
360  //}
361 }
362 
363 // Force compilation of the following template instantiations
365 template class editor_palette<const unit_type&>;
366 template class editor_palette<overlay>;
367 
368 } // end namespace editor
std::vector< events::sdl_handler * > sdl_handler_vector
Definition: events.hpp:187
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 set_help_string(const std::string &str)
Displays a help string with the given text.
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:181
void clear_help_string()
Removes the help string.
virtual void hide(bool value=true)
Definition: widget.cpp:142
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:967
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:252
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