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