The Battle for Wesnoth  1.15.1+dev
floating_label.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 by David White <dave@whitevine.net>
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 #include "floating_label.hpp"
16 
17 #include "display.hpp"
18 #include "font/text.hpp"
19 #include "log.hpp"
20 #include "video.hpp"
21 
22 #include <map>
23 #include <set>
24 #include <stack>
25 
26 static lg::log_domain log_font("font");
27 #define DBG_FT LOG_STREAM(debug, log_font)
28 #define LOG_FT LOG_STREAM(info, log_font)
29 #define WRN_FT LOG_STREAM(warn, log_font)
30 #define ERR_FT LOG_STREAM(err, log_font)
31 
32 namespace
33 {
34 typedef std::map<int, font::floating_label> label_map;
35 label_map labels;
36 int label_id = 1;
37 
38 std::stack<std::set<int>> label_contexts;
39 }
40 
41 namespace font
42 {
43 floating_label::floating_label(const std::string& text, const surface& surf)
44 #if 0
45  : img_(),
46 #else
47  : surf_(surf)
48  , buf_(nullptr)
49 #endif
50  , text_(text)
51  , font_size_(SIZE_NORMAL)
52  , color_(NORMAL_COLOR)
53  , bgcolor_()
54  , bgalpha_(0)
55  , xpos_(0)
56  , ypos_(0)
57  , xmove_(0)
58  , ymove_(0)
59  , lifetime_(-1)
60  , width_(-1)
61  , height_(-1)
62  , clip_rect_(CVideo::get_singleton().screen_area())
63  , alpha_change_(0)
64  , visible_(true)
65  , align_(CENTER_ALIGN)
66  , border_(0)
67  , scroll_(ANCHOR_LABEL_SCREEN)
68  , use_markup_(true)
69 {
70 }
71 
72 void floating_label::move(double xmove, double ymove)
73 {
74  xpos_ += xmove;
75  ypos_ += ymove;
76 }
77 
78 int floating_label::xpos(std::size_t width) const
79 {
80  int xpos = int(xpos_);
81  if(align_ == font::CENTER_ALIGN) {
82  xpos -= width / 2;
83  } else if(align_ == font::RIGHT_ALIGN) {
84  xpos -= width;
85  }
86 
87  return xpos;
88 }
89 
91 {
92  if(!surf_) {
93  font::pango_text text;
96  text.set_maximum_width(width_ < 0 ? clip_rect_.w : width_);
97  text.set_maximum_height(height_ < 0 ? clip_rect_.h : height_, true);
98 
99  // ignore last '\n'
100  if(!text_.empty() && *(text_.rbegin()) == '\n') {
101  text.set_text(std::string(text_.begin(), text_.end() - 1), use_markup_);
102  } else {
103  text.set_text(text_, use_markup_);
104  }
105 
106  surface foreground = text.render();
107 
108  if(foreground == nullptr) {
109  ERR_FT << "could not create floating label's text" << std::endl;
110  return nullptr;
111  }
112 
113  // combine foreground text with its background
114  if(bgalpha_ != 0) {
115  // background is a dark tooltip box
116  surface background(foreground->w + border_ * 2, foreground->h + border_ * 2);
117 
118  if(background == nullptr) {
119  ERR_FT << "could not create tooltip box" << std::endl;
120  return surf_ = foreground;
121  }
122 
123  uint32_t color = SDL_MapRGBA(foreground->format, bgcolor_.r, bgcolor_.g, bgcolor_.b, bgalpha_);
124  sdl::fill_surface_rect(background, nullptr, color);
125 
126  // we make the text less transparent, because the blitting on the
127  // dark background will darken the anti-aliased part.
128  // This 1.13 value seems to restore the brightness of version 1.4
129  // (where the text was blitted directly on screen)
130  adjust_surface_alpha(foreground, ftofxp(1.13));
131 
132  SDL_Rect r{border_, border_, 0, 0};
133  adjust_surface_alpha(foreground, SDL_ALPHA_OPAQUE);
134  sdl_blit(foreground, nullptr, background, &r);
135 
136  surf_ = background;
137  } else {
138  // background is blurred shadow of the text
139  surface background(foreground->w + 4, foreground->h + 4);
140  sdl::fill_surface_rect(background, nullptr, 0);
141  SDL_Rect r{2, 2, 0, 0};
142  sdl_blit(foreground, nullptr, background, &r);
143  background = shadow_image(background);
144 
145  if(background == nullptr) {
146  ERR_FT << "could not create floating label's shadow" << std::endl;
147  return surf_ = foreground;
148  }
149  sdl_blit(foreground, nullptr, background, &r);
150  surf_ = background;
151  }
152  }
153 
154  return surf_;
155 }
156 
158 {
159  if(!visible_) {
160  buf_ = nullptr;
161  return;
162  }
163 
164  if(screen == nullptr) {
165  return;
166  }
167 
168  create_surface();
169  if(surf_ == nullptr) {
170  return;
171  }
172 
173  if(buf_ == nullptr) {
174  buf_ = surface(surf_->w, surf_->h);
175  if(buf_ == nullptr) {
176  return;
177  }
178  }
179 
180  SDL_Rect rect = sdl::create_rect(xpos(surf_->w), ypos_, surf_->w, surf_->h);
181  const clip_rect_setter clip_setter(screen, &clip_rect_);
182  sdl_copy_portion(screen,&rect,buf_,nullptr);
183  sdl_blit(surf_,nullptr,screen,&rect);
184 }
185 
187 {
188  if(screen == nullptr || buf_ == nullptr) {
189  return;
190  }
191  SDL_Rect rect = sdl::create_rect(xpos(surf_->w), ypos_, surf_->w, surf_->h);
192  const clip_rect_setter clip_setter(screen, &clip_rect_);
193  sdl_blit(buf_,nullptr,screen,&rect);
194 
195  move(xmove_,ymove_);
196  if(lifetime_ > 0) {
197  --lifetime_;
198  if(alpha_change_ != 0 && (xmove_ != 0.0 || ymove_ != 0.0) && surf_ != nullptr) {
199  // fade out moving floating labels
201  }
202  }
203 }
204 
206 {
207  if(label_contexts.empty()) {
208  return 0;
209  }
210 
211  ++label_id;
212  labels.emplace(label_id, flabel);
213  label_contexts.top().insert(label_id);
214  return label_id;
215 }
216 
217 void move_floating_label(int handle, double xmove, double ymove)
218 {
219  const label_map::iterator i = labels.find(handle);
220  if(i != labels.end()) {
221  i->second.move(xmove, ymove);
222  }
223 }
224 
225 void scroll_floating_labels(double xmove, double ymove)
226 {
227  for(label_map::iterator i = labels.begin(); i != labels.end(); ++i) {
228  if(i->second.scroll() == ANCHOR_LABEL_MAP) {
229  i->second.move(xmove, ymove);
230  }
231  }
232 }
233 
235 {
236  const label_map::iterator i = labels.find(handle);
237  if(i != labels.end()) {
238  labels.erase(i);
239  }
240 
241  if(!label_contexts.empty()) {
242  label_contexts.top().erase(handle);
243  }
244 }
245 
246 void show_floating_label(int handle, bool value)
247 {
248  const label_map::iterator i = labels.find(handle);
249  if(i != labels.end()) {
250  i->second.show(value);
251  }
252 }
253 
255 {
256  const label_map::iterator i = labels.find(handle);
257  if(i != labels.end()) {
258  const surface surf = i->second.create_surface();
259  if(surf != nullptr) {
260  return {0, 0, surf->w, surf->h};
261  }
262  }
263  return sdl::empty_rect;
264 }
265 
267 {
268  label_contexts.emplace();
269 }
270 
272 {
273  const std::set<int>& context = label_contexts.top();
274 
275  while(!context.empty()) {
276  // Remove_floating_label removes the passed label from the context.
277  // This loop removes a different label in every iteration.
278  remove_floating_label(*context.begin());
279  }
280 
281  label_contexts.pop();
282 }
283 
285 {
286  if(label_contexts.empty()) {
287  return;
288  }
289 
290  const std::set<int>& context = label_contexts.top();
291 
292  // draw the labels in the order they were added, so later added labels (likely to be tooltips)
293  // are displayed over earlier added labels.
294  for(label_map::iterator i = labels.begin(); i != labels.end(); ++i) {
295  if(context.count(i->first) > 0) {
296  i->second.draw(screen);
297  }
298  }
299 }
300 
302 {
303  if(label_contexts.empty()) {
304  return;
305  }
306 
307  std::set<int>& context = label_contexts.top();
308 
309  //undraw labels in reverse order, so that a LIFO process occurs, and the screen is restored
310  //into the exact state it started in.
311  for(label_map::reverse_iterator i = labels.rbegin(); i != labels.rend(); ++i) {
312  if(context.count(i->first) > 0) {
313  i->second.undraw(screen);
314  }
315  }
316 
317  //remove expired labels
318  for(label_map::iterator j = labels.begin(); j != labels.end(); ) {
319  if(context.count(j->first) > 0 && j->second.expired()) {
320  context.erase(j->first);
321  labels.erase(j++);
322  } else {
323  ++j;
324  }
325  }
326 }
327 }
floating_label(const std::string &text, const surface &surface=nullptr)
int xpos(std::size_t width) const
static lg::log_domain log_font("font")
bool set_text(const std::string &text, const bool markedup)
Sets the text to render.
Definition: text.cpp:283
Note: Specific to sdl_ttf.
void scroll_floating_labels(double xmove, double ymove)
moves all floating labels that have &#39;scroll_mode&#39; set to ANCHOR_LABEL_MAP
void show_floating_label(int handle, bool value)
hides or shows a floating label
void remove_floating_label(int handle)
removes the floating label given by &#39;handle&#39; from the screen
void fill_surface_rect(surface &dst, SDL_Rect *dst_rect, const uint32_t color)
Fill a rectangle on a given surface.
Definition: rect.hpp:114
static CVideo & get_singleton()
Definition: video.hpp:43
void move(double xmove, double ymove)
-file util.hpp
const int SIZE_NORMAL
Definition: constants.cpp:19
void move_floating_label(int handle, double xmove, double ymove)
moves the floating label given by &#39;handle&#39; by (xmove,ymove)
void adjust_surface_alpha(surface &surf, fixed_t amount)
Definition: utils.cpp:1086
surface shadow_image(const surface &surf)
create an heavy shadow of the image, by blurring, increasing alpha and darkening
Definition: utils.cpp:866
surface adjust_surface_alpha_add(const surface &surf, int amount)
Definition: utils.cpp:1095
pango_text & set_font_size(const unsigned font_size)
Definition: text.cpp:331
#define ERR_FT
uint8_t r
Red value.
Definition: color.hpp:177
map_display and display: classes which take care of displaying the map and game-data on the screen...
const color_t NORMAL_COLOR
#define ftofxp(x)
IN: float or int - OUT: fixed_t.
Definition: math.hpp:297
std::size_t i
Definition: function.cpp:933
void undraw_floating_labels(surface screen)
int add_floating_label(const floating_label &flabel)
add a label floating on the screen above everything else.
SDL_Rect get_floating_label_rect(int handle)
void undraw(surface screen)
Text class.
Definition: text.hpp:74
SDL_Rect create_rect(const int x, const int y, const int w, const int h)
Creates an SDL_Rect with the given dimensions.
Definition: rect.hpp:39
void draw(surface screen)
pango_text & set_maximum_width(int width)
Definition: text.cpp:364
constexpr const SDL_Rect empty_rect
Definition: rect.hpp:31
Standard logging facilities (interface).
void sdl_copy_portion(const surface &screen, SDL_Rect *screen_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:37
surface & render()
Returns the rendered text.
Definition: text.cpp:90
pango_text & set_maximum_height(int height, bool multiline)
Definition: text.cpp:391
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:33
uint8_t g
Green value.
Definition: color.hpp:180
uint8_t b
Blue value.
Definition: color.hpp:183
pango_text & set_foreground_color(const color_t &color)
Definition: text.cpp:354
std::shared_ptr< halo_record > handle
Definition: halo.hpp:31
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
void draw_floating_labels(surface screen)