wesnoth-cvs-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Wesnoth-cvs-commits] wesnoth ./changelog src/checksum.hpp src/multip...


From: David White
Subject: [Wesnoth-cvs-commits] wesnoth ./changelog src/checksum.hpp src/multip...
Date: Tue, 10 May 2005 18:15:57 -0400

CVSROOT:        /cvsroot/wesnoth
Module name:    wesnoth
Branch:         
Changes by:     David White <address@hidden>    05/05/10 22:15:57

Modified files:
        .              : changelog 
        src            : checksum.hpp multiplayer_lobby.hpp 
                         show_dialog.hpp tstring.hpp util.hpp 
                         variable.hpp wml_separators.hpp checksum.cpp 
                         dialogs.cpp font.cpp game.cpp game_config.cpp 
                         intro.cpp multiplayer_lobby.cpp 
                         playcampaign.cpp playturn.cpp preferences.cpp 
                         random.cpp show_dialog.cpp tstring.cpp unit.cpp 
                         variable.cpp 
        src/serialization: binary_or_text.cpp preprocessor.cpp 
        src/server     : metrics.cpp 
        src/widgets    : menu.hpp slider.hpp widget.hpp menu.cpp 
                         widget.cpp 

Log message:
        made menu widgets sortable

CVSWeb URLs:
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/changelog.diff?tr1=1.661&tr2=1.662&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/checksum.hpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/multiplayer_lobby.hpp.diff?tr1=1.10&tr2=1.11&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/show_dialog.hpp.diff?tr1=1.47&tr2=1.48&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/tstring.hpp.diff?tr1=1.6&tr2=1.7&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/util.hpp.diff?tr1=1.22&tr2=1.23&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/variable.hpp.diff?tr1=1.4&tr2=1.5&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/wml_separators.hpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/checksum.cpp.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/dialogs.cpp.diff?tr1=1.100&tr2=1.101&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/font.cpp.diff?tr1=1.139&tr2=1.140&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/game.cpp.diff?tr1=1.243&tr2=1.244&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/game_config.cpp.diff?tr1=1.95&tr2=1.96&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/intro.cpp.diff?tr1=1.76&tr2=1.77&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/multiplayer_lobby.cpp.diff?tr1=1.71&tr2=1.72&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/playcampaign.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/playturn.cpp.diff?tr1=1.367&tr2=1.368&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/preferences.cpp.diff?tr1=1.153&tr2=1.154&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/random.cpp.diff?tr1=1.4&tr2=1.5&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/show_dialog.cpp.diff?tr1=1.126&tr2=1.127&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/tstring.cpp.diff?tr1=1.8&tr2=1.9&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/unit.cpp.diff?tr1=1.150&tr2=1.151&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/variable.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/serialization/binary_or_text.cpp.diff?tr1=1.11&tr2=1.12&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/serialization/preprocessor.cpp.diff?tr1=1.13&tr2=1.14&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/server/metrics.cpp.diff?tr1=1.4&tr2=1.5&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/widgets/menu.hpp.diff?tr1=1.35&tr2=1.36&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/widgets/slider.hpp.diff?tr1=1.23&tr2=1.24&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/widgets/widget.hpp.diff?tr1=1.26&tr2=1.27&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/widgets/menu.cpp.diff?tr1=1.88&tr2=1.89&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/widgets/widget.cpp.diff?tr1=1.31&tr2=1.32&r1=text&r2=text

Patches:
Index: wesnoth/changelog
diff -u wesnoth/changelog:1.661 wesnoth/changelog:1.662
--- wesnoth/changelog:1.661     Tue May 10 13:48:39 2005
+++ wesnoth/changelog   Tue May 10 22:15:56 2005
@@ -1,6 +1,7 @@
 CVS HEAD:
  * balancing change: reduced cost of dwarvish fighter by 1 gold; made 
Lieutenant more powerful
  * user interface improvements:
+   * made menu widgets sortable
    * added %-to-kill to Damage Calculations
    * made it so a unit's defense in a terrain is displayed over the terrain 
when choosing to move the unit
    * added 'Advanced' preferences section with 'binary save files' and 'show 
