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