The Battle for Wesnoth  1.15.2+dev
label.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2018 by Mark de Wever <koraq@xs4all.nl>
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 
17 #include "gui/widgets/label.hpp"
18 
19 #include "gui/core/log.hpp"
20 
24 #include "gui/dialogs/message.hpp"
25 #include "gui/widgets/settings.hpp"
26 #include "gui/widgets/window.hpp"
27 
28 #include "desktop/clipboard.hpp"
29 #include "desktop/open.hpp"
30 #include "gettext.hpp"
31 
32 #include "utils/functional.hpp"
33 #include <string>
34 #include <sstream>
35 
36 namespace gui2
37 {
38 
39 // ------------ WIDGET -----------{
40 
41 REGISTER_WIDGET(label)
42 
43 label::label(const implementation::builder_label& builder)
44  : styled_widget(builder, type())
45  , state_(ENABLED)
46  , can_wrap_(false)
47  , characters_per_line_(0)
48  , link_aware_(false)
49  , link_color_(color_t::from_hex_string("ffff00"))
50  , can_shrink_(false)
51  , text_alpha_(255)
52 {
53  connect_signal<event::LEFT_BUTTON_CLICK>(std::bind(&label::signal_handler_left_button_click, this, _2, _3));
54  connect_signal<event::RIGHT_BUTTON_CLICK>(std::bind(&label::signal_handler_right_button_click, this, _2, _3));
55 }
56 
57 bool label::can_wrap() const
58 {
59  return can_wrap_ || characters_per_line_ != 0;
60 }
61 
63 {
64  return characters_per_line_;
65 }
66 
68 {
69  return link_aware_;
70 }
71 
73 {
74  return link_color_;
75 }
76 
77 void label::set_text_alpha(unsigned short alpha)
78 {
79  text_alpha_ = alpha;
80 
81  for(auto& tmp : get_canvases()) {
82  tmp.set_variable("text_alpha", wfl::variant(text_alpha_));
83  }
84 
85  set_is_dirty(true);
86 }
87 
88 void label::set_active(const bool active)
89 {
90  if(get_active() != active) {
91  set_state(active ? ENABLED : DISABLED);
92  }
93 }
94 
95 bool label::get_active() const
96 {
97  return state_ != DISABLED;
98 }
99 
100 unsigned label::get_state() const
101 {
102  return state_;
103 }
104 
106 {
107  return false;
108 }
109 
110 void label::set_characters_per_line(const unsigned characters_per_line)
111 {
112  characters_per_line_ = characters_per_line;
113 }
114 
115 void label::set_link_aware(bool link_aware)
116 {
117  if(link_aware == link_aware_) {
118  return;
119  }
120 
121  link_aware_ = link_aware;
122  update_canvas();
123  set_is_dirty(true);
124 }
125 
126 void label::set_link_color(const color_t& color)
127 {
128  if(color == link_color_) {
129  return;
130  }
131  link_color_ = color;
132  update_canvas();
133  set_is_dirty(true);
134 }
135 
136 void label::set_state(const state_t state)
137 {
138  if(state != state_) {
139  state_ = state;
140  set_is_dirty(true);
141  }
142 }
143 
144 void label::signal_handler_left_button_click(const event::ui_event /* event */, bool & handled)
145 {
146  DBG_GUI_E << "label click" << std::endl;
147 
148  if (!get_link_aware()) {
149  return; // without marking event as "handled".
150  }
151 
153  show_message("", _("Opening links is not supported, contact your packager"), dialogs::message::auto_close);
154  handled = true;
155  return;
156  }
157 
158 
159  point mouse = get_mouse_position();
160 
161  mouse.x -= get_x();
162  mouse.y -= get_y();
163 
164  std::string link = get_label_link(mouse);
165 
166  if (link.length() == 0) {
167  return ; // without marking event as "handled"
168  }
169 
170  DBG_GUI_E << "Clicked Link:\"" << link << "\"\n";
171 
172  const int res = show_message(_("Do you want to open this link?"), link, dialogs::message::yes_no_buttons);
173  if(res == gui2::retval::OK) {
174  desktop::open_object(link);
175  }
176 
177  handled = true;
178 }
179 
180 void label::signal_handler_right_button_click(const event::ui_event /* event */, bool & handled)
181 {
182  DBG_GUI_E << "label right click" << std::endl;
183 
184  if (!get_link_aware()) {
185  return ; // without marking event as "handled".
186  }
187 
188  point mouse = get_mouse_position();
189 
190  mouse.x -= get_x();
191  mouse.y -= get_y();
192 
193  std::string link = get_label_link(mouse);
194 
195  if (link.length() == 0) {
196  return ; // without marking event as "handled"
197  }
198 
199  DBG_GUI_E << "Right Clicked Link:\"" << link << "\"\n";
200 
202 
203  (void) show_message("", _("Copied link!"), dialogs::message::auto_close);
204 
205  handled = true;
206 }
207 
208 // }---------- DEFINITION ---------{
209 
212 {
213  DBG_GUI_P << "Parsing label " << id << '\n';
214 
215  load_resolutions<resolution>(cfg);
216 }
217 
218 /*WIKI
219  * @page = GUIWidgetDefinitionWML
220  * @order = 1_label
221  *
222  * == Label ==
223  *
224  * @macro = label_description
225  *
226  * Although the label itself has no event interaction it still has two states.
227  * The reason is that labels are often used as visual indication of the state
228  * of the widget it labels.
229  *
230  * Note: The above is outdated, if "link_aware" is enabled then there is interaction.
231  *
232  *
233  * The following states exist:
234  * * state_enabled, the label is enabled.
235  * * state_disabled, the label is disabled.
236  * @begin{parent}{name="gui/"}
237  * @begin{tag}{name="label_definition"}{min=0}{max=-1}{super="generic/widget_definition"}
238  * @begin{tag}{name="resolution"}{min=0}{max=-1}{super="generic/widget_definition/resolution"}
239  * @begin{table}{config}
240  * link_aware & f_bool & false & Whether the label is link aware. This means
241  * it is rendered with links highlighted,
242  * and responds to click events on those
243  * links. $
244  * link_color & string & #ffff00 & The color to render links with. This
245  * string will be used verbatim in pango
246  * markup for each link. $
247  * @end{table}
248  * @begin{tag}{name="state_enabled"}{min=0}{max=1}{super="generic/state"}
249  * @end{tag}{name="state_enabled"}
250  * @begin{tag}{name="state_disabled"}{min=0}{max=1}{super="generic/state"}
251  * @end{tag}{name="state_disabled"}
252  * @end{tag}{name="resolution"}
253  * @end{tag}{name="label_definition"}
254  * @end{parent}{name="gui/"}
255  */
257  : resolution_definition(cfg)
258  , link_aware(cfg["link_aware"].to_bool(false))
259  , link_color(cfg["link_color"].empty() ? color_t::from_hex_string("ffff00") : color_t::from_rgba_string(cfg["link_color"].str()))
260 {
261  // Note the order should be the same as the enum state_t is label.hpp.
262  state.emplace_back(cfg.child("state_enabled"));
263  state.emplace_back(cfg.child("state_disabled"));
264 }
265 
266 // }---------- BUILDER -----------{
267 
268 /*WIKI_MACRO
269  * @begin{macro}{label_description}
270  *
271  * A label displays a text, the text can be wrapped but no scrollbars
272  * are provided.
273  * @end{macro}
274  */
275 
276 /*WIKI
277  * @page = GUIWidgetInstanceWML
278  * @order = 2_label
279  * @begin{parent}{name="gui/window/resolution/grid/row/column/"}
280  * @begin{tag}{name="label"}{min=0}{max=-1}{super="generic/widget_instance"}
281  * == Label ==
282  *
283  * @macro = label_description
284  *
285  * List with the label specific variables:
286  * @begin{table}{config}
287  * wrap & bool & false & Is wrapping enabled for the label. $
288  * characters_per_line & unsigned & 0 &
289  * Sets the maximum number of characters per
290  * line. The amount is an approximate since the
291  * width of a character differs. E.g. iii is
292  * smaller than MMM. When the value is non-zero
293  * it also implies can_wrap is true.
294  * When having long strings wrapping them can
295  * increase readability, often 66 characters per
296  * line is considered the optimum for a one
297  * column text.
298  * text_alignment & h_align & "left" &
299  * How is the text aligned in the label. $
300  * @end{table}
301  * @end{tag}{name="label"}
302  * @end{parent}{name="gui/window/resolution/grid/row/column/"}
303  */
304 
305 namespace implementation
306 {
307 
308 builder_label::builder_label(const config& cfg)
309  : builder_styled_widget(cfg)
310  , wrap(cfg["wrap"].to_bool())
311  , characters_per_line(cfg["characters_per_line"])
312  , text_alignment(decode_text_alignment(cfg["text_alignment"]))
313  , can_shrink(cfg["can_shrink"].to_bool(false))
314 {
315 }
316 
318 {
319  label* lbl = new label(*this);
320 
321  const auto conf = lbl->cast_config_to<label_definition>();
322  assert(conf);
323 
324  lbl->set_can_wrap(wrap);
329  lbl->set_link_aware(conf->link_aware);
330  lbl->set_link_color(conf->link_color);
331 
332  DBG_GUI_G << "Window builder: placed label '" << id << "' with definition '"
333  << definition << "'.\n";
334 
335  return lbl;
336 }
337 
338 } // namespace implementation
339 
340 // }------------ END --------------
341 
342 } // namespace gui2
Define the common log macros for the gui toolkit.
Base class of a resolution, contains the common keys for a resolution.
#define DBG_GUI_P
Definition: log.hpp:68
void set_can_shrink(bool can_shrink)
Definition: label.hpp:78
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:152
int get_x() const
Definition: widget.cpp:312
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:420
std::vector< state_definition > state
color_t link_color_
What color links will be rendered in.
Definition: label.hpp:125
void set_can_wrap(const bool wrap)
Definition: label.hpp:65
virtual color_t get_link_color() const override
See styled_widget::get_link_aware.
Definition: label.cpp:72
void set_characters_per_line(const unsigned set_characters_per_line)
Definition: label.cpp:110
This file contains the window object, this object is a top level container which has the event manage...
Base class for all widgets.
Definition: widget.hpp:47
void signal_handler_left_button_click(const event::ui_event event, bool &handled)
Left click signal handler: checks if we clicked on a hyperlink.
Definition: label.cpp:144
void signal_handler_right_button_click(const event::ui_event event, bool &handled)
Right click signal handler: checks if we clicked on a hyperlink, copied to clipboard.
Definition: label.cpp:180
Label showing a text.
Definition: label.hpp:32
PangoAlignment decode_text_alignment(const std::string &alignment)
Converts a text alignment string to a text alignment.
Definition: helper.cpp:63
unsigned short text_alpha_
Definition: label.hpp:129
int x
x coordinate.
Definition: point.hpp:44
Generic file dialog.
Definition: field-fwd.hpp:22
unsigned characters_per_line_
The maximum number of characters per line.
Definition: label.hpp:114
Desktop environment interaction functions.
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
std::string definition
Parameters for the styled_widget.
This file contains the settings handling of the widget library.
void set_is_dirty(const bool is_dirty)
Definition: widget.cpp:463
virtual bool get_link_aware() const override
See styled_widget::get_link_aware.
Definition: label.cpp:67
virtual unsigned get_state() const override
See styled_widget::get_state.
Definition: label.cpp:100
void set_text_alpha(unsigned short alpha)
Definition: label.cpp:77
virtual void update_canvas()
Updates the canvas(ses).
Shows a yes and no button.
Definition: message.hpp:79
virtual void set_text_alignment(const PangoAlignment text_alignment)
std::vector< canvas > & get_canvases()
int get_y() const
Definition: widget.cpp:317
bool disable_click_dismiss() const override
See widget::disable_click_dismiss.
Definition: label.cpp:105
void set_link_color(const color_t &color)
Definition: label.cpp:126
state_t state_
Current state of the widget.
Definition: label.hpp:104
virtual bool get_active() const override
See styled_widget::get_active.
Definition: label.cpp:95
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
bool link_aware_
Whether the label is link aware, rendering links with special formatting and handling click events...
Definition: label.hpp:120
bool open_object(const std::string &path_or_url)
Opens the specified object with the default application configured for its type.
Definition: open.cpp:55
std::string get_label_link(const point &position) const
#define DBG_GUI_E
Definition: log.hpp:34
std::shared_ptr< const typename T::resolution > cast_config_to() const
Casts the current resolution definition config to the respective type of a derived widget...
state_t
Possible states of the widget.
Definition: label.hpp:91
Holds a 2D point.
Definition: point.hpp:23
resolution(const config &cfg)
Definition: label.cpp:256
Base class for all visible items.
virtual unsigned get_characters_per_line() const override
See styled_widget::get_characters_per_line.
Definition: label.cpp:62
virtual bool can_wrap() const override
See widget::can_wrap.
Definition: label.cpp:57
point get_mouse_position()
Returns the current mouse position.
Definition: helper.cpp:116
bool open_object_is_supported()
Returns whether open_object() is supported/implemented for the current platform.
Definition: open.cpp:46
void copy_to_clipboard(const std::string &text, const bool)
Copies text to the clipboard.
Definition: clipboard.cpp:35
const uint8_t ALPHA_OPAQUE
Definition: color.hpp:48
void set_state(const state_t state)
Definition: label.cpp:136
label_definition(const config &cfg)
Definition: label.cpp:210
Dialog was closed with the OK button.
Definition: retval.hpp:34
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
Enables auto close.
Definition: message.hpp:69
int y
y coordinate.
Definition: point.hpp:47
#define DBG_GUI_G
Definition: log.hpp:40
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: label.cpp:88
void set_link_aware(bool l)
Definition: label.cpp:115
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
ui_event
The event send to the dispatcher.
Definition: handler.hpp:55
bool can_wrap_
Holds the label can wrap or not.
Definition: label.hpp:107