combat' as initial options
Index: wesnoth/src/checksum.cpp
diff -u wesnoth/src/checksum.cpp:1.2 wesnoth/src/checksum.cpp:1.3
--- wesnoth/src/checksum.cpp:1.2        Mon Apr 25 18:06:41 2005
+++ wesnoth/src/checksum.cpp    Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: checksum.cpp,v 1.2 2005/04/25 18:06:41 gruikya Exp $ */
+/* $Id: checksum.cpp,v 1.3 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2005 by Philippe Plantier <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -57,7 +57,7 @@
 }
 
 
-checksumstream::checksumstream() : std::ostream(&sbuf)
+checksumstream::checksumstream() : std::basic_ostream<char>(this), sbuf(*this)
 {
 }
 
Index: wesnoth/src/checksum.hpp
diff -u wesnoth/src/checksum.hpp:1.1 wesnoth/src/checksum.hpp:1.2
--- wesnoth/src/checksum.hpp:1.1        Sat Apr 23 12:13:10 2005
+++ wesnoth/src/checksum.hpp    Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: checksum.hpp,v 1.1 2005/04/23 12:13:10 gruikya Exp $ */
+/* $Id: checksum.hpp,v 1.2 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2005 by Philippe Plantier <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -39,13 +39,13 @@
        unsigned short csumb;
 };
 
-class checksumstream : public std::basic_ostream<char>
+class checksumstream : private checksumstreambuf, public 
std::basic_ostream<char>
 {
 public:
        checksumstream();
        unsigned long checksum();
 private:
-       checksumstreambuf sbuf;
+       checksumstreambuf& sbuf;
 };
 
 #endif // CHECKSUM_HPP_INCLUDED
Index: wesnoth/src/dialogs.cpp
diff -u wesnoth/src/dialogs.cpp:1.100 wesnoth/src/dialogs.cpp:1.101
--- wesnoth/src/dialogs.cpp:1.100       Fri May  6 17:20:53 2005
+++ wesnoth/src/dialogs.cpp     Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: dialogs.cpp,v 1.100 2005/05/06 17:20:53 ettin Exp $ */
+/* $Id: dialogs.cpp,v 1.101 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -391,6 +391,51 @@
 
        font::draw_text(&video(), area, font::SIZE_SMALL, font::NORMAL_COLOUR, 
str.str(), area.x, ypos, true);
 }
+
+std::string format_time_summary(time_t t)
+{
+       time_t curtime = time(NULL);
+       const struct tm* timeptr = localtime(&curtime);
+       if(timeptr == NULL) {
+               return "";
+       }
+
+       const struct tm current_time = *timeptr;
+
+       timeptr = localtime(&t);
+       if(timeptr == NULL) {
+               return "";
+       }
+
+       const struct tm save_time = *timeptr;
+
+       const char* format_string = _("%b %d %y");
+
+       if(current_time.tm_year == save_time.tm_year) {
+               const int days_apart = current_time.tm_yday - save_time.tm_yday;
+               if(days_apart == 0) {
+                       //save is from today
+                       format_string = _("%H:%M");
+               } else if(days_apart > 0 && days_apart <= current_time.tm_wday) 
{
+                       //save is from this week
+                       format_string = _("%A, %H:%M");
+               } else {
+                       //save is from current year
+                       format_string = _("%b %d");
+               }
+       } else {
+               //save is from a different year
+               format_string = _("%b %d %y");
+       }
+       
+       char buf[40];
+       const size_t res = strftime(buf,sizeof(buf),format_string,&save_time);
+       if(res == 0) {
+               buf[0] = 0;
+       }
+
+       return buf;
+}
 
 } //end anon namespace
 
@@ -494,13 +539,23 @@
                write_save_index();
        }
 
-       std::vector<std::string> items;
+       std::vector<std::string> items;
+       std::ostringstream heading;
+       heading << HEADING_PREFIX << _("Name") << COLUMN_SEPARATOR << _("Date");
+       items.push_back(heading.str());
+
        for(i = games.begin(); i != games.end(); ++i) {
                std::string name = i->name;
-               name.resize(minimum<size_t>(name.size(),40));
-
-               items.push_back(name);
-       }
+               name.resize(minimum<size_t>(name.size(),40));
+
+               std::ostringstream str;
+               str << name << COLUMN_SEPARATOR << 
format_time_summary(i->time_modified);
+
+               items.push_back(str.str());
+       }
+
+       gui::menu::basic_sorter sorter;
+       sorter.set_alpha_sort(0).set_id_sort(1);
 
        gamemap map_obj(game_config,"");
 
@@ -517,7 +572,7 @@
        const int res = gui::show_dialog(disp,NULL,
                                         _("Load Game"),
                                         _("Choose the game to load"),
-                                
gui::OK_CANCEL,&items,&preview_panes,"",NULL,-1,NULL,&options,-1,-1,NULL,&buttons);
+                                
gui::OK_CANCEL,&items,&preview_panes,"",NULL,-1,NULL,&options,-1,-1,NULL,&buttons,"",&sorter);
 
        if(res == -1)
                return "";
Index: wesnoth/src/font.cpp
diff -u wesnoth/src/font.cpp:1.139 wesnoth/src/font.cpp:1.140
--- wesnoth/src/font.cpp:1.139  Sat May  7 21:53:42 2005
+++ wesnoth/src/font.cpp        Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: font.cpp,v 1.139 2005/05/07 21:53:42 ettin Exp $ */
+/* $Id: font.cpp,v 1.140 2005/05/10 22:15:57 Sirp Exp $ */
 /* vim:set encoding=utf-8: */
 /*
    Copyright (C) 2003 by David White <address@hidden>
@@ -490,6 +490,8 @@
                hit_ = 0;
        }
        return cache_.front();
+}
+
 }
 
 surface render_text(const std::string& text, int fontsize, const SDL_Color& 
colour, int style)
@@ -546,6 +548,8 @@
                return res;
        }
 }
+
+namespace {
 
 //function which will parse the markup tags at the front of a string
 std::string::const_iterator parse_markup(std::string::const_iterator i1, 
std::string::const_iterator i2,
@@ -812,13 +816,24 @@
        if(font == NULL)
                return 0;
        return TTF_FontHeight(font);
-}
+}
 
 bool is_format_char(char c)
-{
-       switch(c) {
+{
+       //side coloring
+       if(c > 0 && c <= 10) {
+               return true;
+       }
+
+       switch(c) {
+       case LARGE_TEXT:
+       case SMALL_TEXT:
        case GOOD_TEXT:
-       case BAD_TEXT:
+       case BAD_TEXT:
+       case NORMAL_TEXT:
+       case BLACK_TEXT:
+       case BOLD_TEXT:
+       case NULL_MARKUP:
                return true;
        default:
                return false;
Index: wesnoth/src/game.cpp
diff -u wesnoth/src/game.cpp:1.243 wesnoth/src/game.cpp:1.244
--- wesnoth/src/game.cpp:1.243  Sat May  7 20:53:48 2005
+++ wesnoth/src/game.cpp        Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: game.cpp,v 1.243 2005/05/07 20:53:48 silene Exp $ */
+/* $Id: game.cpp,v 1.244 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -874,17 +874,20 @@
                        return;
                }
 
-               std::vector<std::string> campaigns, options;
-               std::string sep(1, COLUMN_SEPARATOR);
-               options.push_back(sep + _("Name") +
-                                 sep + _("Version") +
-                                 sep + _("Author") +
-                                 sep + _("Downloads") +
-                                 sep + _("Size"));
+               std::vector<std::string> campaigns, options;
+
+               std::string sep(1, COLUMN_SEPARATOR);
+
+               std::stringstream heading;
+               heading << HEADING_PREFIX << sep << _("Name") << sep << 
_("Version") << sep
+                               << _("Author") << sep << _("Downloads") << sep 
<< _("Size");
+
                const config::child_list& cmps = 
campaigns_cfg->get_children("campaign");
                const std::vector<std::string>& publish_options = 
available_campaigns();
 
-               std::vector<std::string> delete_options;
+               std::vector<std::string> delete_options;
+
+               std::vector<int> sizes;
 
                for(config::child_list::const_iterator i = cmps.begin(); i != 
cmps.end(); ++i) {
                        const std::string& name = (**i)["name"];
@@ -913,7 +916,10 @@
 
                        if(author.size() > 16) {
                                author.resize(16);
-                       }
+                       }
+
+                       //add negative sizes to reverse the sort order
+                       sizes.push_back(-atoi((**i)["size"].c_str()));
                        
                        options.push_back(IMAGE_PREFIX + (**i)["icon"].str() + 
COLUMN_SEPARATOR +
                                          title + COLUMN_SEPARATOR +
@@ -922,6 +928,8 @@
                                          (**i)["downloads"].str() + 
COLUMN_SEPARATOR +
                                          format_file_size((**i)["size"]));
                }
+               
+               options.push_back(heading.str());
 
                for(std::vector<std::string>::const_iterator j = 
publish_options.begin(); j != publish_options.end(); ++j) {
                        options.push_back(sep + _("Publish campaign: ") + *j);
@@ -934,9 +942,13 @@
                if(campaigns.empty() && publish_options.empty()) {
                        gui::show_error_message(disp(), _("There are no 
campaigns available for download from this server."));
                        return;
-               }
+               }
+
+               gui::menu::basic_sorter sorter;
+               
sorter.set_alpha_sort(1).set_alpha_sort(2).set_alpha_sort(3).set_numeric_sort(4).set_position_sort(5,sizes);
 
-               const int index = gui::show_dialog(disp(),NULL,_("Get 
Campaign"),_("Choose the campaign to download."),gui::OK_CANCEL,&options) - 1;
+               const int index = gui::show_dialog(disp(),NULL,_("Get 
Campaign"),_("Choose the campaign to download."),gui::OK_CANCEL,&options,
+                                                      
NULL,"",NULL,0,NULL,NULL,-1,-1,NULL,NULL,"",&sorter) - 1;
                if(index < 0) {
                        return;
                }
Index: wesnoth/src/game_config.cpp
diff -u wesnoth/src/game_config.cpp:1.95 wesnoth/src/game_config.cpp:1.96
--- wesnoth/src/game_config.cpp:1.95    Fri May  6 01:07:59 2005
+++ wesnoth/src/game_config.cpp Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: game_config.cpp,v 1.95 2005/05/06 01:07:59 Sirp Exp $ */
+/* $Id: game_config.cpp,v 1.96 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -32,7 +32,7 @@
        int recall_cost = 20;
        int kill_experience = 8;
        int leadership_bonus = 25;
-       const std::string version = VERSION;
+       const std::string version = "0.9.1"; //VERSION;
        bool debug = false, editor = false, ignore_replay_errors = false;
 
        std::string game_icon = "wesnoth-icon.png", game_title, game_logo, 
title_music;
Index: wesnoth/src/intro.cpp
diff -u wesnoth/src/intro.cpp:1.76 wesnoth/src/intro.cpp:1.77
--- wesnoth/src/intro.cpp:1.76  Mon Mar 28 09:44:05 2005
+++ wesnoth/src/intro.cpp       Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: intro.cpp,v 1.76 2005/03/28 09:44:05 silene Exp $ */
+/* $Id: intro.cpp,v 1.77 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -234,7 +234,13 @@
                                //to find out if the next word will fit, or if 
it has to be wrapped
                                utils::utf8_iterator start_word = itor;
                                ++start_word;
-                               utils::utf8_iterator end_word = 
std::find(start_word, utils::utf8_iterator::end(story), ' ');
+                               utils::utf8_iterator end_word = start_word;
+                               const utils::utf8_iterator end_story = 
utils::utf8_iterator::end(story);
+                               for(; end_word != end_story; ++end_word) {
+                                       if(*end_word == ' ') {
+                                               break;
+                                       }
+                               }
 
                                std::string word;
                                for(; start_word != end_word; ++start_word) {
Index: wesnoth/src/multiplayer_lobby.cpp
diff -u wesnoth/src/multiplayer_lobby.cpp:1.71 
wesnoth/src/multiplayer_lobby.cpp:1.72
--- wesnoth/src/multiplayer_lobby.cpp:1.71      Sun May  8 00:45:26 2005
+++ wesnoth/src/multiplayer_lobby.cpp   Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: multiplayer_lobby.cpp,v 1.71 2005/05/08 00:45:26 Sirp Exp $ */
+/* $Id: multiplayer_lobby.cpp,v 1.72 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 
    Part of the Battle for Wesnoth Project http://www.wesnoth.org
@@ -19,8 +19,86 @@
 #include "wml_separators.hpp"
 #include "game_config.hpp"
 #include "gettext.hpp"
+
+namespace {
+
+std::string games_menu_heading()
+{
+       std::ostringstream str;
+       str << HEADING_PREFIX << _("Map") << COLUMN_SEPARATOR << _("Name")
+               << COLUMN_SEPARATOR << _("Status");
+       return str.str();
+}
+
+}
 
 namespace mp {
+
+lobby::lobby_sorter::lobby_sorter(const config& cfg) : cfg_(cfg)
+{
+       set_alpha_sort(1);
+}
+
+bool lobby::lobby_sorter::column_sortable(int column) const
+{
+       switch(column)
+       {
+       case MAP_COLUMN:
+       case STATUS_COLUMN:
+               return true;
+       default:
+               return basic_sorter::column_sortable(column);
+       }
+}
+
+bool lobby::lobby_sorter::less(int column, const gui::menu::item& row1, const 
gui::menu::item& row2) const
+{
+       const config* const list = cfg_.child("gamelist");
+       if(list == NULL) {
+               return false;
+       }
+
+       const config::child_list& games = list->get_children("game");
+       if(row1.id >= games.size() || row2.id >= games.size()) {
+               return false;
+       }
+
+       const config& game1 = *games[row1.id];
+       const config& game2 = *games[row2.id];
+
+       if(column == MAP_COLUMN) {
+               size_t mapsize1 = game1["map_data"].size();
+               if(mapsize1 == 0) {
+                       mapsize1 = game1["map"].size();
+               }
+
+               size_t mapsize2 = game2["map_data"].size();
+               if(mapsize2 == 0) {
+                       mapsize2 = game2["map"].size();
+               }
+
+               return mapsize1 < mapsize2;
+               
+       } else if(column == STATUS_COLUMN) {
+               const int nslots1 = atoi(game1["slots"].c_str());
+               const int nslots2 = atoi(game2["slots"].c_str());
+
+               const int turn1 = atoi(game1["turn"].c_str());
+               const int turn2 = atoi(game2["turn"].c_str());
+
+               if(nslots1 > nslots2) {
+                       return true;
+               } else if(nslots1 < nslots2) {
+                       return false;
+               } else {
+                       return turn1 < turn2;
+               }
+       } else {
+               return basic_sorter::less(column,row1,row2);
+       }
+
+       return false;
+}
 
 lobby::lobby(display& disp, const config& cfg, chat& c, config& gamelist) :
        mp::ui(disp, cfg, c, gamelist),
@@ -28,8 +106,9 @@
        observe_game_(disp.video(), _("Observe Game")),
        join_game_(disp.video(), _("Join Game")),
        create_game_(disp.video(), _("Create Game")),
-       quit_game_(disp.video(), _("Quit")),
-       games_menu_(disp.video(), std::vector<std::string>()),
+       quit_game_(disp.video(), _("Quit")),
+       sorter_(gamelist),
+       games_menu_(disp.video(), 
std::vector<std::string>(1,games_menu_heading()),false,-1,-1,&sorter_),
        current_game_(0)
 {
        game_config::debug = false;
Index: wesnoth/src/multiplayer_lobby.hpp
diff -u wesnoth/src/multiplayer_lobby.hpp:1.10 
wesnoth/src/multiplayer_lobby.hpp:1.11
--- wesnoth/src/multiplayer_lobby.hpp:1.10      Sat Mar 19 16:21:02 2005
+++ wesnoth/src/multiplayer_lobby.hpp   Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: multiplayer_lobby.hpp,v 1.10 2005/03/19 16:21:02 gruikya Exp $ */
+/* $Id: multiplayer_lobby.hpp,v 1.11 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 
    Part of the Battle for Wesnoth Project http://www.wesnoth.org
@@ -38,6 +38,18 @@
 
        virtual void gamelist_updated(bool silent=true);
 private:
+
+       class lobby_sorter : public gui::menu::basic_sorter
+       {
+               const config& cfg_;
+
+               bool column_sortable(int column) const;
+               bool less(int column, const gui::menu::item& row1, const 
gui::menu::item& row2) const;
+
+               enum { MAP_COLUMN = 0, STATUS_COLUMN = 2};
+       public:
+               lobby_sorter(const config& cfg);
+       };
 
        std::vector<bool> game_vacant_slots_;
        std::vector<bool> game_observers_;
@@ -46,7 +58,8 @@
        gui::button join_game_;
        gui::button create_game_;
        gui::button quit_game_;
-
+
+       lobby_sorter sorter_;
        gui::menu games_menu_;
        int current_game_;
 };
Index: wesnoth/src/playcampaign.cpp
diff -u wesnoth/src/playcampaign.cpp:1.1 wesnoth/src/playcampaign.cpp:1.2
--- wesnoth/src/playcampaign.cpp:1.1    Wed Apr 27 21:11:44 2005
+++ wesnoth/src/playcampaign.cpp        Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: playcampaign.cpp,v 1.1 2005/04/27 21:11:44 gruikya Exp $ */
+/* $Id: playcampaign.cpp,v 1.2 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003-2005 by David White <address@hidden>
    Copyright (C) 2005 by Philippe Plantier <address@hidden>
@@ -10,7 +10,9 @@
    but WITHOUT ANY WARRANTY.
 
    See the COPYING file for more details.
-*/
+*/
+
+#include "global.hpp"
 
 #include <map>
 
