The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
show_dialog.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2016 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 "global.hpp"
16 
17 #define GETTEXT_DOMAIN "wesnoth-lib"
18 
19 #include "show_dialog.hpp"
20 
21 #include "construct_dialog.hpp"
22 #include "floating_label.hpp"
23 #include "image.hpp"
24 #include "gettext.hpp"
26 #include "help/help.hpp"
28 #include "log.hpp"
29 #include "marked-up_text.hpp"
30 #include "sdl/rect.hpp"
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 const dialog_frame::style dialog_frame::message_style("translucent65", 3);
49 const dialog_frame::style dialog_frame::preview_style("../dialogs/selection", 0);
51 
52 const int dialog_frame::title_border_w = 10;
53 const int dialog_frame::title_border_h = 5;
54 
55 
56 
57 bool in_dialog()
58 {
59  return is_in_dialog || gui2::is_in_dialog();
60 }
61 
63 {
64  is_in_dialog = true;
65 }
66 
68 {
70  int mousex, mousey;
71  SDL_GetMouseState(&mousex, &mousey);
72  SDL_Event pb_event;
73  pb_event.type = SDL_MOUSEMOTION;
74  pb_event.motion.state = 0;
75  pb_event.motion.x = mousex;
76  pb_event.motion.y = mousey;
77  pb_event.motion.xrel = 0;
78  pb_event.motion.yrel = 0;
79  SDL_PushEvent(&pb_event);
80 }
81 
83  const style& style, bool auto_restore,
84  std::vector<button*>* buttons, button* help_button) :
85  title_(title),
86  video_(video),
87  dialog_style_(style),
88  buttons_(buttons),
89  help_button_(help_button),
90  restorer_(nullptr),
91  auto_restore_(auto_restore),
92  dim_(),
93 #ifdef SDL_GPU
94  top_(image::get_texture("dialogs/" + dialog_style_.panel + "-border-top.png")),
95  bot_(image::get_texture("dialogs/" + dialog_style_.panel + "-border-bottom.png")),
96  left_(image::get_texture("dialogs/" + dialog_style_.panel + "-border-left.png")),
97  right_(image::get_texture("dialogs/" + dialog_style_.panel + "-border-right.png")),
98  top_left_(image::get_texture("dialogs/" + dialog_style_.panel + "-border-topleft.png")),
99  bot_left_(image::get_texture("dialogs/" + dialog_style_.panel + "-border-botleft.png")),
100  top_right_(image::get_texture("dialogs/" + dialog_style_.panel + "-border-topright.png")),
101  bot_right_(image::get_texture("dialogs/" + dialog_style_.panel + "-border-botright.png")),
102  bg_(image::get_texture("dialogs/" + dialog_style_.panel + "-background.png")),
103  have_border_(!top_.null() && !bot_.null() && !left_.null() && !right_.null())
104 #else
105  top_(image::get_image("dialogs/" + dialog_style_.panel + "-border-top.png")),
106  bot_(image::get_image("dialogs/" + dialog_style_.panel + "-border-bottom.png")),
107  left_(image::get_image("dialogs/" + dialog_style_.panel + "-border-left.png")),
108  right_(image::get_image("dialogs/" + dialog_style_.panel + "-border-right.png")),
109  top_left_(image::get_image("dialogs/" + dialog_style_.panel + "-border-topleft.png")),
110  bot_left_(image::get_image("dialogs/" + dialog_style_.panel + "-border-botleft.png")),
111  top_right_(image::get_image("dialogs/" + dialog_style_.panel + "-border-topright.png")),
112  bot_right_(image::get_image("dialogs/" + dialog_style_.panel + "-border-botright.png")),
113  bg_(image::get_image("dialogs/" + dialog_style_.panel + "-background.png")),
114  have_border_(top_ != nullptr && bot_ != nullptr && left_ != nullptr && right_ != nullptr),
115  dirty_(true)
116 #endif
117 {
118 }
119 
121 {
122  delete restorer_;
123 }
124 
126  interior(sdl::empty_rect), exterior(sdl::empty_rect), title(sdl::empty_rect), button_row(sdl::empty_rect)
127 {}
128 
130  return layout(rect.x, rect.y, rect.w, rect.h);
131 }
132 
134  int padding = 0;
135  if(have_border_) {
136 #ifdef SDL_GPU
137  padding += top_.height();
138 #else
139  padding += top_->h;
140 #endif
141  }
142  if(!title_.empty()) {
144  }
145  return padding;
146 }
147 
148 void dialog_frame::set_dirty(bool dirty) {
149  dirty_ = dirty;
150 }
151 
152 void dialog_frame::handle_window_event(const SDL_Event& event) {
153 
154  if (event.type == SDL_WINDOWEVENT) {
155  switch (event.window.event) {
156  case SDL_WINDOWEVENT_RESIZED:
157  case SDL_WINDOWEVENT_RESTORED:
158  case SDL_WINDOWEVENT_SHOWN:
159  case SDL_WINDOWEVENT_EXPOSED:
160  set_dirty();
161  }
162  }
163 }
164 
165 void dialog_frame::handle_event(const SDL_Event& event) {
166 
167  if (event.type == DRAW_ALL_EVENT) {
168  set_dirty();
169 
170  if (buttons_) {
171  for(std::vector<button *>::iterator it = buttons_->begin(); it != buttons_->end(); ++it) {
172  (*it)->set_dirty(true);
173  }
174  }
175  }
176 
177  if (event.type == DRAW_EVENT || event.type == DRAW_ALL_EVENT) {
178  draw();
179  }
180 }
181 
183  int padding = 0;
184  if(buttons_ != nullptr) {
185  for(std::vector<button*>::const_iterator b = buttons_->begin(); b != buttons_->end(); ++b) {
186  padding = std::max<int>((**b).height() + ButtonVPadding, padding);
187  }
188  }
189  if(have_border_) {
190 #ifdef SDL_GPU
191  padding += bot_.height();
192 #else
193  padding += bot_->h;
194 #endif
195  }
196  return padding;
197 }
198 
201  if(!title_.empty()) {
202  dim_.title = draw_title(nullptr);
204  }
205  if(buttons_ != nullptr) {
206  for(std::vector<button*>::const_iterator b = buttons_->begin(); b != buttons_->end(); ++b) {
207  dim_.button_row.w += (**b).width() + ButtonHPadding;
208  dim_.button_row.h = std::max<int>((**b).height() + ButtonVPadding,dim_.button_row.h);
209  }
210 
212  dim_.button_row.y = y + h;
213 
215  }
216 
217  size_t buttons_width = dim_.button_row.w;
218 
219  if(help_button_ != nullptr) {
220  buttons_width += help_button_->width() + ButtonHPadding*2;
221  dim_.button_row.y = y + h;
222  }
223 
224  y -= dim_.title.h;
225  w = std::max<int>(w,std::max<int>(int(dim_.title.w),int(buttons_width)));
226  h += dim_.title.h + dim_.button_row.h;
227  dim_.button_row.x += x + w;
228 
229  SDL_Rect bounds = screen_area();
230  if(have_border_) {
231 #ifdef SDL_GPU
232  bounds.x += left_.width();
233  bounds.y += top_.height();
234  bounds.w -= left_.width();
235  bounds.h -= top_.height();
236 #else
237  bounds.x += left_->w;
238  bounds.y += top_->h;
239  bounds.w -= left_->w;
240  bounds.h -= top_->h;
241 #endif
242  }
243  if(x < bounds.x) {
244  w += x;
245  x = bounds.x;
246  }
247  if(y < bounds.y) {
248  h += y;
249  y = bounds.y;
250  }
251  if(x > bounds.w) {
252  w = 0;
253  } else if(x + w > bounds.w) {
254  w = bounds.w - x;
255  }
256  if(y > bounds.h) {
257  h = 0;
258  } else if(y + h > bounds.h) {
259  h = bounds.h - y;
260  }
261  dim_.interior.x = x;
262  dim_.interior.y = y;
263  dim_.interior.w = w;
264  dim_.interior.h = h;
265  if(have_border_) {
266 #ifdef SDL_GPU
267  dim_.exterior.x = dim_.interior.x - left_.width();
268  dim_.exterior.y = dim_.interior.y - top_.height();
269  dim_.exterior.w = dim_.interior.w + left_.width() + right_.width();
270  dim_.exterior.h = dim_.interior.h + top_.height() + bot_.height();
271 #else
272  dim_.exterior.x = dim_.interior.x - left_->w;
273  dim_.exterior.y = dim_.interior.y - top_->h;
274  dim_.exterior.w = dim_.interior.w + left_->w + right_->w;
275  dim_.exterior.h = dim_.interior.h + top_->h + bot_->h;
276 #endif
277  } else {
279  }
282  return dim_;
283 }
284 
286 {
287  if(have_border_ == false) {
288  return;
289  }
290 
291 #ifdef SDL_GPU
292  top_.set_hscale(float(dim_.interior.w )/ top_.base_width());
293  video_.draw_texture(top_, dim_.interior.x, dim_.exterior.y);
294 
295  bot_.set_hscale(float(dim_.interior.w) / bot_.base_width());
296  video_.draw_texture(bot_, dim_.interior.x, dim_.interior.y + dim_.interior.h);
297 
298  left_.set_vscale(float(dim_.interior.h) / left_.base_height());
299  video_.draw_texture(left_, dim_.exterior.x, dim_.interior.y);
300 
301  right_.set_vscale(float(dim_.interior.h) / right_.base_height());
302  video_.draw_texture(right_, dim_.interior.x + dim_.interior.w, dim_.interior.y);
303 
304  if(top_left_.null() || bot_left_.null() || top_right_.null() || bot_right_.null()) {
305  return;
306  }
307 
308  video_.draw_texture(top_left_, dim_.interior.x - left_.width(), dim_.interior.y - top_.height());
309  video_.draw_texture(bot_left_, dim_.interior.x - left_.width(), dim_.interior.y + dim_.interior.h + bot_.height() - bot_left_.height());
310  video_.draw_texture(top_right_, dim_.interior.x + dim_.interior.w + right_.width() - top_right_.width(), dim_.interior.y - top_.height());
311  video_.draw_texture(bot_right_, dim_.interior.x + dim_.interior.w + right_.width() - bot_right_.width(), dim_.interior.y + dim_.interior.h + bot_.height() - bot_right_.height());
312 #else
313  surface top_image(scale_surface(top_, dim_.interior.w, top_->h));
314 
315  if(top_image != nullptr) {
316  video_.blit_surface(dim_.interior.x, dim_.exterior.y, top_image);
317  }
318 
319  surface bot_image(scale_surface(bot_, dim_.interior.w, bot_->h));
320 
321  if(bot_image != nullptr) {
322  video_.blit_surface(dim_.interior.x, dim_.interior.y + dim_.interior.h, bot_image);
323  }
324 
325  surface left_image(scale_surface(left_, left_->w, dim_.interior.h));
326 
327  if(left_image != nullptr) {
328  video_.blit_surface(dim_.exterior.x, dim_.interior.y, left_image);
329  }
330 
331  surface right_image(scale_surface(right_, right_->w, dim_.interior.h));
332 
333  if(right_image != nullptr) {
334  video_.blit_surface(dim_.interior.x + dim_.interior.w, dim_.interior.y, right_image);
335  }
336 
338 
339  if(top_left_ == nullptr || bot_left_ == nullptr || top_right_ == nullptr || bot_right_ == nullptr) {
340  return;
341  }
342 
347 #endif
348 }
349 
351 {
352  delete restorer_;
353  restorer_ = nullptr;
354 }
355 
357 {
358  if(auto_restore_) {
361  }
362 
365  surf = blur_surface(surf, dialog_style_.blur_radius, false);
366  sdl_blit(surf, nullptr, video_.getSurface(), &dim_.exterior);
367  }
368 
369 #ifdef SDL_GPU
370  if(bg_.null()) {
371  ERR_DP << "could not find dialog background '" << dialog_style_.panel << "'" << std::endl;
372  return;
373  }
374  for(int i = 0; i < dim_.interior.w; i += bg_.width()) {
375  for(int j = 0; j < dim_.interior.h; j += bg_.height()) {
376  SDL_Rect src = {0,0,0,0};
377  src.w = std::min(dim_.interior.w - i, bg_.width());
378  src.h = std::min(dim_.interior.h - j, bg_.height());
379  SDL_Rect dst = src;
380  dst.x = dim_.interior.x + i;
381  dst.y = dim_.interior.y + j;
382  bg_.set_clip(src);
383  video_.draw_texture(bg_, dst.x, dst.y);
384  }
385  }
386 #else
387  if(bg_ == nullptr) {
388  ERR_DP << "could not find dialog background '" << dialog_style_.panel << "'" << std::endl;
389  return;
390  }
391  for(int i = 0; i < dim_.interior.w; i += bg_->w) {
392  for(int j = 0; j < dim_.interior.h; j += bg_->h) {
393  SDL_Rect src = {0,0,0,0};
394  src.w = std::min(dim_.interior.w - i, bg_->w);
395  src.h = std::min(dim_.interior.h - j, bg_->h);
396  SDL_Rect dst = src;
397  dst.x = dim_.interior.x + i;
398  dst.y = dim_.interior.y + j;
399  sdl_blit(bg_, &src, video_.getSurface(), &dst);
400  }
401  }
402 #endif
403 }
404 
406 {
407  SDL_Rect rect = screen_area();
409  title_, dim_.title.x, dim_.title.y, false, TTF_STYLE_NORMAL);
410 }
411 
413 {
414  if (!dirty_)
415  return;
416 
417  //draw background
418  draw_background();
419 
420  //draw frame border
421  draw_border();
422 
423  //draw title
424  if (!title_.empty()) {
425  draw_title(&video_);
426  }
427 
428  //draw buttons
429  SDL_Rect buttons_area = dim_.button_row;
430  if(buttons_ != nullptr) {
431 #ifdef OK_BUTTON_ON_RIGHT
432  std::reverse(buttons_->begin(),buttons_->end());
433 #endif
434  for(std::vector<button*>::const_iterator b = buttons_->begin(); b != buttons_->end(); ++b) {
435  (**b).set_location(buttons_area.x, buttons_area.y);
436  buttons_area.x += (**b).width() + ButtonHPadding;
437  }
438  }
439 
440  if(help_button_ != nullptr) {
441  help_button_->set_location(dim_.interior.x+ButtonHPadding, buttons_area.y);
442  }
443 
444  dirty_ = false;
445 }
446 
448  const std::string& caption, const std::string& message,
450  const std::vector<std::string>* menu_items,
451  const std::vector<preview_pane*>* preview_panes,
452  const std::string& text_widget_label,
453  std::string* text_widget_text,
454  const int text_widget_max_chars,
455  std::vector<check_item>* options,
456  int xloc,
457  int yloc,
458  const dialog_frame::style* dialog_style,
459  std::vector<dialog_button_info>* action_buttons,
460  const menu::sorter* sorter,
461  menu::style* menu_style)
462 {
463  std::string title;
464  if (image.null()) title = caption;
465  const dialog::style& style = (dialog_style)? *dialog_style : dialog::default_style;
466 
467  gui::dialog d(video, title, message, type, style);
468 
469  //add the components
470  if(!image.null()) {
471  d.set_image(image, caption);
472  }
473  if(menu_items) {
474  d.set_menu( new gui::menu(video,*menu_items,type == MESSAGE,-1,dialog::max_menu_width,sorter,menu_style,false));
475  }
476  if(preview_panes) {
477  for(unsigned int i=0; i < preview_panes->size(); ++i) {
478  d.add_pane((*preview_panes)[i]);
479  }
480  }
481  if(text_widget_text) {
482  d.set_textbox(text_widget_label,*text_widget_text, text_widget_max_chars);
483  }
484  if(options) {
485  for(unsigned int i=0; i < options->size(); ++i) {
486  check_item& item = (*options)[i];
487  d.add_option(item.label, item.checked);
488  }
489  }
490  if(action_buttons) {
491  for(unsigned int i=0; i < action_buttons->size(); ++i) {
492  d.add_button((*action_buttons)[i]);
493  }
494  }
495  //enter the dialog loop
496  d.show(xloc, yloc);
497 
498  //send back results
499  if(options) {
500  for(unsigned int i=0; i < options->size(); ++i)
501  {
502  (*options)[i].checked = d.option_checked(i);
503  }
504  }
505  if(text_widget_text) {
506  *text_widget_text = d.textbox_text();
507  }
508  return d.result();
509 }
510 
511 }
512 
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
Definition: image.cpp:878
static const style preview_style
Definition: show_dialog.hpp:71
bool null() const
Definition: utils.hpp:104
const SDL_Color TITLE_COLOR
Definition: font.cpp:573
void add_option(const std::string &label, bool checked=false, BUTTON_LOCATION loc=BUTTON_CHECKBOX, const std::string &help_string="")
void set_textbox(dialog_textbox *const box)
static const style default_style
Definition: show_dialog.hpp:69
void set_dirty(bool dirty=true)
expression_ptr right_
Definition: formula.cpp:409
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
Definition: video.hpp:58
bool in_dialog()
Definition: show_dialog.cpp:57
const SDL_Rect empty_rect
Definition: rect.cpp:26
static const style & default_style
void add_button(dialog_button *const btn, BUTTON_LOCATION loc)
General purpose widgets.
bool is_in_dialog()
Is a dialog open?
Definition: handler.cpp:960
std::vector< button * > * buttons_
#define DRAW_EVENT
Definition: events.hpp:26
surface_restorer * restorer_
#define h
GLint GLint GLint GLint GLint GLint y
Definition: glew.h:1220
GLenum src
Definition: glew.h:2392
surface scale_surface(const surface &surf, int w, int h)
Definition: utils.cpp:443
void blit_surface(int x, int y, surface surf, SDL_Rect *srcrect=nullptr, SDL_Rect *clip_rect=nullptr)
Definition: video.cpp:290
#define d
int show(int xloc, int yloc)
surface get_surface_portion(const surface &src, SDL_Rect &area)
Get a portion of the screen.
Definition: utils.cpp:2335
surface & getSurface()
Definition: dummy_video.cpp:22
std::string textbox_text() const
const style & dialog_style_
SDL_Rect screen_area()
Definition: video.cpp:135
const int ButtonHPadding
Definition: show_dialog.cpp:43
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
dimension_measurements layout(int x, int y, int w, int h)
SDL_Rect draw_title(CVideo *video)
int top_padding() const
const config & options()
int bottom_padding() const
void add_pane(preview_pane *const pp)
GLubyte GLubyte GLubyte GLubyte w
Definition: glew.h:1858
GLenum GLenum dst
Definition: glew.h:2392
void set_menu(menu *const m)
virtual void handle_event(const SDL_Event &)
int show_dialog(CVideo &video, surface image, const std::string &caption, const std::string &message, DIALOG_TYPE type, const std::vector< std::string > *menu_items, const std::vector< preview_pane * > *preview_panes, const std::string &text_widget_label, std::string *text_widget_text, const int text_widget_max_chars, std::vector< check_item > *options, int xloc, int yloc, const dialog_frame::style *dialog_style, std::vector< dialog_button_info > *action_buttons, const menu::sorter *sorter, menu::style *menu_style)
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
surface blur_surface(const surface &surf, int depth, bool optimize)
Cross-fades a surface.
Definition: utils.cpp:1524
surf
Definition: filter.cpp:143
int get_max_height(int size)
Definition: font.cpp:960
#define DRAW_ALL_EVENT
Definition: events.hpp:29
std::string title_
void set_image(dialog_image *const img)
SDL_Rect draw_text(surface &dst, const SDL_Rect &area, int size, const SDL_Color &color, const std::string &txt, int x, int y, bool use_tooltips, int style)
Function to draw text on a surface.
static const int title_border_w
Definition: show_dialog.hpp:68
static lg::log_domain log_display("display")
static const style titlescreen_style
Definition: show_dialog.hpp:72
int result() const
dimension_measurements dim_
GLfloat GLfloat GLfloat GLfloat h
Definition: glew.h:5910
size_t i
Definition: function.cpp:1057
GLint GLint GLint GLint GLint x
Definition: glew.h:1220
#define ERR_DP
Definition: show_dialog.cpp:33
const int SIZE_TITLE
Definition: font.hpp:67
void handle_window_event(const SDL_Event &event)
bool option_checked(unsigned int option_index=0)
Contains the SDL_Rect helper code.
cl_event event
Definition: glew.h:3070
static const int max_menu_width
this module manages the cache of images.
Definition: image.cpp:75
Standard logging facilities (interface).
GLsizei GLenum GLuint GLuint GLsizei char * message
Definition: glew.h:2499
virtual void set_location(SDL_Rect const &rect)
Definition: widget.cpp:85
expression_ptr left_
Definition: formula.cpp:409
static const int title_border_h
Definition: show_dialog.hpp:68
int width() const
Definition: widget.cpp:134
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:112
const int ButtonVPadding
Definition: show_dialog.cpp:44
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
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:82
void update_rect(const SDL_Rect &)
Definition: dummy_video.cpp:27
GLsizei const GLcharARB ** string
Definition: glew.h:4503
static const style message_style
Definition: show_dialog.hpp:70
std::string label