00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "global.hpp"
00016
00017 #define GETTEXT_DOMAIN "wesnoth-lib"
00018
00019 #include "config.hpp"
00020 #include "construct_dialog.hpp"
00021 #include "cursor.hpp"
00022 #include "display.hpp"
00023 #include "events.hpp"
00024 #include "gettext.hpp"
00025 #include "help.hpp"
00026 #include "hotkeys.hpp"
00027 #include "image.hpp"
00028 #include "key.hpp"
00029 #include "log.hpp"
00030 #include "marked-up_text.hpp"
00031 #include "language.hpp"
00032 #include "sdl_utils.hpp"
00033 #include "tooltips.hpp"
00034 #include "util.hpp"
00035 #include "video.hpp"
00036 #include "widgets/button.hpp"
00037 #include "widgets/menu.hpp"
00038 #include "widgets/progressbar.hpp"
00039 #include "widgets/textbox.hpp"
00040
00041 #include "SDL_ttf.h"
00042
00043 #include <iostream>
00044 #include <numeric>
00045
00046 #define ERR_DP LOG_STREAM(err, display)
00047 #define LOG_DP LOG_STREAM(info, display)
00048 #define ERR_G LOG_STREAM(err, general)
00049
00050 namespace {
00051 bool is_in_dialog = false;
00052 }
00053
00054 namespace gui {
00055
00056
00057 const int ButtonHPadding = 10;
00058 const int ButtonVPadding = 10;
00059
00060
00061 const dialog_frame::style dialog_frame::default_style("opaque", 0);
00062 const dialog_frame::style dialog_frame::message_style("translucent65", 3);
00063 const dialog_frame::style dialog_frame::preview_style("../misc/selection", 0);
00064 const dialog_frame::style dialog_frame::titlescreen_style("translucent54", 1);
00065
00066 const int dialog_frame::title_border_w = 10;
00067 const int dialog_frame::title_border_h = 5;
00068
00069
00070
00071 bool in_dialog() { return is_in_dialog; }
00072
00073 dialog_manager::dialog_manager() : cursor::setter(cursor::NORMAL), reset_to(is_in_dialog)
00074 {
00075 is_in_dialog = true;
00076 }
00077
00078 dialog_manager::~dialog_manager()
00079 {
00080 is_in_dialog = reset_to;
00081 int mousex, mousey;
00082 SDL_GetMouseState(&mousex, &mousey);
00083 SDL_Event pb_event;
00084 pb_event.type = SDL_MOUSEMOTION;
00085 pb_event.motion.state = 0;
00086 pb_event.motion.x = mousex;
00087 pb_event.motion.y = mousey;
00088 pb_event.motion.xrel = 0;
00089 pb_event.motion.yrel = 0;
00090 SDL_PushEvent(&pb_event);
00091 }
00092
00093 dialog_frame::dialog_frame(CVideo &video, const std::string& title, const style& style,
00094 bool auto_restore, std::vector<button*>* buttons, button* help_button)
00095 :title_(title), video_(video), dialog_style_(style),
00096 buttons_(buttons), help_button_(help_button), restorer_(NULL), auto_restore_(auto_restore),
00097 top_(image::get_image("dialogs/" + dialog_style_.panel + "-border-top.png")),
00098 bot_(image::get_image("dialogs/" + dialog_style_.panel + "-border-bottom.png")),
00099 left_(image::get_image("dialogs/" + dialog_style_.panel + "-border-left.png")),
00100 right_(image::get_image("dialogs/" + dialog_style_.panel + "-border-right.png")),
00101 top_left_(image::get_image("dialogs/" + dialog_style_.panel + "-border-topleft.png")),
00102 bot_left_(image::get_image("dialogs/" + dialog_style_.panel + "-border-botleft.png")),
00103 top_right_(image::get_image("dialogs/" + dialog_style_.panel + "-border-topright.png")),
00104 bot_right_(image::get_image("dialogs/" + dialog_style_.panel + "-border-botright.png")),
00105 bg_(image::get_image("dialogs/" + dialog_style_.panel + "-background.png"))
00106 {
00107 have_border_ = top_ != NULL && bot_ != NULL && left_ != NULL && right_ != NULL;
00108 }
00109
00110 dialog_frame::~dialog_frame()
00111 {
00112 delete restorer_;
00113 }
00114
00115 dialog_frame::dimension_measurements::dimension_measurements() :
00116 interior(empty_rect), exterior(empty_rect), title(empty_rect), button_row(empty_rect)
00117 {}
00118
00119 dialog_frame::dimension_measurements dialog_frame::layout(SDL_Rect const& rect) {
00120 return layout(rect.x, rect.y, rect.w, rect.h);
00121 }
00122
00123 int dialog_frame::top_padding() const {
00124 int padding = 0;
00125 if(have_border_) {
00126 padding += top_->h;
00127 }
00128 if(!title_.empty()) {
00129 padding += font::get_max_height(font::SIZE_LARGE) + 2*dialog_frame::title_border_h;
00130 }
00131 return padding;
00132 }
00133
00134 int dialog_frame::bottom_padding() const {
00135 int padding = 0;
00136 if(buttons_ != NULL) {
00137 for(std::vector<button*>::const_iterator b = buttons_->begin(); b != buttons_->end(); ++b) {
00138 padding = maximum<int>((**b).height() + ButtonVPadding, padding);
00139 }
00140 }
00141 if(have_border_) {
00142 padding += bot_->h;
00143 }
00144 return padding;
00145 }
00146
00147 dialog_frame::dimension_measurements dialog_frame::layout(int x, int y, int w, int h) {
00148 dim_ = dimension_measurements();
00149 if(!title_.empty()) {
00150 dim_.title = draw_title(NULL);
00151 dim_.title.w += title_border_w;
00152 }
00153 if(buttons_ != NULL) {
00154 for(std::vector<button*>::const_iterator b = buttons_->begin(); b != buttons_->end(); ++b) {
00155 dim_.button_row.w += (**b).width() + ButtonHPadding;
00156 dim_.button_row.h = maximum<int>((**b).height() + ButtonVPadding,dim_.button_row.h);
00157 }
00158
00159 dim_.button_row.x = -dim_.button_row.w;
00160 dim_.button_row.y = y + h;
00161
00162 dim_.button_row.w += ButtonHPadding;
00163 }
00164
00165 size_t buttons_width = dim_.button_row.w;
00166
00167 if(help_button_ != NULL) {
00168 buttons_width += help_button_->width() + ButtonHPadding*2;
00169 dim_.button_row.y = y + h;
00170 }
00171
00172 y -= dim_.title.h;
00173 w = maximum<int>(w,maximum<int>(int(dim_.title.w),int(buttons_width)));
00174 h += dim_.title.h + dim_.button_row.h;
00175 dim_.button_row.x += x + w;
00176
00177 SDL_Rect bounds = screen_area();
00178 if(have_border_) {
00179 bounds.x += left_->w;
00180 bounds.y += top_->h;
00181 bounds.w -= left_->w;
00182 bounds.h -= top_->h;
00183 }
00184 if(x < bounds.x) {
00185 w += x;
00186 x = bounds.x;
00187 }
00188 if(y < bounds.y) {
00189 h += y;
00190 y = bounds.y;
00191 }
00192 if(x > bounds.w) {
00193 w = 0;
00194 } else if(x + w > bounds.w) {
00195 w = bounds.w - x;
00196 }
00197 if(y > bounds.h) {
00198 h = 0;
00199 } else if(y + h > bounds.h) {
00200 h = bounds.h - y;
00201 }
00202 dim_.interior.x = x;
00203 dim_.interior.y = y;
00204 dim_.interior.w = w;
00205 dim_.interior.h = h;
00206 if(have_border_) {
00207 dim_.exterior.x = dim_.interior.x - left_->w;
00208 dim_.exterior.y = dim_.interior.y - top_->h;
00209 dim_.exterior.w = dim_.interior.w + left_->w + right_->w;
00210 dim_.exterior.h = dim_.interior.h + top_->h + bot_->h;
00211 } else {
00212 dim_.exterior = dim_.interior;
00213 }
00214 dim_.title.x = dim_.interior.x + title_border_w;
00215 dim_.title.y = dim_.interior.y + title_border_h;
00216 return dim_;
00217 }
00218
00219 void dialog_frame::draw_border()
00220 {
00221 if(have_border_ == false) {
00222 return;
00223 }
00224
00225 surface top_image(scale_surface(top_, dim_.interior.w, top_->h));
00226
00227 if(top_image != NULL) {
00228 video_.blit_surface(dim_.interior.x, dim_.exterior.y, top_image);
00229 }
00230
00231 surface bot_image(scale_surface(bot_, dim_.interior.w, bot_->h));
00232
00233 if(bot_image != NULL) {
00234 video_.blit_surface(dim_.interior.x, dim_.interior.y + dim_.interior.h, bot_image);
00235 }
00236
00237 surface left_image(scale_surface(left_, left_->w, dim_.interior.h));
00238
00239 if(left_image != NULL) {
00240 video_.blit_surface(dim_.exterior.x, dim_.interior.y, left_image);
00241 }
00242
00243 surface right_image(scale_surface(right_, right_->w, dim_.interior.h));
00244
00245 if(right_image != NULL) {
00246 video_.blit_surface(dim_.interior.x + dim_.interior.w, dim_.interior.y, right_image);
00247 }
00248
00249 update_rect(dim_.exterior);
00250
00251 if(top_left_ == NULL || bot_left_ == NULL || top_right_ == NULL || bot_right_ == NULL) {
00252 return;
00253 }
00254
00255 video_.blit_surface(dim_.interior.x - left_->w, dim_.interior.y - top_->h, top_left_);
00256 video_.blit_surface(dim_.interior.x - left_->w, dim_.interior.y + dim_.interior.h + bot_->h - bot_left_->h, bot_left_);
00257 video_.blit_surface(dim_.interior.x + dim_.interior.w + right_->w - top_right_->w, dim_.interior.y - top_->h, top_right_);
00258 video_.blit_surface(dim_.interior.x + dim_.interior.w + right_->w - bot_right_->w, dim_.interior.y + dim_.interior.h + bot_->h - bot_right_->h, bot_right_);
00259 }
00260
00261 void dialog_frame::clear_background()
00262 {
00263 delete restorer_;
00264 restorer_ = NULL;
00265 }
00266
00267 void dialog_frame::draw_background()
00268 {
00269 if(auto_restore_) {
00270 clear_background();
00271 restorer_ = new surface_restorer(&video_, dim_.exterior);
00272 }
00273
00274 if (dialog_style_.blur_radius) {
00275 surface surf = ::get_surface_portion(video_.getSurface(), dim_.exterior);
00276 surf = blur_surface(surf, dialog_style_.blur_radius, false);
00277 SDL_BlitSurface(surf, NULL, video_.getSurface(), &dim_.exterior);
00278 }
00279
00280 if(bg_ == NULL) {
00281 ERR_DP << "could not find dialog background '" << dialog_style_.panel << "'\n";
00282 return;
00283 }
00284 for(int i = 0; i < dim_.interior.w; i += bg_->w) {
00285 for(int j = 0; j < dim_.interior.h; j += bg_->h) {
00286 SDL_Rect src = {0,0,0,0};
00287 src.w = minimum(dim_.interior.w - i, bg_->w);
00288 src.h = minimum(dim_.interior.h - j, bg_->h);
00289 SDL_Rect dst = src;
00290 dst.x = dim_.interior.x + i;
00291 dst.y = dim_.interior.y + j;
00292 SDL_BlitSurface(bg_, &src, video_.getSurface(), &dst);
00293 }
00294 }
00295 }
00296
00297 SDL_Rect dialog_frame::draw_title(CVideo* video)
00298 {
00299 SDL_Rect rect = {0, 0, 10000, 10000};
00300 rect = screen_area();
00301 return font::draw_text(video, rect, font::SIZE_LARGE, font::TITLE_COLOUR,
00302 title_, dim_.title.x, dim_.title.y, false, TTF_STYLE_BOLD);
00303 }
00304
00305 void dialog_frame::draw()
00306 {
00307
00308 draw_background();
00309
00310
00311 draw_border();
00312
00313
00314 if (!title_.empty()) {
00315 draw_title(&video_);
00316 }
00317
00318
00319 SDL_Rect buttons_area = dim_.button_row;
00320 if(buttons_ != NULL) {
00321 #ifdef OK_BUTTON_ON_RIGHT
00322 std::reverse(buttons_->begin(),buttons_->end());
00323 #endif
00324 for(std::vector<button*>::const_iterator b = buttons_->begin(); b != buttons_->end(); ++b) {
00325 (**b).set_location(buttons_area.x, buttons_area.y);
00326 buttons_area.x += (**b).width() + ButtonHPadding;
00327 }
00328 }
00329
00330 if(help_button_ != NULL) {
00331 help_button_->set_location(dim_.interior.x+ButtonHPadding, buttons_area.y);
00332 }
00333 }
00334
00335 }
00336
00337 namespace {
00338
00339 struct help_handler : public hotkey::command_executor
00340 {
00341 help_handler(display& disp, const std::string& topic) : disp_(disp), topic_(topic)
00342 {}
00343
00344 private:
00345 void show_help()
00346 {
00347 if(topic_.empty() == false) {
00348 help::show_help(disp_,topic_);
00349 }
00350 }
00351
00352 bool can_execute_command(hotkey::HOTKEY_COMMAND cmd, int ) const
00353 {
00354 return (topic_.empty() == false && cmd == hotkey::HOTKEY_HELP) || cmd == hotkey::HOTKEY_SCREENSHOT;
00355 }
00356
00357 display& disp_;
00358 std::string topic_;
00359 };
00360
00361 }
00362
00363 namespace gui
00364 {
00365
00366 void show_error_message(display &disp, std::string const &message)
00367 {
00368 ERR_G << message << std::endl;
00369 dialog(disp, _("Error"), message, OK_ONLY).show();
00370 }
00371
00372 int show_dialog(display& screen, surface image,
00373 const std::string& caption, const std::string& message,
00374 DIALOG_TYPE type,
00375 const std::vector<std::string>* menu_items,
00376 const std::vector<preview_pane*>* preview_panes,
00377 const std::string& text_widget_label,
00378 std::string* text_widget_text,
00379 const int text_widget_max_chars,
00380 std::vector<check_item>* options,
00381 int xloc,
00382 int yloc,
00383 const dialog_frame::style* dialog_style,
00384 std::vector<dialog_button_info>* action_buttons,
00385 const menu::sorter* sorter,
00386 menu::style* menu_style)
00387 {
00388 const std::string& title = (image.null())? caption : "";
00389 const dialog::style& style = (dialog_style)? *dialog_style : dialog::default_style;
00390 CVideo &disp = screen.video();
00391
00392 gui::dialog d(screen, title, message, type, style);
00393
00394
00395 if(!image.null()) {
00396 d.set_image(image, caption);
00397 }
00398 if(menu_items) {
00399 d.set_menu( new gui::menu(disp,*menu_items,type == MESSAGE,-1,dialog::max_menu_width,sorter,menu_style,false));
00400 }
00401 if(preview_panes) {
00402 for(unsigned int i=0; i < preview_panes->size(); ++i) {
00403 d.add_pane((*preview_panes)[i]);
00404 }
00405 }
00406 if(text_widget_text) {
00407 d.set_textbox(text_widget_label,*text_widget_text, text_widget_max_chars);
00408 }
00409 if(options) {
00410 for(unsigned int i=0; i < options->size(); ++i) {
00411 check_item& item = (*options)[i];
00412 d.add_option(item.label, item.checked);
00413 }
00414 }
00415 if(action_buttons) {
00416 for(unsigned int i=0; i < action_buttons->size(); ++i) {
00417 d.add_button((*action_buttons)[i]);
00418 }
00419 }
00420
00421 d.show(xloc, yloc);
00422
00423
00424 if(options) {
00425 for(unsigned int i=0; i < options->size(); ++i)
00426 {
00427 (*options)[i].checked = d.option_checked(i);
00428 }
00429 }
00430 if(text_widget_text) {
00431 *text_widget_text = d.textbox_text();
00432 }
00433 return d.result();
00434 }
00435
00436 }
00437