The Battle for Wesnoth  1.17.17+dev
unit_recall.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2016 - 2023
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 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
18 
19 #include "font/text_formatting.hpp"
21 #include "gui/core/log.hpp"
23 #include "gui/dialogs/message.hpp"
24 #include "gui/widgets/listbox.hpp"
25 #include "gui/widgets/settings.hpp"
26 #include "gui/widgets/button.hpp"
27 #include "gui/widgets/image.hpp"
28 #include "gui/widgets/label.hpp"
29 #include "gui/widgets/text_box.hpp"
32 #include "gui/widgets/window.hpp"
33 #include "help/help.hpp"
34 #include "game_board.hpp"
35 #include "gettext.hpp"
36 #include "replay_helper.hpp"
37 #include "play_controller.hpp"
38 #include "resources.hpp"
39 #include "synced_context.hpp"
40 #include "team.hpp"
41 #include "units/types.hpp"
42 #include "units/unit.hpp"
43 #include "units/ptr.hpp"
44 #include <functional>
45 #include "whiteboard/manager.hpp"
46 
47 #include <boost/dynamic_bitset.hpp>
48 
49 static lg::log_domain log_display("display");
50 #define LOG_DP LOG_STREAM(info, log_display)
51 
52 namespace gui2::dialogs
53 {
54 
55 // Index 2 is by-level
56 static listbox::order_pair sort_last {-1, sort_order::type::none};
57 static listbox::order_pair sort_default { 2, sort_order::type::descending};
58 
60 
61 unit_recall::unit_recall(std::vector<unit_const_ptr>& recall_list, team& team)
62  : modal_dialog(window_id())
63  , recall_list_(recall_list)
64  , team_(team)
65  , selected_index_()
66  , filter_options_()
67  , last_words_()
68 {
69 }
70 
71 template<typename T>
72 static void dump_recall_list_to_console(const T& units)
73 {
74  log_scope2(log_display, "dump_recall_list_to_console()")
75 
76  LOG_DP << "size: " << units.size();
77 
78  std::size_t idx = 0;
79  for(const auto& u_ptr : units) {
80  LOG_DP << "\tunit[" << (idx++) << "]: " << u_ptr->id() << " name = '" << u_ptr->name() << "'";
81  }
82 }
83 
84 static const color_t inactive_row_color(0x96, 0x96, 0x96);
85 
86 static const inline std::string maybe_inactive(const std::string& str, bool active)
87 {
88  if(active)
89  return str;
90  else
92 }
93 
94 static std::string format_level_string(const int level, bool recallable)
95 {
96  std::string lvl = std::to_string(level);
97 
98  if(!recallable) {
99  // Same logic as when recallable, but always in inactive_row_color.
100  if(level < 2) {
102  } else {
103  return font::span_color(inactive_row_color, "<b>" + lvl + "</b>");
104  }
105  } else if(level < 1) {
107  } else if(level == 1) {
108  return lvl;
109  } else if(level == 2) {
110  return "<b>" + lvl + "</b>";
111  } else {
112  return"<b><span color='#ffffff'>" + lvl + "</span></b>";
113  }
114 }
115 
116 static std::string format_cost_string(int unit_recall_cost, const int team_recall_cost)
117 {
118  std::stringstream str;
119 
120  if(unit_recall_cost < 0) {
121  unit_recall_cost = team_recall_cost;
122  }
123 
124  if(unit_recall_cost > team_recall_cost) {
125  str << "<span color='#ff0000'>" << unit_recall_cost << "</span>";
126  } else if(unit_recall_cost == team_recall_cost) {
127  str << unit_recall_cost;
128  } else if(unit_recall_cost < team_recall_cost) {
129  str << "<span color='#00ff00'>" << unit_recall_cost << "</span>";
130  }
131 
132  return str.str();
133 }
134 
135 static std::string get_title_suffix(int side_num)
136 {
137  if(!resources::gameboard) {
138  return "";
139  }
140 
141  unit_map& units = resources::gameboard->units();
142 
143  int controlled_recruiters = 0;
144  for(const auto& team : resources::gameboard->teams()) {
145  if(team.is_local_human() && !team.recruits().empty() && units.find_leader(team.side()) !=units.end()) {
146  ++controlled_recruiters;
147  }
148  }
149 
150  std::stringstream msg;
151  if(controlled_recruiters >= 2) {
153  if(leader != resources::gameboard->units().end() && !leader->name().empty()) {
154  msg << " (" << leader->name(); msg << ")";
155  }
156  }
157 
158  return msg.str();
159 }
160 
162 {
163  label& title = find_widget<label>(&window, "title", true);
164  title.set_label(title.get_label() + get_title_suffix(team_.side()));
165 
166  text_box* filter
167  = find_widget<text_box>(&window, "filter_box", false, true);
168 
170  std::bind(&unit_recall::filter_text_changed, this, std::placeholders::_2));
171 
172  listbox& list = find_widget<listbox>(&window, "recall_list", false);
173 
175 
176  list.clear();
177 
178  window.keyboard_capture(filter);
180 
182  find_widget<button>(&window, "rename", false),
183  std::bind(&unit_recall::rename_unit, this));
184 
186  find_widget<button>(&window, "dismiss", false),
187  std::bind(&unit_recall::dismiss_unit, this));
188 
190  find_widget<button>(&window, "show_help", false),
191  std::bind(&unit_recall::show_help, this));
192 
193  for(const unit_const_ptr& unit : recall_list_) {
194  widget_data row_data;
195  widget_item column;
196 
197  std::string mods = unit->image_mods();
198 
199  int wb_gold = 0;
201  if(const std::shared_ptr<wb::manager>& whiteb = resources::controller->get_whiteboard()) {
202  wb::future_map future; // So gold takes into account planned spending
203  wb_gold = whiteb->get_spent_gold_for(team_.side());
204  }
205  }
206 
207  // Note: Our callers apply [filter_recall], but leave it to us
208  // to apply cost-based filtering.
209  const int recall_cost = (unit->recall_cost() > -1 ? unit->recall_cost() : team_.recall_cost());
210  const bool recallable = (recall_cost <= team_.gold() - wb_gold);
211 
212  if(unit->can_recruit()) {
213  mods += "~BLIT(" + unit::leader_crown() + ")";
214  }
215 
216  for(const std::string& overlay : unit->overlays()) {
217  mods += "~BLIT(" + overlay + ")";
218  }
219 
220  if(!recallable) {
221  mods += "~GS()";
222 
223  // Just set the tooltip on every single element in this row.
224  if(wb_gold > 0)
225  column["tooltip"] = _("This unit cannot be recalled because you will not have enough gold at this point in your plan.");
226  else
227  column["tooltip"] = _("This unit cannot be recalled because you do not have enough gold.");
228  }
229 
230  column["use_markup"] = "true";
231 
232  column["label"] = unit->absolute_image() + mods;
233  row_data.emplace("unit_image", column);
234 
235  column["label"] = maybe_inactive(unit->type_name(), recallable);
236  row_data.emplace("unit_type", column);
237 
238  // gold_icon is handled below
239 
240  column["label"] =
241  recallable
243  : maybe_inactive(std::to_string(recall_cost), recallable);
244  row_data.emplace("unit_recall_cost", column);
245 
246  const std::string& name = !unit->name().empty() ? unit->name().str() : font::unicode_en_dash;
247  column["label"] = maybe_inactive(name, recallable);
248  row_data.emplace("unit_name", column);
249 
250  column["label"] = format_level_string(unit->level(), recallable);
251  row_data.emplace("unit_level", column);
252 
253  std::stringstream exp_str;
254  if(unit->can_advance()) {
255  exp_str << unit->experience() << "/" << unit->max_experience();
256  } else {
257  exp_str << font::unicode_en_dash;
258  }
259 
260  column["label"] = font::span_color(recallable ? unit->xp_color() : inactive_row_color, exp_str.str());
261  row_data.emplace("unit_experience", column);
262 
263  // Since the table widgets use heavy formatting, we save a bare copy
264  // of certain options to filter on.
265  std::string filter_text = unit->type_name() + " " + name + " " + std::to_string(unit->level());
266 
267  if(recallable) {
268  // This is to allow filtering for recallable units by typing "vvv" in the search box.
269  // That's intended to be easy to type and unlikely to match unit or type names.
270  //
271  // TODO: document this. (Also, implement a "Hide non-recallable units" checkbox.)
272  filter_text += " " + std::string("vvv");
273  }
274 
275  std::string traits;
276  for(const std::string& trait : unit->trait_names()) {
277  traits += (traits.empty() ? "" : "\n") + trait;
278  filter_text += " " + trait;
279  }
280 
281  column["label"] = maybe_inactive(
282  !traits.empty() ? traits : font::unicode_en_dash,
283  recallable);
284  row_data.emplace("unit_traits", column);
285 
286  filter_options_.push_back(filter_text);
287  grid& grid = list.add_row(row_data);
288  if(!recallable) {
289  image *gold_icon = dynamic_cast<image*>(grid.find("gold_icon", false));
290  assert(gold_icon);
291  gold_icon->set_image(gold_icon->get_image() + "~GS()");
292  }
293  }
294 
295  list.register_translatable_sorting_option(0, [this](const int i) { return recall_list_[i]->type_name().str(); });
296  list.register_translatable_sorting_option(1, [this](const int i) { return recall_list_[i]->name().str(); });
297  list.register_sorting_option(2, [this](const int i) {
298  const unit& u = *recall_list_[i];
299  return std::tuple(u.level(), -static_cast<int>(u.experience_to_advance()));
300  });
301  list.register_sorting_option(3, [this](const int i) { return recall_list_[i]->experience(); });
302  list.register_translatable_sorting_option(4, [this](const int i) {
303  return !recall_list_[i]->trait_names().empty() ? recall_list_[i]->trait_names().front().str() : "";
304  });
305 
306  list.set_active_sorting_option(sort_last.first >= 0 ? sort_last : sort_default, true);
307 
309 }
310 
312 {
313  listbox& list = find_widget<listbox>(get_window(), "recall_list", false);
314 
315  const int index = list.get_selected_row();
316  if (index == -1) {
317  return;
318  }
319 
320  unit& selected_unit = const_cast<unit&>(*recall_list_[index].get());
321 
322  std::string name = selected_unit.name();
323  const std::string dialog_title(_("Rename Unit"));
324  const std::string dialog_label(_("Name:"));
325 
326  if(gui2::dialogs::edit_text::execute(dialog_title, dialog_label, name)) {
327  selected_unit.rename(name);
328 
329  find_widget<label>(list.get_row_grid(index), "unit_name", false).set_label(name);
330 
331  filter_options_.erase(filter_options_.begin() + index);
332  std::ostringstream filter_text;
333  filter_text << selected_unit.type_name() << " " << name << " " << std::to_string(selected_unit.level());
334  for(const std::string& trait : selected_unit.trait_names()) {
335  filter_text << " " << trait;
336  }
337  filter_options_.insert(filter_options_.begin() + index, filter_text.str());
338 
341  }
342 }
343 
345 {
346  LOG_DP << "Recall list units:"; dump_recall_list_to_console(recall_list_);
347 
348  listbox& list = find_widget<listbox>(get_window(), "recall_list", false);
349  const int index = list.get_selected_row();
350  if (index == -1) {
351  return;
352  }
353 
354  const unit& u = *recall_list_[index].get();
355 
356  // If the unit is of level > 1, or is close to advancing, we warn the player about it
357  std::stringstream message;
358  if(u.loyal()) {
359  message << _("This unit is loyal and requires no upkeep.") << " " << (u.gender() == unit_race::MALE
360  ? _("Do you really want to dismiss him?")
361  : _("Do you really want to dismiss her?"));
362 
363  } else if(u.level() > 1) {
364  message << _("This unit is an experienced one, having advanced levels.") << " " << (u.gender() == unit_race::MALE
365  ? _("Do you really want to dismiss him?")
366  : _("Do you really want to dismiss her?"));
367 
368  } else if(u.experience() > u.max_experience()/2) {
369  message << _("This unit is close to advancing a level.") << " " << (u.gender() == unit_race::MALE
370  ? _("Do you really want to dismiss him?")
371  : _("Do you really want to dismiss her?"));
372  }
373 
374  if(!message.str().empty()) {
375  const int res = gui2::show_message(_("Dismiss Unit"), message.str(), message::yes_no_buttons);
376 
377  if(res != gui2::retval::OK) {
378  return;
379  }
380  }
381 
382  recall_list_.erase(recall_list_.begin() + index);
383 
384  // Remove the entry from the dialog list
385  list.remove_row(index);
387 
388  // Remove the entry from the filter list
389  filter_options_.erase(filter_options_.begin() + index);
390  assert(filter_options_.size() == list.get_item_count());
391 
392  LOG_DP << "Dismissing a unit, side = " << u.side() << ", id = '" << u.id() << "'";
393  LOG_DP << "That side's recall list:";
395 
396  // Find the unit in the recall list.
397  unit_ptr dismissed_unit = team_.recall_list().find_if_matches_id(u.id());
398  assert(dismissed_unit);
399 
400  // Record the dismissal, then delete the unit.
401  synced_context::run_and_throw("disband", replay_helper::get_disband(dismissed_unit->id()));
402 
403  // Close the dialog if all units are dismissed
404  if(list.get_item_count() == 0) {
406  }
407 }
408 
410 {
411  help::show_help("recruit_and_recall");
412 }
413 
415 {
416  const int selected_row
417  = find_widget<listbox>(get_window(), "recall_list", false).get_selected_row();
418 
419  if(selected_row == -1) {
420  return;
421  }
422 
423  const unit& selected_unit = *recall_list_[selected_row].get();
424 
425  find_widget<unit_preview_pane>(get_window(), "unit_details", false)
426  .set_displayed_unit(selected_unit);
427 
428  find_widget<button>(get_window(), "rename", false).set_active(!selected_unit.unrenamable());
429 }
430 
432 {
433  listbox& list = find_widget<listbox>(&window, "recall_list", false);
435 
436  if(get_retval() == retval::OK) {
438  }
439 }
440 
441 void unit_recall::filter_text_changed(const std::string& text)
442 {
443  listbox& list = find_widget<listbox>(get_window(), "recall_list", false);
444 
445  const std::vector<std::string> words = utils::split(text, ' ');
446 
447  if(words == last_words_)
448  return;
449  last_words_ = words;
450 
451  boost::dynamic_bitset<> show_items;
452  show_items.resize(list.get_item_count(), true);
453 
454  if(!text.empty()) {
455  for(unsigned int i = 0; i < list.get_item_count(); i++) {
456  bool found = false;
457 
458  for(const auto & word : words) {
459  found = translation::ci_search(filter_options_[i], word);
460 
461  if(!found) {
462  // one word doesn't match, we don't reach words.end()
463  break;
464  }
465  }
466 
467  show_items[i] = found;
468  }
469  }
470 
471  list.set_row_shown(show_items);
472 
473  // Disable rename and dismiss buttons if no units are shown
474  const bool any_shown = list.any_rows_shown();
475  find_widget<button>(get_window(), "rename", false).set_active(any_shown);
476  find_widget<button>(get_window(), "dismiss", false).set_active(any_shown);
477 }
478 
479 } // namespace dialogs
virtual const unit_map & units() const override
Definition: game_board.hpp:113
Main class to show messages to the user.
Definition: message.hpp:36
@ yes_no_buttons
Shows a yes and no button.
Definition: message.hpp:81
Abstract base class for all modal dialogs.
int get_retval() const
Returns the cached window exit code.
window * get_window()
Returns a pointer to the dialog's window.
virtual void post_show(window &window) override
Actions to be taken after the window has been shown.
std::vector< std::string > filter_options_
Definition: unit_recall.hpp:53
void list_item_clicked()
Callbacks.
void filter_text_changed(const std::string &text)
virtual void pre_show(window &window) override
Actions to be taken before showing the window.
std::vector< unit_const_ptr > & recall_list_
Definition: unit_recall.hpp:47
std::vector< std::string > last_words_
Definition: unit_recall.hpp:54
Base container class.
Definition: grid.hpp:32
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
Definition: grid.cpp:645
t_string get_image() const
Wrapper for label.
Definition: image.hpp:66
void set_image(const t_string &label)
Wrapper for set_label.
Definition: image.hpp:53
A label displays a text, the text can be wrapped but no scrollbars are provided.
Definition: label.hpp:58
The listbox class.
Definition: listbox.hpp:46
void set_row_shown(const unsigned row, const bool shown)
Makes a row visible or invisible.
Definition: listbox.cpp:139
void set_active_sorting_option(const order_pair &sort_by, const bool select_first=false)
Sorts the listbox by a pre-set sorting option.
Definition: listbox.cpp:624
std::pair< int, sort_order::type > order_pair
Definition: listbox.hpp:276
grid & add_row(const widget_item &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
Definition: listbox.cpp:62
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
Definition: listbox.cpp:233
void register_translatable_sorting_option(const int col, translatable_sorter_func_t f)
Registers a special sorting function specifically for translatable values.
Definition: listbox.cpp:616
bool any_rows_shown() const
Definition: listbox.cpp:222
void register_sorting_option(const int col, const Func &f)
Definition: listbox.hpp:263
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
Definition: listbox.cpp:82
void clear()
Removes all the rows in the listbox, clearing it.
Definition: listbox.cpp:121
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:271
unsigned get_item_count() const
Returns the number of items in the listbox.
Definition: listbox.cpp:127
const order_pair get_active_sorting_option()
Definition: listbox.cpp:643
const t_string & get_label() const
virtual void set_label(const t_string &label)
void set_text_changed_callback(std::function< void(text_box_base *textbox, const std::string text)> cb)
Set the text_changed callback.
Class for a single line text area.
Definition: text_box.hpp:142
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition: window.hpp:67
void set_retval(const int retval, const bool close_window=true)
Sets there return value of the window.
Definition: window.hpp:358
void keyboard_capture(widget *widget)
Definition: window.cpp:1130
void invalidate_layout()
Updates the size of the window.
Definition: window.cpp:682
void add_to_keyboard_chain(widget *widget)
Adds the widget to the keyboard chain.
Definition: window.cpp:1136
unit_ptr find_if_matches_id(const std::string &unit_id)
Find a unit by id.
static config get_disband(const std::string &unit_id)
static bool run_and_throw(const std::string &commandname, const config &data, bool use_undo=true, bool show=true, synced_command::error_handler_function error_handler=default_error_function)
bool empty() const
Definition: tstring.hpp:187
const std::string & str() const
Definition: tstring.hpp:191
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:76
int side() const
Definition: team.hpp:176
int recall_cost() const
Definition: team.hpp:181
bool is_local_human() const
Definition: team.hpp:255
int gold() const
Definition: team.hpp:177
recall_list_manager & recall_list()
Definition: team.hpp:203
const std::set< std::string > & recruits() const
Definition: team.hpp:211
Container associating units to locations.
Definition: map.hpp:99
unit_iterator end()
Definition: map.hpp:429
unit_iterator find_leader(int side)
Definition: map.cpp:319
@ MALE
Definition: race.hpp:27
This class represents a single unit of a specific type.
Definition: unit.hpp:134
static const std::string & leader_crown()
The path to the leader crown overlay.
Definition: unit.cpp:1050
std::size_t i
Definition: function.cpp:968
static std::string _(const char *str)
Definition: gettext.hpp:93
int level() const
The current level of this unit.
Definition: unit.hpp:560
const t_string & type_name() const
Gets the translatable name of this unit's type.
Definition: unit.hpp:370
bool unrenamable() const
Whether this unit can be renamed.
Definition: unit.hpp:437
int recall_cost() const
How much gold it costs to recall this unit, or -1 if the side's default recall cost is used.
Definition: unit.hpp:641
void rename(const std::string &name)
Attempts to rename this unit's translatable display name, taking the 'unrenamable' flag into account.
Definition: unit.hpp:425
int experience() const
The current number of experience points this unit has.
Definition: unit.hpp:524
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
Definition: unit.hpp:613
const std::string & id() const
Gets this unit's id.
Definition: unit.hpp:381
int side() const
The side this unit belongs to.
Definition: unit.hpp:344
unsigned int experience_to_advance() const
The number of experience points this unit needs to level up, or 0 if current XP > max XP.
Definition: unit.hpp:542
int max_experience() const
The max number of experience points this unit can have.
Definition: unit.hpp:530
unit_race::GENDER gender() const
The gender of this unit.
Definition: unit.hpp:466
const t_string & name() const
Gets this unit's translatable display name.
Definition: unit.hpp:404
bool can_advance() const
Checks whether this unit has any options to advance to.
Definition: unit.hpp:273
color_t xp_color() const
Color for this unit's XP.
Definition: unit.cpp:1152
std::string image_mods() const
Gets an IPF string containing all IPF image mods.
Definition: unit.cpp:2798
const std::vector< std::string > & overlays() const
Get the unit's overlay images.
Definition: unit.hpp:1600
std::string absolute_image() const
The name of the file to game_display (used in menus).
Definition: unit.cpp:2617
const std::vector< t_string > & trait_names() const
Gets the names of the currently registered traits.
Definition: unit.hpp:1084
bool loyal() const
Gets whether this unit is loyal - ie, it costs no upkeep.
Definition: unit.cpp:1782
Define the common log macros for the gui toolkit.
This file contains the window object, this object is a top level container which has the event manage...
#define log_scope2(domain, description)
Definition: log.hpp:241
#define REGISTER_DIALOG(window_id)
Wrapper for REGISTER_DIALOG2.
const std::string unicode_en_dash
Definition: constants.cpp:43
std::string span_color(const color_t &color)
Returns a Pango formatting string using the provided color_t object.
static std::string get_title_suffix(int side_num)
static listbox::order_pair sort_default
Definition: unit_recall.cpp:57
static const std::string maybe_inactive(const std::string &str, bool active)
Definition: unit_recall.cpp:86
static std::string format_level_string(const int level)
Definition: unit_list.cpp:54
static void dump_recall_list_to_console(const T &units)
Definition: unit_recall.cpp:72
static const color_t inactive_row_color(0x96, 0x96, 0x96)
static listbox::order_pair sort_last
Definition: unit_recall.cpp:56
static std::string format_cost_string(int unit_recall_cost, const int team_recall_cost)
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification &signal)
Connects a signal handler for getting a notification upon modification.
Definition: dispatcher.cpp:205
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:179
std::map< std::string, widget_item > widget_data
Definition: widget.hpp:35
std::map< std::string, t_string > widget_item
Definition: widget.hpp:32
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
Definition: message.cpp:151
@ OK
Dialog was closed with the OK button.
Definition: retval.hpp:35
@ CANCEL
Dialog was closed with the CANCEL button.
Definition: retval.hpp:38
void show_help(const std::string &show_topic, int xloc, int yloc)
Open the help browser, show topic with id show_topic.
Definition: help.cpp:144
Functions to load and save images from/to disk.
game_board * gameboard
Definition: resources.cpp:21
play_controller * controller
Definition: resources.cpp:22
bool ci_search(const std::string &s1, const std::string &s2)
Definition: gettext.cpp:563
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
std::vector< std::string > split(const config_attribute_value &val)
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:110
std::shared_ptr< const unit > unit_const_ptr
Definition: ptr.hpp:27
std::shared_ptr< unit > unit_ptr
Definition: ptr.hpp:26
This file contains the settings handling of the widget library.
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:59
Applies the planned unit map for the duration of the struct's life.
Definition: manager.hpp:253
#define LOG_DP
Definition: unit_recall.cpp:50
static lg::log_domain log_display("display")