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