The Battle for Wesnoth  1.15.12+dev
show_dialog.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 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 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
17 #include "show_dialog.hpp"
18 
19 #include "floating_label.hpp"
20 #include "picture.hpp"
21 #include "gettext.hpp"
23 #include "help/help.hpp"
25 #include "log.hpp"
26 #include "font/sdl_ttf_compat.hpp"
27 #include "font/standard_colors.hpp"
28 #include "sdl/rect.hpp"
29 
30 static lg::log_domain log_display("display");
31 #define ERR_DP LOG_STREAM(err, log_display)
32 #define ERR_G LOG_STREAM(err, lg::general)
33 
34 namespace {
35 bool is_in_dialog = false;
36 }
37 
38 namespace gui {
39 
40 //static initialization
41 const int ButtonHPadding = 10;
42 const int ButtonVPadding = 10;
43 
44 //note: style names are directly related to the panel image file names
46 
47 const int dialog_frame::title_border_w = 10;
48 const int dialog_frame::title_border_h = 5;
49 
50 
51 
52 bool in_dialog()
53 {
54  return is_in_dialog || gui2::is_in_dialog();
55 }
56 
58 {
59  is_in_dialog = true;
60 }
61 
63 {
65  int mousex, mousey;
66  SDL_GetMouseState(&mousex, &mousey);
67  SDL_Event pb_event;
68  pb_event.type = SDL_MOUSEMOTION;
69  pb_event.motion.state = 0;
70  pb_event.motion.x = mousex;
71  pb_event.motion.y = mousey;
72  pb_event.motion.xrel = 0;
73  pb_event.motion.yrel = 0;
74  SDL_PushEvent(&pb_event);
75 }
76 
77 dialog_frame::dialog_frame(CVideo& video, const std::string& title,
78  const style& style, bool auto_restore,
79  std::vector<button*>* buttons, button* help_button) :
80  title_(title),
81  video_(video),
82  dialog_style_(style),
83  buttons_(buttons),
84  help_button_(help_button),
85  restorer_(nullptr),
86  auto_restore_(auto_restore),
87  dim_(),
88  top_(image::get_image("dialogs/" + dialog_style_.panel + "-border-top.png")),
89  bot_(image::get_image("dialogs/" + dialog_style_.panel + "-border-bottom.png")),
90  left_(image::get_image("dialogs/" + dialog_style_.panel + "-border-left.png")),
91  right_(image::get_image("dialogs/" + dialog_style_.panel + "-border-right.png")),
92  top_left_(image::get_image("dialogs/" + dialog_style_.panel + "-border-topleft.png")),
93  bot_left_(image::get_image("dialogs/" + dialog_style_.panel + "-border-botleft.png")),
94  top_right_(image::get_image("dialogs/" + dialog_style_.panel + "-border-topright.png")),
95  bot_right_(image::get_image("dialogs/" + dialog_style_.panel + "-border-botright.png")),
96  bg_(image::get_image("dialogs/" + dialog_style_.panel + "-background.png")),
97  have_border_(top_ != nullptr && bot_ != nullptr && left_ != nullptr && right_ != nullptr),
98  dirty_(true)
99 {
100 }
101 
103 {
104  delete restorer_;
105 }
106 
108  interior(sdl::empty_rect), exterior(sdl::empty_rect), title(sdl::empty_rect), button_row(sdl::empty_rect)
109 {}
110 
112  return layout(rect.x, rect.y, rect.w, rect.h);
113 }
114 
116  int padding = 0;
117  if(have_border_) {
118  padding += top_->h;
119  }
120  if(!title_.empty()) {
122  }
123  return padding;
124 }
125 
126 void dialog_frame::set_dirty(bool dirty) {
127  dirty_ = dirty;
128 }
129 
130 void dialog_frame::handle_window_event(const SDL_Event& event) {
131 
132  if (event.type == SDL_WINDOWEVENT) {
133  switch (event.window.event) {
134  case SDL_WINDOWEVENT_RESIZED:
135  case SDL_WINDOWEVENT_RESTORED:
136  case SDL_WINDOWEVENT_SHOWN:
137  case SDL_WINDOWEVENT_EXPOSED:
138  set_dirty();
139  }
140  }
141 }
142 
143 void dialog_frame::handle_event(const SDL_Event& event) {
144 
145  if (event.type == DRAW_ALL_EVENT) {
146  set_dirty();
147 
148  if (buttons_) {
149  for(std::vector<button *>::iterator it = buttons_->begin(); it != buttons_->end(); ++it) {
150  (*it)->set_dirty(true);
151  }
152  }
153  }
154 
155  if (event.type == DRAW_EVENT || event.type == DRAW_ALL_EVENT) {
156  draw();
157  }
158 }
159 
161  int padding = 0;
162  if(buttons_ != nullptr) {
163  for(std::vector<button*>::const_iterator b = buttons_->begin(); b != buttons_->end(); ++b) {
164  padding = std::max<int>((**b).height() + ButtonVPadding, padding);
165  }
166  }
167  if(have_border_) {
168  padding += bot_->h;
169  }
170  return padding;
171 }
172 
175  if(!title_.empty()) {
176  dim_.title = draw_title(nullptr);
178  }
179  if(buttons_ != nullptr) {
180  for(std::vector<button*>::const_iterator b = buttons_->begin(); b != buttons_->end(); ++b) {
181  dim_.button_row.w += (**b).width() + ButtonHPadding;
182  dim_.button_row.h = std::max<int>((**b).height() + ButtonVPadding,dim_.button_row.h);
183  }
184 
186  dim_.button_row.y = y + h;
187 
189  }
190 
191  std::size_t buttons_width = dim_.button_row.w;
192 
193  if(help_button_ != nullptr) {
194  buttons_width += help_button_->width() + ButtonHPadding*2;
195  dim_.button_row.y = y + h;
196  }
197 
198  y -= dim_.title.h;
199  w = std::max(w, std::max(dim_.title.w, static_cast<int>(buttons_width)));
200  h += dim_.title.h + dim_.button_row.h;
201  dim_.button_row.x += x + w;
202 
203  SDL_Rect bounds = video_.screen_area();
204  if(have_border_) {
205  bounds.x += left_->w;
206  bounds.y += top_->h;
207  bounds.w -= left_->w;
208  bounds.h -= top_->h;
209  }
210  if(x < bounds.x) {
211  w += x;
212  x = bounds.x;
213  }
214  if(y < bounds.y) {
215  h += y;
216  y = bounds.y;
217  }
218  if(x > bounds.w) {
219  w = 0;
220  } else if(x + w > bounds.w) {
221  w = bounds.w - x;
222  }
223  if(y > bounds.h) {
224  h = 0;
225  } else if(y + h > bounds.h) {
226  h = bounds.h - y;
227  }
228  dim_.interior.x = x;
229  dim_.interior.y = y;
230  dim_.interior.w = w;
231  dim_.interior.h = h;
232  if(have_border_) {
233  dim_.exterior.x = dim_.interior.x - left_->w;
234  dim_.exterior.y = dim_.interior.y - top_->h;
235  dim_.exterior.w = dim_.interior.w + left_->w + right_->w;
236  dim_.exterior.h = dim_.interior.h + top_->h + bot_->h;
237  } else {
239  }
242  return dim_;
243 }
244 
246 {
247  if(have_border_ == false) {
248  return;
249  }
250 
251  surface top_image(scale_surface(top_, dim_.interior.w, top_->h));
252 
253  if(top_image != nullptr) {
254  video_.blit_surface(dim_.interior.x, dim_.exterior.y, top_image);
255  }
256 
257  surface bot_image(scale_surface(bot_, dim_.interior.w, bot_->h));
258 
259  if(bot_image != nullptr) {
260  video_.blit_surface(dim_.interior.x, dim_.interior.y + dim_.interior.h, bot_image);
261  }
262 
263  surface left_image(scale_surface(left_, left_->w, dim_.interior.h));
264 
265  if(left_image != nullptr) {
266  video_.blit_surface(dim_.exterior.x, dim_.interior.y, left_image);
267  }
268 
269  surface right_image(scale_surface(right_, right_->w, dim_.interior.h));
270 
271  if(right_image != nullptr) {
272  video_.blit_surface(dim_.interior.x + dim_.interior.w, dim_.interior.y, right_image);
273  }
274 
275  if(top_left_ == nullptr || bot_left_ == nullptr || top_right_ == nullptr || bot_right_ == nullptr) {
276  return;
277  }
278 
283 }
284 
286 {
287  delete restorer_;
288  restorer_ = nullptr;
289 }
290 
292 {
293  if(auto_restore_) {
296  }
297 
300  surf = blur_surface(surf, dialog_style_.blur_radius);
301  sdl_blit(surf, nullptr, video_.getSurface(), &dim_.exterior);
302  }
303 
304  if(bg_ == nullptr) {
305  ERR_DP << "could not find dialog background '" << dialog_style_.panel << "'" << std::endl;
306  return;
307  }
308  for(int i = 0; i < dim_.interior.w; i += bg_->w) {
309  for(int j = 0; j < dim_.interior.h; j += bg_->h) {
310  SDL_Rect src {0,0,0,0};
311  src.w = std::min(dim_.interior.w - i, bg_->w);
312  src.h = std::min(dim_.interior.h - j, bg_->h);
313  SDL_Rect dst = src;
314  dst.x = dim_.interior.x + i;
315  dst.y = dim_.interior.y + j;
316  sdl_blit(bg_, &src, video_.getSurface(), &dst);
317  }
318  }
319 }
320 
322 {
323  SDL_Rect rect = CVideo::get_singleton().screen_area();
326 }
327 
329 {
330  if (!dirty_)
331  return;
332 
333  //draw background
334  draw_background();
335 
336  //draw frame border
337  draw_border();
338 
339  //draw title
340  if (!title_.empty()) {
341  draw_title(&video_);
342  }
343 
344  //draw buttons
345  SDL_Rect buttons_area = dim_.button_row;
346  if(buttons_ != nullptr) {
347 #ifdef OK_BUTTON_ON_RIGHT
348  std::reverse(buttons_->begin(),buttons_->end());
349 #endif
350  for(std::vector<button*>::const_iterator b = buttons_->begin(); b != buttons_->end(); ++b) {
351  (**b).set_location(buttons_area.x, buttons_area.y);
352  buttons_area.x += (**b).width() + ButtonHPadding;
353  }
354  }
355 
356  if(help_button_ != nullptr) {
357  help_button_->set_location(dim_.interior.x+ButtonHPadding, buttons_area.y);
358  }
359 
360  dirty_ = false;
361 }
362 
363 }
surface get_image(const image::locator &i_locator, TYPE type)
Caches and returns an image.
Definition: picture.cpp:815
int top_padding() const
static const style default_style
Definition: show_dialog.hpp:66
void set_dirty(bool dirty=true)
Definition: video.hpp:31
const color_t TITLE_COLOR
bool in_dialog()
Definition: show_dialog.cpp:52
General purpose widgets.
bool is_in_dialog()
Is a dialog open?
Definition: handler.cpp:1115
std::vector< button * > * buttons_
#define DRAW_EVENT
Definition: events.hpp:26
surface_restorer * restorer_
static CVideo & get_singleton()
Definition: video.hpp:48
#define h
dialog_frame(CVideo &video, const std::string &title="", const style &dialog_style=default_style, bool auto_restore=true, std::vector< button *> *buttons=nullptr, button *help_button=nullptr)
Definition: show_dialog.cpp:77
surface scale_surface(const surface &surf, int w, int h)
Scale a surface using alpha-weighted modified bilinear filtering Note: causes artifacts with alpha gr...
Definition: utils.cpp:196
void blit_surface(int x, int y, surface surf, SDL_Rect *srcrect=nullptr, SDL_Rect *clip_rect=nullptr)
Draws a surface directly onto the screen framebuffer.
Definition: video.cpp:162
surface get_surface_portion(const surface &src, SDL_Rect &area)
Get a portion of the screen.
Definition: utils.cpp:2157
int get_max_height(unsigned size, font::family_class fclass, pango_text::FONT_STYLE style)
Returns the maximum glyph height of a font, in pixels.
Definition: text.cpp:896
surface & getSurface()
Returns a reference to the framebuffer.
Definition: video.cpp:482
const style & dialog_style_
int bottom_padding() const
#define b
const int ButtonHPadding
Definition: show_dialog.cpp:41
dimension_measurements layout(int x, int y, int w, int h)
SDL_Rect draw_title(CVideo *video)
virtual void handle_event(const SDL_Event &)
SDL_Rect pango_draw_text(CVideo *gui, const SDL_Rect &area, int size, const color_t &color, const std::string &text, int x, int y, bool use_tooltips, pango_text::FONT_STYLE style)
Draws text on the screen.
surface blur_surface(const surface &surf, int depth)
Cross-fades a surface.
Definition: utils.cpp:1376
virtual void set_location(const SDL_Rect &rect)
Definition: widget.cpp:75
#define DRAW_ALL_EVENT
Definition: events.hpp:29
std::string title_
Definition: show_dialog.hpp:99
static const int title_border_w
Definition: show_dialog.hpp:65
A button is a control that can be pushed to start an action or close a dialog.
Definition: button.hpp:49
static lg::log_domain log_display("display")
std::size_t i
Definition: function.cpp:940
dimension_measurements dim_
int width() const
Definition: widget.cpp:124
int w
#define ERR_DP
Definition: show_dialog.cpp:31
const int SIZE_TITLE
Definition: constants.cpp:30
void handle_window_event(const SDL_Event &event)
Contains the SDL_Rect helper code.
constexpr const SDL_Rect empty_rect
Definition: rect.hpp:31
Functions to load and save images from/to disk.
Standard logging facilities (interface).
static const int title_border_h
Definition: show_dialog.hpp:65
static void reverse(lua_State *L, StkId from, StkId to)
Definition: lapi.cpp:203
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:31
const int ButtonVPadding
Definition: show_dialog.cpp:42
SDL_Rect screen_area(bool as_pixels=true) const
Returns the current window renderer area, either in pixels or screen coordinates. ...
Definition: video.cpp:270
Transitional API for porting SDL_ttf-based code to Pango.
std::string::const_iterator iterator
Definition: tokenizer.hpp:24