Index: wesnoth/src/playturn.cpp
diff -u wesnoth/src/playturn.cpp:1.367 wesnoth/src/playturn.cpp:1.368
--- wesnoth/src/playturn.cpp:1.367      Wed May  4 03:16:39 2005
+++ wesnoth/src/playturn.cpp    Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: playturn.cpp,v 1.367 2005/05/04 03:16:39 Sirp Exp $ */
+/* $Id: playturn.cpp,v 1.368 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -1700,12 +1700,16 @@
 {
        std::vector<std::string> items;
        std::stringstream heading;
-       heading << _("Leader") << COLUMN_SEPARATOR << ' ' << COLUMN_SEPARATOR
+       heading << HEADING_PREFIX << _("Leader") << COLUMN_SEPARATOR << ' ' << 
COLUMN_SEPARATOR
                << _("Gold") << COLUMN_SEPARATOR
                << _("Villages") << COLUMN_SEPARATOR
                << _("Units") << COLUMN_SEPARATOR
                << _("Upkeep") << COLUMN_SEPARATOR
-               << _("Income");
+               << _("Income");
+
+       gui::menu::basic_sorter sorter;
+       
sorter.set_redirect_sort(0,1).set_alpha_sort(1).set_numeric_sort(2).set_numeric_sort(3)
+             
.set_numeric_sort(4).set_numeric_sort(5).set_numeric_sort(6).set_numeric_sort(7);
 
        if(game_config::debug)
                heading << COLUMN_SEPARATOR << _("Gold");
@@ -1763,7 +1767,8 @@
                items.push_back(IMAGE_PREFIX + std::string("random-enemy.png") 
+ COLUMN_SEPARATOR +
                                IMAGE_PREFIX + "random-enemy.png");
 
-       gui::show_dialog(gui_,NULL,"","",gui::CLOSE_ONLY,&items);
+       gui::show_dialog(gui_,NULL,"","",gui::CLOSE_ONLY,&items,
+                        NULL,"",NULL,0,NULL,NULL,-1,-1,NULL,NULL,"",&sorter);
 }
 
 void turn_info::recruit()
@@ -1968,15 +1973,27 @@
                msg << vgettext("You must have at least $cost gold pieces to 
recall a unit", i18n_symbols);
                gui::show_dialog(gui_,NULL,"",msg.str());
        } else {
-               std::vector<std::string> options;
+               std::vector<std::string> options;
+
+               std::ostringstream heading;
+               heading << HEADING_PREFIX << COLUMN_SEPARATOR << _("Type")
+                           << COLUMN_SEPARATOR << _("Name")
+                               << COLUMN_SEPARATOR << _("Level")
+                               << COLUMN_SEPARATOR << _("XP");
+
+               gui::menu::basic_sorter sorter;
+               
sorter.set_alpha_sort(1).set_alpha_sort(2).set_id_sort(3).set_numeric_sort(4);
+
+               options.push_back(heading.str());
+
                for(std::vector<unit>::const_iterator u = recall_list.begin(); 
u != recall_list.end(); ++u) {
                        std::stringstream option;
                        const std::string& description = 
u->description().empty() ? "-" : u->description();
                        option << IMAGE_PREFIX << u->type().image() << 
COLUMN_SEPARATOR
                               << u->type().language_name() << COLUMN_SEPARATOR
                               << description << COLUMN_SEPARATOR
-                              << _("level: ") << u->type().level() << 
COLUMN_SEPARATOR
-                              << _("XP: ") << u->experience() << "/";
+                              << u->type().level() << COLUMN_SEPARATOR
+                              << u->experience() << "/";
 
                        if(u->can_advance() == false) {
                                option << "-";
@@ -2004,7 +2021,7 @@
                                        _("Select unit:") + std::string("\n"),
                                        gui::OK_CANCEL,&options,
                                        &preview_panes,"",NULL,-1,
-                                       NULL,NULL,-1,-1,NULL,&buttons);
+                                       
NULL,NULL,-1,-1,NULL,&buttons,"",&sorter);
                }
 
                if(res >= 0) {
@@ -2135,13 +2152,18 @@
 
 void turn_info::unit_list()
 {
-       const std::string heading = _("Type") + std::string(1, 
COLUMN_SEPARATOR) +
+       const std::string heading = std::string(1,HEADING_PREFIX) +
+                                   _("Type") + std::string(1, 
COLUMN_SEPARATOR) +
                                    _("Name") + COLUMN_SEPARATOR +
                                    _("HP") + COLUMN_SEPARATOR +
                                    _("XP") + COLUMN_SEPARATOR +
                                    _("Traits") + COLUMN_SEPARATOR +
                                    _("Moves") + COLUMN_SEPARATOR +
-                                   _("Location");
+                                   _("Location");
+
+       gui::menu::basic_sorter sorter;
+       
sorter.set_alpha_sort(0).set_alpha_sort(1).set_numeric_sort(2).set_numeric_sort(3)
+                 .set_alpha_sort(4).set_numeric_sort(5).set_numeric_sort(6);
 
        std::vector<std::string> items;
        items.push_back(heading);
@@ -2190,7 +2212,8 @@
                preview_panes.push_back(&unit_preview);
 
                selected = gui::show_dialog(gui_,NULL,_("Unit List"),"",
-                                           gui::OK_ONLY,&items,&preview_panes);
+                                           gui::OK_ONLY,&items,&preview_panes,
+                                                                       
"",NULL,0,NULL,NULL,-1,-1,NULL,NULL,"",&sorter);
        }
 
        if(selected > 0 && selected < int(locations_list.size())) {
Index: wesnoth/src/preferences.cpp
diff -u wesnoth/src/preferences.cpp:1.153 wesnoth/src/preferences.cpp:1.154
--- wesnoth/src/preferences.cpp:1.153   Wed May  4 03:16:39 2005
+++ wesnoth/src/preferences.cpp Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: preferences.cpp,v 1.153 2005/05/04 03:16:39 Sirp Exp $ */
+/* $Id: preferences.cpp,v 1.154 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -1277,12 +1277,21 @@
                std::stringstream str,name;
                name << i->get_description();
                str << name.str();
-               str << COLUMN_SEPARATOR << "  :  " << COLUMN_SEPARATOR;
+               str << COLUMN_SEPARATOR;
                str << i->get_name();
-               menu_items.push_back (str.str ());
+               menu_items.push_back(str.str());
        }
+
+       std::ostringstream heading;
+       heading << HEADING_PREFIX << _("Action") << COLUMN_SEPARATOR << 
_("Binding");
+       menu_items.push_back(heading.str());
+
+       gui::menu::basic_sorter sorter;
+       sorter.set_alpha_sort(0).set_alpha_sort(1);
 
-       gui::menu menu_(disp.video(), menu_items, false, height);
+       gui::menu menu_(disp.video(), menu_items, false, height, -1, &sorter);
+       menu_.sort_by(0);
+       menu_.reset_selection();
        menu_.set_width(font::relative_size(400));      
        menu_.set_location(xpos + font::relative_size(20), ypos);
        
@@ -1340,7 +1349,7 @@
                                newhk.set_key(key, (mod & KMOD_SHIFT) != 0, 
                                                (mod & KMOD_CTRL) != 0, (mod & 
KMOD_ALT) != 0, (mod & KMOD_LMETA) != 0);
 
-                               menu_.change_item(menu_.selection(), 2, 
newhk.get_name());
+                               menu_.change_item(menu_.selection(), 1, 
newhk.get_name());
                        };
                }
                if (save_button.pressed()) {
Index: wesnoth/src/random.cpp
diff -u wesnoth/src/random.cpp:1.4 wesnoth/src/random.cpp:1.5
--- wesnoth/src/random.cpp:1.4  Sat Apr 30 12:31:20 2005
+++ wesnoth/src/random.cpp      Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: random.cpp,v 1.4 2005/04/30 12:31:20 silene Exp $ */
+/* $Id: random.cpp,v 1.5 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Copyright (C) 2005 by Yann Dirson <address@hidden>
@@ -10,7 +10,12 @@
    but WITHOUT ANY WARRANTY.
 
    See the COPYING file for more details.
-*/
+*/
+
+#include "global.hpp"
+
+#include <cstdio>
+
 #include "config.hpp"
 #include "random.hpp"
 #include "wassert.hpp"
