The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
floating_label.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 by David White <[email protected]>
3  Part of the Battle for Wesnoth Project http://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.hpp"
19 #include "log.hpp"
20 #include "text.hpp"
21 
22 #include <map>
23 #include <set>
24 #include <stack>
25 
26 #include "sdl/alpha.hpp"
27 
28 static lg::log_domain log_font("font");
29 #define DBG_FT LOG_STREAM(debug, log_font)
30 #define LOG_FT LOG_STREAM(info, log_font)
31 #define WRN_FT LOG_STREAM(warn, log_font)
32 #define ERR_FT LOG_STREAM(err, log_font)
33 
34 namespace {
35 
36 typedef std::map<int, font::floating_label> label_map;
37 label_map labels;
38 int label_id = 1;
39 
40 std::stack<std::set<int> > label_contexts;
41 }
42 
43 namespace font {
44 
46 #if 0
47  : img_(),
48 #else
49  : surf_(surf), buf_(nullptr),
50 #endif
51  text_(text),
53  color_(NORMAL_COLOR), bgcolor_(), bgalpha_(0),
54  xpos_(0), ypos_(0),
55  xmove_(0), ymove_(0), lifetime_(-1),
56  width_(-1), height_(-1),
57  clip_rect_(screen_area()),
58  alpha_change_(0), visible_(true), align_(CENTER_ALIGN),
59  border_(0), scroll_(ANCHOR_LABEL_SCREEN), use_markup_(true)
60 {}
61 
62 void floating_label::move(double xmove, double ymove)
63 {
64  xpos_ += xmove;
65  ypos_ += ymove;
66 }
67 
68 int floating_label::xpos(size_t width) const
69 {
70  int xpos = int(xpos_);
71  if(align_ == font::CENTER_ALIGN) {
72  xpos -= width/2;
73  } else if(align_ == font::RIGHT_ALIGN) {
74  xpos -= width;
75  }
76 
77  return xpos;
78 }
79 
80 #if 0
81 sdl::timage floating_label::create_image()
82 {
83  if (img_.null()) {
84  font::ttext text;
85  text.set_foreground_color((color_.r << 24) | (color_.g << 16) | (color_.b << 8) | 255);
87  text.set_maximum_width(width_ < 0 ? clip_rect_.w : width_);
88  text.set_maximum_height(height_ < 0 ? clip_rect_.h : height_, true);
89 
90  //ignore last '\n'
91  if(!text_.empty() && *(text_.rbegin()) == '\n'){
92  text.set_text(std::string(text_.begin(), text_.end()-1), use_markup_);
93  } else {
94  text.set_text(text_, use_markup_);
95  }
96 
97  surface foreground = text.render();
98 
99  if(foreground == nullptr) {
100  ERR_FT << "could not create floating label's text" << std::endl;
101  return sdl::timage();
102  }
103 
104  // combine foreground text with its background
105  if(bgalpha_ != 0) {
106  // background is a dark tooltip box
107  surface background = create_neutral_surface(foreground->w + border_*2, foreground->h + border_*2);
108 
109  if (background == nullptr) {
110  ERR_FT << "could not create tooltip box" << std::endl;
111  img_ = sdl::timage(foreground);
112  return img_;
113  }
114 
115  Uint32 color = SDL_MapRGBA(foreground->format, bgcolor_.r,bgcolor_.g, bgcolor_.b, bgalpha_);
116  sdl::fill_rect(background,nullptr, color);
117 
118  // we make the text less transparent, because the blitting on the
119  // dark background will darken the anti-aliased part.
120  // This 1.13 value seems to restore the brightness of version 1.4
121  // (where the text was blitted directly on screen)
122  foreground = adjust_surface_alpha(foreground, ftofxp(1.13), false);
123 
124  SDL_Rect r = sdl::create_rect( border_, border_, 0, 0);
125  SDL_SetAlpha(foreground,SDL_SRCALPHA,SDL_ALPHA_OPAQUE);
126  blit_surface(foreground, nullptr, background, &r);
127 
128  img_ = sdl::timage(background);
129  }
130  else {
131  // background is blurred shadow of the text
132  surface background = create_neutral_surface
133  (foreground->w + 4, foreground->h + 4);
134  sdl::fill_rect(background, nullptr, 0);
135  SDL_Rect r = { 2, 2, 0, 0 };
136  blit_surface(foreground, nullptr, background, &r);
137  background = shadow_image(background, false);
138 
139  if (background == nullptr) {
140  ERR_FT << "could not create floating label's shadow" << std::endl;
141  img_ = sdl::timage(foreground);
142  return img_;
143  }
144  SDL_SetAlpha(foreground,SDL_SRCALPHA,SDL_ALPHA_OPAQUE);
145  blit_surface(foreground, nullptr, background, &r);
146  img_ = sdl::timage(background);
147  }
148  }
149 
150  return img_;
151 }
152 
153 #else
155 {
156  if (surf_.null()) {
157  font::ttext text;
158  text.set_foreground_color((color_.r << 24) | (color_.g << 16) | (color_.b << 8) | 255);
160  text.set_maximum_width(width_ < 0 ? clip_rect_.w : width_);
161  text.set_maximum_height(height_ < 0 ? clip_rect_.h : height_, true);
162 
163  //ignore last '\n'
164  if(!text_.empty() && *(text_.rbegin()) == '\n'){
165  text.set_text(std::string(text_.begin(), text_.end()-1), use_markup_);
166  } else {
167  text.set_text(text_, use_markup_);
168  }
169 
170  surface foreground = text.render();
171 
172  if(foreground == nullptr) {
173  ERR_FT << "could not create floating label's text" << std::endl;
174  return nullptr;
175  }
176 
177  // combine foreground text with its background
178  if(bgalpha_ != 0) {
179  // background is a dark tooltip box
180  surface background = create_neutral_surface(foreground->w + border_*2, foreground->h + border_*2);
181 
182  if (background == nullptr) {
183  ERR_FT << "could not create tooltip box" << std::endl;
184  surf_ = create_optimized_surface(foreground);
185  return surf_;
186  }
187 
188  Uint32 color = SDL_MapRGBA(foreground->format, bgcolor_.r,bgcolor_.g, bgcolor_.b, bgalpha_);
189  sdl::fill_rect(background,nullptr, color);
190 
191  // we make the text less transparent, because the blitting on the
192  // dark background will darken the anti-aliased part.
193  // This 1.13 value seems to restore the brightness of version 1.4
194  // (where the text was blitted directly on screen)
195  foreground = adjust_surface_alpha(foreground, ftofxp(1.13), false);
196 
197  SDL_Rect r = sdl::create_rect( border_, border_, 0, 0);
198  SDL_SetAlpha(foreground,SDL_SRCALPHA,SDL_ALPHA_OPAQUE);
199  blit_surface(foreground, nullptr, background, &r);
200 
201  surf_ = create_optimized_surface(background);
202  // RLE compression seems less efficient for big semi-transparent area
203  // so, remove it for this case, but keep the optimized display format
204  SDL_SetAlpha(surf_,SDL_SRCALPHA,SDL_ALPHA_OPAQUE);
205  }
206  else {
207  // background is blurred shadow of the text
208  surface background = create_neutral_surface
209  (foreground->w + 4, foreground->h + 4);
210  sdl::fill_rect(background, nullptr, 0);
211  SDL_Rect r = { 2, 2, 0, 0 };
212  blit_surface(foreground, nullptr, background, &r);
213  background = shadow_image(background, false);
214 
215  if (background == nullptr) {
216  ERR_FT << "could not create floating label's shadow" << std::endl;
217  surf_ = create_optimized_surface(foreground);
218  return surf_;
219  }
220  SDL_SetAlpha(foreground,SDL_SRCALPHA,SDL_ALPHA_OPAQUE);
221  blit_surface(foreground, nullptr, background, &r);
222  surf_ = create_optimized_surface(background);
223  }
224  }
225 
226  return surf_;
227 }
228 #endif
229 
230 #ifdef SDL_GPU
231 void floating_label::draw(CVideo &video)
232 {
233  if (!visible_) {
234  return;
235  }
236 #if 0
237  create_image();
238  if (img_.null()) {
239  return;
240  }
241 
242  video.draw_texture(img_, xpos(img_.width()), int(ypos_));
243 #else
244  create_surface();
245  if (surf_.null()) {
246  return;
247  }
248 
249  video.blit_to_overlay(surf_, xpos(surf_->w), int(ypos_));
250 #endif
251 }
252 
253 #else
255 {
256  if(!visible_) {
257  buf_.assign(nullptr);
258  return;
259  }
260 
261  if(screen == nullptr) {
262  return;
263  }
264 
265  create_surface();
266  if(surf_ == nullptr) {
267  return;
268  }
269 
270  if(buf_ == nullptr) {
272  if(buf_ == nullptr) {
273  return;
274  }
275  }
276 
277  SDL_Rect rect = sdl::create_rect(xpos(surf_->w), ypos_, surf_->w, surf_->h);
278  const clip_rect_setter clip_setter(screen, &clip_rect_);
279  sdl_copy_portion(screen,&rect,buf_,nullptr);
280  sdl_blit(surf_,nullptr,screen,&rect);
281 
282  update_rect(rect);
283 }
284 #endif
285 
286 #ifdef SDL_GPU
287 void floating_label::undraw(CVideo &video)
288 {
289  SDL_Rect r = sdl::create_rect(xpos(surf_->w), ypos_, surf_->w, surf_->h);
290  video.clear_overlay_area(r);
291 }
292 #else
294 {
295  if(screen == nullptr || buf_ == nullptr) {
296  return;
297  }
298  SDL_Rect rect = sdl::create_rect(xpos(surf_->w), ypos_, surf_->w, surf_->h);
299  const clip_rect_setter clip_setter(screen, &clip_rect_);
300  sdl_blit(buf_,nullptr,screen,&rect);
301 
302  update_rect(rect);
303 
304  move(xmove_,ymove_);
305  if(lifetime_ > 0) {
306  --lifetime_;
307  if(alpha_change_ != 0 && (xmove_ != 0.0 || ymove_ != 0.0) && surf_ != nullptr) {
308  // fade out moving floating labels
309  // note that we don't optimize these surfaces since they will always change
311  }
312  }
313 }
314 #endif
315 
317 {
318  if(label_contexts.empty()) {
319  return 0;
320  }
321 
322  ++label_id;
323  labels.insert(std::pair<int, floating_label>(label_id, flabel));
324  label_contexts.top().insert(label_id);
325  return label_id;
326 }
327 
328 void move_floating_label(int handle, double xmove, double ymove)
329 {
330  const label_map::iterator i = labels.find(handle);
331  if(i != labels.end()) {
332  i->second.move(xmove,ymove);
333  }
334 }
335 
336 void scroll_floating_labels(double xmove, double ymove)
337 {
338  for(label_map::iterator i = labels.begin(); i != labels.end(); ++i) {
339  if(i->second.scroll() == ANCHOR_LABEL_MAP) {
340  i->second.move(xmove,ymove);
341  }
342  }
343 }
344 
346 {
347  const label_map::iterator i = labels.find(handle);
348  if(i != labels.end()) {
349  if(label_contexts.empty() == false) {
350  label_contexts.top().erase(i->first);
351  }
352 
353  labels.erase(i);
354  }
355 }
356 
358 {
359  const label_map::iterator i = labels.find(handle);
360  if(i != labels.end()) {
361  i->second.show(value);
362  }
363 }
364 
366 {
367  const label_map::iterator i = labels.find(handle);
368 #if 0
369  if(i != labels.end()) {
370  const sdl::timage img = i->second.create_image();
371  if(!img.null()) {
372  return sdl::create_rect(0, 0, img.width(), img.height());
373  }
374  }
375 #else
376  if(i != labels.end()) {
377  const surface surf = i->second.create_surface();
378  if(surf != nullptr) {
379  return sdl::create_rect(0, 0, surf->w, surf->h);
380  }
381  }
382 #endif
383  return sdl::empty_rect;
384 }
385 
387 {
388 #ifdef SDL_GPU
389 
390 #else
391  surface const screen = nullptr;
392  if(screen != nullptr) {
393  draw_floating_labels(screen);
394  }
395 #endif
396 
397  label_contexts.push(std::set<int>());
398 }
399 
401 {
402  const std::set<int>& labels = label_contexts.top();
403  for(std::set<int>::const_iterator i = labels.begin(); i != labels.end(); ) {
405  }
406 
407  label_contexts.pop();
408 
409 #ifdef SDL_GPU
410  //TODO
411 #else
412  surface const screen = nullptr;
413  if(screen != nullptr) {
414  undraw_floating_labels(screen);
415  }
416 #endif
417 }
418 
419 #ifdef SDL_GPU
420 void draw_floating_labels(CVideo &video)
421 {
422  if(label_contexts.empty()) {
423  return;
424  }
425 
426  const std::set<int>& context = label_contexts.top();
427 
428  //draw the labels in the order they were added, so later added labels (likely to be tooltips)
429  //are displayed over earlier added labels.
430  for(label_map::iterator i = labels.begin(); i != labels.end(); ++i) {
431  if(context.count(i->first) > 0) {
432  i->second.draw(video);
433  }
434  }
435 }
436 
437 void undraw_floating_labels(CVideo &video)
438 {
439  if(label_contexts.empty()) {
440  return;
441  }
442 
443  std::set<int>& context = label_contexts.top();
444 
445  //remove expired labels
446  for(label_map::iterator j = labels.begin(); j != labels.end(); ) {
447  if(context.count(j->first) > 0 && j->second.expired()) {
448  j->second.undraw(video);
449  context.erase(j->first);
450  labels.erase(j++);
451  } else {
452  ++j;
453  }
454  }
455 }
456 
457 #else
459 {
460  if(label_contexts.empty()) {
461  return;
462  }
463 
464  const std::set<int>& context = label_contexts.top();
465 
466  //draw the labels in the order they were added, so later added labels (likely to be tooltips)
467  //are displayed over earlier added labels.
468  for(label_map::iterator i = labels.begin(); i != labels.end(); ++i) {
469  if(context.count(i->first) > 0) {
470  i->second.draw(screen);
471  }
472  }
473 }
474 
476 {
477  if(label_contexts.empty()) {
478  return;
479  }
480 
481  std::set<int>& context = label_contexts.top();
482 
483  //undraw labels in reverse order, so that a LIFO process occurs, and the screen is restored
484  //into the exact state it started in.
485  for(label_map::reverse_iterator i = labels.rbegin(); i != labels.rend(); ++i) {
486  if(context.count(i->first) > 0) {
487  i->second.undraw(screen);
488  }
489  }
490 
491  //remove expired labels
492  for(label_map::iterator j = labels.begin(); j != labels.end(); ) {
493  if(context.count(j->first) > 0 && j->second.expired()) {
494  context.erase(j->first);
495  labels.erase(j++);
496  } else {
497  ++j;
498  }
499  }
500 }
501 #endif
502 }
503 
floating_label(const std::string &text, const surface &surface=nullptr)
surface create_neutral_surface(int w, int h)
Definition: utils.cpp:150
bool null() const
Definition: utils.hpp:104
static lg::log_domain log_font("font")
void fill_rect(surface &dst, SDL_Rect *dst_rect, const Uint32 color)
Fill a rectangle on a given surface.
Definition: rect.hpp:143
Graphical text output.
surface adjust_surface_alpha_add(const surface &surf, int amount, bool optimize)
Definition: utils.cpp:1241
void scroll_floating_labels(double xmove, double ymove)
moves all floating labels that have 'scroll_mode' set to ANCHOR_LABEL_MAP
surface create_optimized_surface(const surface &surf)
Definition: utils.cpp:168
void show_floating_label(int handle, bool value)
hides or shows a floating label
Definition: video.hpp:58
game_display * screen
Definition: resources.cpp:27
const SDL_Rect empty_rect
Definition: rect.cpp:26
void remove_floating_label(int handle)
removes the floating label given by 'handle' from the screen
ttext & set_font_size(const unsigned font_size)
Definition: text.cpp:406
SDL_Color color_
Definition: font.cpp:605
ttext & set_maximum_width(int width)
Definition: text.cpp:446
void move(double xmove, double ymove)
tformula< t_string > text_
The text to draw.
Definition: canvas.cpp:1268
const SDL_Color NORMAL_COLOR
Definition: font.cpp:564
const int SIZE_NORMAL
Definition: font.hpp:58
void move_floating_label(int handle, double xmove, double ymove)
moves the floating label given by 'handle' by (xmove,ymove)
SDL_Rect screen_area()
Definition: video.cpp:135
void blit_surface(const surface &surf, const SDL_Rect *srcrect, surface &dst, const SDL_Rect *dstrect)
Replacement for sdl_blit.
Definition: utils.cpp:2185
surface shadow_image(const surface &surf, bool optimize)
create an heavy shadow of the image, by blurring, increasing alpha and darkening
Definition: utils.cpp:987
ttext & set_maximum_height(int height, bool multiline)
Definition: text.cpp:491
GLsizei const GLfloat * value
Definition: glew.h:1817
surface adjust_surface_alpha(const surface &surf, fixed_t amount, bool optimize)
Definition: utils.cpp:1202
#define ERR_FT
map_display and display: classes which take care of displaying the map and game-data on the screen...
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
surf
Definition: filter.cpp:143
GLuint color
Definition: glew.h:5801
surface render() const
Returns the rendered text.
Definition: text.cpp:166
int xpos(size_t width) const
void undraw_floating_labels(surface screen)
size_t i
Definition: function.cpp:1057
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)
GLdouble GLdouble GLdouble r
Definition: glew.h:1374
#define SDL_SRCALPHA
Definition: alpha.hpp:28
void undraw(surface screen)
int font_size_
Definition: font.cpp:604
SDL_Rect create_rect(const int x, const int y, const int w, const int h)
Creates an empty SDL_Rect.
Definition: rect.cpp:28
void draw(surface screen)
GLint GLvoid * img
Definition: glew.h:1353
Standard logging facilities (interface).
void assign(const surface &o)
Definition: utils.hpp:83
surface create_compatible_surface(const surface &surf, int width, int height)
Definition: utils.cpp:2166
bool set_text(const std::string &text, const bool markedup)
Sets the text to render.
Definition: text.cpp:360
GLint GLint GLint GLint GLint GLint GLsizei width
Definition: glew.h:1220
void sdl_copy_portion(const surface &screen, SDL_Rect *screen_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:116
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:112
int SDL_SetAlpha(SDL_Surface *surface, Uint32 flag, Uint8 alpha)
Definition: alpha.cpp:18
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
Compatibility layer for using SDL 1.2 and 2.0.
void update_rect(const SDL_Rect &)
Definition: dummy_video.cpp:27
GLsizei const GLcharARB ** string
Definition: glew.h:4503
Text class.
Definition: text.hpp:66
void draw_floating_labels(surface screen)
#define ftofxp(x)
IN: float or int - OUT: fixed_t.
Definition: util.hpp:503
boost::shared_ptr< halo_record > handle
Definition: halo.hpp:34
ttext & set_foreground_color(const Uint32 color)
Definition: text.cpp:429