preferences_display.cpp

Go to the documentation of this file.
00001 /* $Id: preferences_display.cpp 53010 2012-02-14 18:17:09Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2003 - 2012 by David White <dave@whitevine.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 #define GETTEXT_DOMAIN "wesnoth-lib"
00017 
00018 /**
00019  *  @file
00020  *  Manage display-related preferences, e.g. screen-size, etc.
00021  */
00022 
00023 #include "global.hpp"
00024 #include "preferences_display.hpp"
00025 
00026 #include "construct_dialog.hpp"
00027 #include "display.hpp"
00028 #include "foreach.hpp"
00029 #include "formatter.hpp"
00030 #include "game_preferences.hpp"
00031 #include "gettext.hpp"
00032 #include "gui/dialogs/message.hpp"
00033 #include "gui/dialogs/simple_item_selector.hpp"
00034 #include "gui/dialogs/transient_message.hpp"
00035 #include "gui/widgets/window.hpp"
00036 #include "hotkeys.hpp"
00037 #include "log.hpp"
00038 #include "marked-up_text.hpp"
00039 #include "wml_separators.hpp"
00040 
00041 namespace preferences {
00042 
00043 display* disp = NULL;
00044 
00045 display_manager::display_manager(display* d)
00046 {
00047     disp = d;
00048 
00049     load_hotkeys();
00050 
00051     set_grid(grid());
00052     set_turbo(turbo());
00053     set_turbo_speed(turbo_speed());
00054     set_fullscreen(fullscreen());
00055     set_scroll_to_action(scroll_to_action());
00056     set_color_cursors(preferences::get("color_cursors", false));
00057 }
00058 
00059 display_manager::~display_manager()
00060 {
00061     disp = NULL;
00062 }
00063 
00064 bool detect_video_settings(CVideo& video, std::pair<int,int>& resolution, int& bpp, int& video_flags)
00065 {
00066     video_flags = fullscreen() ? FULL_SCREEN : 0;
00067     resolution = preferences::resolution();
00068 
00069     int DefaultBPP = 24;
00070     const SDL_VideoInfo* const video_info = SDL_GetVideoInfo();
00071     if(video_info != NULL && video_info->vfmt != NULL) {
00072         DefaultBPP = video_info->vfmt->BitsPerPixel;
00073     }
00074 
00075     std::cerr << "Checking video mode: " << resolution.first << 'x'
00076         << resolution.second << 'x' << DefaultBPP << "...\n";
00077 
00078     typedef std::pair<int, int> res_t;
00079     std::vector<res_t> res_list;
00080     res_list.push_back(res_t(1024, 768));
00081     res_list.push_back(res_t(1024, 600));
00082     res_list.push_back(res_t(800, 600));
00083     res_list.push_back(res_t(800, 480));
00084 
00085     bpp = video.modePossible(resolution.first, resolution.second,
00086         DefaultBPP, video_flags, true);
00087 
00088     foreach (const res_t &res, res_list)
00089     {
00090         if (bpp != 0) break;
00091         std::cerr << "Video mode " << resolution.first << 'x'
00092             << resolution.second << 'x' << DefaultBPP
00093             << " is not supported; attempting " << res.first
00094             << 'x' << res.second << 'x' << DefaultBPP << "...\n";
00095         resolution = res;
00096         bpp = video.modePossible(resolution.first, resolution.second,
00097             DefaultBPP, video_flags);
00098     }
00099 
00100     return bpp != 0;
00101 }
00102 
00103 void set_fullscreen(CVideo& video, const bool ison)
00104 {
00105     _set_fullscreen(ison);
00106 
00107     const std::pair<int,int>& res = resolution();
00108     if(video.isFullScreen() != ison) {
00109         const int flags = ison ? FULL_SCREEN : 0;
00110         int bpp = video.bppForMode(res.first, res.second, flags);
00111 
00112         if(bpp > 0) {
00113             video.setMode(res.first,res.second,bpp,flags);
00114             if(disp) {
00115                 disp->redraw_everything();
00116             }
00117         } else {
00118             int tmp_flags = flags;
00119             std::pair<int,int> tmp_res;
00120             if(detect_video_settings(video, tmp_res, bpp, tmp_flags)) {
00121                 set_resolution(video, tmp_res.first, tmp_res.second);
00122             // TODO: see if below line is actually needed, possibly for displays that only support 16 bbp
00123             } else if(video.modePossible(1024,768,16,flags)) {
00124                 set_resolution(video, 1024, 768);
00125             } else {
00126                 gui2::show_transient_message(video,"",_("The video mode could not be changed. Your window manager must be set to 16 bits per pixel to run the game in windowed mode. Your display must support 1024x768x16 to run the game full screen."));
00127             }
00128             // We reinit color cursors, because SDL on Mac seems to forget the SDL_Cursor
00129             set_color_cursors(preferences::get("color_cursors", false));
00130         }
00131     }
00132 }
00133 
00134 void set_fullscreen(bool ison)
00135 {
00136     _set_fullscreen(ison);
00137 
00138     if(disp != NULL) {
00139         set_fullscreen(disp->video(), ison);
00140     }
00141 }
00142 
00143 void set_scroll_to_action(bool ison)
00144 {
00145     _set_scroll_to_action(ison);
00146 }
00147 void set_resolution(const std::pair<int,int>& resolution)
00148 {
00149     if(disp) {
00150         set_resolution(disp->video(), resolution.first, resolution.second);
00151     } else {
00152         /* This part is needed when wesnoth is started with the -r parameter. */
00153         const std::string postfix = fullscreen() ? "resolution" : "windowsize";
00154         preferences::set(
00155                 'x' + postfix, lexical_cast<std::string>(resolution.first));
00156         preferences::set(
00157                 'y' + postfix, lexical_cast<std::string>(resolution.second));
00158     }
00159 }
00160 
00161 bool set_resolution(CVideo& video
00162         , const unsigned width, const unsigned height)
00163 {
00164     SDL_Rect rect;
00165     SDL_GetClipRect(video.getSurface(), &rect);
00166     if(rect.w == width && rect.h == height) {
00167         return true;
00168     }
00169 
00170     const int flags = fullscreen() ? FULL_SCREEN : 0;
00171     int bpp = video.bppForMode(width, height, flags);
00172 
00173     if(bpp != 0) {
00174         video.setMode(width, height, bpp, flags);
00175 
00176         if(disp) {
00177             disp->redraw_everything();
00178         }
00179 
00180     } else {
00181         // grzywacz: is this even true?
00182         gui2::show_transient_message(video,"",_("The video mode could not be changed. Your window manager must be set to 16 bits per pixel to run the game in windowed mode. Your display must support 1024x768x16 to run the game full screen."));
00183         return false;
00184     }
00185 
00186     const std::string postfix = fullscreen() ? "resolution" : "windowsize";
00187     preferences::set('x' + postfix, lexical_cast<std::string>(width));
00188     preferences::set('y' + postfix, lexical_cast<std::string>(height));
00189 
00190     return true;
00191 }
00192 
00193 void set_turbo(bool ison)
00194 {
00195     _set_turbo(ison);
00196 
00197     if(disp != NULL) {
00198         disp->set_turbo(ison);
00199     }
00200 }
00201 
00202 void set_turbo_speed(double speed)
00203 {
00204     save_turbo_speed(speed);
00205 
00206     if(disp != NULL) {
00207         disp->set_turbo_speed(speed);
00208     }
00209 }
00210 
00211 void set_ellipses(bool ison)
00212 {
00213     _set_ellipses(ison);
00214 }
00215 
00216 void set_grid(bool ison)
00217 {
00218     _set_grid(ison);
00219 
00220     if(disp != NULL) {
00221         disp->set_grid(ison);
00222     }
00223 }
00224 
00225 void set_color_cursors(bool value)
00226 {
00227     _set_color_cursors(value);
00228 
00229     cursor::set();
00230 }
00231 
00232 void set_idle_anim(bool ison) {
00233     _set_idle_anim(ison);
00234     if(disp != NULL) {
00235         disp->set_idle_anim(ison);
00236     }
00237 }
00238 
00239 void set_idle_anim_rate(int rate) {
00240     _set_idle_anim_rate(rate);
00241     if(disp != NULL) {
00242         disp->set_idle_anim_rate(rate);
00243     }
00244 }
00245 
00246 namespace {
00247 class escape_handler : public events::handler {
00248 public:
00249     escape_handler() : escape_pressed_(false) {}
00250     bool escape_pressed() const { return escape_pressed_; }
00251     void handle_event(const SDL_Event &event) { escape_pressed_ |= (event.type == SDL_KEYDOWN)
00252         && (reinterpret_cast<const SDL_KeyboardEvent&>(event).keysym.sym == SDLK_ESCAPE); }
00253 private:
00254     bool escape_pressed_;
00255 };
00256 
00257 void repopulate_hotkeys_menu(std::vector<std::string>& menu_items)
00258 {
00259     menu_items.clear();;
00260 
00261     std::vector<hotkey::hotkey_item>& hotkeys = hotkey::get_hotkeys();
00262 
00263     foreach(const hotkey::hotkey_item& hi, hotkeys) {
00264         if(hi.hidden() || !hi.is_in_active_scope())
00265             continue;
00266 
00267         menu_items.push_back((formatter() << hi.get_description() << COLUMN_SEPARATOR << font::NULL_MARKUP << hi.get_name()).str());
00268     }
00269 
00270     menu_items.push_back((formatter() << HEADING_PREFIX << _("Action") << COLUMN_SEPARATOR << _("Binding")).str());
00271 }
00272 
00273 } // end anonymous namespace
00274 
00275 #ifdef _MSC_VER
00276 #pragma warning (push)
00277 #pragma warning (disable:4701)
00278 #endif
00279 void show_hotkeys_dialog(display & disp)
00280 {
00281     log_scope ("show_hotkeys_dialog");
00282 
00283     const events::event_context dialog_events_context;
00284 
00285     const int centerx = disp.w()/2;
00286     const int centery = disp.h()/2;
00287     const int width  = 700;
00288     const int height = disp.video().gety() < 600 ? 380 : 500;
00289     const int xpos = centerx  - width/2;
00290     const int ypos = centery  - height/2;
00291 
00292     gui::button close_button (disp.video(), _("Close"));
00293     std::vector<gui::button*> buttons;
00294     buttons.push_back(&close_button);
00295 
00296     gui::dialog_frame f(disp.video(),_("Hotkey Settings"),gui::dialog_frame::default_style,true,&buttons);
00297     f.layout(xpos,ypos,width,height);
00298     f.draw();
00299 
00300     SDL_Rect clip_rect = create_rect(0, 0, disp.w (), disp.h ());
00301     SDL_Rect text_size = font::draw_text(NULL, clip_rect, font::SIZE_LARGE,
00302                          font::NORMAL_COLOR,_("Press desired hotkey (Esc cancels)"),
00303                          0, 0);
00304 
00305     gui::menu::basic_sorter sorter;
00306     sorter.set_alpha_sort(0).set_alpha_sort(1);
00307 
00308     std::vector<std::string> menu_items;
00309     repopulate_hotkeys_menu(menu_items);
00310 
00311     gui::menu menu_(disp.video(), menu_items, false, height - font::relative_size(10), -1, &sorter, &gui::menu::bluebg_style);
00312     menu_.sort_by(0);
00313     menu_.reset_selection();
00314     menu_.set_width(font::relative_size(500));
00315     menu_.set_location(xpos + font::relative_size(10), ypos + font::relative_size(10));
00316 
00317     gui::button change_button(disp.video(), _("Change Hotkey"));
00318     change_button.set_location(xpos + width - change_button.width () - font::relative_size(30), ypos + font::relative_size(30));
00319 
00320     gui::button clear_button(disp.video(), _("Clear Hotkey"));
00321     clear_button.set_location(xpos + width - clear_button.width () - font::relative_size(30), ypos + font::relative_size(60));
00322 
00323     gui::button reset_button(disp.video(), _("Reset All"));
00324     reset_button.set_location(xpos + width - reset_button.width() - font::relative_size(30), ypos + font::relative_size(90));
00325 
00326     escape_handler esc_hand;
00327 
00328     for(;;) {
00329 
00330         if (close_button.pressed() || esc_hand.escape_pressed())
00331         {
00332             save_hotkeys();
00333             break;
00334         }
00335 
00336         if (change_button.pressed () || menu_.double_clicked()) {
00337             // Lets change this hotkey......
00338             SDL_Rect dlgr = create_rect(centerx - text_size.w / 2 - 30
00339                     , centery - text_size.h / 2 - 16
00340                     , text_size.w + 60
00341                     , text_size.h + 32);
00342 
00343             surface_restorer restorer(&disp.video(),dlgr);
00344             gui::dialog_frame mini_frame(disp.video());
00345             mini_frame.layout(centerx-text_size.w/2 - 20,
00346                                     centery-text_size.h/2 - 6,
00347                                     text_size.w+40,
00348                                     text_size.h+12);
00349             mini_frame.draw_background();
00350             mini_frame.draw_border();
00351             font::draw_text (&disp.video(), clip_rect, font::SIZE_LARGE,font::NORMAL_COLOR,
00352                  _("Press desired hotkey (Esc cancels)"),centerx-text_size.w/2,
00353                  centery-text_size.h/2);
00354             disp.update_display();
00355             SDL_Event event;
00356             event.type = 0;
00357             int character = 0, keycode = 0, mod = 0; // Just to avoid warning
00358             int joystick = 0, button = 0, hat = 0, value = 0;
00359             const int any_mod = KMOD_CTRL | KMOD_ALT | KMOD_LMETA;
00360 
00361             while (event.type!=SDL_KEYDOWN && event.type!=SDL_JOYBUTTONDOWN && event.type!= SDL_JOYHATMOTION) SDL_PollEvent(&event);
00362             do {
00363                 if (event.type==SDL_KEYDOWN)
00364                 {
00365                     keycode=event.key.keysym.sym;
00366                     character=event.key.keysym.unicode;
00367                     mod=event.key.keysym.mod;
00368                 };
00369                 if (event.type==SDL_JOYBUTTONDOWN) {
00370                     joystick = event.jbutton.which;
00371                     button = event.jbutton.button;
00372                 }
00373                 if (event.type==SDL_JOYHATMOTION) {
00374                     joystick = event.jhat.which;
00375                     hat = event.jhat.hat;
00376                     value = event.jhat.value;
00377                 }
00378                 SDL_PollEvent(&event);
00379                 disp.flip();
00380                 disp.delay(10);
00381             } while (event.type!=SDL_KEYUP && event.type!=SDL_JOYBUTTONUP && event.type!=SDL_JOYHATMOTION);
00382             restorer.restore();
00383             disp.update_display();
00384             if (keycode == SDLK_ESCAPE && (mod & any_mod) == 0) {
00385                 //cancel -- no action
00386             } else {
00387                 const hotkey::hotkey_item& oldhk = hotkey::get_hotkey(character, keycode, (mod & KMOD_SHIFT) != 0,
00388                         (mod & KMOD_CTRL) != 0, (mod & KMOD_ALT) != 0, (mod & KMOD_LMETA) != 0);
00389 
00390                 hotkey::hotkey_item& newhk = hotkey::get_visible_hotkey(menu_.selection());
00391 
00392                 if(oldhk.get_id() != newhk.get_id() && !oldhk.null()) {
00393                     std::stringstream msg;
00394                     msg << "   " << oldhk.get_description() << " : " << oldhk.get_name();
00395                     gui2::show_transient_message(disp.video(),_("This hotkey is already in use."),msg.str());
00396                 } else {
00397                     if (event.type == SDL_JOYHATMOTION) {
00398                         const hotkey::hotkey_item& oldhkhat = hotkey::get_hotkey(joystick, hat, value);
00399 
00400                         if(oldhkhat.get_id() != newhk.get_id() && !oldhkhat.null()) {
00401                             std::stringstream msg;
00402                             msg << "   " << oldhkhat.get_description() << " : " << oldhkhat.get_name();
00403                             gui2::show_transient_message(disp.video(),_("This hotkey is already in use."),msg.str());
00404                         } else {
00405                             newhk.set_hat(joystick, hat, value);
00406                             menu_.change_item(menu_.selection(), 1, font::NULL_MARKUP + newhk.get_name());
00407                         }
00408                     } else
00409                     if (event.type == SDL_JOYBUTTONUP) {
00410                         const hotkey::hotkey_item& oldhkbtn = hotkey::get_hotkey(button, joystick);
00411 
00412                         if(oldhkbtn.get_id() != newhk.get_id() && !oldhkbtn.null()) {
00413                             std::stringstream msg;
00414                             msg << "   " << oldhkbtn.get_description() << " : " << oldhkbtn.get_name();
00415                             gui2::show_transient_message(disp.video(),_("This hotkey is already in use."),msg.str());
00416                         } else {
00417                             newhk.set_button(button, joystick);
00418                             menu_.change_item(menu_.selection(), 1, font::NULL_MARKUP + newhk.get_name());
00419                         }
00420                     } else {
00421 
00422                         newhk.set_key(character, keycode, (mod & KMOD_SHIFT) != 0,
00423                                 (mod & KMOD_CTRL) != 0, (mod & KMOD_ALT) != 0, (mod & KMOD_LMETA) != 0);
00424 
00425                         menu_.change_item(menu_.selection(), 1, font::NULL_MARKUP + newhk.get_name());
00426 
00427                         if ((newhk.get_id() == hotkey::HOTKEY_SCREENSHOT
00428                                 || newhk.get_id() == hotkey::HOTKEY_MAP_SCREENSHOT)
00429                                 && (mod & any_mod) == 0) {
00430                             gui2::show_transient_message(disp.video(), _("Warning"), _("Screenshot hotkeys should be combined with the Control, Alt or Meta modifiers to avoid problems."));
00431                         }
00432                     }
00433                 }
00434             }
00435         }
00436 
00437         if (clear_button.pressed()) {
00438             // clear hotkey
00439             hotkey::hotkey_item& newhk = hotkey::get_visible_hotkey(menu_.selection());
00440             newhk.clear_hotkey();
00441             menu_.change_item(menu_.selection(), 1, font::NULL_MARKUP + newhk.get_name());
00442         }
00443 
00444         if (reset_button.pressed()) {
00445             const int res = gui2::show_message(
00446                 disp.video(), _("Reset Hotkeys"),
00447                 _("This will reset all hotkeys to their default values. Do you want to continue?"), gui2::tmessage::yes_no_buttons);
00448 
00449             if(res != gui2::twindow::CANCEL) {
00450                 clear_hotkeys();
00451                 repopulate_hotkeys_menu(menu_items);
00452                 menu_.set_items(menu_items);
00453 
00454                 gui2::show_transient_message(disp.video(), _("Hotkeys Reset"), _("All hotkeys have been reset to their default values."));
00455             }
00456         }
00457 
00458         menu_.process();
00459 
00460         events::pump();
00461         events::raise_process_event();
00462         events::raise_draw_event();
00463 
00464         disp.update_display();
00465 
00466         disp.delay(10);
00467     }
00468 }
00469 #ifdef _MSC_VER
00470 #pragma warning (pop)
00471 #endif
00472 
00473 bool compare_resolutions(const std::pair<int,int>& lhs, const std::pair<int,int>& rhs)
00474 {
00475     return lhs.first*lhs.second < rhs.first*rhs.second;
00476 }
00477 
00478 bool show_video_mode_dialog(display& disp)
00479 {
00480     const resize_lock prevent_resizing;
00481     const events::event_context dialog_events_context;
00482 
00483     CVideo& video = disp.video();
00484 
00485     SDL_PixelFormat format = *video.getSurface()->format;
00486     format.BitsPerPixel = video.getBpp();
00487 
00488     const SDL_Rect* const * modes = SDL_ListModes(&format,FULL_SCREEN);
00489 
00490     // The SDL documentation says that a return value of -1
00491     // means that all dimensions are supported/possible.
00492     if(modes == reinterpret_cast<SDL_Rect**>(-1)) {
00493         std::cerr << "Can support any video mode\n";
00494         // SDL says that all modes are possible, so it's OK to use a
00495         // hardcoded list here. Include tiny and small gui since they
00496         // will be filtered out later if not needed.
00497         static const SDL_Rect scr_modes[] = {
00498             { 0, 0,  320, 240  },
00499             { 0, 0,  640, 480  },
00500             { 0, 0,  800, 480  },   // small-gui (EeePC resolution)
00501             { 0, 0,  800, 600  },
00502             { 0, 0, 1024, 600  },   // used on many netbooks
00503             { 0, 0, 1024, 768  },
00504             { 0, 0, 1280, 960  },
00505             { 0, 0, 1280, 1024 },
00506             { 0, 0, 1366, 768  },   // 16:9 notebooks
00507             { 0, 0, 1440, 900  },
00508             { 0, 0, 1440, 1200 },
00509             { 0, 0, 1600, 1200 },
00510             { 0, 0, 1680, 1050 },
00511             { 0, 0, 1920, 1080 },
00512             { 0, 0, 1920, 1200 },
00513             { 0, 0, 2560, 1600 }
00514         };
00515         static const SDL_Rect * const scr_modes_list[] = {
00516             &scr_modes[0],
00517             &scr_modes[1],
00518             &scr_modes[2],
00519             &scr_modes[3],
00520             &scr_modes[4],
00521             &scr_modes[5],
00522             &scr_modes[6],
00523             &scr_modes[7],
00524             &scr_modes[8],
00525             &scr_modes[9],
00526             &scr_modes[10],
00527             &scr_modes[11],
00528             &scr_modes[12],
00529             &scr_modes[13],
00530             &scr_modes[14],
00531             &scr_modes[15],
00532             NULL
00533         };
00534 
00535         modes = scr_modes_list;
00536     } else if(modes == NULL) {
00537         std::cerr << "No modes supported\n";
00538         gui2::show_transient_message(disp.video(),"",_("There are no alternative video modes available"));
00539         return false;
00540     }
00541 
00542     std::vector<std::pair<int,int> > resolutions;
00543 
00544     for(int i = 0; modes[i] != NULL; ++i) {
00545         if(modes[i]->w >= min_allowed_width() && modes[i]->h >= min_allowed_height()) {
00546             resolutions.push_back(std::pair<int,int>(modes[i]->w,modes[i]->h));
00547         }
00548     }
00549 
00550     const std::pair<int,int> current_res(video.getSurface()->w,video.getSurface()->h);
00551     resolutions.push_back(current_res);
00552 
00553     std::sort(resolutions.begin(),resolutions.end(),compare_resolutions);
00554     resolutions.erase(std::unique(resolutions.begin(),resolutions.end()),resolutions.end());
00555 
00556     std::vector<std::string> options;
00557     unsigned current_choice = 0;
00558 
00559     for(size_t k = 0; k < resolutions.size(); ++k) {
00560         std::pair<int, int> const& res = resolutions[k];
00561         std::ostringstream option;
00562 
00563         if (res == current_res)
00564             current_choice = static_cast<unsigned>(k);
00565 
00566         option << res.first << utils::unicode_multiplication_sign << res.second;
00567         /*widescreen threshold is 16:10*/
00568         if (static_cast<double>(res.first)/res.second >= 16.0/10.0)
00569           option << _(" (widescreen)");
00570         options.push_back(option.str());
00571     }
00572 
00573     gui2::tsimple_item_selector dlg(_("Choose Resolution"), "", options);
00574     dlg.set_selected_index(current_choice);
00575     dlg.show(disp.video());
00576 
00577     int choice = dlg.selected_index();
00578 
00579     if(choice == -1 || resolutions[static_cast<size_t>(choice)] == current_res) {
00580         return false;
00581     }
00582 
00583     set_resolution(resolutions[static_cast<size_t>(choice)]);
00584     return true;
00585 }
00586 
00587 } // end namespace preferences
00588 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:08 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs