The Battle for Wesnoth  1.19.10+dev
label.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2025
3  by Mark de Wever <koraq@xs4all.nl>
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-lib"
17 
18 #include "gui/widgets/label.hpp"
19 
20 #include "gui/core/log.hpp"
21 
24 #include "gui/dialogs/message.hpp"
25 
26 #include "cursor.hpp"
27 #include "desktop/clipboard.hpp"
28 #include "desktop/open.hpp"
29 #include "font/standard_colors.hpp"
30 #include "gettext.hpp"
31 #include "wml_exception.hpp"
32 
33 #include <functional>
34 #include <string>
35 
36 namespace gui2
37 {
38 
39 // ------------ WIDGET -----------{
40 
42 
43 label::label(const implementation::builder_label& builder)
44  : styled_widget(builder, type())
45  , state_(ENABLED)
46  , can_wrap_(builder.wrap)
47  , characters_per_line_(builder.characters_per_line)
48  , link_aware_(builder.link_aware)
49  , link_color_(font::YELLOW_COLOR)
50  , can_shrink_(builder.can_shrink)
51  , text_alpha_(ALPHA_OPAQUE)
52 {
53  connect_signal<event::LEFT_BUTTON_CLICK>(
54  std::bind(&label::signal_handler_left_button_click, this, std::placeholders::_3));
55  connect_signal<event::RIGHT_BUTTON_CLICK>(
56  std::bind(&label::signal_handler_right_button_click, this, std::placeholders::_3));
57  connect_signal<event::MOUSE_MOTION>(
58  std::bind(&label::signal_handler_mouse_motion, this, std::placeholders::_3, std::placeholders::_5));
59  connect_signal<event::MOUSE_LEAVE>(
60  std::bind(&label::signal_handler_mouse_leave, this, std::placeholders::_3));
61 }
62 
64 {
65  // Inherit.
67 
68  for(auto& tmp : get_canvases()) {
69  tmp.set_variable("text_alpha", wfl::variant(text_alpha_));
70  }
71 }
72 
73 void label::set_text_alpha(unsigned short alpha)
74 {
75  if(alpha != text_alpha_) {
76  text_alpha_ = alpha;
77  update_canvas();
78  queue_redraw();
79  }
80 }
81 
82 void label::set_active(const bool active)
83 {
84  if(get_active() != active) {
85  set_state(active ? ENABLED : DISABLED);
86  }
87 }
88 
89 void label::set_link_aware(bool link_aware)
90 {
91  if(link_aware != link_aware_) {
92  link_aware_ = link_aware;
93  update_canvas();
94  queue_redraw();
95  }
96 }
97 
98 void label::set_link_color(const color_t& color)
99 {
100  if(color != link_color_) {
101  link_color_ = color;
102  update_canvas();
103  queue_redraw();
104  }
105 }
106 
107 void label::set_state(const state_t state)
108 {
109  if(state != state_) {
110  state_ = state;
111  queue_redraw();
112  }
113 }
114 
116 {
117  DBG_GUI_E << "label click";
118 
119  if(!get_link_aware()) {
120  return; // without marking event as "handled".
121  }
122 
124  show_message("", _("Opening links is not supported, contact your packager"), dialogs::message::auto_close);
125  handled = true;
126  return;
127  }
128 
129  std::string link = get_label_link(get_mouse_position());
130 
131  if(link.empty()) {
132  return; // without marking event as "handled"
133  }
134 
135  DBG_GUI_E << "Clicked Link:\"" << link << "\"";
136 
137  const int res = show_message(_("Open link?"), link, dialogs::message::yes_no_buttons);
138  if(res == gui2::retval::OK) {
139  desktop::open_object(link);
140  }
141 
142  handled = true;
143 }
144 
146 {
147  DBG_GUI_E << "label right click";
148 
149  if(!get_link_aware()) {
150  return; // without marking event as "handled".
151  }
152 
153  std::string link = get_label_link(get_mouse_position());
154  if(link.empty()) {
155  return ; // without marking event as "handled"
156  }
157 
158  DBG_GUI_E << "Right Clicked Link:\"" << link << "\"";
159 
161 
162  show_message("", _("Copied link!"), dialogs::message::auto_close);
163 
164  handled = true;
165 }
166 
168 {
169  DBG_GUI_E << "label mouse motion";
170 
171  if(!get_link_aware()) {
172  return; // without marking event as "handled"
173  }
174 
176 
177  handled = true;
178 }
179 
181 {
182  DBG_GUI_E << "label mouse leave";
183 
184  if(!get_link_aware()) {
185  return; // without marking event as "handled"
186  }
187 
188  // We left the widget, so just unconditionally reset the cursor
189  update_mouse_cursor(false);
190 
191  handled = true;
192 }
193 
194 void label::update_mouse_cursor(bool enable)
195 {
196  // Someone else may set the mouse cursor for us to something unusual (e.g.
197  // the WAIT cursor) so we ought to mess with that only if it's set to
198  // NORMAL or HYPERLINK.
199 
200  if(enable && cursor::get() == cursor::NORMAL) {
202  } else if(!enable && cursor::get() == cursor::HYPERLINK) {
204  }
205 }
206 
207 // }---------- DEFINITION ---------{
208 
211 {
212  DBG_GUI_P << "Parsing label " << id;
213 
214  load_resolutions<resolution>(cfg);
215 }
216 
218  : resolution_definition(cfg)
219  , link_color(cfg["link_color"].empty() ? font::YELLOW_COLOR : color_t::from_rgba_string(cfg["link_color"].str()))
220 {
221  // Note the order should be the same as the enum state_t is label.hpp.
222  state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_enabled", missing_mandatory_wml_tag("label_definition][resolution", "state_enabled")));
223  state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_disabled", missing_mandatory_wml_tag("label_definition][resolution", "state_disabled")));
224 }
225 
226 // }---------- BUILDER -----------{
227 
228 namespace implementation
229 {
230 
231 builder_label::builder_label(const config& cfg)
232  : builder_styled_widget(cfg)
233  , wrap(cfg["wrap"].to_bool())
234  , characters_per_line(cfg["characters_per_line"].to_unsigned())
235  , text_alignment(decode_text_alignment(cfg["text_alignment"]))
236  , can_shrink(cfg["can_shrink"].to_bool(false))
237  , link_aware(cfg["link_aware"].to_bool(false))
238 {
239 }
240 
241 std::unique_ptr<widget> builder_label::build() const
242 {
243  auto lbl = std::make_unique<label>(*this);
244 
245  const auto conf = lbl->cast_config_to<label_definition>();
246  assert(conf);
247 
248  lbl->set_text_alignment(text_alignment);
249  lbl->set_link_color(conf->link_color);
250 
251  DBG_GUI_G << "Window builder: placed label '" << id << "' with definition '"
252  << definition << "'.";
253 
254  return lbl;
255 }
256 
257 } // namespace implementation
258 
259 // }------------ END --------------
260 
261 } // namespace gui2
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:158
@ yes_no_buttons
Shows a yes and no button.
Definition: message.hpp:81
@ auto_close
Enables auto close.
Definition: message.hpp:71
unsigned short text_alpha_
Definition: label.hpp:159
virtual bool get_link_aware() const override
See styled_widget::get_link_aware.
Definition: label.hpp:51
void signal_handler_left_button_click(bool &handled)
Left click signal handler: checks if we clicked on a hyperlink.
Definition: label.cpp:115
void set_link_color(const color_t &color)
Definition: label.cpp:98
void signal_handler_mouse_leave(bool &handled)
Mouse leave signal handler: checks if the cursor left a hyperlink.
Definition: label.cpp:180
color_t link_color_
What color links will be rendered in.
Definition: label.hpp:155
void signal_handler_right_button_click(bool &handled)
Right click signal handler: checks if we clicked on a hyperlink, copied to clipboard.
Definition: label.cpp:145
bool link_aware_
Whether the label is link aware, rendering links with special formatting and handling click events.
Definition: label.hpp:150
virtual void update_canvas() override
See styled_widget::update_canvas.
Definition: label.cpp:63
void set_state(const state_t state)
Definition: label.cpp:107
state_t
Possible states of the widget.
Definition: label.hpp:121
virtual bool get_active() const override
See styled_widget::get_active.
Definition: label.hpp:66
state_t state_
Current state of the widget.
Definition: label.hpp:134
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: label.cpp:82
void update_mouse_cursor(bool enable)
Implementation detail for (re)setting the hyperlink cursor.
Definition: label.cpp:194
void set_link_aware(bool l)
Definition: label.cpp:89
void set_text_alpha(unsigned short alpha)
Definition: label.cpp:73
void signal_handler_mouse_motion(bool &handled, const point &coordinate)
Mouse motion signal handler: checks if the cursor is on a hyperlink.
Definition: label.cpp:167
std::vector< canvas > & get_canvases()
std::string get_label_link(const point &position) const
virtual void update_canvas()
Updates the canvas(ses).
void queue_redraw()
Indicates that this widget should be redrawn.
Definition: widget.cpp:464
constexpr uint8_t ALPHA_OPAQUE
Definition: color.hpp:47
static std::string _(const char *str)
Definition: gettext.hpp:97
Define the common log macros for the gui toolkit.
#define DBG_GUI_G
Definition: log.hpp:41
#define DBG_GUI_P
Definition: log.hpp:66
#define DBG_GUI_E
Definition: log.hpp:35
std::string label
What to show in the filter's drop-down list.
Definition: manager.cpp:201
CURSOR_TYPE get()
Definition: cursor.cpp:218
@ NORMAL
Definition: cursor.hpp:28
@ HYPERLINK
Definition: cursor.hpp:28
void set(CURSOR_TYPE type)
Use the default parameter to reset cursors.
Definition: cursor.cpp:178
void copy_to_clipboard(const std::string &text)
Copies text to the clipboard.
Definition: clipboard.cpp:27
bool open_object([[maybe_unused]] const std::string &path_or_url)
Definition: open.cpp:46
constexpr bool open_object_is_supported()
Returns whether open_object() is supported/implemented for the current platform.
Definition: open.hpp:54
Graphical text output.
const color_t YELLOW_COLOR
Generic file dialog.
point get_mouse_position()
Returns the current mouse position.
Definition: helper.cpp:168
PangoAlignment decode_text_alignment(const std::string &alignment)
Converts a text alignment string to a text alignment.
Definition: helper.cpp:84
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:148
@ OK
Dialog was closed with the OK button.
Definition: retval.hpp:35
Contains the implementation details for lexical_cast and shouldn't be used directly.
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
Desktop environment interaction functions.
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:61
virtual std::unique_ptr< widget > build() const override
Definition: label.cpp:241
std::string definition
Parameters for the styled_widget.
resolution(const config &cfg)
Definition: label.cpp:217
label_definition(const config &cfg)
Definition: label.cpp:209
std::vector< state_definition > state
Holds a 2D point.
Definition: point.hpp:25
std::string missing_mandatory_wml_tag(const std::string &section, const std::string &tag)
Returns a standard message for a missing wml child (tag).
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define VALIDATE_WML_CHILD(cfg, key, message)