diff --git a/src/Makefile.am b/src/Makefile.am index 9b2813c84..284c670c7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -105,6 +105,7 @@ supertuxkart_SOURCES = main.cpp \ gui/track_sel.cpp gui/track_sel.hpp \ gui/player_controls.cpp gui/player_controls.hpp \ gui/config_display.cpp gui/config_display.hpp \ + gui/display_res_confirm.cpp gui/display_res_confirm.hpp \ gui/config_sound.cpp gui/config_sound.hpp \ gui/config_controls.cpp gui/config_controls.hpp \ gui/options.cpp gui/options.hpp \ diff --git a/src/gui/base_gui.cpp b/src/gui/base_gui.cpp index d0cdc41f7..f909cde40 100644 --- a/src/gui/base_gui.cpp +++ b/src/gui/base_gui.cpp @@ -141,4 +141,7 @@ BaseGUI::inputKeyboard(SDLKey, int) } //----------------------------------------------------------------------------- +void BaseGUI::countdown() +{ +} /* EOF */ diff --git a/src/gui/base_gui.hpp b/src/gui/base_gui.hpp index 3dd116eac..426940d76 100644 --- a/src/gui/base_gui.hpp +++ b/src/gui/base_gui.hpp @@ -37,6 +37,8 @@ public: virtual void handle(GameAction, int); virtual void inputKeyboard(SDLKey, int); + + virtual void countdown(); void inputPointer(int x, int y); diff --git a/src/gui/config_display.cpp b/src/gui/config_display.cpp index fdd538c53..0713f6bd8 100644 --- a/src/gui/config_display.cpp +++ b/src/gui/config_display.cpp @@ -49,8 +49,12 @@ enum WidgetTokens WTOK_EMPTY1, WTOK_EMPTY2, + + WTOK_EMPTY3, - WTOK_QUIT + WTOK_QUIT, + + WTOK_CLEAR_BLACKLIST }; ConfigDisplay::ConfigDisplay() @@ -88,15 +92,26 @@ ConfigDisplay::ConfigDisplay() widget_manager->setWgtText( WTOK_INCR_RES, _("Increase Resolution")); widget_manager->addWgt( WTOK_DECR_RES, 40, 7); - widget_manager->setWgtText( WTOK_DECR_RES, ("Decrease Resolution")); + widget_manager->setWgtText( WTOK_DECR_RES, _("Decrease Resolution")); - widget_manager->addWgt( WTOK_EMPTY2, 40, 2); + widget_manager->addWgt( WTOK_EMPTY2, 40, 2); widget_manager->deactivateWgt( WTOK_EMPTY2 ); widget_manager->hideWgtRect( WTOK_EMPTY2 ); widget_manager->hideWgtText( WTOK_EMPTY2 ); widget_manager->addWgt( WTOK_APPLY_RES, 40, 7); - widget_manager->setWgtText( WTOK_APPLY_RES, ("Apply ")); + widget_manager->setWgtText( WTOK_APPLY_RES, _("Apply ")); + + if (!user_config->m_blacklist_res.empty()) + { + widget_manager->addWgt( WTOK_EMPTY3, 40, 2); + widget_manager->deactivateWgt( WTOK_EMPTY3 ); + widget_manager->hideWgtRect( WTOK_EMPTY3 ); + widget_manager->hideWgtText( WTOK_EMPTY3 ); + + widget_manager->addWgt( WTOK_CLEAR_BLACKLIST, 55, 7); + widget_manager->setWgtText( WTOK_CLEAR_BLACKLIST, _("Clear Resolution Blacklist")); + } widget_manager->addWgt( WTOK_EMPTY1, 40, 7); widget_manager->deactivateWgt( WTOK_EMPTY1 ); @@ -107,18 +122,28 @@ ConfigDisplay::ConfigDisplay() widget_manager->setWgtText( WTOK_QUIT, _("Press to go back")); widget_manager->setWgtTextSize( WTOK_QUIT, WGT_FNT_SML ); + //if prev resolution different to current res then a resolution change has been rejected + if (user_config->m_width != user_config->m_prev_width + && user_config->m_height != user_config->m_prev_height) + { + changeResolution(user_config->m_prev_width, + user_config->m_prev_height,true); + } + widget_manager->layout( WGT_AREA_ALL ); //get current resolution and set wgt txt - getScreenModes(); - if (m_sizes_index == -1) + getScreenModes(); //Populate a list with possible resolutions + if (m_sizes_index == -1) //A custom res has been set previously that is not in list { - snprintf (m_resolution, MAX_MESSAGE_LENGTH, "Current: %dx%d", user_config->m_width, user_config->m_height); + snprintf (m_resolution, MAX_MESSAGE_LENGTH, _("Current: %dx%d"), user_config->m_width, user_config->m_height); widget_manager->setWgtText(WTOK_CURRENT_RES, m_resolution); } - else + else // Find the current res from those in the list { - snprintf(m_resolution, MAX_MESSAGE_LENGTH, "Current: %dx%d",m_sizes[m_sizes_index].first,m_sizes[m_sizes_index].second); + m_curr_width = m_sizes[m_sizes_index].first; + m_curr_height = m_sizes[m_sizes_index].second; + snprintf(m_resolution, MAX_MESSAGE_LENGTH, _("Current: %dx%d"),m_curr_width,m_curr_height); widget_manager->setWgtText(WTOK_CURRENT_RES, m_resolution); } } @@ -148,21 +173,28 @@ void ConfigDisplay::select() break; case WTOK_INCR_RES: m_sizes_index = std::min(m_sizes_size-1,m_sizes_index+1); - snprintf(m_resolution, MAX_MESSAGE_LENGTH, "Apply %dx%d",m_sizes[m_sizes_index].first,m_sizes[m_sizes_index].second); + snprintf(m_resolution, MAX_MESSAGE_LENGTH, _("Apply %dx%d"),m_sizes[m_sizes_index].first,m_sizes[m_sizes_index].second); widget_manager->setWgtText(WTOK_APPLY_RES, m_resolution); break; - case WTOK_DECR_RES: + case WTOK_DECR_RES: m_sizes_index = std::max(0,m_sizes_index-1); - snprintf(m_resolution, MAX_MESSAGE_LENGTH, "Apply %dx%d",m_sizes[m_sizes_index].first,m_sizes[m_sizes_index].second); + snprintf(m_resolution, MAX_MESSAGE_LENGTH, _("Apply %dx%d"),m_sizes[m_sizes_index].first,m_sizes[m_sizes_index].second); widget_manager->setWgtText(WTOK_APPLY_RES, m_resolution); break; - case WTOK_APPLY_RES: - changeResolution(m_sizes[m_sizes_index].first,m_sizes[m_sizes_index].second); - snprintf (m_resolution, MAX_MESSAGE_LENGTH, "Current: %dx%d", user_config->m_width, user_config->m_height); - widget_manager->setWgtText(WTOK_CURRENT_RES, m_resolution); - + case WTOK_APPLY_RES: + if (m_curr_width != m_sizes[m_sizes_index].first + || m_curr_height != m_sizes[m_sizes_index].second) //Only allow Apply if a new res has been selected + { + changeResolution(m_sizes[m_sizes_index].first,m_sizes[m_sizes_index].second); + menu_manager->pushMenu(MENUID_DISPLAY_RES_CONFIRM); + } break; - + case WTOK_CLEAR_BLACKLIST: + user_config->m_blacklist_res.clear(); + widget_manager->hideWgtRect( WTOK_CLEAR_BLACKLIST ); + widget_manager->hideWgtText( WTOK_CLEAR_BLACKLIST ); + widget_manager->layout(); + break; case WTOK_QUIT: menu_manager->popMenu(); break; @@ -171,17 +203,33 @@ void ConfigDisplay::select() } //----------------------------------------------------------------------------- -void ConfigDisplay::changeResolution(int width, int height) +void ConfigDisplay::changeResolution(int width, int height, bool reverse) { + if (!reverse) // don't store previous res if returning to it + { + //store previous width and height + user_config->m_prev_width = user_config->m_width; + user_config->m_prev_height = user_config->m_height; + } + + //change to new height and width user_config->m_width = width; user_config->m_height = height; + + if (!reverse) + { + // Store settings in user config file in case new video mode + // causes a crash + user_config->m_crashed = true; //set flag. + user_config->saveConfig(); + } setVideoMode(); - - widget_manager->layout(); - + glViewport(0,0,user_config->m_width, user_config->m_height); glScissor(0,0,user_config->m_width, user_config->m_height); + + user_config->m_crashed = false; //if got here,then res change didn't crash STK } //----------------------------------------------------------------------------- @@ -194,11 +242,11 @@ void ConfigDisplay::getScreenModes() SDL_Rect **modes = SDL_ListModes(NULL, SDL_OPENGL | SDL_FULLSCREEN | SDL_HWSURFACE ); //Check if any modes are available - if (!modes) + if (!modes) { std::cerr << "No Screen Modes available" <m_blacklist_res.empty()) + { + int blacklist_res_size = (int)user_config->m_blacklist_res.size(); + int black_width, black_height = 0; + for (int i = 0; i < blacklist_res_size; i++) + { + sscanf(user_config->m_blacklist_res[i].c_str(), + "%dx%d",& black_width, & black_height); + + for (int i = m_sizes_size-1; i >=0; i--) + { + if (m_sizes[i].first == black_width + && m_sizes[i].second == black_height) + { + m_sizes.erase(m_sizes.begin()+i); + } + } + } + } + // search m_sizes for the current resolution m_sizes_index = -1; m_sizes_size = (int)m_sizes.size(); diff --git a/src/gui/config_display.hpp b/src/gui/config_display.hpp index d0b45648d..5fe87be74 100644 --- a/src/gui/config_display.hpp +++ b/src/gui/config_display.hpp @@ -24,6 +24,7 @@ #include "base_gui.hpp" #include "translation.hpp" +#include "display_res_confirm.hpp" class ConfigDisplay: public BaseGUI { @@ -34,14 +35,15 @@ public: void select(); private: - int m_fullscreen_menu_id; - std::vector > m_sizes; int m_sizes_index; int m_sizes_size; char m_resolution[MAX_MESSAGE_LENGTH]; - - void changeResolution(int width, int height); + int m_curr_width; + int m_curr_height; + + // changeResolution reverse param is set true when changing to a previous resolution + void changeResolution(int width, int height, bool reverse=false); void getScreenModes(); }; diff --git a/src/gui/display_res_confirm.cpp b/src/gui/display_res_confirm.cpp new file mode 100644 index 000000000..a016c109d --- /dev/null +++ b/src/gui/display_res_confirm.cpp @@ -0,0 +1,153 @@ +// $Id$ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2008 Paul Elms +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include +#include + +#include "display_res_confirm.hpp" +#include "menu_manager.hpp" +#include "widget_manager.hpp" +#include "translation.hpp" +#include "user_config.hpp" + + +#if defined(WIN32) && !defined(__CYGWIN__) +# define snprintf _snprintf +#endif + +enum WidgetTokens +{ + WTOK_TITLE, + + WTOK_APPLY_RES, + + WTOK_EMPTY, + + WTOK_EMPTY1, + + WTOK_QUIT +}; + +DisplayResConfirm::DisplayResConfirm() +{ + m_counter = 10; + + const bool SHOW_RECT = true; + const bool SHOW_TEXT = true; + widget_manager->setInitialRectState(SHOW_RECT, WGT_AREA_ALL, WGT_TRANS_BLACK); + widget_manager->setInitialTextState(SHOW_TEXT, "", WGT_FNT_MED, + WGT_FONT_GUI ); + + widget_manager->insertColumn(); + widget_manager->addWgt( WTOK_TITLE, 70, 7); + widget_manager->setWgtText( WTOK_TITLE, _("Confirm Resolution Within 10 Seconds")); + + widget_manager->setInitialActivationState(true); + + widget_manager->addWgt( WTOK_EMPTY, 40, 2); + widget_manager->deactivateWgt( WTOK_EMPTY ); + widget_manager->hideWgtRect( WTOK_EMPTY ); + widget_manager->hideWgtText( WTOK_EMPTY ); + + widget_manager->addWgt( WTOK_APPLY_RES, 40, 7); + widget_manager->setWgtText( WTOK_APPLY_RES, _("Confirm Resolution")); + + widget_manager->addWgt( WTOK_EMPTY1, 40, 2); + widget_manager->deactivateWgt( WTOK_EMPTY1 ); + widget_manager->hideWgtRect( WTOK_EMPTY1 ); + widget_manager->hideWgtText( WTOK_EMPTY1 ); + + widget_manager->addWgt( WTOK_QUIT, 40, 7); + widget_manager->setWgtText( WTOK_QUIT, _("Press to Cancel")); + widget_manager->setWgtTextSize( WTOK_QUIT, WGT_FNT_SML ); + + widget_manager->layout( WGT_AREA_ALL ); + + m_timer = SDL_AddTimer(1000,timeout,NULL); + + +} + +//----------------------------------------------------------------------------- +DisplayResConfirm::~DisplayResConfirm() +{ + widget_manager->reset(); +} + +//----------------------------------------------------------------------------- +void DisplayResConfirm::select() +{ + switch ( widget_manager->getSelectedWgt()) + { + case WTOK_APPLY_RES: + //set prev resolution to current values to confirm change + user_config->m_prev_width = user_config->m_width; + user_config->m_prev_height = user_config->m_height; + SDL_RemoveTimer(m_timer); + menu_manager->popMenu(); + break; + case WTOK_QUIT: + SDL_RemoveTimer(m_timer); + menu_manager->popMenu(); + break; + default: break; + } +} + +//----------------------------------------------------------------------------- +void DisplayResConfirm::countdown() +{ + if (m_counter > 1) + { + m_counter--; + snprintf(m_count, MAX_MESSAGE_LENGTH, _("Confirm Resolution Within %d Seconds"), m_counter); + widget_manager->setWgtText(WTOK_TITLE, m_count); + } + else + { + SDL_RemoveTimer(m_timer); + + // blacklist the resolution + std::ostringstream o; + o << user_config->m_width << "x" << user_config->m_height; + user_config->m_blacklist_res.push_back (o.str()); + + menu_manager->popMenu(); + } +} + + +//============================================================================= +Uint32 timeout(Uint32 interval, void *param) +{ + SDL_Event event; + SDL_UserEvent userevent; + + userevent.type = SDL_USEREVENT; + userevent.code = 0; + userevent.data1 = NULL; + userevent.data2 = NULL; + + event.type = SDL_USEREVENT; + event.user = userevent; + + SDL_PushEvent(&event); + + return (interval); +} diff --git a/src/gui/display_res_confirm.hpp b/src/gui/display_res_confirm.hpp new file mode 100644 index 000000000..fafb15dbe --- /dev/null +++ b/src/gui/display_res_confirm.hpp @@ -0,0 +1,45 @@ +// $Id$ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2008 Paul Elms +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_DISPLAY_RES_CONFIRM_H +#define HEADER_DISPLAY_RES_CONFIRM_H + +#include "base_gui.hpp" +//#include "translation.hpp" + +#include + +class DisplayResConfirm: public BaseGUI +{ +public: + DisplayResConfirm(); + ~DisplayResConfirm(); + + void select(); + void countdown(); + +private: + SDL_TimerID m_timer; + char m_count[60]; + int m_counter; +}; + +Uint32 timeout(Uint32 interval, void *param); + +#endif diff --git a/src/gui/menu_manager.cpp b/src/gui/menu_manager.cpp index c28223cde..210e6d198 100644 --- a/src/gui/menu_manager.cpp +++ b/src/gui/menu_manager.cpp @@ -34,6 +34,7 @@ #include "num_players.hpp" #include "config_controls.hpp" #include "config_display.hpp" +#include "display_res_confirm.hpp" #include "config_sound.hpp" #include "player_controls.hpp" #include "race_gui.hpp" @@ -199,6 +200,9 @@ void MenuManager::update() case MENUID_CONFIG_DISPLAY: m_current_menu= new ConfigDisplay(); break; + case MENUID_DISPLAY_RES_CONFIRM: + m_current_menu= new DisplayResConfirm(); + break; case MENUID_CONFIG_SOUND: m_current_menu= new ConfigSound(); break; diff --git a/src/gui/menu_manager.hpp b/src/gui/menu_manager.hpp index 6477b5c96..aaac38d46 100644 --- a/src/gui/menu_manager.hpp +++ b/src/gui/menu_manager.hpp @@ -46,6 +46,7 @@ enum MenuManagerIDs // menu configuration MENUID_CONFIG_DISPLAY, + MENUID_DISPLAY_RES_CONFIRM, MENUID_CONFIG_SOUND, MENUID_CONFIG_CONTROLS, MENUID_CONFIG_P1, diff --git a/src/lisp/writer.cpp b/src/lisp/writer.cpp index 656ccf267..7854c454b 100644 --- a/src/lisp/writer.cpp +++ b/src/lisp/writer.cpp @@ -192,7 +192,19 @@ namespace lisp } //----------------------------------------------------------------------------- + + void + Writer::write(const std::string& name, const std::vector& value) + { + indent(); + *m_out << '(' << name; + for(std::vector::const_iterator i = value.begin(); i != value.end(); ++i) + *m_out << " " << "\"" << *i << "\""; + *m_out << ")\n"; + } +//----------------------------------------------------------------------------- + void Writer::indent() { diff --git a/src/lisp/writer.hpp b/src/lisp/writer.hpp index f2d19a617..61ff68cb0 100644 --- a/src/lisp/writer.hpp +++ b/src/lisp/writer.hpp @@ -46,6 +46,7 @@ namespace lisp void write(const std::string& name, bool value); void write(const std::string& name, const std::vector& value); void write(const std::string& name, const std::vector& value); + void write(const std::string& name, const std::vector& value); // add more write-functions when needed... void endList(const std::string& listname); diff --git a/src/main.cpp b/src/main.cpp index 2406a171d..0596d53d9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -264,8 +264,12 @@ int handleCmdLine(int argc, char **argv) else if ( !strcmp(argv[i], "--screensize") || !strcmp(argv[i], "-s") ) { if (sscanf(argv[i+1], "%dx%d", &user_config->m_width, &user_config->m_height) == 2) - fprintf ( stdout, _("You choose to be in %dx%d.\n"), user_config->m_width, + { + fprintf ( stdout, _("You choose to be in %dx%d.\n"), user_config->m_width, user_config->m_height ); + user_config->m_prev_width = user_config->m_width; + user_config->m_prev_height = user_config->m_height; + } else { fprintf(stderr, _("Error: --screensize argument must be given as WIDTHxHEIGHT\n")); diff --git a/src/sdldrv.cpp b/src/sdldrv.cpp index 4b09fb903..72b33e686 100755 --- a/src/sdldrv.cpp +++ b/src/sdldrv.cpp @@ -20,6 +20,9 @@ #include #include +#include +#include +#include #include "input.hpp" #include "actionmap.hpp" @@ -66,10 +69,35 @@ void drv_init() SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_TIMER); flags = SDL_OPENGL | SDL_HWSURFACE; - - if(user_config->m_fullscreen) + + //detect if previous resolution crashed STK + if (user_config->m_crashed) + { + //STK crashed last time + user_config->m_crashed = false; //reset flag + // set window mode as a precaution + user_config->m_fullscreen = false; + // blacklist the res + std::ostringstream o; + o << user_config->m_width << "x" << user_config->m_height; + user_config->m_blacklist_res.push_back (o.str()); + //use prev screen res settings if available + if (user_config->m_width != user_config->m_prev_width + || user_config->m_height != user_config->m_prev_height) + { + user_config->m_width = user_config->m_prev_width; + user_config->m_height = user_config->m_prev_height; + } + else //set 'safe' resolution to return to + { + user_config->m_width = user_config->m_prev_width = 800; + user_config->m_height = user_config->m_prev_height = 600; + } + } + + if(user_config->m_fullscreen) flags |= SDL_FULLSCREEN; - + setVideoMode(false); SDL_JoystickEventState(SDL_ENABLE); @@ -110,11 +138,18 @@ void drv_toggleFullscreen(bool resetTextures) if(menu_manager->isSomewhereOnStack(MENUID_RACE)) showPointer(); + + // Store settings in user config file in case new video mode + // causes a crash + user_config->m_crashed = true; //set flag. + user_config->saveConfig(); } else if(menu_manager->isSomewhereOnStack(MENUID_RACE)) hidePointer(); - + setVideoMode(resetTextures); + + user_config->m_crashed = false; //if got here,then fullscreen change didn't crash STK } //----------------------------------------------------------------------------- @@ -371,6 +406,10 @@ void sdl_input() input(IT_STICKBUTTON, !mode ? 0 : ev.jbutton.which, ev.jbutton.button, 0, 32768); break; + case SDL_USEREVENT: + // used in display_res_confirm for the countdown timer + (menu_manager->getCurrentMenu())->countdown(); + } // switch } // while (SDL_PollEvent()) diff --git a/src/user_config.cpp b/src/user_config.cpp index 72c36b4ad..ce7187420 100644 --- a/src/user_config.cpp +++ b/src/user_config.cpp @@ -130,6 +130,10 @@ void UserConfig::setDefaults() m_replay_history = false; m_width = 800; m_height = 600; + m_prev_width = m_width; + m_prev_height = m_height; + m_crashed = false; + m_blacklist_res.clear(); m_karts = 4; m_log_errors = false; @@ -433,7 +437,13 @@ void UserConfig::loadConfig(const std::string& filename) /*get resolution width/height*/ lisp->get("width", m_width); lisp->get("height", m_height); - + lisp->get("prev_width", m_prev_width); + lisp->get("prev_height", m_prev_height); + //detect if resolution change previously crashed STK + lisp->get("crash_detected", m_crashed); + // blacklisted resolutions + lisp->getVector("blacklisted_resolutions", m_blacklist_res); + /*get number of karts*/ lisp->get("karts", m_karts); @@ -612,6 +622,10 @@ void UserConfig::saveConfig(const std::string& filename) writer->writeComment("screen resolution and windowing mode"); writer->write("width\t", m_width); writer->write("height\t", m_height); + writer->write("prev_width\t", m_prev_width); + writer->write("prev_height\t", m_prev_height); + writer->write("crash_detected\t", m_crashed); + writer->write("blacklisted_resolutions\t", m_blacklist_res); writer->write("fullscreen\t", m_fullscreen); writer->writeComment("number of karts. -1 means use all"); diff --git a/src/user_config.hpp b/src/user_config.hpp index 1353b717e..a97690e43 100644 --- a/src/user_config.hpp +++ b/src/user_config.hpp @@ -37,6 +37,7 @@ #define SUPPORTED_CONFIG_VERSION 3 #include +#include #include "input.hpp" #include "player.hpp" #include "lisp/lisp.hpp" @@ -147,6 +148,10 @@ public: bool m_improved_physics; int m_width; int m_height; + int m_prev_width; + int m_prev_height; + bool m_crashed; + std::vector m_blacklist_res; int m_karts; Player m_player[PLAYERS]; bool m_log_errors;