Index: wesnoth/src/serialization/binary_or_text.cpp
diff -u wesnoth/src/serialization/binary_or_text.cpp:1.11 
wesnoth/src/serialization/binary_or_text.cpp:1.12
--- wesnoth/src/serialization/binary_or_text.cpp:1.11   Wed Apr 27 22:17:37 2005
+++ wesnoth/src/serialization/binary_or_text.cpp        Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: binary_or_text.cpp,v 1.11 2005/04/27 22:17:37 silene Exp $ */
+/* $Id: binary_or_text.cpp,v 1.12 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Copyright (C) 2005 by Guillaume Melquiond <address@hidden>
@@ -11,6 +11,8 @@
 
    See the COPYING file for more details.
 */
+
+#include "global.hpp"
 
 #include "config.hpp"
 #include "filesystem.hpp"
Index: wesnoth/src/serialization/preprocessor.cpp
diff -u wesnoth/src/serialization/preprocessor.cpp:1.13 
wesnoth/src/serialization/preprocessor.cpp:1.14
--- wesnoth/src/serialization/preprocessor.cpp:1.13     Sat May  7 19:01:16 2005
+++ wesnoth/src/serialization/preprocessor.cpp  Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: preprocessor.cpp,v 1.13 2005/05/07 19:01:16 silene Exp $ */
+/* $Id: preprocessor.cpp,v 1.14 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Copyright (C) 2005 by Guillaume Melquiond <address@hidden>
@@ -89,7 +89,7 @@
 }
 
 preprocessor_streambuf::preprocessor_streambuf(preprocessor_streambuf const &t)
-       : std::streambuf(), current_(NULL), defines_(t.defines_),
+       : current_(NULL), defines_(t.defines_),
          textdomain_(PACKAGE), depth_(t.depth_), quoted_(t.quoted_)
 {
 }
@@ -676,10 +676,10 @@
        return true;
 }
 
-struct preprocessor_deleter: std::istream
+struct preprocessor_deleter: std::basic_istream<char>
 {
        preprocessor_streambuf *buf_;
-       preprocessor_deleter(preprocessor_streambuf *buf): std::istream(buf), 
buf_(buf) {}
+       preprocessor_deleter(preprocessor_streambuf *buf) : 
std::basic_istream<char>(buf), buf_(buf) {}
        ~preprocessor_deleter() { rdbuf(NULL); delete buf_->defines_; delete 
buf_; }
 };
 
Index: wesnoth/src/server/metrics.cpp
diff -u wesnoth/src/server/metrics.cpp:1.4 wesnoth/src/server/metrics.cpp:1.5
--- wesnoth/src/server/metrics.cpp:1.4  Thu Dec  2 01:59:05 2004
+++ wesnoth/src/server/metrics.cpp      Tue May 10 22:15:57 2005
@@ -39,7 +39,7 @@
        const int seconds = time_up%60;
        const int minutes = (time_up/60)%60;
        const int hours = (time_up/(60*60))%24;
-       const int days = time_up/(60*60*14);
+       const int days = time_up/(60*60*24);
        const int requests_immediate = met.nrequests_ - met.nrequests_waited_;
        const int percent_immediate = (requests_immediate*100)/(met.nrequests_ 
> 0 ? met.nrequests_ : 1);
        out << "METRICS\n----\nUp " << days << " days, " << hours << " hours, "
Index: wesnoth/src/show_dialog.cpp
diff -u wesnoth/src/show_dialog.cpp:1.126 wesnoth/src/show_dialog.cpp:1.127
--- wesnoth/src/show_dialog.cpp:1.126   Sun Apr 17 20:42:10 2005
+++ wesnoth/src/show_dialog.cpp Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: show_dialog.cpp,v 1.126 2005/04/17 20:42:10 gruikya Exp $ */
+/* $Id: show_dialog.cpp,v 1.127 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -322,7 +322,7 @@
                                int text_widget_max_chars,
                                dialog_action* action, std::vector<check_item>* 
options, int xloc, int yloc,
                                const std::string* dialog_style, 
std::vector<dialog_button>* action_buttons,
-                               const std::string& help_topic)
+                               const std::string& help_topic, const 
menu::sorter* sorter)
 {
        if(disp.update_locked())
                return -1;
@@ -372,7 +372,7 @@
                text_widget_height = text_widget.location().h + 
message_font_size;
        }
 
-       menu menu_(screen,menu_items,type == MESSAGE);
+       menu menu_(screen,menu_items,type == MESSAGE,-1,-1,sorter);
 
        menu_.set_numeric_keypress_selection(use_textbox == false);
 
Index: wesnoth/src/show_dialog.hpp
diff -u wesnoth/src/show_dialog.hpp:1.47 wesnoth/src/show_dialog.hpp:1.48
--- wesnoth/src/show_dialog.hpp:1.47    Wed Mar 23 21:30:46 2005
+++ wesnoth/src/show_dialog.hpp Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: show_dialog.hpp,v 1.47 2005/03/23 21:30:46 ydirson Exp $ */
+/* $Id: show_dialog.hpp,v 1.48 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -23,7 +23,8 @@
 #include "network.hpp"
 #include "tooltips.hpp"
 
-#include "widgets/button.hpp"
+#include "widgets/button.hpp"
+#include "widgets/menu.hpp"
 
 #include "SDL.h"
 
@@ -133,7 +134,8 @@
                                std::vector<check_item>* options=NULL, int 
xloc=-1, int yloc=-1,
                                const std::string* dialog_style=NULL,
                                std::vector<dialog_button>* buttons=NULL,
-                               const std::string& help_topic=""
+                               const std::string& help_topic="",
+                               const menu::sorter* sorter=NULL
                         );
 
 void show_error_message(display &disp, std::string const &message);
Index: wesnoth/src/tstring.cpp
diff -u wesnoth/src/tstring.cpp:1.8 wesnoth/src/tstring.cpp:1.9
--- wesnoth/src/tstring.cpp:1.8 Sat Apr 23 21:06:47 2005
+++ wesnoth/src/tstring.cpp     Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: tstring.cpp,v 1.8 2005/04/23 21:06:47 silene Exp $ */
+/* $Id: tstring.cpp,v 1.9 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2004 by Philippe Plantier <address@hidden>
    Part of the Battle for Wesnoth Project http://www.wesnoth.org
@@ -10,7 +10,10 @@
 
    See the COPYING file for more details.
 */
-
+
+#include "global.hpp"
+
+#include <sstream>
 #include <vector>
 #include <map>
 
Index: wesnoth/src/tstring.hpp
diff -u wesnoth/src/tstring.hpp:1.6 wesnoth/src/tstring.hpp:1.7
--- wesnoth/src/tstring.hpp:1.6 Mon Apr 18 19:25:04 2005
+++ wesnoth/src/tstring.hpp     Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: tstring.hpp,v 1.6 2005/04/18 19:25:04 gruikya Exp $ */
+/* $Id: tstring.hpp,v 1.7 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2004 by Philippe Plantier <address@hidden>
    Part of the Battle for Wesnoth Project http://www.wesnoth.org
@@ -40,7 +40,9 @@
                std::string::size_type end_;
                std::string textdomain_;
                bool translatable_;
-       };
+       };
+
+       friend class walker;
 
        t_string();
        t_string(const t_string&);
Index: wesnoth/src/unit.cpp
diff -u wesnoth/src/unit.cpp:1.150 wesnoth/src/unit.cpp:1.151
--- wesnoth/src/unit.cpp:1.150  Sat Apr 30 13:47:22 2005
+++ wesnoth/src/unit.cpp        Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: unit.cpp,v 1.150 2005/04/30 13:47:22 ott Exp $ */
+/* $Id: unit.cpp,v 1.151 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -163,8 +163,6 @@
                traits.push_back(candidate_traits[num]);
                candidate_traits.erase(candidate_traits.begin()+num);
        }
-
-       std::vector<std::string> description;
        
        for(std::vector<config*>::const_iterator j = traits.begin(); j != 
traits.end(); ++j) {
                modifications_.add_child("trait",**j);
Index: wesnoth/src/util.hpp
diff -u wesnoth/src/util.hpp:1.22 wesnoth/src/util.hpp:1.23
--- wesnoth/src/util.hpp:1.22   Sat Apr 23 20:22:59 2005
+++ wesnoth/src/util.hpp        Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: util.hpp,v 1.22 2005/04/23 20:22:59 silene Exp $ */
+/* $Id: util.hpp,v 1.23 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -79,7 +79,8 @@
        return lexical_cast<std::string,From>(a);
 }
 
-inline bool chars_equal_insensitive(char a, char b) { return tolower(a) == 
tolower(b); }
+inline bool chars_equal_insensitive(char a, char b) { return tolower(a) == 
tolower(b); }
+inline bool chars_less_insensitive(char a, char b) { return tolower(a) < 
tolower(b); }
 
 //a definition of 'push_back' for strings, since some implementations
 //don't support string::push_back
Index: wesnoth/src/variable.cpp
diff -u wesnoth/src/variable.cpp:1.1 wesnoth/src/variable.cpp:1.2
--- wesnoth/src/variable.cpp:1.1        Sun Mar 27 23:06:17 2005
+++ wesnoth/src/variable.cpp    Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: variable.cpp,v 1.1 2005/03/27 23:06:17 gruikya Exp $ */
+/* $Id: variable.cpp,v 1.2 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Copyright (C) 2005 by Philippe Plantier <address@hidden>
@@ -11,7 +11,9 @@
    but WITHOUT ANY WARRANTY.
 
    See the COPYING file for more details.
-*/
+*/
+
+#include "global.hpp"
 
 #include "variable.hpp"
 #include "gamestatus.hpp"
