preferences_display.cpp

Go to the documentation of this file.
00001 /* $Id: preferences_display.cpp 25934 2008-04-19 16:02:16Z alink $ */
00002 /*
00003    Copyright (C) 2003 - 2008 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 version 2
00008    or at your option any later version.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013 */
00014 
00015 //! @file preferences_display.cpp 
00016 //! Manage display-related preferences, e.g. screen-size, gamma etc.
00017 
00018 #include "global.hpp"
00019 
00020 #define GETTEXT_DOMAIN "wesnoth-lib"
00021 
00022 #include "cursor.hpp"
00023 #include "display.hpp"
00024 #include "game_preferences.hpp"
00025 #include "gettext.hpp"
00026 #include "hotkeys.hpp"
00027 #include "log.hpp"
00028 #include "marked-up_text.hpp"
00029 #include "preferences_display.hpp"
00030 #include "construct_dialog.hpp"
00031 #include "show_dialog.hpp"
00032 #include "video.hpp"
00033 #include "wml_separators.hpp"
00034 #include "widgets/button.hpp"
00035 #include "widgets/label.hpp"
00036 #include "widgets/menu.hpp"
00037 #include "widgets/slider.hpp"
00038 #include "widgets/textbox.hpp"
00039 #include "theme.hpp"
00040 
00041 #include <vector>
00042 #include <string>
00043 
00044 namespace preferences {
00045 
00046 display* disp = NULL;
00047 
00048 display_manager::display_manager(display* d)
00049 {
00050     disp = d;
00051 
00052     load_hotkeys();
00053 
00054     set_grid(grid());
00055     set_turbo(turbo());
00056     set_turbo_speed(turbo_speed());
00057     set_fullscreen(fullscreen());
00058     set_gamma(gamma());
00059     set_colour_cursors(utils::string_bool(preferences::get("colour_cursors")));
00060 }
00061 
00062 display_manager::~display_manager()
00063 {
00064     disp = NULL;
00065 }
00066 
00067 void set_fullscreen(bool ison)
00068 {
00069     _set_fullscreen(ison);
00070 
00071     if(disp != NULL) {
00072         const std::pair<int,int>& res = resolution();
00073         CVideo& video = disp->video();
00074         if(video.isFullScreen() != ison) {
00075             const int flags = ison ? FULL_SCREEN : 0;
00076             const int bpp = video.modePossible(res.first,res.second,16,flags);
00077             if(bpp > 0) {
00078                 video.setMode(res.first,res.second,bpp,flags);
00079                 disp->redraw_everything();
00080             } else if(video.modePossible(1024,768,16,flags)) {
00081                 set_resolution(std::pair<int,int>(1024,768));
00082             } else {
00083                 gui::message_dialog(*disp,"",_("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.")).show();
00084             }
00085             // We reinit color cursors, because SDL on Mac seems to forget the SDL_Cursor
00086             set_colour_cursors(utils::string_bool(preferences::get("colour_cursors")));
00087         }
00088     }
00089 }
00090 
00091 void set_resolution(const std::pair<int,int>& resolution)
00092 {
00093     std::pair<int,int> res = resolution;
00094 
00095     // - Ayin: disabled the following code. Why would one want to enforce that?
00096     // Some 16:9, or laptop screens, may have resolutions which do not
00097     // comply to this rule (see bug 10630). 
00098     // I'm commenting this until it proves absolutely necessary.
00099     //
00100     // Make sure resolutions are always divisible by 4
00101     //res.first &= ~3;
00102     //res.second &= ~3;
00103 
00104     bool write_resolution = true;
00105 
00106     if(disp != NULL) {
00107         CVideo& video = disp->video();
00108         const int flags = fullscreen() ? FULL_SCREEN : 0;
00109         const int bpp = video.modePossible(res.first,res.second,16,flags);
00110         if(bpp != 0) {
00111             video.setMode(res.first,res.second,bpp,flags);
00112             disp->redraw_everything();
00113 
00114         } else {
00115             write_resolution = false;
00116             gui::message_dialog(*disp,"",_("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.")).show();
00117         }
00118     }
00119 
00120     if(write_resolution) {
00121         const std::string postfix = fullscreen() ? "resolution" : "windowsize";
00122         preferences::set('x' + postfix, lexical_cast<std::string>(res.first));
00123         preferences::set('y' + postfix, lexical_cast<std::string>(res.second));
00124     }
00125 }
00126 
00127 void set_turbo(bool ison)
00128 {
00129     _set_turbo(ison);
00130 
00131     if(disp != NULL) {
00132         disp->set_turbo(ison);
00133     }
00134 }
00135 
00136 void set_turbo_speed(double speed)
00137 {
00138     save_turbo_speed(speed);
00139 
00140     if(disp != NULL) {
00141         disp->set_turbo_speed(speed);
00142     }
00143 }
00144 
00145 void set_adjust_gamma(bool val)
00146 {
00147     // If we are turning gamma adjustment off, then set it to '1.0'
00148     if(val == false && adjust_gamma()) {
00149         CVideo& video = disp->video();
00150         video.setGamma(1.0);
00151     }
00152 
00153     _set_adjust_gamma(val);
00154 }
00155 
00156 void set_gamma(int gamma)
00157 {
00158     _set_gamma(gamma);
00159 
00160     if(adjust_gamma()) {
00161         CVideo& video = disp->video();
00162         video.setGamma(static_cast<float>(gamma) / 100);
00163     }
00164 }
00165 
00166 void set_grid(bool ison)
00167 {
00168     _set_grid(ison);
00169 
00170     if(disp != NULL) {
00171         disp->set_grid(ison);
00172     }
00173 }
00174 
00175 void set_colour_cursors(bool value)
00176 {
00177     _set_colour_cursors(value);
00178 
00179     cursor::set();
00180 }
00181 
00182 void set_idle_anim(bool ison) {
00183     _set_idle_anim(ison);
00184     if(disp != NULL) {
00185         disp->set_idle_anim(ison);
00186     }
00187 }
00188 
00189 void set_idle_anim_rate(int rate) {
00190     _set_idle_anim_rate(rate);
00191     if(disp != NULL) {
00192         disp->set_idle_anim_rate(rate);
00193     }
00194 }
00195 
00196 namespace {
00197 class escape_handler : public events::handler {
00198 public:
00199     escape_handler() : escape_pressed_(false) {}
00200     bool escape_pressed() { return escape_pressed_; }
00201     void handle_event(const SDL_Event &event) { escape_pressed_ |= (event.type == SDL_KEYDOWN)
00202         && (reinterpret_cast<const SDL_KeyboardEvent&>(event).keysym.sym == SDLK_ESCAPE); }
00203 private:
00204     bool escape_pressed_;
00205 };
00206 } // end anonymous namespace
00207 
00208 void show_hotkeys_dialog (display & disp, config *save_config)
00209 {
00210     log_scope ("show_hotkeys_dialog");
00211 
00212     const events::event_context dialog_events_context;
00213 
00214     const int centerx = disp.w()/2;
00215     const int centery = disp.h()/2;
00216 #ifdef USE_TINY_GUI
00217     const int width  = 300;           //! @todo FIXME: We should compute this, but using what data ? 
00218         //! @todo FIXME:  suokko: window width and height could be usefull. min(300,disp.w()*0.9)  So it would be either 300 or max 90% of width
00219     const int height = 220;
00220 #else
00221     const int width  = 700;
00222     const int height = 500;
00223 #endif
00224     const int xpos = centerx  - width/2;
00225     const int ypos = centery  - height/2;
00226 
00227     gui::button close_button (disp.video(), _("Close Window"));
00228     std::vector<gui::button*> buttons;
00229     buttons.push_back(&close_button);
00230 
00231     gui::dialog_frame f(disp.video(),_("Hotkey Settings"),gui::dialog_frame::default_style,true,&buttons);
00232     f.layout(xpos,ypos,width,height);
00233     f.draw();
00234 
00235     SDL_Rect clip_rect = { 0, 0, disp.w (), disp.h () };
00236     SDL_Rect text_size = font::draw_text(NULL, clip_rect, font::SIZE_LARGE,
00237                          font::NORMAL_COLOUR,_("Press desired Hotkey (Esc cancels)"),
00238                          0, 0);
00239 
00240     std::vector<std::string> menu_items;
00241 
00242     std::vector<hotkey::hotkey_item>& hotkeys = hotkey::get_hotkeys();
00243     for(std::vector<hotkey::hotkey_item>::iterator i = hotkeys.begin(); i != hotkeys.end(); ++i) {
00244         if(i->hidden())
00245             continue;
00246         std::stringstream str,name;
00247         name << i->get_description();
00248         str << name.str();
00249         str << COLUMN_SEPARATOR;
00250         // This trick allows to display chars identical to markup characters
00251         str << font::NULL_MARKUP << i->get_name();
00252         menu_items.push_back(str.str());
00253     }
00254 
00255     std::ostringstream heading;
00256     heading << HEADING_PREFIX << _("Action") << COLUMN_SEPARATOR << _("Binding");
00257     menu_items.push_back(heading.str());
00258 
00259     gui::menu::basic_sorter sorter;
00260     sorter.set_alpha_sort(0).set_alpha_sort(1);
00261 
00262     gui::menu menu_(disp.video(), menu_items, false, height, -1, &sorter, &gui::menu::bluebg_style);
00263     menu_.sort_by(0);
00264     menu_.reset_selection();
00265     menu_.set_width(font::relative_size(400));
00266     menu_.set_location(xpos + font::relative_size(20), ypos);
00267 
00268     gui::button change_button (disp.video(), _("Change Hotkey"));
00269     change_button.set_location(xpos + width - change_button.width () - font::relative_size(30),ypos + font::relative_size(30));
00270 
00271     //! @todo Remember to make Clear Hotkey translateable
00272     gui::button clear_button (disp.video(), _("Clear Hotkey"));
00273     clear_button.set_location(xpos + width - clear_button.width () - font::relative_size(30),ypos + font::relative_size(80));
00274 //  gui::button save_button (disp.video(), _("Save Hotkeys"));
00275 //  save_button.set_location(xpos + width - save_button.width () - font::relative_size(30),ypos + font::relative_size(130));
00276 
00277     escape_handler esc_hand;
00278 
00279     for(;;) {
00280 
00281         if (close_button.pressed() || esc_hand.escape_pressed())
00282         {
00283             if (save_config == NULL) {
00284                 save_hotkeys();
00285             } else {
00286                 hotkey::save_hotkeys(*save_config);
00287             }
00288             break;
00289         }
00290 
00291         if (change_button.pressed () || menu_.double_clicked()) {
00292             // Lets change this hotkey......
00293             SDL_Rect dlgr = {centerx-text_size.w/2 - 30,
00294                                 centery-text_size.h/2 - 16,
00295                                     text_size.w+60,
00296                                     text_size.h+32};
00297             surface_restorer restorer(&disp.video(),dlgr);
00298             gui::dialog_frame mini_frame(disp.video());
00299             mini_frame.layout(centerx-text_size.w/2 - 20,
00300                                     centery-text_size.h/2 - 6,
00301                                     text_size.w+40,
00302                                     text_size.h+12);
00303             mini_frame.draw_background();
00304             mini_frame.draw_border();
00305             font::draw_text (&disp.video(), clip_rect, font::SIZE_LARGE,font::NORMAL_COLOUR,
00306                  _("Press desired Hotkey (Esc cancels)"),centerx-text_size.w/2,
00307                  centery-text_size.h/2);
00308             disp.update_display();
00309             SDL_Event event;
00310             event.type = 0;
00311             int character=0,keycode=0; // Just to avoid warning
00312             int mod=0;
00313             while (event.type!=SDL_KEYDOWN) SDL_PollEvent(&event);
00314             do {
00315                 if (event.type==SDL_KEYDOWN)
00316                 {
00317                     keycode=event.key.keysym.sym;
00318                     character=event.key.keysym.unicode;
00319                     mod=event.key.keysym.mod;
00320                 };
00321                 SDL_PollEvent(&event);
00322                 disp.flip();
00323                 disp.delay(10);
00324             } while (event.type!=SDL_KEYUP);
00325             restorer.restore();
00326             disp.update_display();
00327 
00328             if (keycode == SDLK_ESCAPE && mod == 0) {
00329                 //cancel -- no action
00330             } else {
00331                 const hotkey::hotkey_item& oldhk = hotkey::get_hotkey(character, keycode, (mod & KMOD_SHIFT) != 0,
00332                         (mod & KMOD_CTRL) != 0, (mod & KMOD_ALT) != 0, (mod & KMOD_LMETA) != 0);
00333 
00334                 hotkey::hotkey_item& newhk = hotkey::get_visible_hotkey(menu_.selection());
00335 
00336                 if(oldhk.get_id() != newhk.get_id() && !oldhk.null()) {
00337                     std::stringstream msg;
00338                     msg << "   " << oldhk.get_description() << " : " << oldhk.get_name();
00339                     gui::message_dialog(disp,_("This Hotkey is already in use."),msg.str()).show();
00340                 } else {
00341 
00342                     newhk.set_key(character, keycode, (mod & KMOD_SHIFT) != 0,
00343                             (mod & KMOD_CTRL) != 0, (mod & KMOD_ALT) != 0, (mod & KMOD_LMETA) != 0);
00344         
00345                     menu_.change_item(menu_.selection(), 1, font::NULL_MARKUP + newhk.get_name());
00346 
00347                     if ((newhk.get_id() == hotkey::HOTKEY_SCREENSHOT
00348                             || newhk.get_id() == hotkey::HOTKEY_MAP_SCREENSHOT)
00349                              && (mod & KMOD_CTRL) == 0 && (mod & KMOD_ALT) == 0
00350                              && (mod & KMOD_LMETA) == 0) {
00351                         gui::message_dialog(disp,"", _("Warning: screenshot hotkeys not combined with Control, Alt or Meta keys.")).show();
00352                     }
00353                 }
00354             }
00355         }
00356 //      if (save_button.pressed()) {
00357 //          if (save_config == NULL) {
00358 //              save_hotkeys();
00359 //          } else {
00360 //              hotkey::save_hotkeys(*save_config);
00361 //          }
00362 //      }
00363 
00364         if (clear_button.pressed()) {
00365             // clear hotkey
00366             hotkey::hotkey_item& newhk = hotkey::get_visible_hotkey(menu_.selection());
00367             newhk.clear_hotkey();
00368             menu_.change_item(menu_.selection(), 1, font::NULL_MARKUP + newhk.get_name());
00369         }
00370 
00371         menu_.process();
00372 
00373         events::pump();
00374         events::raise_process_event();
00375         events::raise_draw_event();
00376 
00377         disp.update_display();
00378 
00379         disp.delay(10);
00380     }
00381 }
00382 
00383 bool compare_resolutions(const std::pair<int,int>& lhs, const std::pair<int,int>& rhs)
00384 {
00385     return lhs.first*lhs.second < rhs.first*rhs.second;
00386 }
00387 
00388 bool show_video_mode_dialog(display& disp)
00389 {
00390     const resize_lock prevent_resizing;
00391     const events::event_context dialog_events_context;
00392 
00393     CVideo& video = disp.video();
00394 
00395     SDL_PixelFormat format = *video.getSurface()->format;
00396     format.BitsPerPixel = video.getBpp();
00397 
00398     const SDL_Rect* const * modes = SDL_ListModes(&format,FULL_SCREEN);
00399 
00400     // The SDL documentation says that a return value of -1 
00401     // means that all dimensions are supported/possible.
00402     if(modes == reinterpret_cast<SDL_Rect**>(-1)) {
00403         std::cerr << "Can support any video mode\n";
00404         // SDL says that all modes are possible, so it's OK to use a 
00405         // hardcoded list here. Include tiny and small gui since they
00406         // will be filter out later if not needed.
00407         static const SDL_Rect scr_modes[] = {
00408             { 0, 0,  320, 240 },    
00409             { 0, 0,  640, 480 },    
00410             { 0, 0,  800, 480 },    // small-gui (EeePC resolution)
00411             { 0, 0,  800, 600 },
00412             { 0, 0, 1024, 768 },
00413             { 0, 0, 1280, 960 },
00414             { 0, 0, 1280, 1024 },
00415         };
00416         static const SDL_Rect * const scr_modes_list[] = {
00417             &scr_modes[0],
00418             &scr_modes[1],
00419             &scr_modes[2],
00420             &scr_modes[3],
00421             &scr_modes[4],
00422             &scr_modes[5],
00423             &scr_modes[6],
00424             NULL
00425         };
00426 
00427         modes = scr_modes_list;
00428     } else if(modes == NULL) {
00429         std::cerr << "No modes supported\n";
00430         gui::message_dialog(disp,"",_("There are no alternative video modes available")).show();
00431         return false;
00432     }
00433 
00434     std::vector<std::pair<int,int> > resolutions;
00435 
00436     for(int i = 0; modes[i] != NULL; ++i) {
00437         if(modes[i]->w >= min_allowed_width && modes[i]->h >= min_allowed_height) {
00438             resolutions.push_back(std::pair<int,int>(modes[i]->w,modes[i]->h));
00439         }
00440     }
00441 
00442     const std::pair<int,int> current_res(video.getSurface()->w,video.getSurface()->h);
00443     resolutions.push_back(current_res);
00444 
00445     std::sort(resolutions.begin(),resolutions.end(),compare_resolutions);
00446     resolutions.erase(std::unique(resolutions.begin(),resolutions.end()),resolutions.end());
00447 
00448     std::vector<std::string> options;
00449     for(std::vector<std::pair<int,int> >::const_iterator j = resolutions.begin(); j != resolutions.end(); ++j) {
00450         std::ostringstream option;
00451         if (*j == current_res)
00452             option << DEFAULT_ITEM;
00453 
00454         option << j->first << "x" << j->second;
00455         options.push_back(option.str());
00456     }
00457 
00458     const int result = gui::show_dialog(disp,NULL,"",
00459                                         _("Choose Resolution"),
00460                                         gui::OK_CANCEL,&options);
00461     if(size_t(result) < resolutions.size() && resolutions[result] != current_res) {
00462         set_resolution(resolutions[result]);
00463         return true;
00464     } else {
00465         return false;
00466     }
00467 }
00468 
00469 } // end namespace preferences
00470 

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs