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