@@ -78,7 +80,8 @@
 vconfig::child_list vconfig::get_children(const std::string& key) const
 {
        const config::child_list& list = cfg_->get_children(key);
-       vconfig::child_list res(list.begin(), list.end());
+       vconfig::child_list res(list.size());
+       std::copy(list.begin(), list.end(),res.begin());
        return res;
 }
 
Index: wesnoth/src/variable.hpp
diff -u wesnoth/src/variable.hpp:1.4 wesnoth/src/variable.hpp:1.5
--- wesnoth/src/variable.hpp:1.4        Sun Mar 27 23:06:17 2005
+++ wesnoth/src/variable.hpp    Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: variable.hpp,v 1.4 2005/03/27 23:06:17 gruikya Exp $ */
+/* $Id: variable.hpp,v 1.5 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Copyright (C) 2005 by Philippe Plantier <address@hidden>
@@ -20,7 +20,7 @@
 
 class config;
 class t_string;
-class game_state;
+struct game_state;
 
 /**
  * A variable-expanding proxy for the config class. This class roughly behaves
Index: wesnoth/src/widgets/menu.cpp
diff -u wesnoth/src/widgets/menu.cpp:1.88 wesnoth/src/widgets/menu.cpp:1.89
--- wesnoth/src/widgets/menu.cpp:1.88   Wed May  4 03:16:39 2005
+++ wesnoth/src/widgets/menu.cpp        Tue May 10 22:15:57 2005
@@ -9,7 +9,9 @@
 #include "../video.hpp"
 #include "../wml_separators.hpp"
 #include "serialization/string_utils.hpp"
-
+
+#include <algorithm>
+#include <cassert>
 #include <numeric>
 
 namespace {
@@ -18,60 +20,241 @@
 }
 
 namespace gui {
+
+menu::basic_sorter& menu::basic_sorter::set_alpha_sort(int column)
+{
+       alpha_sort_.insert(column);
+       return *this;
+}
+
+menu::basic_sorter& menu::basic_sorter::set_numeric_sort(int column)
+{
+       numeric_sort_.insert(column);
+       return *this;
+}
+
+menu::basic_sorter& menu::basic_sorter::set_id_sort(int column)
+{
+       id_sort_.insert(column);
+       return *this;
+}
+
+menu::basic_sorter& menu::basic_sorter::set_redirect_sort(int column, int to)
+{
+       if(column != to) {
+               redirect_sort_.insert(std::pair<int,int>(column,to));
+       }
+
+       return *this;
+}
+
+menu::basic_sorter& menu::basic_sorter::set_position_sort(int column, const 
std::vector<int>& pos)
+{
+       pos_sort_[column] = pos;
+       return *this;
+}
+
+bool menu::basic_sorter::column_sortable(int column) const
+{
+       const std::map<int,int>::const_iterator redirect = 
redirect_sort_.find(column);
+       if(redirect != redirect_sort_.end()) {
+               return column_sortable(redirect->second);
+       }
+
+       return alpha_sort_.count(column) == 1 || numeric_sort_.count(column) == 
1 ||
+                  pos_sort_.count(column) == 1 || id_sort_.count(column) == 1;
+}
+
+bool menu::basic_sorter::less(int column, const item& row1, const item& row2) 
const
+{
+       const std::map<int,int>::const_iterator redirect = 
redirect_sort_.find(column);
+       if(redirect != redirect_sort_.end()) {
+               return less(redirect->second,row1,row2);
+       }
+
+       if(column < 0 || column >= int(row2.fields.size())) {
+               return false;
+       }
+
+       if(column >= int(row1.fields.size())) {
+               return true;
+       }
+
+       const std::string& item1 = row1.fields[column];
+       const std::string& item2 = row2.fields[column];
+       if(alpha_sort_.count(column) == 1) {
+               std::string::const_iterator begin1 = item1.begin(), end1 = 
item1.end(),
+                                           begin2 = item2.begin(), end2 = 
item2.end();
+               while(begin1 != end1 && (font::is_format_char(*begin1) || 
is_wml_separator(*begin1))) {
+                       ++begin1;
+               }
+
+               while(begin2 != end2 && (font::is_format_char(*begin2) || 
is_wml_separator(*begin2))) {
+                       ++begin2;
+               }
+
+               return 
std::lexicographical_compare(begin1,end1,begin2,end2,chars_less_insensitive);
+       } else if(numeric_sort_.count(column) == 1) {
+               const char* a = item1.c_str();
+               const char* b = item2.c_str();
+
+               while(*a != 0 && !isdigit(*a)) {
+                       ++a;
+               }
+
+               while(*b != 0 && !isdigit(*b)) {
+                       ++b;
+               }
+
+               return atoi(a) > atoi(b);
+       } else if(id_sort_.count(column) == 1) {
+               return row1.id < row2.id;
+       }
+
+       const std::map<int,std::vector<int> >::const_iterator itor = 
pos_sort_.find(column);
+       if(itor != pos_sort_.end()) {
+               const std::vector<int>& pos = itor->second;
+               if(row1.id >= pos.size()) {
+                       return false;
+               }
+
+               if(row2.id >= pos.size()) {
+                       return true;
+               }
+
+               return pos[row1.id] < pos[row2.id];
+       }
+
+       return false;
+}
 
 menu::menu(CVideo& video, const std::vector<std::string>& items,
-           bool click_selects, int max_height, int max_width)
+           bool click_selects, int max_height, int max_width,
+                  const sorter* sorter_obj)
         : scrollarea(video),
-          max_height_(max_height), max_width_(max_width), max_items_(-1), 
item_height_(-1),
+          max_height_(max_height), max_width_(max_width), max_items_(-1), 
item_height_(-1),
+                 heading_height_(-1),
          cur_help_(-1,-1), help_string_(-1),
          selected_(0), click_selects_(click_selects),
          previous_button_(true), show_result_(false),
          double_clicked_(false),
          num_selects_(true),
          ignore_next_doubleclick_(false),
-         last_was_doubleclick_(false)
+         last_was_doubleclick_(false),
+         sorter_(sorter_obj), sortby_(-1), highlight_heading_(-1)
 {
        fill_items(items, true);
 }
 
 void menu::fill_items(const std::vector<std::string>& items, bool strip_spaces)
 {
-       for(std::vector<std::string>::const_iterator item = items.begin();
-           item != items.end(); ++item) {
-               items_.push_back(utils::quoted_split(*item, COLUMN_SEPARATOR, 
!strip_spaces));
+       for(std::vector<std::string>::const_iterator itor = items.begin();
+           itor != items.end(); ++itor) {
+
+               if(itor->empty() == false && (*itor)[0] == HEADING_PREFIX) {
+                       heading_ = 
utils::quoted_split(itor->substr(1),COLUMN_SEPARATOR, !strip_spaces);
+                       continue;
+               }
+
+               const size_t id = items_.size();
+               item_pos_.push_back(id);
+               const item new_item(utils::quoted_split(*itor, 
COLUMN_SEPARATOR, !strip_spaces),id);
+               items_.push_back(new_item);
 
                //make sure there is always at least one item
-               if(items_.back().empty())
-                       items_.back().push_back(" ");
+               if(items_.back().fields.empty()) {
+                       items_.back().fields.push_back(" ");
+               }
 
                //if the first character in an item is an asterisk,
                //it means this item should be selected by default
-               std::string& first_item = items_.back().front();
+               std::string& first_item = items_.back().fields.front();
                if(first_item.empty() == false && first_item[0] == 
DEFAULT_ITEM) {
-                       selected_ = items_.size()-1;
+                       selected_ = id;
                        first_item.erase(first_item.begin());
                }
        }
 
-       create_help_strings();
+       create_help_strings();
+       do_sort();
        update_size();
+}
+
+namespace {
+
+class sort_func
+{
+public:
+       sort_func(const menu::sorter& pred, int column) : pred_(&pred), 
column_(column)
+       {}
+
+       bool operator()(const menu::item& a, const menu::item& b) const
+       {
+               return pred_->less(column_,a,b);
+       }
+
+private:
+       const menu::sorter* pred_;
+       int column_;
+};
+
+}
+
+void menu::do_sort(SORT_TYPE type)
+{
+       if(sortby_ < 0 || sorter_ == NULL || sorter_->column_sortable(sortby_) 
== false) {
+               return;
+       }
+
+       const int selectid = selection();
+
+       if(type == NORMAL_SORT) {
+               
std::stable_sort(items_.begin(),items_.end(),sort_func(*sorter_,sortby_));
+       } else if(type == INVERT_SORT) {
+               std::reverse(items_.begin(),items_.end());
+       }
+
+       recalculate_pos();
+
+       if(selectid >= 0 && selectid < int(item_pos_.size())) {
+               move_selection(selectid,NO_MOVE_VIEWPORT);
+       }
+
+       set_dirty();
+}
+
+void menu::recalculate_pos()
+{
+       item_pos_.resize(items_.size());
+       for(std::vector<item>::const_iterator i = items_.begin(); i != 
items_.end(); ++i) {
+               item_pos_[i->id] = i - items_.begin();
+       }
+
+       assert_pos();
+}
+
+void menu::assert_pos()
+{
+       assert(item_pos_.size() == items_.size());
+       for(size_t n = 0; n != item_pos_.size(); ++n) {
+               assert(n == items_[item_pos_[n]].id);
+       }
 }
 
 void menu::create_help_strings()
 {
-       help_.clear();
-       for(std::vector<std::vector<std::string> >::iterator i = 
items_.begin(); i != items_.end(); ++i) {
-               help_.resize(help_.size()+1);
-               for(std::vector<std::string>::iterator j = i->begin(); j != 
i->end(); ++j) {
+       for(std::vector<item>::iterator i = items_.begin(); i != items_.end(); 
++i) {
+               i->help.clear();
+               for(std::vector<std::string>::iterator j = i->fields.begin(); j 
!= i->fields.end(); ++j) {
                        
if(std::find(j->begin(),j->end(),static_cast<char>(HELP_STRING_SEPARATOR)) == 
j->end()) {
-                               help_.back().push_back("");
+                               i->help.push_back("");
                        } else {
                                const std::vector<std::string>& items = 
utils::split(*j, HELP_STRING_SEPARATOR, 0);
                                if(items.size() >= 2) {
                                        *j = items.front();
-                                       help_.back().push_back(items.back());
+                                       i->help.push_back(items.back());
                                } else {
-                                       help_.back().push_back("");
+                                       i->help.push_back("");
                                }
                        }
                }
@@ -84,8 +267,9 @@
        set_shown_size(max_items_onscreen());
 }
 
-void menu::update_size() {
-       unsigned h = 0;
+void menu::update_size()
+{
+       unsigned int h = heading_height();
        for(size_t i = get_position(),
            i_end = minimum(items_.size(), i + max_items_onscreen());
            i != i_end; ++i)
@@ -106,7 +290,14 @@
        set_measurements(w, h);
 }
 
-int menu::selection() const { return selected_; }
+int menu::selection() const
+{
+       if(selected_ < 0 || selected_ >= int(items_.size())) {
+               return -1;
+       }
+
+       return items_[selected_].id;
+}
 
 void menu::set_inner_location(SDL_Rect const &rect)
 {
@@ -115,10 +306,14 @@
        bg_register(rect);
 }
 
-void menu::change_item(int pos1, int pos2,std::string str)
-{
-       items_[pos1][pos2] = str;
-       //undrawn_items_.insert(pos1);
+void menu::change_item(int pos1, int pos2,const std::string& str)
+{
+       if(pos1 < 0 || pos1 >= int(item_pos_.size()) ||
+               pos2 < 0 || pos2 >= int(items_[item_pos_[pos1]].fields.size())) 
{
+               return;
+       }
+
+       items_[item_pos_[pos1]].fields[pos2] = str;
        set_dirty();
 }
 
@@ -126,10 +321,20 @@
 {
        size_t nb_items = items_.size();
        if (index >= nb_items)
-               return;
+               return;
+
+       clear_item(nb_items - 1);
+
+       const size_t pos = item_pos_[index];
+
+       item_pos_.erase(item_pos_.begin() + index);
+       for(std::vector<size_t>::iterator i = item_pos_.begin(); i != 
item_pos_.end(); ++i) {
+               if(*i > pos) {
+                       *i = *i-1;
+               }
+       }
 
-       clear_item(nb_items - 1);
-       items_.erase(items_.begin() + index);
+       items_.erase(items_.begin() + pos);
        if (selected_ >= nb_items - 1)
                selected_ = nb_items - 2;
 
@@ -137,11 +342,23 @@
        adjust_viewport_to_selection();
        itemRects_.clear();
        set_dirty();
+}
+
+void menu::set_heading(const std::vector<std::string>& heading)
+{
+       itemRects_.clear();
+       column_widths_.clear();
+
+       heading_ = heading;
+       max_items_ = -1;
+
+       set_dirty();
 }
 
 void menu::set_items(const std::vector<std::string>& items, bool strip_spaces, 
bool keep_viewport)
 {
-       items_.clear();
+       items_.clear();
+       item_pos_.clear();
        itemRects_.clear();
        column_widths_.clear();
        //undrawn_items_.clear();
@@ -153,10 +370,15 @@
        }
 
        fill_items(items, strip_spaces);
-       if (!keep_viewport)
-               set_position(0);
-       update_scrollbar_grip_height();
-       adjust_viewport_to_selection();
+       if(!keep_viewport) {
+               set_position(0);
+       }
+
+       update_scrollbar_grip_height();
+
+       if(!keep_viewport) {
+               adjust_viewport_to_selection();
+       }
        set_dirty();
 }
 
@@ -174,7 +396,7 @@
                return size_t(max_items_);
        }
 
-       const size_t max_height = max_height_ == -1 ? (video().gety()*66)/100 : 
max_height_;
+       const size_t max_height = (max_height_ == -1 ? (video().gety()*66)/100 
: max_height_) - heading_height();
        std::vector<int> heights;
        size_t n;
        for(n = 0; n != items_.size(); ++n) {
@@ -191,7 +413,7 @@
                --n;
 
        return max_items_ = n;
-}
+}
 
 void menu::adjust_viewport_to_selection()
 {
@@ -202,25 +424,39 @@
 
 void menu::move_selection_up(size_t dep)
 {
-       move_selection(selected_ > dep ? selected_ - dep : 0);
+       set_selection_pos(selected_ > dep ? selected_ - dep : 0);
+}
+
+void menu::reset_selection()
+{
+       set_selection_pos(0);
 }
 
 void menu::move_selection_down(size_t dep)
 {
        size_t nb_items = items_.size();
-       move_selection(selected_ + dep >= nb_items ? nb_items - 1 : selected_ + 
dep);
+       set_selection_pos(selected_ + dep >= nb_items ? nb_items - 1 : 
selected_ + dep);
 }
 
-void menu::move_selection(size_t new_selected)
+void menu::set_selection_pos(size_t new_selected, SELECTION_MOVE_VIEWPORT 
move_viewport)
 {
        if (new_selected == selected_ || new_selected >= items_.size())
                return;
-
-       //undrawn_items_.insert(selected_);
-       //undrawn_items_.insert(new_selected);
-       set_dirty();
-       selected_ = new_selected;
-       adjust_viewport_to_selection();
+
+       invalidate_row_pos(selected_);
+       invalidate_row_pos(new_selected);
+       selected_ = new_selected;
+
+       if(move_viewport == MOVE_VIEWPORT) {
+               adjust_viewport_to_selection();
+       }
+}
+
+void menu::move_selection(size_t id, SELECTION_MOVE_VIEWPORT move_viewport)
+{
+       if(id < item_pos_.size()) {
+               set_selection_pos(item_pos_[id],move_viewport);
+       }
 }
 
 void menu::key_press(SDLKey key)
@@ -240,10 +476,10 @@
                        move_selection_down(max_items_onscreen());
                        break;
                case SDLK_HOME:
-                       move_selection(0);
+                       set_selection_pos(0);
                        break;
                case SDLK_END:
-                       move_selection(items_.size() - 1);
+                       set_selection_pos(items_.size() - 1);
                        break;
                //case SDLK_RETURN:
                //      double_clicked_ = true;
@@ -254,7 +490,7 @@
        }
 
        if (num_selects_ && key >= SDLK_1 && key <= SDLK_9)
-               move_selection(key - SDLK_1);
+               set_selection_pos(key - SDLK_1);
 }
 
 void menu::handle_event(const SDL_Event& event)
@@ -302,11 +538,27 @@
                                }
                                last_was_doubleclick_ = false;
                        }
+               }
+
+
+               if(sorter_ != NULL) {
+                       const int heading = hit_heading(x,y);
+                       if(heading >= 0 && sorter_->column_sortable(heading)) {
+                               sort_by(heading);
+                       }
+               }
+       } else if(event.type == SDL_MOUSEMOTION) { 
+               if(click_selects_) {
+                       const int item = hit(event.motion.x,event.motion.y);
+                       if (item != -1)
+                               move_selection(item);
+               }
+
+               const int heading_item = 
hit_heading(event.motion.x,event.motion.y);
+               if(heading_item != highlight_heading_) {
+                       highlight_heading_ = heading_item;
+                       invalidate_heading();
                }
-       } else if(event.type == SDL_MOUSEMOTION && click_selects_) { 
-               const int item = hit(event.motion.x,event.motion.y);
-               if (item != -1)
-                       move_selection(item);
        }
 }
 
@@ -326,16 +578,30 @@
        double_clicked_ = false;
        return old;
 }
+
+void menu::set_click_selects(bool value)
+{
+       click_selects_ = value;
+}
 
 void menu::set_numeric_keypress_selection(bool value)
 {
        num_selects_ = value;
-}
+}
 
 void menu::scroll(int)
 {
        itemRects_.clear();
        set_dirty();
+}
+
+void menu::sort_by(int column)
+{
+       const bool already_sorted = (column == sortby_);
+       sortby_ = column;
+       do_sort(already_sorted ? INVERT_SORT : NORMAL_SORT);
+       itemRects_.clear();
+       set_dirty();
 }
 
 namespace {
@@ -367,20 +633,26 @@
                return res;
        }
 }
+
+void menu::column_widths_item(const std::vector<std::string>& row, 
std::vector<int>& widths) const
+{
+       for(size_t col = 0; col != row.size(); ++col) {
+               const SDL_Rect res = item_size(row[col]);
+
+               if(col == widths.size()) {
+                       widths.push_back(res.w + menu_cell_padding);
+               } else if(res.w > widths[col] - menu_cell_padding) {
+                       widths[col] = res.w + menu_cell_padding;
+               }
+       }
+}
 
 const std::vector<int>& menu::column_widths() const
 {
-       if(column_widths_.empty()) {
-               for(size_t row = 0; row != items_.size(); ++row) {
-                       for(size_t col = 0; col != items_[row].size(); ++col) {
-                               const SDL_Rect res = 
item_size(items_[row][col]);
-
-                               if(col == column_widths_.size()) {
-                                       column_widths_.push_back(res.w + 
menu_cell_padding);
-                               } else if(res.w > column_widths_[col] - 
menu_cell_padding) {
-                                       column_widths_[col] = res.w + 
menu_cell_padding;
-                               }
-                       }
+       if(column_widths_.empty()) {
+               column_widths_item(heading_,column_widths_);
+               for(size_t row = 0; row != items_.size(); ++row) {
+                       column_widths_item(items_[row].fields,column_widths_);
                }
        }
 
@@ -395,29 +667,50 @@
        bg_restore(rect);
 }
 
-void menu::draw_item(int item)
+void menu::draw_row(const std::vector<std::string>& row, const SDL_Rect& rect, 
ROW_TYPE type)
 {
-       SDL_Rect rect = get_item_rect(item);
-       if(rect.w == 0) {
+       if(rect.w == 0 || rect.h == 0) {
                return;
-       }
+       }
+
+       bg_restore(rect);
+
+       int rgb = 0;
+       double alpha = 0.0;
+
+       switch(type) {
+       case NORMAL_ROW:
+               rgb = 0x000000;
+               alpha = 0.2;
+               break;
+       case SELECTED_ROW:
+               rgb = 0x990000;
+               alpha = 0.6;
+               break;
+       case HEADING_ROW:
+               rgb = 0x333333;
+               alpha = 0.3;
+               break;
+       }
 
-       clear_item(item);
        draw_solid_tinted_rectangle(rect.x, rect.y, rect.w, rect.h,
-                                   item == selected_ ? 150:0,0,0,
-                                   item == selected_ ? 0.6 : 0.2,
+                                   (rgb&0xff0000) >> 16,(rgb&0xff00) >> 
8,rgb&0xff,alpha,
                                    video().getSurface());
 
        SDL_Rect const &area = screen_area();
-       //SDL_Rect area = { 0, 0, rect.w, rect.h };
        SDL_Rect const &loc = inner_location();
 
-       const std::vector<int>& widths = column_widths();
+       const std::vector<int>& widths = column_widths();
 
        int xpos = rect.x;
-       for(size_t i = 0; i != items_[item].size(); ++i) {
+       for(size_t i = 0; i != row.size(); ++i) {
+
+               if(type == HEADING_ROW && highlight_heading_ == int(i)) {
+                       
draw_solid_tinted_rectangle(xpos,rect.y,widths[i],rect.h,255,255,255,0.3,video().getSurface());
+               }
+
                const int last_x = xpos;
-               std::string str = items_[item][i];
+               std::string str = row[i];
                std::vector<std::string> img_text_items = utils::split(str, 
IMG_TEXT_SEPARATOR);
                for (std::vector<std::string>::const_iterator it = 
img_text_items.begin();
                         it != img_text_items.end(); it++) {
@@ -447,28 +740,56 @@
 }
 
 void menu::draw_contents()
-{
-#if 0
-       if (undrawn_items_.empty())
-               return;
+{
+       SDL_Rect heading_rect = inner_location();
+       heading_rect.h = heading_height();
+       draw_row(heading_,heading_rect,HEADING_ROW);
 
-       if (!dirty()) {
-               for(std::set<size_t>::const_iterator i = 
undrawn_items_.begin(); i != undrawn_items_.end(); ++i) {
-                       if(*i < items_.size()) {
-                               draw_item(*i);
-                               update_rect(get_item_rect(*i));
-                       }
-               }
-
-               undrawn_items_.clear();
-               return;
+       for(size_t i = 0; i != item_pos_.size(); ++i) {
+               
draw_row(items_[item_pos_[i]].fields,get_item_rect(i),item_pos_[i] == selected_ 
? SELECTED_ROW : NORMAL_ROW);
        }
-
-       undrawn_items_.clear();
-#endif
-
-       for(size_t i = 0; i != items_.size(); ++i)
-               draw_item(i);
+}
+
+void menu::draw()
+{
+       if(hidden()) {
+               return;
+       }
+       
+       if(!dirty()) {
+
+               for(std::set<int>::const_iterator i = invalid_.begin(); i != 
invalid_.end(); ++i) {
+                       if(*i == -1) {
+                               SDL_Rect heading_rect = inner_location();
+                               heading_rect.h = heading_height();
+                               bg_restore(heading_rect);
+                               draw_row(heading_,heading_rect,HEADING_ROW);
+                               update_rect(heading_rect);
+                       } else if(*i >= 0 && *i < int(item_pos_.size())) {
+                               const int pos = item_pos_[*i];
+                               const SDL_Rect& rect = get_item_rect(*i);
+                               bg_restore(rect);
+                               draw_row(items_[pos].fields,rect,pos == 
selected_ ? SELECTED_ROW : NORMAL_ROW);
+                               update_rect(rect);
+                       }
+               }
+
+               invalid_.clear();
+               return;
+       }
+
+       invalid_.clear();
+
+       bg_restore();
+
+       util::scoped_ptr<clip_rect_setter> clipper(NULL);
+       if(clip_rect())
+               clipper.assign(new clip_rect_setter(video().getSurface(), 
*clip_rect()));
+
+       draw_contents();
+
+       update_rect(location());
+       set_dirty(false);
 }
 
 int menu::hit(int x, int y) const
@@ -483,26 +804,54 @@
        }
 
        return -1;
+}
+
+int menu::hit_column(int x, int y) const
+{
+       std::vector<int> const &widths = column_widths();
+       x -= location().x;
+       for(int j = 0, j_end = widths.size(); j != j_end; ++j) {
+               x -= widths[j];
+               if (x < 0) {
+                       return j;
+               }
+       }
+
+       return -1;
 }
 
 std::pair<int,int> menu::hit_cell(int x, int y) const
 {
-       int i = hit(x, y);
-       if (i < 0)
-               return std::pair<int,int>(-1, -1);
-
-       std::vector<int> const &widths = column_widths();
-       x -= location().x;
-       for(int j = 0, j_end = widths.size(); j != j_end; ++j) {
-               x -= widths[j];
-               if (x < 0)
-                       return std::pair<int,int>(i, j);
-       }
-
-       return std::pair<int,int>(-1, -1);
+       const int row = hit(x, y);
+       if(row < 0) {
+               return std::pair<int,int>(-1, -1);
+       }
+
+       const int col = hit_column(x,y);
+       if(col < 0) {
+               return std::pair<int,int>(-1, -1);
+       }
+
+       return std::pair<int,int>(x,y);
+}
+
+int menu::hit_heading(int x, int y) const
+{
+       const size_t height = heading_height();
+       const SDL_Rect& loc = inner_location();
+       if(y >= loc.y && y < loc.y + height) {
+               return hit_column(x,y);
+       } else {
+               return -1;
+       }
 }
+
+SDL_Rect menu::get_item_rect(int item) const
+{
+       return get_item_rect_internal(item_pos_[item]);
+}
 
-SDL_Rect menu::get_item_rect(int item) const
+SDL_Rect menu::get_item_rect_internal(size_t item) const
 {
        const SDL_Rect empty_rect = {0,0,0,0};
        int first_item_on_screen = get_position();
@@ -517,9 +866,9 @@
 
        SDL_Rect const &loc = inner_location();
 
-       int y = loc.y;
+       int y = loc.y + heading_height();
        if (item != first_item_on_screen) {
-               const SDL_Rect& prev = get_item_rect(item-1);
+               const SDL_Rect& prev = get_item_rect_internal(item-1);
                y = prev.y + prev.h;
        }
 
@@ -547,15 +896,24 @@
        return res;
 }
 
-size_t menu::get_item_height_internal(int item) const
+size_t menu::get_item_height_internal(const std::vector<std::string>& item) 
const
 {
        size_t res = 0;
-       for(size_t n = 0; n != items_[item].size(); ++n) {
-               SDL_Rect rect = item_size(items_[item][n]);
+       for(std::vector<std::string>::const_iterator i = item.begin(); i != 
item.end(); ++i) {
+               SDL_Rect rect = item_size(*i);
                res = maximum<int>(rect.h,res);
        }
 
        return res;
+}
+
+size_t menu::heading_height() const
+{
+       if(heading_height_ == -1) {
+               heading_height_ = int(get_item_height_internal(heading_));
+       }
+
+       return minimum<unsigned int>(heading_height_,max_height_);
 }
 
 size_t menu::get_item_height(int) const
@@ -565,7 +923,7 @@
 
        size_t max_height = 0;
        for(size_t n = 0; n != items_.size(); ++n) {
-               max_height = 
maximum<int>(max_height,get_item_height_internal(n));
+               max_height = 
maximum<int>(max_height,get_item_height_internal(items_[n].fields));
        }
 
        return item_height_ = max_height;
@@ -585,8 +943,8 @@
                        help_string_ = -1;
                }
 
-               if(size_t(loc.first) < help_.size()) {
-                       const std::vector<std::string>& row = help_[loc.first];
+               if(size_t(loc.first) < items_.size()) {
+                       const std::vector<std::string>& row = 
items_[loc.first].help;
                        if(size_t(loc.second) < row.size()) {
                                const std::string& help = row[loc.second];
                                if(help.empty() == false) {
@@ -598,6 +956,29 @@
        }
 
        cur_help_ = loc;
+}
+
+void menu::invalidate_row(size_t id)
+{
+       if(id >= items_.size()) {
+               return;
+       }
+
+       invalid_.insert(int(id));
+}
+
+void menu::invalidate_row_pos(size_t pos)
+{
+       if(pos >= items_.size()) {
+               return;
+       }
+
+       invalidate_row(items_[pos].id);
+}
+
+void menu::invalidate_heading()
+{
+       invalid_.insert(-1);
 }
 
 }
Index: wesnoth/src/widgets/menu.hpp
diff -u wesnoth/src/widgets/menu.hpp:1.35 wesnoth/src/widgets/menu.hpp:1.36
--- wesnoth/src/widgets/menu.hpp:1.35   Fri Mar 18 21:21:48 2005
+++ wesnoth/src/widgets/menu.hpp        Tue May 10 22:15:57 2005
@@ -1,6 +1,8 @@
 #ifndef WIDGET_MENU_HPP_INCLUDED
 #define WIDGET_MENU_HPP_INCLUDED
-
+
+#include <map>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -16,17 +18,66 @@
 
 class menu : public scrollarea
 {
-public:
+public:
+
+       struct item
+       {
+               item() : id(0)
+               {}
+
+               item(const std::vector<std::string>& fields, size_t id)
+                       : fields(fields), id(id)
+               {}
+
+               std::vector<std::string> fields;
+               std::vector<std::string> help;
+               size_t id;
+       };
+
+       class sorter
+       {
+       public:
+               virtual ~sorter() {}
+               virtual bool column_sortable(int column) const = 0;
+               virtual bool less(int column, const item& row1, const item& 
row2) const = 0;
+       };
+
+       class basic_sorter : public sorter
+       {
+       public:
+               virtual ~basic_sorter() {}
+
+               basic_sorter& set_alpha_sort(int column);
+               basic_sorter& set_numeric_sort(int column);
+               basic_sorter& set_id_sort(int column);
+               basic_sorter& set_redirect_sort(int column, int to);
+               basic_sorter& set_position_sort(int column, const 
std::vector<int>& pos);
+       protected:
+               virtual bool column_sortable(int column) const;
+               virtual bool less(int column, const item& row1, const item& 
row2) const;
+
+       private:
+               std::set<int> alpha_sort_, numeric_sort_, id_sort_;
+               std::map<int,int> redirect_sort_;
+               std::map<int,std::vector<int> > pos_sort_;
+       };
+
        menu(CVideo& video, const std::vector<std::string>& items,
-            bool click_selects=false, int max_height=-1, int max_width=-1);
+            bool click_selects=false, int max_height=-1, int max_width=-1,
+                const sorter* sorter_obj=NULL);
 
-       int selection() const;
-       void move_selection(size_t pos);
+       int selection() const;
+
+       enum SELECTION_MOVE_VIEWPORT { MOVE_VIEWPORT, NO_MOVE_VIEWPORT };
+       void move_selection(size_t id, SELECTION_MOVE_VIEWPORT 
move_viewport=MOVE_VIEWPORT);
+       void reset_selection();
 
        // allows user to change_item while running (dangerous)
-       void change_item(int pos1,int pos2,std::string str);
+       void change_item(int pos1,int pos2,const std::string& str);
 
-       void erase_item(size_t index);
+       void erase_item(size_t index);
+
+       void set_heading(const std::vector<std::string>& heading);
 
        /// Set new items to show and redraw/recalculate everything. If
        /// strip_spaces is false, spaces will remain at the item edges. If
@@ -46,17 +97,22 @@
        int process();
 
        bool double_clicked();
-
+
+       void set_click_selects(bool value);
        void set_numeric_keypress_selection(bool value);
 
-       void scroll(int pos);
+       void scroll(int pos);
+
+       void sort_by(int column);
 
 protected:
        void handle_event(const SDL_Event& event);
        void set_inner_location(const SDL_Rect& rect);
 
 private:
-       size_t max_items_onscreen() const;
+       size_t max_items_onscreen() const;
+
+       size_t heading_height() const;
 
        int max_height_, max_width_;
        mutable int max_items_, item_height_;
@@ -64,7 +120,11 @@
        void adjust_viewport_to_selection();
        void key_press(SDLKey key);
 
-       std::vector<std::vector<std::string> > items_, help_;
+       std::vector<item> items_;
+       std::vector<size_t> item_pos_;
+
+       std::vector<std::string> heading_;
+       mutable int heading_height_;
 
        void create_help_strings();
        void process_help_string(int mousex, int mousey);
@@ -83,18 +143,26 @@
 
        bool double_clicked_;
 
-       const std::vector<int>& column_widths() const;
-       void draw_item(int item);
+       const std::vector<int>& column_widths() const;
+       void column_widths_item(const std::vector<std::string>& row, 
std::vector<int>& widths) const;
+
+       enum ROW_TYPE { NORMAL_ROW, SELECTED_ROW, HEADING_ROW };
+       void draw_row(const std::vector<std::string>& row, const SDL_Rect& 
rect, ROW_TYPE type);
        void clear_item(int item);
-       void draw_contents();
+       void draw_contents();
+       void draw();
        int hit(int x, int y) const;
 
-       std::pair<int,int> hit_cell(int x, int y) const;
+       std::pair<int,int> hit_cell(int x, int y) const;
+       int hit_column(int x, int y) const;
+
+       int hit_heading(int x, int y) const;
 
        mutable std::map<int,SDL_Rect> itemRects_;
 
-       SDL_Rect get_item_rect(int item) const;
-       size_t get_item_height_internal(int item) const;
+       SDL_Rect get_item_rect(int item) const;
+       SDL_Rect get_item_rect_internal(size_t pos) const;
+       size_t get_item_height_internal(const std::vector<std::string>& item) 
const;
        size_t get_item_height(int item) const;
        int items_start() const;
 
@@ -110,15 +178,31 @@
        // behavior so that a click that causes one double click wont be
        // counted as a first click in the "next" double click.
        bool ignore_next_doubleclick_;
-       bool last_was_doubleclick_;
+       bool last_was_doubleclick_;
+
+       const sorter* sorter_;
+       int sortby_;
+       int highlight_heading_;
 
        /// Set new items to show. If strip_spaces is false, spaces will
        /// remain at the item edges.
-       void fill_items(const std::vector<std::string>& items, bool 
strip_spaces);
+       void fill_items(const std::vector<std::string>& items, bool 
strip_spaces);
+
+       enum SORT_TYPE { NORMAL_SORT, INVERT_SORT };
+       void do_sort(SORT_TYPE type=NORMAL_SORT);
+       void recalculate_pos();
+       void assert_pos();
 
-       void update_size();
+       void update_size();
+       void set_selection_pos(size_t pos, SELECTION_MOVE_VIEWPORT 
move_viewport=MOVE_VIEWPORT);
        void move_selection_up(size_t dep);
-       void move_selection_down(size_t dep);
+       void move_selection_down(size_t dep);
+
+       void invalidate_row(size_t id);
+       void invalidate_row_pos(size_t pos);
+       void invalidate_heading();
+
+       std::set<int> invalid_;
 };
 
 }
Index: wesnoth/src/widgets/slider.hpp
diff -u wesnoth/src/widgets/slider.hpp:1.23 wesnoth/src/widgets/slider.hpp:1.24
--- wesnoth/src/widgets/slider.hpp:1.23 Fri Mar 18 21:21:48 2005
+++ wesnoth/src/widgets/slider.hpp      Tue May 10 22:15:57 2005
@@ -1,4 +1,4 @@
-/* $Id: slider.hpp,v 1.23 2005/03/18 21:21:48 ydirson Exp $ */
+/* $Id: slider.hpp,v 1.24 2005/05/10 22:15:57 Sirp Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -38,7 +38,10 @@
        int min_value() const;
 
        virtual void set_location(SDL_Rect const &rect);
-       using widget::set_location;
+
+       //VC++ doesn't like a 'using scrollarea::set_location' directive here, 
so we declare
+       //an inline forwarding function instead
+       void set_location(int x, int y) { widget::set_location(x,y); }
 
 protected:
        virtual void handle_event(const SDL_Event& event);
Index: wesnoth/src/widgets/widget.cpp
diff -u wesnoth/src/widgets/widget.cpp:1.31 wesnoth/src/widgets/widget.cpp:1.32
--- wesnoth/src/widgets/widget.cpp:1.31 Fri Mar 18 21:21:48 2005
+++ wesnoth/src/widgets/widget.cpp      Tue May 10 22:15:57 2005
@@ -52,6 +52,11 @@
 void widget::update_location(SDL_Rect const &rect)
 {
        bg_register(rect);
+}
+
+const SDL_Rect* widget::clip_rect() const
+{
+       return clip_ ? &clip_rect_ : NULL;
 }
 
 void widget::bg_register(SDL_Rect const &rect)
Index: wesnoth/src/widgets/widget.hpp
diff -u wesnoth/src/widgets/widget.hpp:1.26 wesnoth/src/widgets/widget.hpp:1.27
--- wesnoth/src/widgets/widget.hpp:1.26 Fri Mar 18 21:21:48 2005
+++ wesnoth/src/widgets/widget.hpp      Tue May 10 22:15:57 2005
@@ -70,7 +70,9 @@
 
        virtual void draw();
        virtual void draw_contents() {};
-       virtual void update_location(SDL_Rect const &rect);
+       virtual void update_location(SDL_Rect const &rect);
+
+       const SDL_Rect* clip_rect() const;
 
 private:
        void volatile_draw();
Index: wesnoth/src/wml_separators.hpp
diff -u wesnoth/src/wml_separators.hpp:1.1 wesnoth/src/wml_separators.hpp:1.2
--- wesnoth/src/wml_separators.hpp:1.1  Fri Feb 25 01:07:19 2005
+++ wesnoth/src/wml_separators.hpp      Tue May 10 22:15:57 2005
@@ -2,6 +2,22 @@
 #define WIDGET_DEFINES_HPP_INCLUDED
 
 char const HELP_STRING_SEPARATOR = '|', DEFAULT_ITEM = '*', COLUMN_SEPARATOR = 
'=',
-           IMAGE_PREFIX = '&', IMG_TEXT_SEPARATOR = 1;
+           IMAGE_PREFIX = '&', IMG_TEXT_SEPARATOR = 1, HEADING_PREFIX = 2;
+
+inline bool is_wml_separator(char c)
+{
+       switch(c)
+       {
+       case HELP_STRING_SEPARATOR:
+       case DEFAULT_ITEM:
+       case COLUMN_SEPARATOR:
+       case IMAGE_PREFIX:
+       case IMG_TEXT_SEPARATOR:
+       case HEADING_PREFIX:
+               return true;
+       default:
+               return false;
+       }
+}
 
 #endif




reply via email to

[Prev in Thread] Current Thread [Next in Thread]