← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/bug-1390793 into lp:widelands

 

GunChleoc has proposed merging lp:~widelands-dev/widelands/bug-1390793 into lp:widelands.

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #814500 in widelands: "The Edit box in the Editor's "Map Options" should have a "save" and "cancel" button to exit this window"
  https://bugs.launchpad.net/widelands/+bug/814500
  Bug #1390793 in widelands: "Editor should always show filenames, not map names when dealing with saving and loading"
  https://bugs.launchpad.net/widelands/+bug/1390793
  Bug #1402786 in widelands: ""Set origin" should be in the tools menu"
  https://bugs.launchpad.net/widelands/+bug/1402786

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/bug-1390793/+merge/254558

This branch still has 2 issues:

1. Load/Save Map screens start with a correctly sorted table, but when a table header is clicked, the sorting becomes garbage. I haven't been able to find out why - ideas are welcome.

2. For Map Options -> Suggested Teams, I need images in the Listselect. This will be possible when the fh1 branch has been merged, so I left the implementation of this tab blank with a comment in it. We should create a bug report for this before merging.


Summary:

Reworked the editor's Load/Save Map and Map Origins dialogs. Set Map Origin is now a tool.

General UI Changes:
- New button graphic for main options in the wui.
- Removed some superfluous tooltips.
- Multiline edit boxes now have the same background and borders as edit boxes.

UI Changes for Load/Save Map:
- Added toggle for filenames/Map names.
- Load Map: Added localize/don't localize map names checkbox.
- Save Map: now uses Maptable and always shows the details for the map to be saved rather than the file selected on the list.
- Save Map: Added Map Options button.
- Save Map: Map name is now independent of filename when saving. Changing the directory does no longer affect the editbox.

UI Changes for Map Options:
- Moved "Set origin" tool to Tools menu.
- Map Options now is a tabbed dialog. Everything for the map's elemental packet is now editable (e.g. tags and hints), except for the Suggested Teams, which is still a mockup.

Refactoring:
- Shifted Map list and details into two new classes, which are now used both by the "New Game" and the editor's "Load Map" functions. Shifted common functionality from UI screens into MapData.
- Common Details panel for all load/save map screens, including editor and ui-fsmenu.
- New common super class for Editor Load/Save Map.
- Switched Map Options and Map Details contents to Box layout.

-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/bug-1390793 into lp:widelands.
=== modified file 'maps/Trident of Fire.wmf/elemental'
--- maps/Trident of Fire.wmf/elemental	2014-10-08 19:52:48 +0000
+++ maps/Trident of Fire.wmf/elemental	2015-03-30 10:39:30 +0000
@@ -9,7 +9,7 @@
 name=_"Trident of Fire"
 author="Robnick"
 descr=_"In the vicinity of three major volcanoes, six lovely islands are inviting settlers to start a new life. Deserts and a quickly growing forest wait to be discovered. But only by becoming a naval power will your tribe be able to explore enough resources to compete with its opponents."
-hint=_"Suggested teams: red vs. green | (blue, yellow) vs. (green, orange) | (blue, black) vs. (green, red) | (blue, black, yellow) vs. (green, red, orange)"
+hint=
 tags="official,seafaring,1v1,2teams,3teams"
 
 [teams00]

=== added file 'pics/but5.png'
Binary files pics/but5.png	1970-01-01 00:00:00 +0000 and pics/but5.png	2015-03-30 10:39:30 +0000 differ
=== added file 'pics/editor_menu_tool_set_origin.png'
Binary files pics/editor_menu_tool_set_origin.png	1970-01-01 00:00:00 +0000 and pics/editor_menu_tool_set_origin.png	2015-03-30 10:39:30 +0000 differ
=== modified file 'src/editor/CMakeLists.txt'
--- src/editor/CMakeLists.txt	2015-01-31 16:03:59 +0000
+++ src/editor/CMakeLists.txt	2015-03-30 10:39:30 +0000
@@ -51,6 +51,8 @@
     ui_menus/editor_main_menu.h
     ui_menus/editor_main_menu_load_map.cc
     ui_menus/editor_main_menu_load_map.h
+    ui_menus/editor_main_menu_load_or_save_map.cc
+    ui_menus/editor_main_menu_load_or_save_map.h
     ui_menus/editor_main_menu_map_options.cc
     ui_menus/editor_main_menu_map_options.h
     ui_menus/editor_main_menu_new_map.cc
@@ -101,7 +103,7 @@
     ui_basic
     ui_fsmenu
     widelands_ball_of_mud
-    wui
+    wui_common
     wui_mapview_pixelfunctions
     wui_overlay_manager
 )

=== modified file 'src/editor/editorinteractive.h'
--- src/editor/editorinteractive.h	2014-10-14 06:30:20 +0000
+++ src/editor/editorinteractive.h	2015-03-30 10:39:30 +0000
@@ -80,7 +80,8 @@
 			place_immovable(delete_immovable),
 			place_bob(delete_bob),
 			increase_resources(decrease_resources, set_resources),
-			set_port_space(unset_port_space)
+			set_port_space(unset_port_space),
+			set_origin()
 		{}
 		EditorTool & current() const {return *current_pointer;}
 		using ToolVector = std::vector<EditorTool *>;

=== modified file 'src/editor/ui_menus/editor_main_menu.cc'
--- src/editor/ui_menus/editor_main_menu.cc	2014-11-30 18:49:38 +0000
+++ src/editor/ui_menus/editor_main_menu.cc	2015-03-30 10:39:30 +0000
@@ -82,7 +82,7 @@
 	m_button_exit_editor
 		(this, "exit",
 		 hmargin, vmargin + 6 * (height + vspacing), width, height,
-		 g_gr->images().get("pics/but0.png"),
+		 g_gr->images().get("pics/but5.png"),
 		 _("Exit Editor"))
 {
 	m_button_new_map.sigclicked.connect(boost::bind(&EditorMainMenu::new_map_btn, this));

=== modified file 'src/editor/ui_menus/editor_main_menu_load_map.cc'
--- src/editor/ui_menus/editor_main_menu_load_map.cc	2014-11-30 18:49:38 +0000
+++ src/editor/ui_menus/editor_main_menu_load_map.cc	2015-03-30 10:39:30 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2002-2004, 2006-2012 by the Widelands Development Team
+ * Copyright (C) 2002-2004, 2006-2015 by the Widelands Development Team
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -19,134 +19,35 @@
 
 #include "editor/ui_menus/editor_main_menu_load_map.h"
 
-#include <cstdio>
-#include <memory>
-#include <string>
-
-#include <boost/format.hpp>
-
 #include "base/i18n.h"
-#include "base/wexception.h"
 #include "editor/editorinteractive.h"
-#include "editor/tools/editor_set_starting_pos_tool.h"
-#include "graphic/graphic.h"
 #include "io/filesystem/layered_filesystem.h"
-#include "logic/building.h"
-#include "logic/editor_game_base.h"
-#include "map_io/map_loader.h"
 #include "map_io/widelands_map_loader.h"
-#include "profile/profile.h"
-#include "ui_basic/button.h"
-#include "ui_basic/editbox.h"
-#include "ui_basic/listselect.h"
-#include "ui_basic/multilinetextarea.h"
-#include "ui_basic/progresswindow.h"
-#include "ui_basic/textarea.h"
-#include "wui/overlay_manager.h"
-
-using Widelands::WidelandsMapLoader;
+#include "wui/mapdetails.h"
+#include "wui/maptable.h"
 
 /**
  * Create all the buttons etc...
 */
-MainMenuLoadMap::MainMenuLoadMap(EditorInteractive & parent)
-	: UI::Window(&parent, "load_map_menu", 0, 0, 560, 300, _("Load Map"))
-{
-	int32_t const spacing =  5;
-	int32_t const offsx   = spacing;
-	int32_t const offsy   = 10;
-	int32_t       posx    = offsx;
-	int32_t       posy    = offsy;
-	int32_t const descr_label_w = 100;
-
-	m_ls = new UI::Listselect<const char *>
-		(this,
-		 posx, posy,
-		 get_inner_w() / 2 - spacing, get_inner_h() - spacing - offsy - 40);
-	m_ls->selected.connect(boost::bind(&MainMenuLoadMap::selected, this, _1));
-	m_ls->double_clicked.connect(boost::bind(&MainMenuLoadMap::double_clicked, this, _1));
-	m_ls->focus();
-
-	posx = get_inner_w() / 2 + spacing;
-	new UI::Textarea
-		(this, posx, posy, descr_label_w, 20, _("Name:"), UI::Align_CenterLeft);
-	m_name =
-		new UI::MultilineTextarea
-			(this, posx + descr_label_w, posy, 200, 40, "---", UI::Align_CenterLeft);
-	posy += 40 + spacing;
-
-	new UI::Textarea
-		(this, posx, posy, 150, 20, _("Authors:"), UI::Align_CenterLeft);
-	m_author =
-		new UI::Textarea
-			(this, posx + descr_label_w, posy, 200, 20, "---", UI::Align_CenterLeft);
-	posy += 20 + spacing;
-
-	new UI::Textarea
-		(this, posx, posy, descr_label_w, 20, _("Size:"), UI::Align_CenterLeft);
-	m_size =
-		new UI::Textarea
-			(this, posx + descr_label_w, posy, 200, 20, "---", UI::Align_CenterLeft);
-	posy += 20 + spacing;
-
-	new UI::Textarea
-		(this, posx, posy, descr_label_w, 20, _("Players:"), UI::Align_CenterLeft);
-	m_nrplayers =
-		new UI::Textarea
-			(this, posx + descr_label_w, posy, 200, 20, "---", UI::Align_CenterLeft);
-	posy += 20 + spacing;
-
-
-	new UI::Textarea
-		(this, posx, posy, descr_label_w, 20, _("Descr:"), UI::Align_CenterLeft);
-	m_descr =
-		new UI::MultilineTextarea
-			(this,
-			 posx + descr_label_w, posy,
-			 get_inner_w() - posx - spacing - descr_label_w,
-			 get_inner_h() - posy - spacing - 40,
-			 "---", UI::Align_CenterLeft);
-
-	posy = get_inner_h() - 30;
-
-	m_ok_btn = new UI::Button
-		(this, "ok",
-		 posx, posy,
-		 get_inner_w() / 4 - 1.5 * spacing, 20,
-		 g_gr->images().get("pics/but0.png"),
-		 _("OK"),
-		 std::string(),
-		 false);
-	m_ok_btn->sigclicked.connect(boost::bind(&MainMenuLoadMap::clicked_ok, this));
-
-	UI::Button * cancelbtn = new UI::Button
-		(this, "cancel",
-		 posx + get_inner_w() / 4 - spacing / 2, posy,
-		 get_inner_w() / 4 - 1.5 * spacing, 20,
-		 g_gr->images().get("pics/but1.png"),
-		 _("Cancel"));
-	cancelbtn->sigclicked.connect(boost::bind(&MainMenuLoadMap::die, this));
-
-	m_basedir = "maps";
-	m_curdir  = "maps";
-
-	fill_list();
-
-	center_to_parent();
-	move_to_top();
+MainMenuLoadMap::MainMenuLoadMap(EditorInteractive& parent)
+   : MainMenuLoadOrSaveMap(parent, "load_map_menu", _("Load Map")) {
+
+	table_.selected.connect(boost::bind(&MainMenuLoadMap::entry_selected, this));
+	table_.double_clicked.connect(boost::bind(&MainMenuLoadMap::clicked_ok, boost::ref(*this)));
+
+	ok_.sigclicked.connect(boost::bind(&MainMenuLoadMap::clicked_ok, this));
+	cancel_.sigclicked.connect(boost::bind(&MainMenuLoadMap::die, this));
 }
 
-
 void MainMenuLoadMap::clicked_ok() {
-	const char * const filename(m_ls->get_selected());
-
-	if (g_fs->is_directory(filename) && !WidelandsMapLoader::is_widelands_map(filename)) {
-		m_curdir = filename;
-		m_ls->clear();
-		m_mapfiles.clear();
-		fill_list();
+	assert(ok_.enabled());
+	const MapData& mapdata = *table_.get_map();
+	if (g_fs->is_directory(mapdata.filename) &&
+	    !Widelands::WidelandsMapLoader::is_widelands_map(mapdata.filename)) {
+		curdir_ = mapdata.filename;
+		fill_table();
 	} else {
-		dynamic_cast<EditorInteractive&>(*get_parent()).load(filename);
+		dynamic_cast<EditorInteractive&>(*get_parent()).load(mapdata.filename);
 		die();
 	}
 }
@@ -154,110 +55,12 @@
 /**
  * Called when a entry is selected
  */
-void MainMenuLoadMap::selected(uint32_t) {
-	const char * const name = m_ls->get_selected();
-
-	m_ok_btn->set_enabled(true);
-
-	if (!g_fs->is_directory(name) || WidelandsMapLoader::is_widelands_map(name)) {
-		Widelands::Map map;
-		{
-			std::unique_ptr<Widelands::MapLoader> map_loader = map.get_correct_loader(name);
-			map_loader->preload_map(true); //  This has worked before, no problem.
-		}
-
-		// Translate the map data
-		i18n::Textdomain td("maps");
-		m_name  ->set_text(map.get_name());
-		m_name  ->set_tooltip(map.get_name());
-		m_author->set_text(map.get_author());
-		m_descr ->set_text
-			(_(map.get_description()) +
-			 (map.get_hint().empty() ? "" : (std::string("\n\n") + _(map.get_hint()))));
-
-		m_nrplayers->set_text(std::to_string(static_cast<unsigned int>(map.get_nrplayers())));
-
-		m_size     ->set_text((boost::format(_("%1$ix%2$i"))
-									  % map.get_width()
-									  % map.get_height()).str());
+void MainMenuLoadMap::entry_selected() {
+	bool has_selection = table_.has_selection();
+	ok_.set_enabled(has_selection);
+	if (!has_selection) {
+		map_details_.clear();
 	} else {
-		m_name     ->set_text("");
-		m_name     ->set_tooltip("");
-		m_author   ->set_text("");
-		m_descr    ->set_text("");
-		m_nrplayers->set_text("");
-		m_size     ->set_text("");
-	}
-}
-
-/**
- * An entry has been doubleclicked
- */
-void MainMenuLoadMap::double_clicked(uint32_t) {clicked_ok();}
-
-/**
- * fill the file list
- */
-void MainMenuLoadMap::fill_list() {
-	//  Fill it with all files we find.
-	m_mapfiles = g_fs->list_directory(m_curdir);
-
-	//  First, we add all directories. We manually add the parent directory.
-	if (m_curdir != m_basedir) {
-#ifndef _WIN32
-		m_parentdir = m_curdir.substr(0, m_curdir.rfind('/'));
-#else
-		m_parentdir = m_curdir.substr(0, m_curdir.rfind('\\'));
-#endif
-
-		m_ls->add
-				/** TRANSLATORS: Parent directory */
-				((boost::format("\\<%s\\>") % _("parent")).str(),
-				 m_parentdir.c_str(),
-				 g_gr->images().get("pics/ls_dir.png"));
-	}
-
-	const FilenameSet::const_iterator mapfiles_end = m_mapfiles.end();
-	for
-		(FilenameSet::const_iterator pname = m_mapfiles.begin();
-		 pname != mapfiles_end;
-		 ++pname)
-	{
-		const char * const name = pname->c_str();
-		if
-			(strcmp(FileSystem::fs_filename(name), ".")    &&
-			 strcmp(FileSystem::fs_filename(name), "..")   &&
-			 g_fs->is_directory(name)                       &&
-			 !WidelandsMapLoader::is_widelands_map(name))
-
-		m_ls->add
-			(FileSystem::fs_filename(name),
-			 name,
-			 g_gr->images().get("pics/ls_dir.png"));
-	}
-
-	Widelands::Map map;
-
-	for
-		(FilenameSet::const_iterator pname = m_mapfiles.begin();
-		 pname != mapfiles_end;
-		 ++pname)
-	{
-		char const * const name = pname->c_str();
-		std::unique_ptr<Widelands::MapLoader> map_loader = map.get_correct_loader(name);
-		if (map_loader.get() != nullptr) {
-			try {
-				map_loader->preload_map(true);
-				m_ls->add
-					(FileSystem::filename_without_ext(name),
-					 name,
-					 g_gr->images().get
-						 (dynamic_cast<WidelandsMapLoader*>(map_loader.get())
-							? "pics/ls_wlmap.png" : "pics/ls_s2map.png"));
-			} catch (const WException &) {} //  we simply skip illegal entries
-		}
-	}
-
-	if (m_ls->size())
-		m_ls->select(0);
+		map_details_.update(*table_.get_map(), !cb_dont_localize_mapnames_->get_state());
+	}
 }

=== modified file 'src/editor/ui_menus/editor_main_menu_load_map.h'
--- src/editor/ui_menus/editor_main_menu_load_map.h	2014-09-25 08:58:07 +0000
+++ src/editor/ui_menus/editor_main_menu_load_map.h	2015-03-30 10:39:30 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2002-2004, 2006, 2008-2011 by the Widelands Development Team
+ * Copyright (C) 2002-2004, 2006, 2008-2015 by the Widelands Development Team
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -20,40 +20,22 @@
 #ifndef WL_EDITOR_UI_MENUS_EDITOR_MAIN_MENU_LOAD_MAP_H
 #define WL_EDITOR_UI_MENUS_EDITOR_MAIN_MENU_LOAD_MAP_H
 
-#include "io/filesystem/filesystem.h"
-#include "ui_basic/window.h"
+#include <string>
 
-struct EditorInteractive;
-namespace UI {
-struct Button;
-template <typename T> struct Listselect;
-struct Textarea;
-struct MultilineTextarea;
-}
+#include "editor/editorinteractive.h"
+#include "editor/ui_menus/editor_main_menu_load_or_save_map.h"
 
 /**
  * Choose a filename and save your brand new created map
 */
-struct MainMenuLoadMap : public UI::Window {
-	MainMenuLoadMap(EditorInteractive &);
+struct MainMenuLoadMap : public MainMenuLoadOrSaveMap {
+	MainMenuLoadMap(EditorInteractive& parent);
+
+protected:
+	void clicked_ok() override;
 
 private:
-	void clicked_ok();
-	void selected      (uint32_t);
-	void double_clicked(uint32_t);
-
-	void fill_list();
-
-	UI::MultilineTextarea * m_name;
-	UI::Textarea * m_author, * m_size, * m_nrplayers;
-	UI::MultilineTextarea * m_descr;
-	UI::Listselect<const char *> * m_ls;
-	UI::Button * m_ok_btn;
-
-	std::string m_basedir;
-	std::string m_curdir;
-	std::string m_parentdir;
-	FilenameSet m_mapfiles;
+	void entry_selected();
 };
 
 #endif  // end of include guard: WL_EDITOR_UI_MENUS_EDITOR_MAIN_MENU_LOAD_MAP_H

=== added file 'src/editor/ui_menus/editor_main_menu_load_or_save_map.cc'
--- src/editor/ui_menus/editor_main_menu_load_or_save_map.cc	1970-01-01 00:00:00 +0000
+++ src/editor/ui_menus/editor_main_menu_load_or_save_map.cc	2015-03-30 10:39:30 +0000
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2002-2004, 2006-2015 by the Widelands Development Team
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include "editor/ui_menus/editor_main_menu_load_or_save_map.h"
+
+#include <cstdio>
+#include <memory>
+
+#include "base/i18n.h"
+#include "base/wexception.h"
+#include "editor/editorinteractive.h"
+#include "graphic/graphic.h"
+#include "io/filesystem/filesystem.h"
+#include "io/filesystem/layered_filesystem.h"
+#include "map_io/widelands_map_loader.h"
+
+MainMenuLoadOrSaveMap::MainMenuLoadOrSaveMap(EditorInteractive& parent,
+                                             const std::string& name,
+                                             const std::string& title)
+   : UI::Window(&parent, name, 0, 0, parent.get_inner_w() - 40, parent.get_inner_h() - 40, title),
+
+     // Values for alignment and size
+     padding_(4),
+     buth_(20),
+     tablex_(padding_),
+     tabley_(buth_ + 2 * padding_),
+     tablew_(get_inner_w() * 7 / 12),
+     tableh_(get_inner_h() - tabley_ - 3 * buth_ - 2 * padding_),
+     right_column_x_(tablew_ + 2 * padding_),
+     butw_((get_inner_w() - right_column_x_ - 2 * padding_) / 2),
+
+     table_(this, tablex_, tabley_, tablew_, tableh_, false),
+     map_details_(
+        this, right_column_x_, tabley_, get_inner_w() - right_column_x_ - padding_, tableh_),
+     ok_(this,
+         "ok",
+         get_inner_w() / 2 - butw_ - padding_,
+         get_inner_h() - padding_ - buth_,
+         butw_,
+         buth_,
+         g_gr->images().get("pics/but5.png"),
+         _("OK")),
+     cancel_(this,
+             "cancel",
+             get_inner_w() / 2 + padding_,
+             get_inner_h() - padding_ - buth_,
+             butw_,
+             buth_,
+             g_gr->images().get("pics/but1.png"),
+             _("Cancel")),
+     basedir_("maps"),
+     has_translated_mapname_(false),
+     showing_mapames_(false) {
+	curdir_ = basedir_;
+
+	UI::Box* vbox = new UI::Box(this, tablex_, padding_, UI::Box::Horizontal, padding_, get_w());
+	show_mapnames_ = new UI::Button(vbox,
+	                                "show_mapnames",
+	                                0,
+	                                0,
+	                                butw_,
+	                                buth_,
+	                                g_gr->images().get("pics/but1.png"),
+	                                _("Show Map Names"));
+	vbox->add(show_mapnames_, UI::Box::AlignLeft, true);
+
+	cb_dont_localize_mapnames_ = new UI::Checkbox(vbox, Point(0, 0));
+	cb_dont_localize_mapnames_->set_state(false);
+	vbox->add_space(2 * padding_);
+	vbox->add(cb_dont_localize_mapnames_, UI::Box::AlignLeft, true);
+	vbox->add_space(padding_);
+	UI::Textarea* ta_dont_localize_mapnames =
+	   /** TRANSLATORS: Checkbox title. If this checkbox is enabled, map names aren't translated. */
+	   new UI::Textarea(vbox, _("Show original map names"), UI::Align_CenterLeft);
+	vbox->add(ta_dont_localize_mapnames, UI::Box::AlignLeft);
+	vbox->set_size(get_inner_w(), buth_);
+
+	table_.focus();
+	fill_table();
+
+	// We don't need the unlocalizing option if there is nothing to unlocalize.
+	// We know this after the list is filled.
+	cb_dont_localize_mapnames_->set_visible(has_translated_mapname_);
+	ta_dont_localize_mapnames->set_visible(has_translated_mapname_);
+
+	cb_dont_localize_mapnames_->changedto.connect(
+	   boost::bind(&MainMenuLoadOrSaveMap::fill_table, boost::ref(*this)));
+	show_mapnames_->sigclicked.connect(
+	   boost::bind(&MainMenuLoadOrSaveMap::toggle_mapnames, boost::ref(*this)));
+
+	center_to_parent();
+	move_to_top();
+}
+
+void MainMenuLoadOrSaveMap::toggle_mapnames() {
+	if (showing_mapames_) {
+		show_mapnames_->set_title(_("Show Map Names"));
+	} else {
+		show_mapnames_->set_title(_("Show Filenames"));
+	}
+	showing_mapames_ = !showing_mapames_;
+	fill_table();
+}
+
+/**
+ * fill the file list
+ */
+void MainMenuLoadOrSaveMap::fill_table() {
+	std::vector<MapData> maps_data;
+	has_translated_mapname_ = false;
+
+	//  Fill it with all files we find.
+	FilenameSet files = g_fs->list_directory(curdir_);
+
+	// If we are not at the top of the map directory hierarchy (we're not talking
+	// about the absolute filesystem top!) we manually add ".."
+	if (curdir_ != basedir_) {
+		maps_data.push_back(MapData::create_parent_dir(curdir_));
+	}
+
+	Widelands::Map map;
+
+	for (const std::string& mapfilename : files) {
+
+		// Add map file (compressed) or map directory (uncompressed)
+		if (Widelands::WidelandsMapLoader::is_widelands_map(mapfilename)) {
+			std::unique_ptr<Widelands::MapLoader> ml = map.get_correct_loader(mapfilename);
+			if (ml.get() != nullptr) {
+				try {
+					ml->preload_map(true);
+
+					if (!map.get_width() || !map.get_height()) {
+						continue;
+					}
+
+					MapData::MapType maptype;
+
+					if (map.scenario_types() & Widelands::Map::MP_SCENARIO ||
+					    map.scenario_types() & Widelands::Map::SP_SCENARIO) {
+						maptype = MapData::MapType::kScenario;
+					} else if (dynamic_cast<Widelands::WidelandsMapLoader*>(ml.get())) {
+						maptype = MapData::MapType::kNormal;
+					} else {
+						maptype = MapData::MapType::kSettlers2;
+					}
+
+					MapData mapdata(map, mapfilename, maptype);
+
+					has_translated_mapname_ =
+					   has_translated_mapname_ || (mapdata.name != mapdata.localized_name);
+
+					maps_data.push_back(mapdata);
+
+				} catch (const WException&) {
+				}  //  we simply skip illegal entries
+			}
+		} else if (g_fs->is_directory(mapfilename)) {
+			// Add subdirectory to the list
+			const char* fs_filename = FileSystem::fs_filename(mapfilename.c_str());
+			if (!strcmp(fs_filename, ".") || !strcmp(fs_filename, ".."))
+				continue;
+			maps_data.push_back(MapData::create_directory(mapfilename));
+		}
+	}
+
+	if (!showing_mapames_) {
+		table_.fill(maps_data, MapTable::Type::kFilenames);
+	} else if (cb_dont_localize_mapnames_->get_state()) {
+		table_.fill(maps_data, MapTable::Type::kMapnames);
+	} else {
+		table_.fill(maps_data, MapTable::Type::kMapnamesLocalized);
+	}
+	ok_.set_enabled(false);
+}

=== added file 'src/editor/ui_menus/editor_main_menu_load_or_save_map.h'
--- src/editor/ui_menus/editor_main_menu_load_or_save_map.h	1970-01-01 00:00:00 +0000
+++ src/editor/ui_menus/editor_main_menu_load_or_save_map.h	2015-03-30 10:39:30 +0000
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2002-2004, 2006, 2008-2015 by the Widelands Development Team
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef WL_EDITOR_UI_MENUS_EDITOR_MAIN_MENU_LOAD_OR_SAVE_MAP_H
+#define WL_EDITOR_UI_MENUS_EDITOR_MAIN_MENU_LOAD_OR_SAVE_MAP_H
+
+#include <string>
+
+#include "editor/editorinteractive.h"
+#include "ui_basic/button.h"
+#include "ui_basic/checkbox.h"
+#include "ui_basic/window.h"
+#include "wui/mapdetails.h"
+#include "wui/maptable.h"
+
+/**
+ * Choose a filename and save your brand new created map
+*/
+struct MainMenuLoadOrSaveMap : public UI::Window {
+	MainMenuLoadOrSaveMap(EditorInteractive& parent,
+	                      const std::string& name,
+	                      const std::string& title);
+
+protected:
+	virtual void clicked_ok() = 0;
+	void toggle_mapnames();
+	void fill_table();
+
+	// UI coordinates and spacers
+	int32_t const padding_;  // Common padding between panels
+	int32_t const buth_;     // Button dimensions
+	int32_t const tablex_, tabley_, tablew_, tableh_;
+	int32_t const right_column_x_;
+	int32_t const butw_;  // Button dimensions
+
+	MapTable table_;
+	MapDetails map_details_;
+
+	UI::Button ok_, cancel_;
+
+	const std::string basedir_;
+	std::string curdir_;
+
+	bool has_translated_mapname_;
+	UI::Checkbox* cb_dont_localize_mapnames_;
+	bool showing_mapames_;
+	UI::Button* show_mapnames_;
+};
+
+#endif  // end of include guard: WL_EDITOR_UI_MENUS_EDITOR_MAIN_MENU_LOAD_OR_SAVE_MAP_H

=== modified file 'src/editor/ui_menus/editor_main_menu_map_options.cc'
--- src/editor/ui_menus/editor_main_menu_map_options.cc	2014-11-30 18:49:38 +0000
+++ src/editor/ui_menus/editor_main_menu_map_options.cc	2015-03-30 10:39:30 +0000
@@ -43,70 +43,114 @@
 /**
  * Create all the buttons etc...
 */
-MainMenuMapOptions::MainMenuMapOptions(EditorInteractive & parent)
+MainMenuMapOptions::MainMenuMapOptions(EditorInteractive & parent, bool modal)
 	:
 	UI::Window
 		(&parent, "map_options",
-		 250, (parent.get_h() - 300) / 2, 305, 305,
-		 _("Map Options"))
-{
-
-	int32_t const offsx   =  5;
-	int32_t const offsy   =  5;
-	int32_t const spacing =  3;
-	int32_t const height  = 20;
-	int32_t       posx    = offsx;
-	int32_t       posy    = offsy;
-	UI::Textarea * ta = new UI::Textarea(this, posx, posy - 2, _("Map Name:"));
-	m_name =
-		new UI::EditBox
-			(this,
-			 posx + ta->get_w() + spacing, posy,
-			 get_inner_w() - (posx + ta->get_w() + spacing) - spacing, 20,
-			 g_gr->images().get("pics/but1.png"));
-	m_name->changed.connect(boost::bind(&MainMenuMapOptions::changed, this, 0));
-	posy += height + spacing;
-	ta = new UI::Textarea(this, posx, posy - 2, _("Size:"));
-	m_size =
-		new UI::Textarea
-			(this, posx + ta->get_w() + spacing, posy - 2, "512x512");
-	posy += height + spacing;
-	ta = new UI::Textarea(this, posx, posy - 2, _("Nr Players:"));
-	m_nrplayers =
-		new UI::Textarea(this, posx + ta->get_w() + spacing, posy - 2, "1");
-	posy += height + spacing;
-	ta = new UI::Textarea(this, posx, posy - 2, _("Authors:"));
-	m_author =
-		new UI::EditBox
-			(this,
-			 posx + ta->get_w() + spacing, posy,
-			 get_inner_w() - (posx + ta->get_w() + spacing) - spacing, 20,
-			 g_gr->images().get("pics/but1.png"));
-	m_author->changed.connect(boost::bind(&MainMenuMapOptions::changed, this, 1));
-	posy += height + spacing;
-	m_descr =
-		new UI::MultilineEditbox
-			(this,
-			 posx, posy,
-			 get_inner_w() - spacing - posx, get_inner_h() - 25 - spacing - posy,
-			 parent.egbase().map().get_description());
-	m_descr->changed.connect(boost::bind(&MainMenuMapOptions::editbox_changed, this));
-
-	UI::Button * btn =
-		new UI::Button
-			(this, "set_origin",
-			 5, get_inner_h() - 25, get_inner_w() - 10, 20,
-			 g_gr->images().get("pics/but0.png"),
-			 _("Set origin"),
-			 _
-				("Set the position that will have the coordinates (0, 0). This will "
-				 "be the top-left corner of a generated minimap."));
-	btn->sigclicked.connect
-		(boost::bind
-		 (&EditorInteractive::select_tool, &parent,
-		  boost::ref(parent.tools.set_origin), EditorTool::First));
+		 0, 0, 350, 520,
+		 _("Map Options")),
+	padding_(4),
+	indent_(10),
+	labelh_(20),
+	checkbox_space_(25),
+	butw_((get_inner_w() - 3 * padding_) / 2),
+	buth_(20),
+	max_w_(get_inner_w() - 2 * padding_),
+	ok_(
+		this, "ok",
+		padding_, get_inner_h() - padding_ - buth_,
+		butw_, buth_,
+		g_gr->images().get("pics/but5.png"),
+		_("OK")),
+	cancel_(
+		this, "cancel",
+		butw_ + 2 * padding_, get_inner_h() - padding_ - buth_,
+		butw_, buth_,
+		g_gr->images().get("pics/but1.png"),
+		_("Cancel")),
+	tab_box_(this, padding_, padding_, UI::Box::Vertical, max_w_, get_inner_h(), 0),
+	tabs_(&tab_box_, 0, 0, nullptr),
+
+	main_box_(&tabs_, padding_, padding_, UI::Box::Vertical, max_w_, get_inner_h(), 0),
+	tags_box_(&tabs_, padding_, padding_, UI::Box::Vertical, max_w_, get_inner_h(), 0),
+	teams_box_(&tabs_, padding_, padding_, UI::Box::Vertical, max_w_, get_inner_h(), 0),
+
+	name_(&main_box_, 0, 0, max_w_, labelh_, g_gr->images().get("pics/but1.png")),
+	author_(&main_box_, 0, 0, max_w_, labelh_, g_gr->images().get("pics/but1.png")),
+	size_(&main_box_, 0, 0, max_w_ - indent_, labelh_, ""),
+
+	teams_list_(&teams_box_, 0, 0, max_w_, 60, UI::Align_Left, true),
+
+	modal_(modal) {
+
+	descr_ = new UI::MultilineEditbox(
+					&main_box_, 0, 0, max_w_, 9 * labelh_, "", g_gr->images().get("pics/but1.png"));
+	hint_ = new UI::MultilineEditbox(
+				  &main_box_, 0, 0, max_w_, 4 * labelh_, "", g_gr->images().get("pics/but1.png"));
+
+	main_box_.add(new UI::Textarea(&main_box_, 0, 0, max_w_, labelh_, _("Map Name:")), UI::Box::AlignLeft);
+	main_box_.add(&name_, UI::Box::AlignLeft);
+	main_box_.add_space(indent_);
+
+	main_box_.add(new UI::Textarea(&main_box_, 0, 0, max_w_, labelh_, _("Authors:")), UI::Box::AlignLeft);
+	main_box_.add(&author_, UI::Box::AlignLeft);
+	main_box_.add_space(indent_);
+
+	main_box_.add(new UI::Textarea(&main_box_, 0, 0, max_w_, labelh_, _("Description:")), UI::Box::AlignLeft);
+	main_box_.add(descr_, UI::Box::AlignLeft);
+	main_box_.add_space(indent_);
+
+	main_box_.add(new UI::Textarea(&main_box_, 0, 0, max_w_, labelh_, _("Hint (optional):")), UI::Box::AlignLeft);
+	main_box_.add(hint_, UI::Box::AlignLeft);
+	main_box_.add_space(indent_);
+
+	main_box_.add(&size_, UI::Box::AlignLeft);
+	main_box_.add_space(indent_);
+
+	main_box_.set_size(max_w_, get_inner_h() - buth_ - 2 * padding_);
+
+	tags_box_.add(new UI::Textarea(&tags_box_, 0, 0, max_w_, labelh_, _("Tags:")), UI::Box::AlignLeft);
+	add_tag_checkbox(&tags_box_, "unbalanced", _("Unbalanced"));
+	add_tag_checkbox(&tags_box_, "seafaring", _("Seafaring"));
+	add_tag_checkbox(&tags_box_, "ffa", _("Free for all"));
+	add_tag_checkbox(&tags_box_, "1v1", _("1v1"));
+	add_tag_checkbox(&tags_box_, "2teams", _("Teams of 2"));
+	add_tag_checkbox(&tags_box_, "3teams", _("Teams of 3"));
+	add_tag_checkbox(&tags_box_, "4teams", _("Teams of 4"));
+	tags_box_.set_size(max_w_, get_inner_h() - buth_ - 2 * padding_);
+
+	teams_box_.add(new UI::Textarea(&teams_box_, 0, 0, max_w_, labelh_, _("Suggested Teams:")), UI::Box::AlignLeft);
+	teams_box_.add(&teams_list_, UI::Box::AlignLeft);
+	// TODO(GunChleoc): We need team images in the listselect here,
+	// so map editors will be able to delete entries.
+	// This is waiting for the new RT renderer.
+	teams_list_.add("Not implemented yet.", "", nullptr, false);
+
+	unsigned int nr_players = static_cast<unsigned int>(eia().egbase().map().get_nrplayers());
+	std::string players = (boost::format(ngettext("%u Player", "%u Players", nr_players)) % nr_players).str();
+	teams_box_.add(new UI::Textarea(&teams_box_, 0, 0, max_w_, labelh_, players), UI::Box::AlignLeft);
+	teams_box_.set_size(max_w_, get_inner_h() - buth_ - 2 * padding_);
+
+	tab_box_.add(&tabs_, UI::Box::AlignLeft, true);
+	tabs_.add("main_map_options", g_gr->images().get("pics/menu_toggle_minimap.png"), &main_box_, _("Main Options"));
+	tabs_.add("map_tags", g_gr->images().get("pics/checkbox_checked.png"), &tags_box_, _("Tags"));
+	tabs_.add("map_teams", g_gr->images().get("pics/editor_menu_player_menu.png"), &teams_box_, _("Teams"));
+	tabs_.set_size(max_w_, get_inner_h() - buth_ - 2 * padding_);
+	tab_box_.set_size(max_w_, get_inner_h() - buth_ - 2 * padding_);
+
+	name_.changed.connect(boost::bind(&MainMenuMapOptions::changed, this));
+	author_.changed.connect(boost::bind(&MainMenuMapOptions::changed, this));
+	descr_->changed.connect(boost::bind(&MainMenuMapOptions::changed, this));
+
+	ok_.sigclicked.connect
+		(boost::bind(&MainMenuMapOptions::clicked_ok, boost::ref(*this)));
+	ok_.set_enabled(false);
+	cancel_.sigclicked.connect
+		(boost::bind(&MainMenuMapOptions::clicked_cancel, boost::ref(*this)));
 
 	update();
+	center_to_parent();
+	move_to_top();
 }
 
 /**
@@ -115,34 +159,68 @@
 */
 void MainMenuMapOptions::update() {
 	const Widelands::Map & map = eia().egbase().map();
+	author_.set_text(map.get_author());
+	name_.set_text(map.get_name());
+	size_.set_text((boost::format(_("Size: %1% x %2%"))
+						 % map.get_width()
+						 % map.get_height()).str());
+	descr_->set_text(map.get_description());
+	hint_->set_text(map.get_hint());
 
-	m_size     ->set_text((boost::format(_("%1$ix%2$i"))
-								  % map.get_width()
-								  % map.get_height()).str());
-	m_author->set_text(map.get_author());
-	m_name  ->set_text(map.get_name());
-	m_nrplayers->set_text(std::to_string(static_cast<unsigned int>(map.get_nrplayers())));
-	m_descr ->set_text(map.get_description());
+	std::set<std::string> tags = map.get_tags();
+	for (std::pair<std::string, UI::Checkbox*> tag : tags_checkboxes_) {
+		tag.second->set_state(tags.count(tag.first) > 0);
+	}
 }
 
 
 /**
  * Called when one of the editboxes are changed
 */
-void MainMenuMapOptions::changed(int32_t const id) {
-	if        (id == 0) {
-		eia().egbase().map().set_name(m_name->text());
-	} else if (id == 1) {
-		eia().egbase().map().set_author(m_author->text());
-		g_options.pull_section("global").set_string
-			("realname", m_author->text());
-	}
-	update();
-}
-
-/**
- * Called when the editbox has changed
+void MainMenuMapOptions::changed() {
+	ok_.set_enabled(true);
+}
+
+void MainMenuMapOptions::clicked_ok() {
+	eia().egbase().map().set_name(name_.text());
+	eia().egbase().map().set_author(author_.text());
+	g_options.pull_section("global").set_string("realname", author_.text());
+	eia().egbase().map().set_description(descr_->get_text());
+	eia().egbase().map().set_hint(hint_->get_text());
+
+	eia().egbase().map().clear_tags();
+	for (std::pair<std::string, UI::Checkbox*> tag : tags_checkboxes_) {
+		if (tag.second->get_state()) {
+			eia().egbase().map().add_tag(tag.first);
+		}
+	}
+
+	if (modal_) {
+		end_modal(1);
+	} else {
+		die();
+	}
+}
+
+void MainMenuMapOptions::clicked_cancel() {
+	if (modal_) {
+		end_modal(0);
+	} else {
+		die();
+	}
+}
+
+/*
+ * Add a tag to the checkboxes
  */
-void MainMenuMapOptions::editbox_changed() {
-	eia().egbase().map().set_description(m_descr->get_text());
+void MainMenuMapOptions::add_tag_checkbox(UI::Box* parent, std::string tag, std::string displ_name) {
+	UI::Box* box = new UI::Box(parent, 0, 0, UI::Box::Horizontal, max_w_, checkbox_space_, 0);
+	UI::Checkbox* cb = new UI::Checkbox(box, Point(0, 0));
+	box->add(cb, UI::Box::AlignLeft, true);
+	box->add_space(padding_);
+	box->add(new UI::Textarea(box, displ_name, UI::Align_CenterLeft), UI::Box::AlignLeft);
+	box->add_space(checkbox_space_);
+	parent->add(box, UI::Box::AlignLeft);
+	parent->add_space(padding_);
+	tags_checkboxes_.emplace(tag, cb);
 }

=== modified file 'src/editor/ui_menus/editor_main_menu_map_options.h'
--- src/editor/ui_menus/editor_main_menu_map_options.h	2014-09-10 14:48:40 +0000
+++ src/editor/ui_menus/editor_main_menu_map_options.h	2015-03-30 10:39:30 +0000
@@ -20,15 +20,17 @@
 #ifndef WL_EDITOR_UI_MENUS_EDITOR_MAIN_MENU_MAP_OPTIONS_H
 #define WL_EDITOR_UI_MENUS_EDITOR_MAIN_MENU_MAP_OPTIONS_H
 
+#include "ui_basic/box.h"
 #include "ui_basic/button.h"
+#include "ui_basic/checkbox.h"
+#include "ui_basic/editbox.h"
+#include "ui_basic/listselect.h"
+#include "ui_basic/multilineeditbox.h"
+#include "ui_basic/tabpanel.h"
+#include "ui_basic/textarea.h"
 #include "ui_basic/window.h"
 
 struct EditorInteractive;
-namespace UI {
-struct EditBox;
-struct MultilineEditbox;
-struct Textarea;
-}
 
 /**
  * This is the Main Options Menu. Here, information
@@ -36,16 +38,35 @@
  * author, name and description
 */
 struct MainMenuMapOptions : public UI::Window {
-	MainMenuMapOptions(EditorInteractive &);
+	MainMenuMapOptions(EditorInteractive &, bool modal = false);
 
 private:
 	EditorInteractive & eia();
-	void changed(int32_t);
-	void editbox_changed();
-	UI::MultilineEditbox * m_descr;
-	UI::Textarea * m_nrplayers, * m_size;
-	UI::EditBox * m_name, * m_author;
+	void changed();
 	void update();
+	void clicked_ok();
+	void clicked_cancel();
+	void add_tag_checkbox(UI::Box* box, std::string tag, std::string displ_name);
+
+	const int padding_, indent_, labelh_, checkbox_space_, butw_, buth_, max_w_;
+
+	UI::Button ok_, cancel_;
+
+	UI::Box tab_box_;
+	UI::TabPanel tabs_;
+	UI::Box main_box_;
+	UI::Box tags_box_;
+	UI::Box teams_box_;
+
+	UI::EditBox name_, author_;
+	UI::Textarea size_;
+	UI::MultilineEditbox* descr_;
+	UI::MultilineEditbox* hint_;
+	UI::Listselect<std::string> teams_list_;
+
+	// Tag, Checkbox
+	std::map<std::string, UI::Checkbox*> tags_checkboxes_;
+	bool modal_;
 };
 
 #endif  // end of include guard: WL_EDITOR_UI_MENUS_EDITOR_MAIN_MENU_MAP_OPTIONS_H

=== modified file 'src/editor/ui_menus/editor_main_menu_new_map.cc'
--- src/editor/ui_menus/editor_main_menu_new_map.cc	2014-11-30 18:49:38 +0000
+++ src/editor/ui_menus/editor_main_menu_new_map.cc	2015-03-30 10:39:30 +0000
@@ -105,7 +105,7 @@
 	UI::Button * createbtn = new UI::Button
 		(this, "create_map",
 		 posx, posy, width, height,
-		 g_gr->images().get("pics/but0.png"),
+		 g_gr->images().get("pics/but5.png"),
 		 _("Create Map"));
 	createbtn->sigclicked.connect(boost::bind(&MainMenuNewMap::clicked_create_map, this));
 }

=== modified file 'src/editor/ui_menus/editor_main_menu_random_map.cc'
--- src/editor/ui_menus/editor_main_menu_random_map.cc	2014-11-30 18:49:38 +0000
+++ src/editor/ui_menus/editor_main_menu_random_map.cc	2015-03-30 10:39:30 +0000
@@ -328,7 +328,7 @@
 	m_goButton = new UI::Button
 		(this, "generate_map",
 		 posx, posy, width, height,
-		 g_gr->images().get("pics/but0.png"),
+		 g_gr->images().get("pics/but5.png"),
 		 _("Generate Map"));
 	m_goButton->sigclicked.connect(boost::bind(&MainMenuNewRandomMap::clicked_create_map, this));
 	posy += height + spacing;

=== modified file 'src/editor/ui_menus/editor_main_menu_save_map.cc'
--- src/editor/ui_menus/editor_main_menu_save_map.cc	2015-01-27 20:43:52 +0000
+++ src/editor/ui_menus/editor_main_menu_save_map.cc	2015-03-30 10:39:30 +0000
@@ -22,7 +22,6 @@
 #include <cstdio>
 #include <cstring>
 #include <memory>
-#include <string>
 
 #include <boost/algorithm/string.hpp>
 #include <boost/format.hpp>
@@ -31,6 +30,7 @@
 #include "base/macros.h"
 #include "base/wexception.h"
 #include "editor/editorinteractive.h"
+#include "editor/ui_menus/editor_main_menu_map_options.h"
 #include "editor/ui_menus/editor_main_menu_save_map_make_directory.h"
 #include "graphic/graphic.h"
 #include "io/filesystem/filesystem.h"
@@ -39,160 +39,109 @@
 #include "map_io/map_saver.h"
 #include "map_io/widelands_map_loader.h"
 #include "profile/profile.h"
-#include "ui_basic/button.h"
-#include "ui_basic/editbox.h"
-#include "ui_basic/listselect.h"
 #include "ui_basic/messagebox.h"
-#include "ui_basic/multilinetextarea.h"
-#include "ui_basic/textarea.h"
+#include "wui/mapdetails.h"
+#include "wui/maptable.h"
 
-inline EditorInteractive & MainMenuSaveMap::eia() {
+inline EditorInteractive& MainMenuSaveMap::eia() {
 	return dynamic_cast<EditorInteractive&>(*get_parent());
 }
 
-
-MainMenuSaveMap::MainMenuSaveMap(EditorInteractive & parent)
-	: UI::Window(&parent, "save_map_menu", 0, 0, 560, 330, _("Save Map"))
-{
-	int32_t const spacing =  5;
-	int32_t const offsx   = spacing;
-	int32_t const offsy   = 10;
-	int32_t posx          = offsx;
-	int32_t posy          = offsy;
-	int32_t const descr_label_w = 100;
-
-	m_ls =
-		new UI::Listselect<const char *>
-			(this,
-			 posx, posy,
-			 get_inner_w() / 2 - spacing, get_inner_h() - spacing - offsy - 60);
-	m_ls->clicked.connect(boost::bind(&MainMenuSaveMap::clicked_item, this, _1));
-	m_ls->double_clicked.connect(boost::bind(&MainMenuSaveMap::double_clicked_item, this, _1));
-	m_ls->focus();
-	m_editbox =
-		new UI::EditBox
-			(this,
-			 posx, posy + get_inner_h() - spacing - offsy - 60 + 3,
-			 get_inner_w() / 2 - spacing, 20,
-			 g_gr->images().get("pics/but1.png"), UI::Align::Align_Left);
-	m_editbox->set_text(parent.egbase().map().get_name());
-	m_editbox->changed.connect(boost::bind(&MainMenuSaveMap::edit_box_changed, this));
-
-	posx = get_inner_w() / 2 + spacing;
-	new UI::Textarea
-		(this, posx, posy, descr_label_w, 20, _("Name:"), UI::Align_CenterLeft);
-	m_name =
-		new UI::MultilineTextarea
-			(this, posx + descr_label_w, posy, 200, 40, "---", UI::Align_CenterLeft);
-	posy += 40 + spacing;
-
-	new UI::Textarea
-		(this, posx, posy, descr_label_w, 20, _("Authors:"), UI::Align_CenterLeft);
-	m_author =
-		new UI::Textarea
-			(this, posx + descr_label_w, posy, 200, 20, "---", UI::Align_CenterLeft);
-	posy += 20 + spacing;
-
-	new UI::Textarea
-		(this, posx, posy, descr_label_w, 20, _("Size:"), UI::Align_CenterLeft);
-	m_size =
-		new UI::Textarea
-			(this, posx + descr_label_w, posy, 200, 20, "---", UI::Align_CenterLeft);
-	posy += 20 + spacing;
-
-	new UI::Textarea
-		(this, posx, posy, descr_label_w, 20, _("Players:"), UI::Align_CenterLeft);
-	m_nrplayers =
-		new UI::Textarea
-			(this, posx + descr_label_w, posy, 200, 20, "---", UI::Align_CenterLeft);
-	posy += 20 + spacing;
-
-	new UI::Textarea
-		(this, posx, posy, descr_label_w, 20, _("Descr: "), UI::Align_CenterLeft);
-	m_descr =
-		new UI::MultilineTextarea
-			(this,
-			 posx + descr_label_w, posy,
-			 get_inner_w() - posx - spacing - descr_label_w,
-			 get_inner_h() - posy - spacing - 40,
-			 "---", UI::Align_CenterLeft);
-
-
-	posy = get_inner_h() - 30;
-
-	m_ok_btn = new UI::Button
-		(this, "ok",
-		 posx, posy,
-		 get_inner_w() / 4 - 1.5 * spacing, 20,
-		 g_gr->images().get("pics/but0.png"),
-		 _("OK"));
-	m_ok_btn->sigclicked.connect(boost::bind(&MainMenuSaveMap::clicked_ok, boost::ref(*this)));
-
-	UI::Button * cancelbtn = new UI::Button
-		(this, "cancel",
-		 posx + get_inner_w() / 4 - spacing / 2, posy,
-		 get_inner_w() / 4 - 1.5 * spacing, 20,
-		 g_gr->images().get("pics/but1.png"),
-		 _("Cancel"));
-	cancelbtn->sigclicked.connect(boost::bind(&MainMenuSaveMap::die, boost::ref(*this)));
-
-	UI::Button * make_directorybtn = new UI::Button
-		(this, "make_directory",
-		 spacing, posy, 185, 20,
-		 g_gr->images().get("pics/but1.png"),
-		 _("Make Directory"));
-	make_directorybtn->sigclicked.connect
-		(boost::bind(&MainMenuSaveMap::clicked_make_directory, boost::ref(*this)));
-
-
-	m_basedir = "maps";
-	m_curdir  = "maps";
-
-	fill_list();
+MainMenuSaveMap::MainMenuSaveMap(EditorInteractive& parent)
+   : MainMenuLoadOrSaveMap(parent, "save_map_menu", _("Save Map")),
+
+     make_directory_(this,
+                     "make_directory",
+                     right_column_x_,
+                     tabley_ + tableh_ + 3 * padding_ - 1,
+                     get_inner_w() - right_column_x_ - padding_,
+                     buth_,
+                     g_gr->images().get("pics/but1.png"),
+                     _("Make Directory")),
+     edit_options_(this,
+                   "edit_options",
+                   right_column_x_,
+                   tabley_ + tableh_ - buth_,
+                   get_inner_w() - right_column_x_ - padding_,
+                   buth_,
+                   g_gr->images().get("pics/but5.png"),
+                   _("Map Options")),
+     editbox_label_(this,
+                    padding_,
+                    tabley_ + tableh_ + 3 * padding_,
+                    butw_,
+                    buth_,
+                    _("Filename:"),
+                    UI::Align::Align_Left) {
+
+	// Make room for edit_options_
+	map_details_.set_size(map_details_.get_w(), map_details_.get_h() - buth_ - padding_);
+
+	table_.selected.connect(boost::bind(&MainMenuSaveMap::clicked_item, boost::ref(*this)));
+	table_.double_clicked.connect(
+	   boost::bind(&MainMenuSaveMap::double_clicked_item, boost::ref(*this)));
+
+	editbox_ = new UI::EditBox(this,
+	                           editbox_label_.get_x() + editbox_label_.get_w() + padding_,
+	                           editbox_label_.get_y(),
+	                           tablew_ - editbox_label_.get_w() - padding_ + 1,
+	                           buth_,
+	                           g_gr->images().get("pics/but1.png"),
+	                           UI::Align::Align_Left);
+
+	editbox_->set_text(parent.egbase().map().get_name());
+	editbox_->changed.connect(boost::bind(&MainMenuSaveMap::edit_box_changed, this));
 	edit_box_changed();
 
-	center_to_parent();
-	move_to_top();
+	ok_.sigclicked.connect(boost::bind(&MainMenuSaveMap::clicked_ok, boost::ref(*this)));
+	cancel_.sigclicked.connect(boost::bind(&MainMenuSaveMap::die, boost::ref(*this)));
+	make_directory_.sigclicked.connect(
+	   boost::bind(&MainMenuSaveMap::clicked_make_directory, boost::ref(*this)));
+	edit_options_.sigclicked.connect(
+	   boost::bind(&MainMenuSaveMap::clicked_edit_options, boost::ref(*this)));
+
+	// We always want the current map's data here
+	const Widelands::Map& map = parent.egbase().map();
+	MapData::MapType maptype;
+
+	if (map.scenario_types() & Widelands::Map::MP_SCENARIO ||
+	    map.scenario_types() & Widelands::Map::SP_SCENARIO) {
+		maptype = MapData::MapType::kScenario;
+	} else {
+		maptype = MapData::MapType::kNormal;
+	}
+
+	MapData mapdata(map, "", maptype);
+
+	map_details_.update(mapdata, false);
 }
 
 /**
  * Called when the ok button was pressed or a file in list was double clicked.
  */
 void MainMenuSaveMap::clicked_ok() {
-	assert(m_ok_btn->enabled());
-	std::string filename = m_editbox->text();
-
-	if (filename == "") //  Maybe a directory is selected.
-		filename = m_ls->get_selected();
-
-	if
-		(g_fs->is_directory(filename.c_str())
-		 &&
-		 !Widelands::WidelandsMapLoader::is_widelands_map(filename))
-	{
-		m_curdir = g_fs->canonicalize_name(filename);
-		m_ls->clear();
-		m_mapfiles.clear();
-		fill_list();
-	} else { //  Ok, save this map
-		Widelands::Map & map = eia().egbase().map();
-		if (map.get_name() != _("No Name")) {
+	assert(ok_.enabled());
+	std::string filename = editbox_->text();
+
+	if (filename == "") {  //  Maybe a directory is selected.
+		filename = table_.get_map()->filename;
+	}
+
+	if (g_fs->is_directory(filename.c_str()) &&
+	    !Widelands::WidelandsMapLoader::is_widelands_map(filename)) {
+		curdir_ = g_fs->canonicalize_name(filename);
+		fill_table();
+	} else {  //  Ok, save this map
+		Widelands::Map& map = eia().egbase().map();
+		if (map.get_name() == _("No Name")) {
 			std::string::size_type const filename_size = filename.size();
-			map.set_name
-				((4 <= filename_size
-				  && filename[filename_size - 1] == 'f'
-				  && filename[filename_size - 2] == 'm'
-				  && filename[filename_size - 3] == 'w'
-				  && filename[filename_size - 4] == '.'
-				  ?
-				  filename.substr(0, filename_size - 4) : filename)
-				 .c_str());
+			map.set_name(4 <= filename_size && boost::iends_with(filename, WLMF_SUFFIX) ?
+			                filename.substr(0, filename_size - 4) :
+			                filename);
 		}
-		if
-			(save_map
-			 	(filename,
-			 	 ! g_options.pull_section("global").get_bool("nozip", false)))
+		if (save_map(filename, !g_options.pull_section("global").get_bool("nozip", false))) {
 			die();
+		}
 	}
 }
 
@@ -202,149 +151,67 @@
 void MainMenuSaveMap::clicked_make_directory() {
 	MainMenuSaveMapMakeDirectory md(this, _("unnamed"));
 	if (md.run()) {
-		g_fs->ensure_directory_exists(m_basedir);
+		g_fs->ensure_directory_exists(basedir_);
 		//  create directory
-		std::string fullname = m_curdir;
-		fullname            += "/";
-		fullname            += md.get_dirname();
+		std::string fullname = curdir_;
+		fullname += "/";
+		fullname += md.get_dirname();
 		g_fs->make_directory(fullname);
-		m_ls->clear();
-		m_mapfiles.clear();
-		fill_list();
+		fill_table();
+	}
+}
+
+void MainMenuSaveMap::clicked_edit_options() {
+	MainMenuMapOptions mo(eia(), true);
+	if (mo.run()) {
+		const Widelands::Map& map = eia().egbase().map();
+		MapData::MapType maptype;
+
+		if (map.scenario_types() & Widelands::Map::MP_SCENARIO ||
+		    map.scenario_types() & Widelands::Map::SP_SCENARIO) {
+			maptype = MapData::MapType::kScenario;
+		} else {
+			maptype = MapData::MapType::kNormal;
+		}
+
+		MapData mapdata(map, editbox_->text(), maptype);
+
+		map_details_.update(mapdata, false);
 	}
 }
 
 /**
  * called when an item was selected
  */
-void MainMenuSaveMap::clicked_item(uint32_t) {
-	const char * const name = m_ls->get_selected();
-
-	if (Widelands::WidelandsMapLoader::is_widelands_map(name)) {
-		Widelands::Map map;
-		{
-			std::unique_ptr<Widelands::MapLoader> const ml
-				(map.get_correct_loader(name));
-			ml->preload_map(true); // This has worked before, no problem
-		}
-
-		m_editbox->set_text(FileSystem::fs_filename(name));
-
-		m_name  ->set_text(map.get_name       ());
-		m_name  ->set_tooltip(map.get_name    ());
-		m_author->set_text(map.get_author     ());
-		m_descr ->set_text(map.get_description());
-
-		m_nrplayers->set_text(std::to_string(static_cast<unsigned int>(map.get_nrplayers())));
-
-		m_size->set_text((boost::format(_("%1$ix%2$i"))
-								% map.get_width() % map.get_height()).str());
-	} else {
-		m_name     ->set_text(FileSystem::fs_filename(name));
-		m_name     ->set_tooltip("");
-		m_author   ->set_text("");
-		m_nrplayers->set_text("");
-		m_size     ->set_text("");
-		if (g_fs->is_directory(name)) {
-			m_name->set_tooltip((boost::format(_("Directory: %s"))
-										% FileSystem::fs_filename(name)).str());
-			m_descr->set_text((boost::format("\\<%s\\>") % _("directory")).str());
-		} else {
-			const std::string not_map_string = _("Not a map file");
-			m_name->set_tooltip(not_map_string);
-			m_descr->set_text((boost::format("\\<%s\\>") % not_map_string).str());
-		}
-
+void MainMenuSaveMap::clicked_item() {
+	// Only change editbox contents
+	if (table_.has_selection()) {
+		const MapData& mapdata = *table_.get_map();
+		if (mapdata.maptype != MapData::MapType::kDirectory) {
+			editbox_->set_text(FileSystem::fs_filename(table_.get_map()->filename.c_str()));
+			edit_box_changed();
+		}
 	}
-	edit_box_changed();
 }
 
 /**
  * An Item has been doubleclicked
  */
-void MainMenuSaveMap::double_clicked_item(uint32_t) {
-	const char * const name = m_ls->get_selected();
-
-	if (g_fs->is_directory(name) && !Widelands::WidelandsMapLoader::is_widelands_map(name)) {
-		m_curdir = name;
-		m_ls->clear();
-		m_mapfiles.clear();
-		fill_list();
-	} else
+void MainMenuSaveMap::double_clicked_item() {
+	const MapData& mapdata = *table_.get_map();
+	if (mapdata.maptype == MapData::MapType::kDirectory) {
+		curdir_ = mapdata.filename;
+		fill_table();
+	} else {
 		clicked_ok();
-}
-
-/**
- * fill the file list
- */
-void MainMenuSaveMap::fill_list() {
-	// Fill it with all files we find.
-	m_mapfiles = g_fs->list_directory(m_curdir);
-
-	// First, we add all directories. We manually add the parent directory
-	if (m_curdir != m_basedir) {
-#ifndef _WIN32
-		m_parentdir = m_curdir.substr(0, m_curdir.rfind('/'));
-#else
-		m_parentdir = m_curdir.substr(0, m_curdir.rfind('\\'));
-#endif
-
-		m_ls->add
-				/** TRANSLATORS: Parent directory */
-				((boost::format("\\<%s\\>") % _("parent")).str(),
-				 m_parentdir.c_str(),
-				 g_gr->images().get("pics/ls_dir.png"));
-	}
-
-	const FilenameSet::const_iterator mapfiles_end = m_mapfiles.end();
-	for
-		(FilenameSet::const_iterator pname = m_mapfiles.begin();
-		 pname != mapfiles_end;
-		 ++pname)
-	{
-		const char * const name = pname->c_str();
-		if
-			(strcmp(FileSystem::fs_filename(name), ".")    &&
-			 strcmp(FileSystem::fs_filename(name), "..")   &&
-			 g_fs->is_directory(name)                       &&
-			 !Widelands::WidelandsMapLoader::is_widelands_map(name))
-
-		m_ls->add
-			(FileSystem::fs_filename(name),
-			 name,
-			 g_gr->images().get("pics/ls_dir.png"));
-	}
-
-	Widelands::Map map;
-
-	for
-		(FilenameSet::const_iterator pname = m_mapfiles.begin();
-		 pname != mapfiles_end;
-		 ++pname)
-	{
-		char const * const name = pname->c_str();
-
-		// we do not list S2 files since we only write wmf
-		std::unique_ptr<Widelands::MapLoader> ml(map.get_correct_loader(name));
-		if (upcast(Widelands::WidelandsMapLoader, wml, ml.get())) {
-			try {
-				wml->preload_map(true);
-				m_ls->add
-					(FileSystem::filename_without_ext(name),
-					 name,
-					 g_gr->images().get("pics/ls_wlmap.png"));
-			} catch (const WException &) {} //  we simply skip illegal entries
-		}
-	}
-	if (m_ls->size())
-		m_ls->select(0);
+	}
 }
 
 /**
  * The editbox was changed. Enable ok button
  */
 void MainMenuSaveMap::edit_box_changed() {
-	m_ok_btn->set_enabled(m_editbox->text().size());
+	ok_.set_enabled(!editbox_->text().empty());
 }
 
 /**
@@ -356,47 +223,41 @@
  */
 bool MainMenuSaveMap::save_map(std::string filename, bool binary) {
 	//  Make sure that the base directory exists.
-	g_fs->ensure_directory_exists(m_basedir);
+	g_fs->ensure_directory_exists(basedir_);
 
 	//  OK, first check if the extension matches (ignoring case).
 	if (!boost::iends_with(filename, WLMF_SUFFIX))
 		filename += WLMF_SUFFIX;
 
 	//  append directory name
-	std::string complete_filename = m_curdir;
-	complete_filename            += "/";
-	complete_filename            += filename;
+	std::string complete_filename = curdir_;
+	complete_filename += "/";
+	complete_filename += filename;
 
 	//  Check if file exists. If so, show a warning.
 	if (g_fs->file_exists(complete_filename)) {
-		std::string s =
-			(boost::format(_("A file with the name ‘%s’ already exists. Overwrite?"))
-				% FileSystem::fs_filename(filename.c_str())).str();
-		UI::WLMessageBox mbox
-			(&eia(), _("Error Saving Map!"), s, UI::WLMessageBox::YESNO);
+		std::string s = (boost::format(_("A file with the name ‘%s’ already exists. Overwrite?")) %
+		                 FileSystem::fs_filename(filename.c_str())).str();
+		UI::WLMessageBox mbox(&eia(), _("Error Saving Map!"), s, UI::WLMessageBox::YESNO);
 		if (!mbox.run())
 			return false;
 
 		g_fs->fs_unlink(complete_filename);
 	}
 
-	std::unique_ptr<FileSystem> fs
-			(g_fs->create_sub_file_system(complete_filename, binary ? FileSystem::ZIP : FileSystem::DIR));
+	std::unique_ptr<FileSystem> fs(
+	   g_fs->create_sub_file_system(complete_filename, binary ? FileSystem::ZIP : FileSystem::DIR));
 	Widelands::MapSaver wms(*fs, eia().egbase());
 	try {
 		wms.save();
 		eia().set_need_save(false);
-	} catch (const std::exception & e) {
-		std::string s =
-			_
-			("Error Saving Map!\nSaved map file may be corrupt!\n\nReason "
-			 "given:\n");
+	} catch (const std::exception& e) {
+		std::string s = _("Error Saving Map!\nSaved map file may be corrupt!\n\nReason "
+		                  "given:\n");
 		s += e.what();
-		UI::WLMessageBox  mbox
-			(&eia(), _("Error Saving Map!"), s, UI::WLMessageBox::OK);
+		UI::WLMessageBox mbox(&eia(), _("Error Saving Map!"), s, UI::WLMessageBox::OK);
 		mbox.run();
 	}
 	die();
-
 	return true;
 }

=== modified file 'src/editor/ui_menus/editor_main_menu_save_map.h'
--- src/editor/ui_menus/editor_main_menu_save_map.h	2014-09-25 08:58:07 +0000
+++ src/editor/ui_menus/editor_main_menu_save_map.h	2015-03-30 10:39:30 +0000
@@ -20,46 +20,38 @@
 #ifndef WL_EDITOR_UI_MENUS_EDITOR_MAIN_MENU_SAVE_MAP_H
 #define WL_EDITOR_UI_MENUS_EDITOR_MAIN_MENU_SAVE_MAP_H
 
-#include "io/filesystem/filesystem.h"
-#include "ui_basic/window.h"
+#include <string>
 
-struct EditorInteractive;
-namespace UI {
-struct Button;
-struct EditBox;
-template <typename T> struct Listselect;
-struct MultilineTextarea;
-struct Textarea;
-}
+#include "editor/editorinteractive.h"
+#include "editor/ui_menus/editor_main_menu_load_or_save_map.h"
+#include "ui_basic/button.h"
+#include "ui_basic/editbox.h"
+#include "ui_basic/textarea.h"
 
 /**
  * Choose a filename and save your brand new created map
 */
-struct MainMenuSaveMap : public UI::Window {
-	MainMenuSaveMap(EditorInteractive &);
+struct MainMenuSaveMap : public MainMenuLoadOrSaveMap {
+	MainMenuSaveMap(EditorInteractive& parent);
+
+protected:
+	void clicked_ok() override;
 
 private:
-	EditorInteractive & eia();
-	void clicked_ok            ();
+	EditorInteractive& eia();
+
 	void clicked_make_directory();
-	void        clicked_item(uint32_t);
-	void double_clicked_item(uint32_t);
+	void clicked_edit_options();
+	void clicked_item();
+	void double_clicked_item();
 	void edit_box_changed();
 
-	void fill_list();
 	bool save_map(std::string, bool);
 
-	UI::EditBox * m_editbox;
-	UI::MultilineTextarea * m_name;
-	UI::Textarea * m_author, * m_size, * m_nrplayers;
-	UI::MultilineTextarea * m_descr;
-	UI::Listselect<const char *> * m_ls;
-	UI::Button * m_ok_btn;
+	UI::Button make_directory_, edit_options_;
 
-	std::string   m_basedir;
-	std::string   m_curdir;
-	std::string   m_parentdir;
-	FilenameSet m_mapfiles;
+	UI::Textarea editbox_label_;
+	UI::EditBox* editbox_;
 };
 
 #endif  // end of include guard: WL_EDITOR_UI_MENUS_EDITOR_MAIN_MENU_SAVE_MAP_H

=== modified file 'src/editor/ui_menus/editor_main_menu_save_map_make_directory.cc'
--- src/editor/ui_menus/editor_main_menu_save_map_make_directory.cc	2014-09-19 09:07:14 +0000
+++ src/editor/ui_menus/editor_main_menu_save_map_make_directory.cc	2015-03-30 10:39:30 +0000
@@ -21,52 +21,43 @@
 
 #include "base/i18n.h"
 #include "graphic/graphic.h"
-#include "ui_basic/button.h"
-#include "ui_basic/editbox.h"
-#include "ui_basic/textarea.h"
-#include "ui_basic/window.h"
 
 MainMenuSaveMapMakeDirectory::MainMenuSaveMapMakeDirectory
-	(UI::Panel * const parent, char const * dirname)
-:
-UI::Window(parent, "make_directory", 0, 0, 230, 120, _("Make Directory"))
-{
-	int32_t const spacing =  5;
-	int32_t const offsy   = 30;
-	int32_t       posy    = offsy;
-
-	new UI::Textarea(this, spacing, posy, _("Enter Directory Name: "));
-	posy += 20 + spacing;
-
-	m_edit =
-		new UI::EditBox
-			(this, spacing, posy, get_inner_w() - 2 * spacing, 20,
-			 g_gr->images().get("pics/but1.png"));
-	m_edit->set_text(dirname);
-	m_dirname = dirname;
-	m_edit->changed.connect(boost::bind(&MainMenuSaveMapMakeDirectory::edit_changed, this));
-
-	posy = get_inner_h() - 30;
-
-	m_ok_button = new
-		UI::Button
-		(this, "ok",
-		 get_inner_w() / 2 - spacing - 80, posy, 80, 20,
-		 g_gr->images().get("pics/but0.png"),
-		 _("OK"),
-		 std::string(),
-		 m_dirname.size());
-	m_ok_button->sigclicked.connect
+	(UI::Panel * const parent, char const * dirname) :
+	UI::Window(parent, "make_directory", 0, 0, 330, 100, _("Make Directory")),
+	padding_(5),
+	butw_(get_inner_w() / 2 - 3 * padding_),
+	buth_(20),
+	dirname_(dirname),
+	vbox_(this, padding_, padding_, UI::Box::Vertical,
+		  get_inner_w() - 2 * padding_, get_inner_h() - 3 * padding_ - buth_, padding_ / 2),
+	label_(&vbox_, 0, 0, get_inner_w() - 2 * padding_, buth_, _("Enter Directory Name: "), UI::Align_Left),
+	edit_(&vbox_, 0, 0, get_inner_w() - 2 * padding_, buth_, g_gr->images().get("pics/but1.png")),
+	ok_button_(
+		this, "ok",
+		padding_, get_inner_h() - padding_ - buth_,
+		butw_, buth_,
+		g_gr->images().get("pics/but5.png"),
+		_("OK")),
+	cancel_button_(
+		this, "cancel",
+		get_inner_w() - butw_ - padding_, get_inner_h() - padding_ - buth_,
+		butw_, buth_,
+		g_gr->images().get("pics/but1.png"),
+		_("Cancel")) {
+
+	vbox_.add(&label_, UI::Box::AlignLeft);
+	vbox_.add_space(padding_);
+	vbox_.add(&edit_, UI::Box::AlignLeft);
+	vbox_.set_size(get_inner_w() - 2 * padding_, get_inner_h() - 3 * padding_ - buth_);
+
+	edit_.set_text(dirname_);
+	edit_.changed.connect(boost::bind(&MainMenuSaveMapMakeDirectory::edit_changed, this));
+	ok_button_.sigclicked.connect
 		(boost::bind(&MainMenuSaveMapMakeDirectory::end_modal, boost::ref(*this), 1));
-
-	UI::Button * cancelbtn = new UI::Button
-		(this, "cancel",
-		 get_inner_w() / 2 + spacing, posy, 80, 20,
-		 g_gr->images().get("pics/but1.png"),
-		 _("Cancel"));
-	cancelbtn->sigclicked.connect
+	ok_button_.set_enabled(false);
+	cancel_button_.sigclicked.connect
 		(boost::bind(&MainMenuSaveMapMakeDirectory::end_modal, boost::ref(*this), 0));
-
 	center_to_parent();
 }
 
@@ -75,9 +66,7 @@
  * Editbox changed
  */
 void MainMenuSaveMapMakeDirectory::edit_changed() {
-	const std::string & text = m_edit->text();
-	if (text.size()) {
-		m_ok_button->set_enabled(true);
-		m_dirname = text;
-	}
+	const std::string& text = edit_.text();
+	ok_button_.set_enabled(!text.empty());
+	dirname_ = text;
 }

=== modified file 'src/editor/ui_menus/editor_main_menu_save_map_make_directory.h'
--- src/editor/ui_menus/editor_main_menu_save_map_make_directory.h	2014-09-10 14:08:25 +0000
+++ src/editor/ui_menus/editor_main_menu_save_map_make_directory.h	2015-03-30 10:39:30 +0000
@@ -20,15 +20,14 @@
 #ifndef WL_EDITOR_UI_MENUS_EDITOR_MAIN_MENU_SAVE_MAP_MAKE_DIRECTORY_H
 #define WL_EDITOR_UI_MENUS_EDITOR_MAIN_MENU_SAVE_MAP_MAKE_DIRECTORY_H
 
-#include <cstring>
 #include <string>
 
+#include "ui_basic/box.h"
+#include "ui_basic/button.h"
+#include "ui_basic/editbox.h"
+#include "ui_basic/textarea.h"
 #include "ui_basic/window.h"
 
-namespace UI {
-struct EditBox;
-struct Button;
-}
 
 /**
  * Show a small modal dialog allowing the user to enter
@@ -39,12 +38,17 @@
 struct MainMenuSaveMapMakeDirectory : public UI::Window {
 	MainMenuSaveMapMakeDirectory(UI::Panel *, char const *);
 
-	char const * get_dirname() {return m_dirname.c_str();}
+	char const * get_dirname() {return dirname_.c_str();}
 
 private:
-	std::string               m_dirname;
-	UI::EditBox             * m_edit;
-	UI::Button * m_ok_button;
+	const int padding_;
+	const int butw_, buth_;
+	std::string dirname_;
+	UI::Box vbox_;
+	UI::Textarea label_;
+	UI::EditBox edit_;
+	UI::Button ok_button_;
+	UI::Button cancel_button_;
 	void edit_changed();
 };
 

=== modified file 'src/editor/ui_menus/editor_tool_menu.cc'
--- src/editor/ui_menus/editor_tool_menu.cc	2014-11-30 18:49:38 +0000
+++ src/editor/ui_menus/editor_tool_menu.cc	2015-03-30 10:39:30 +0000
@@ -53,7 +53,7 @@
 	int32_t const height  = 34;
 
 
-	int32_t const num_tools = 7;
+	int32_t const num_tools = 8;
 #define ADD_BUTTON(pic, tooltip)                                              \
    m_radioselect.add_button                                                   \
       (this,                                                                  \
@@ -69,6 +69,8 @@
 	ADD_BUTTON("place_bob",        _("Animals"));
 	ADD_BUTTON("change_resources", _("Resources"));
 	ADD_BUTTON("set_port_space",   _("Set port space"));
+	ADD_BUTTON("set_origin",       _("Set the position that will have the coordinates (0, 0). This will "
+												"be the top-left corner of a generated minimap."));
 
 	set_inner_size
 		(offs.x + (width + spacing) * num_tools, offs.y + (height + spacing));
@@ -82,6 +84,7 @@
 			 &current == &parent.tools.place_bob          ? 4 :
 			 &current == &parent.tools.increase_resources ? 5 :
 			 &current == &parent.tools.set_port_space     ? 6 :
+			 &current == &parent.tools.set_origin         ? 7 :
 			 0);
 	}
 
@@ -132,6 +135,10 @@
 		current_tool_pointer     = &parent.tools.set_port_space;
 		current_registry_pointer = nullptr; // no need for a window
 		break;
+	case 7:
+		current_tool_pointer     = &parent.tools.set_origin;
+		current_registry_pointer = nullptr; // no need for a window
+		break;
 	default:
 		assert(false);
 		break;

=== modified file 'src/logic/map.h'
--- src/logic/map.h	2014-10-29 06:00:52 +0000
+++ src/logic/map.h	2015-03-30 10:39:30 +0000
@@ -216,6 +216,7 @@
 
 	using Tags = std::set<std::string>;
 	const Tags & get_tags() const {return m_tags;}
+	void clear_tags() {m_tags.clear();}
 	bool has_tag(std::string & s) const {return m_tags.count(s);}
 
 	const std::vector<SuggestedTeamLineup>& get_suggested_teams() const {return m_suggested_teams;}

=== modified file 'src/ui_basic/helpwindow.cc'
--- src/ui_basic/helpwindow.cc	2015-01-31 16:03:59 +0000
+++ src/ui_basic/helpwindow.cc	2015-03-30 10:39:30 +0000
@@ -82,7 +82,7 @@
 		(this, "ok",
 		 in_width / 3, in_height - but_height * 3 / 2,
 		 in_width / 3, but_height,
-		 g_gr->images().get("pics/but0.png"),
+		 g_gr->images().get("pics/but5.png"),
 		 _("OK"), std::string(), true, false);
 	btn->sigclicked.connect(boost::bind(&HelpWindow::pressed_ok, boost::ref(*this)));
 	btn->set_font(Font::get((UI::g_fh1->fontset()).serif(),

=== modified file 'src/ui_basic/messagebox.cc'
--- src/ui_basic/messagebox.cc	2014-11-22 10:18:20 +0000
+++ src/ui_basic/messagebox.cc	2015-03-30 10:39:30 +0000
@@ -86,14 +86,14 @@
 		UI::Button * okbtn = new Button
 			(this, "ok",
 			 (get_inner_w() - 120) / 2, get_inner_h() - 30, 120, 20,
-			 g_gr->images().get("pics/but0.png"),
+			 g_gr->images().get("pics/but5.png"),
 			 _("OK"));
 		okbtn->sigclicked.connect(boost::bind(&WLMessageBox::pressed_ok, boost::ref(*this)));
 	} else if (type == YESNO) {
 		UI::Button * yesbtn = new Button
 			(this, "yes",
 			 (get_inner_w() / 2 - 120) / 2, get_inner_h() - 30, 120, 20,
-			 g_gr->images().get("pics/but0.png"),
+			 g_gr->images().get("pics/but5.png"),
 			 _("Yes"));
 		yesbtn->sigclicked.connect(boost::bind(&WLMessageBox::pressed_yes, boost::ref(*this)));
 		UI::Button * nobtn = new Button

=== modified file 'src/ui_basic/multilineeditbox.cc'
--- src/ui_basic/multilineeditbox.cc	2014-11-27 12:02:08 +0000
+++ src/ui_basic/multilineeditbox.cc	2015-03-30 10:39:30 +0000
@@ -26,11 +26,11 @@
 #include "graphic/rendertarget.h"
 #include "graphic/text_layout.h"
 #include "graphic/wordwrap.h"
+#include "ui_basic/mouse_constants.h"
 #include "ui_basic/scrollbar.h"
 
 namespace UI {
 
-static const int32_t ms_darken_value = -20;
 static const int32_t ms_scrollbar_w = 24;
 
 struct MultilineEditbox::Data {
@@ -39,6 +39,9 @@
 	/// The text in the edit box
 	std::string text;
 
+	/// Background tile style.
+	const Image* background;
+
 	/// Position of the cursor inside the text.
 	/// 0 indicates that the cursor is before the first character,
 	/// text.size() inidicates that the cursor is after the last character.
@@ -81,11 +84,13 @@
 MultilineEditbox::MultilineEditbox
 	(Panel * parent,
 	 int32_t x, int32_t y, uint32_t w, uint32_t h,
-	 const std::string & text)
+	 const std::string & text,
+	 const Image* background)
 	:
 	Panel(parent, x, y, w, h),
 	d(new Data(*this))
 {
+	d->background = background;
 	set_handle_mouse(true);
 	set_can_focus(true);
 	set_thinks(false);
@@ -444,8 +449,35 @@
  */
 void MultilineEditbox::draw(RenderTarget & dst)
 {
-	//  make the whole area a bit darker
-	dst.brighten_rect(Rect(Point(0, 0), get_w(), get_h()), ms_darken_value);
+	// Draw the background
+	dst.tile
+		(Rect(Point(0, 0), get_w(), get_h()),
+		 d->background,
+		 Point(get_x(), get_y()));
+
+	// Draw border.
+	if (get_w() >= 4 && get_h() >= 4) {
+		static const RGBColor black(0, 0, 0);
+
+		// bottom edge
+		dst.brighten_rect
+			(Rect(Point(0, get_h() - 2), get_w(), 2),
+			 BUTTON_EDGE_BRIGHT_FACTOR);
+		// right edge
+		dst.brighten_rect
+			(Rect(Point(get_w() - 2, 0), 2, get_h() - 2),
+			 BUTTON_EDGE_BRIGHT_FACTOR);
+		// top edge
+		dst.fill_rect(Rect(Point(0, 0), get_w() - 1, 1), black);
+		dst.fill_rect(Rect(Point(0, 1), get_w() - 2, 1), black);
+		// left edge
+		dst.fill_rect(Rect(Point(0, 0), 1, get_h() - 1), black);
+		dst.fill_rect(Rect(Point(1, 0), 1, get_h() - 2), black);
+	}
+
+	if (has_focus())
+		dst.brighten_rect
+			(Rect(Point(0, 0), get_w(), get_h()), MOUSE_OVER_BRIGHT_FACTOR);
 
 	d->refresh_ww();
 

=== modified file 'src/ui_basic/multilineeditbox.h'
--- src/ui_basic/multilineeditbox.h	2014-11-22 10:18:20 +0000
+++ src/ui_basic/multilineeditbox.h	2015-03-30 10:39:30 +0000
@@ -24,6 +24,7 @@
 
 #include <boost/signals2.hpp>
 
+#include "graphic/graphic.h"
 #include "ui_basic/panel.h"
 
 namespace UI {
@@ -36,7 +37,8 @@
  */
 struct MultilineEditbox : public Panel {
 	MultilineEditbox
-		(Panel *, int32_t x, int32_t y, uint32_t w, uint32_t h, const std::string & text);
+		(Panel *, int32_t x, int32_t y, uint32_t w, uint32_t h,
+		 const std::string & text, const Image* background = g_gr->images().get("pics/but2.png"));
 
 	boost::signals2::signal<void ()> changed;
 

=== modified file 'src/ui_fsmenu/CMakeLists.txt'
--- src/ui_fsmenu/CMakeLists.txt	2015-01-31 16:03:59 +0000
+++ src/ui_fsmenu/CMakeLists.txt	2015-03-30 10:39:30 +0000
@@ -32,8 +32,6 @@
     options.h
     singleplayer.cc
     singleplayer.h
-    suggested_teams_box.cc
-    suggested_teams_box.h
   DEPENDS
     base_exceptions
     base_i18n
@@ -61,6 +59,6 @@
     sound
     ui_basic
     widelands_ball_of_mud
-    wui
     wui_chat_ui
+    wui_common
 )

=== modified file 'src/ui_fsmenu/campaign_select.cc'
--- src/ui_fsmenu/campaign_select.cc	2014-12-11 10:27:30 +0000
+++ src/ui_fsmenu/campaign_select.cc	2015-03-30 10:39:30 +0000
@@ -42,61 +42,61 @@
  */
 FullscreenMenuCampaignSelect::FullscreenMenuCampaignSelect() :
 	FullscreenMenuLoadMapOrGame(),
+	m_table(this, tablex_, tabley_, tablew_, tableh_, false),
 
 	// Main Title
 	m_title
-		(this, get_w() / 2, m_tabley / 3,
+		(this, get_w() / 2, tabley_ / 3,
 		 _("Choose a campaign"),
 		 UI::Align_HCenter),
 
 	// Campaign description
 	m_label_campname
-		(this, m_right_column_x, m_tabley,
+		(this, right_column_x_, tabley_,
 		 "",
 		 UI::Align_Left),
 	m_ta_campname(this,
-					  m_right_column_x + m_indent, get_y_from_preceding(m_label_campname) + m_padding,
-					  get_right_column_w(m_right_column_x) - m_indent, m_label_height),
+					  right_column_x_ + indent_, get_y_from_preceding(m_label_campname) + padding_,
+					  get_right_column_w(right_column_x_) - indent_, m_label_height),
 
 	m_label_tribename
-		(this, m_right_column_x, get_y_from_preceding(m_ta_campname) + 2 * m_padding,
+		(this, right_column_x_, get_y_from_preceding(m_ta_campname) + 2 * padding_,
 		 "",
 		 UI::Align_Left),
 	m_ta_tribename(this,
-						 m_right_column_x + m_indent, get_y_from_preceding(m_label_tribename) + m_padding,
-						 get_right_column_w(m_right_column_x + m_indent), m_label_height),
+						 right_column_x_ + indent_, get_y_from_preceding(m_label_tribename) + padding_,
+						 get_right_column_w(right_column_x_ + indent_), m_label_height),
 
 	m_label_difficulty
-		(this, m_right_column_x, get_y_from_preceding(m_ta_tribename) + 2 * m_padding,
+		(this, right_column_x_, get_y_from_preceding(m_ta_tribename) + 2 * padding_,
 		 "",
 		 UI::Align_Left),
 	m_ta_difficulty(this,
-						 m_right_column_x + m_indent, get_y_from_preceding(m_label_difficulty) + m_padding,
-						 get_right_column_w(m_right_column_x + m_indent), 2 * m_label_height - m_padding),
+						 right_column_x_ + indent_, get_y_from_preceding(m_label_difficulty) + padding_,
+						 get_right_column_w(right_column_x_ + indent_), 2 * m_label_height - padding_),
 
 	m_label_description
-		(this, m_right_column_x, get_y_from_preceding(m_ta_difficulty) + 2 * m_padding,
+		(this, right_column_x_, get_y_from_preceding(m_ta_difficulty) + 2 * padding_,
 		 _("Description:"),
 		 UI::Align_Left),
 	m_ta_description
 		(this,
-		 m_right_column_x + m_indent,
-		 get_y_from_preceding(m_label_description) + m_padding,
-		 get_right_column_w(m_right_column_x + m_indent),
-		 m_buty - get_y_from_preceding(m_label_description) - 4 * m_padding)
+		 right_column_x_ + indent_,
+		 get_y_from_preceding(m_label_description) + padding_,
+		 get_right_column_w(right_column_x_ + indent_),
+		 m_buty - get_y_from_preceding(m_label_description) - 4 * padding_)
 {
 	m_title.set_textstyle(UI::TextStyle::ui_big());
-	m_back.set_tooltip(_("Return to the main menu"));
-	m_ok.set_tooltip(_("Play this campaign"));
+	back_.set_tooltip(_("Return to the main menu"));
+	ok_.set_tooltip(_("Play this campaign"));
 	m_ta_campname.set_tooltip(_("The name of this campaign"));
 	m_ta_tribename.set_tooltip(_("The tribe you will be playing"));
 	m_ta_difficulty.set_tooltip(_("The difficulty of this campaign"));
-	m_ta_description.set_tooltip(_("Story and hints"));
 
-	m_ok.sigclicked.connect
+	ok_.sigclicked.connect
 		(boost::bind
 			 (&FullscreenMenuCampaignSelect::clicked_ok, boost::ref(*this)));
-	m_back.sigclicked.connect
+	back_.sigclicked.connect
 		(boost::bind
 			 (&FullscreenMenuCampaignSelect::clicked_back, boost::ref(*this)));
 	m_table.selected.connect
@@ -143,7 +143,7 @@
 bool FullscreenMenuCampaignSelect::set_has_selection()
 {
 	bool has_selection = m_table.has_selection();
-	FullscreenMenuLoadMapOrGame::set_has_selection();
+	ok_.set_enabled(has_selection);
 
 	if (!has_selection) {
 		m_label_campname.set_text(std::string());
@@ -288,65 +288,65 @@
  */
 FullscreenMenuCampaignMapSelect::FullscreenMenuCampaignMapSelect(bool is_tutorial) :
 	FullscreenMenuLoadMapOrGame(),
+	m_table(this, tablex_, tabley_, tablew_, tableh_, false),
 
 	// Main title
 	m_title
-		(this, get_w() / 2, m_tabley / 3,
+		(this, get_w() / 2, tabley_ / 3,
 		 is_tutorial ? _("Choose a tutorial") : _("Choose a scenario"),
 		 UI::Align_HCenter),
 	m_subtitle
-		(this, get_w() / 6, get_y_from_preceding(m_title) + 6 * m_padding,
+		(this, get_w() / 6, get_y_from_preceding(m_title) + 6 * padding_,
 		 get_w() * 2 / 3, 4 * m_label_height,
 		 "",
 		 UI::Align_HCenter),
 
 	// Map description
 	m_label_mapname
-		(this, m_right_column_x, m_tabley,
+		(this, right_column_x_, tabley_,
 		 "",
 		 UI::Align_Left),
 	m_ta_mapname(this,
-					 m_right_column_x + m_indent, get_y_from_preceding(m_label_mapname) + m_padding,
-					 get_right_column_w(m_right_column_x + m_indent), m_label_height),
+					 right_column_x_ + indent_, get_y_from_preceding(m_label_mapname) + padding_,
+					 get_right_column_w(right_column_x_ + indent_), m_label_height),
 
 	m_label_author
 		(this,
-		 m_right_column_x, get_y_from_preceding(m_ta_mapname) + 2 * m_padding,
+		 right_column_x_, get_y_from_preceding(m_ta_mapname) + 2 * padding_,
 		 "",
 		 UI::Align_Left),
 	m_ta_author(this,
-					m_right_column_x + m_indent, get_y_from_preceding(m_label_author) + m_padding,
-					get_right_column_w(m_right_column_x + m_indent), 2 * m_label_height),
+					right_column_x_ + indent_, get_y_from_preceding(m_label_author) + padding_,
+					get_right_column_w(right_column_x_ + indent_), 2 * m_label_height),
 
 	m_label_description
-		(this, m_right_column_x, get_y_from_preceding(m_ta_author) + m_padding,
+		(this, right_column_x_, get_y_from_preceding(m_ta_author) + padding_,
 		 "",
 		 UI::Align_Left),
 	m_ta_description
 		(this,
-		 m_right_column_x + m_indent,
-		 get_y_from_preceding(m_label_description) + m_padding,
-		 get_right_column_w(m_right_column_x + m_indent),
-		 m_buty - get_y_from_preceding(m_label_description) - 4 * m_padding),
+		 right_column_x_ + indent_,
+		 get_y_from_preceding(m_label_description) + padding_,
+		 get_right_column_w(right_column_x_ + indent_),
+		 m_buty - get_y_from_preceding(m_label_description) - 4 * padding_),
 
 	m_is_tutorial(is_tutorial)
 {
 	m_title.set_textstyle(UI::TextStyle::ui_big());
-	m_back.set_tooltip(_("Return to the main menu"));
+	back_.set_tooltip(_("Return to the main menu"));
 	if (m_is_tutorial) {
-		m_ok.set_tooltip(_("Play this tutorial"));
+		ok_.set_tooltip(_("Play this tutorial"));
 		m_ta_mapname.set_tooltip(_("The name of this tutorial"));
 		m_ta_description.set_tooltip(_("What you will learn in this tutorial"));
 	} else {
-		m_ok.set_tooltip(_("Play this scenario"));
+		ok_.set_tooltip(_("Play this scenario"));
 		m_ta_mapname.set_tooltip(_("The name of this scenario"));
-		m_ta_description.set_tooltip(_("Story and hints"));
 	}
 
-	m_ok.sigclicked.connect
+	ok_.sigclicked.connect
 		(boost::bind
 			 (&FullscreenMenuCampaignMapSelect::clicked_ok, boost::ref(*this)));
-	m_back.sigclicked.connect
+	back_.sigclicked.connect
 		(boost::bind
 			 (&FullscreenMenuCampaignMapSelect::clicked_back, boost::ref(*this)));
 	m_table.selected.connect(boost::bind(&FullscreenMenuCampaignMapSelect::entry_selected, this));
@@ -387,7 +387,7 @@
 bool FullscreenMenuCampaignMapSelect::set_has_selection()
 {
 	bool has_selection = m_table.has_selection();
-	FullscreenMenuLoadMapOrGame::set_has_selection();
+	ok_.set_enabled(has_selection);
 
 	if (!has_selection) {
 		m_label_mapname.set_text(std::string());
@@ -421,8 +421,7 @@
 		map.set_filename(campmapfile);
 		ml->preload_map(true);
 
-		MapAuthorData authors;
-		authors.parse(map.get_author());
+		MapAuthorData authors(map.get_author());
 
 		m_ta_author.set_text(authors.get_names());
 		if (m_is_tutorial) {

=== modified file 'src/ui_fsmenu/campaign_select.h'
--- src/ui_fsmenu/campaign_select.h	2014-11-13 08:39:14 +0000
+++ src/ui_fsmenu/campaign_select.h	2015-03-30 10:39:30 +0000
@@ -47,10 +47,11 @@
 	void clicked_ok() override;
 	void entry_selected() override;
 	void fill_table() override;
-	bool set_has_selection() override;
-
 
 private:
+	/// Updates buttons and text labels and returns whether a table entry is selected.
+	bool set_has_selection();
+
 	/**
 	 * Data about a campaign that we're interested in.
 	 */
@@ -67,6 +68,8 @@
 
 	bool compare_difficulty(uint32_t, uint32_t);
 
+	UI::Table<uintptr_t const>    m_table;
+
 	UI::Textarea                  m_title;
 	UI::Textarea                  m_label_campname;
 	UI::MultilineTextarea         m_ta_campname;
@@ -97,9 +100,10 @@
 protected:
 	void entry_selected() override;
 	void fill_table() override;
-	bool set_has_selection() override;
 
 private:
+	/// Updates buttons and text labels and returns whether a table entry is selected.
+	bool set_has_selection();
 	/**
 	 * Data about a campaign scenario that we're interested in.
 	 */
@@ -111,6 +115,8 @@
 		CampaignScenarioData() : index(0) {}
 	};
 
+	UI::Table<uintptr_t const>    m_table;
+
 	UI::Textarea                  m_title;
 	UI::MultilineTextarea         m_subtitle;
 	UI::Textarea                  m_label_mapname;

=== modified file 'src/ui_fsmenu/launch_mpg.h'
--- src/ui_fsmenu/launch_mpg.h	2014-11-13 08:39:14 +0000
+++ src/ui_fsmenu/launch_mpg.h	2015-03-30 10:39:30 +0000
@@ -28,7 +28,7 @@
 #include "ui_basic/listselect.h"
 #include "ui_basic/multilinetextarea.h"
 #include "ui_basic/textarea.h"
-#include "ui_fsmenu/suggested_teams_box.h"
+#include "wui/suggested_teams_box.h"
 
 struct ChatProvider;
 struct GameChatPanel;

=== modified file 'src/ui_fsmenu/load_map_or_game.cc'
--- src/ui_fsmenu/load_map_or_game.cc	2014-11-23 11:38:50 +0000
+++ src/ui_fsmenu/load_map_or_game.cc	2015-03-30 10:39:30 +0000
@@ -21,8 +21,6 @@
 
 #include <memory>
 
-#include <boost/algorithm/string.hpp>
-
 #include "base/i18n.h"
 #include "graphic/graphic.h"
 #include "io/filesystem/filesystem.h"
@@ -35,36 +33,35 @@
 /// Select a Map, Saved Game or Replay in Fullscreen Mode.
 /// This class defines common coordinates for these UI screens.
 /// It also defines common buttons.
-FullscreenMenuLoadMapOrGame::FullscreenMenuLoadMapOrGame(bool sort_descending) :
+FullscreenMenuLoadMapOrGame::FullscreenMenuLoadMapOrGame() :
 		FullscreenMenuBase("choosemapmenu.jpg"),
 
 		// Values for alignment and size
-		m_padding(4),
-		m_indent(10),
+		padding_(4),
+		indent_(10),
 		m_label_height(20),
-		m_tablex(get_w() *  47 / 2500),
-		m_tabley(get_h() * 17 / 50),
-		m_tablew(get_w() * 711 / 1250),
-		m_tableh(get_h() * 6083 / 10000),
+		tablex_(get_w() *  47 / 2500),
+		tabley_(get_h() * 17 / 50),
+		tablew_(get_w() * 711 / 1250),
+		tableh_(get_h() * 6083 / 10000),
 		m_right_column_margin(15),
-		m_right_column_x(m_tablex + m_tablew + m_right_column_margin),
+		right_column_x_(tablex_ + tablew_ + m_right_column_margin),
 		m_buty (get_h() * 9 / 10),
-		m_butw ((get_w() - m_right_column_x - m_right_column_margin) / 2 - m_padding),
-		m_buth (get_h() * 9 / 200),
+		m_butw ((get_w() - right_column_x_ - m_right_column_margin) / 2 - padding_),
+		buth_ (get_h() * 9 / 200),
 		m_right_column_tab(get_w() - m_right_column_margin - m_butw),
 
 		// Main buttons
-		m_back
+		back_
 		  (this, "back",
-			m_right_column_x, m_buty, m_butw, m_buth,
+			right_column_x_, m_buty, m_butw, buth_,
 			g_gr->images().get("pics/but0.png"),
 			_("Back"), std::string(), true, false),
-		m_ok
+		ok_
 		  (this, "ok",
-			get_w() - m_right_column_margin - m_butw, m_buty, m_butw, m_buth,
+			get_w() - m_right_column_margin - m_butw, m_buty, m_butw, buth_,
 			g_gr->images().get("pics/but2.png"),
-			_("OK"), std::string(), false, false),
-		m_table(this, m_tablex, m_tabley, m_tablew, m_tableh, sort_descending)
+			_("OK"), std::string(), false, false)
 	{}
 
 bool FullscreenMenuLoadMapOrGame::handle_key(bool down, SDL_Keysym code) {

=== modified file 'src/ui_fsmenu/load_map_or_game.h'
--- src/ui_fsmenu/load_map_or_game.h	2015-01-30 23:10:35 +0000
+++ src/ui_fsmenu/load_map_or_game.h	2015-03-30 10:39:30 +0000
@@ -34,6 +34,7 @@
 #include "ui_basic/multilinetextarea.h"
 #include "ui_basic/table.h"
 #include "ui_basic/textarea.h"
+#include "wui/maptable.h"
 
 
 namespace Widelands {
@@ -47,34 +48,12 @@
 class GameController;
 struct GameSettingsProvider;
 
-/**
- * Author data for a map or scenario.
- */
-struct MapAuthorData {
-	const std::string& get_names() const {return m_names;}
-	size_t get_number()            const {return m_number;}
-
-	// Parses author list string into localized contatenated list
-	// string. Use , as list separator and no whitespaces between
-	// author names.
-	void parse(const std::string& author_list) {
-		std::vector<std::string> authors;
-		boost::split(authors, author_list, boost::is_any_of(","));
-		m_names = i18n::localize_list(authors, i18n::ConcatenateWith::AMPERSAND);
-		m_number = authors.size();
-	}
-
-private:
-	std::string m_names;
-	size_t      m_number;
-};
-
 /// Select a Map, Saved Game or Replay in Fullscreen Mode.
 /// This class defines common coordinates for these UI screens.
 /// It also defines common buttons.
 class FullscreenMenuLoadMapOrGame : public FullscreenMenuBase {
 public:
-	FullscreenMenuLoadMapOrGame(bool sortdesc = false);
+	FullscreenMenuLoadMapOrGame();
 
 	bool handle_key(bool down, SDL_Keysym code) override;
 
@@ -87,13 +66,6 @@
 	virtual void entry_selected() {}
 	virtual void fill_table() {}
 
-	// Updates buttons and text labels and returns whether a table entry is selected.
-	virtual bool set_has_selection() {
-		bool has_selection = m_table.has_selection();
-		m_ok.set_enabled(has_selection);
-		return has_selection;
-	}
-
 	// Returns a y coordinate that can be used to position a Panel below the Panel directly above it
 	int32_t get_y_from_preceding(UI::Panel& preceding_panel);
 
@@ -101,20 +73,18 @@
 	int32_t get_right_column_w(int32_t x);
 
 	// UI coordinates and spacers
-	int32_t const m_padding;               // Common padding between panels
-	int32_t const m_indent;                // Indent for elements below labels
+	int32_t const padding_;               // Common padding between panels
+	int32_t const indent_;                // Indent for elements below labels
 	int32_t const m_label_height;
-	int32_t const m_tablex, m_tabley, m_tablew, m_tableh;
+	int32_t const tablex_, tabley_, tablew_, tableh_;
 	int32_t const m_right_column_margin;   // X margins of the right column
-	int32_t const m_right_column_x;
-	int32_t const m_buty, m_butw, m_buth;  // Button dimensions
+	int32_t const right_column_x_;
+	int32_t const m_buty, m_butw, buth_;  // Button dimensions
 	int32_t const m_right_column_tab;
 
 	// Main buttons
-	UI::Button    m_back;
-	UI::Button    m_ok;
-
-	UI::Table<uintptr_t const>    m_table;
+	UI::Button    back_;
+	UI::Button    ok_;
 };
 
 

=== modified file 'src/ui_fsmenu/loadgame.cc'
--- src/ui_fsmenu/loadgame.cc	2015-01-30 23:10:35 +0000
+++ src/ui_fsmenu/loadgame.cc	2015-03-30 10:39:30 +0000
@@ -79,23 +79,24 @@
 
 FullscreenMenuLoadGame::FullscreenMenuLoadGame
 	(Widelands::Game & g, GameSettingsProvider * gsp, GameController * gc, bool is_replay) :
-	FullscreenMenuLoadMapOrGame(true),
+	FullscreenMenuLoadMapOrGame(),
+	m_table(this, tablex_, tabley_, tablew_, tableh_, true),
 
 	m_is_replay(is_replay),
 	// Main title
 	m_title
-		(this, get_w() / 2, m_tabley / 3,
+		(this, get_w() / 2, tabley_ / 3,
 		 m_is_replay ? _("Choose a replay") : _("Choose a saved game"), UI::Align_HCenter),
 
 	// Savegame description
 	m_label_mapname
-		(this, m_right_column_x, m_tabley, "", UI::Align_Left),
+		(this, right_column_x_, tabley_, "", UI::Align_Left),
 	m_ta_mapname(this,
-					 m_right_column_x + m_indent, get_y_from_preceding(m_label_mapname) + m_padding,
-					 get_right_column_w(m_right_column_x + m_indent), 2 * m_label_height - m_padding),
+					 right_column_x_ + indent_, get_y_from_preceding(m_label_mapname) + padding_,
+					 get_right_column_w(right_column_x_ + indent_), 2 * m_label_height - padding_),
 
 	m_label_gametime
-		(this, m_right_column_x, get_y_from_preceding(m_ta_mapname) + 2 * m_padding,
+		(this, right_column_x_, get_y_from_preceding(m_ta_mapname) + 2 * padding_,
 		 "",
 		 UI::Align_Left),
 	m_ta_gametime(this,
@@ -103,7 +104,7 @@
 					  get_right_column_w(m_right_column_tab), m_label_height),
 
 	m_label_players
-		(this, m_right_column_x, get_y_from_preceding(m_ta_gametime),
+		(this, right_column_x_, get_y_from_preceding(m_ta_gametime),
 		 "",
 		 UI::Align_Left),
 	m_ta_players(this,
@@ -111,32 +112,32 @@
 					 get_right_column_w(m_right_column_tab), m_label_height),
 
 	m_label_win_condition
-		(this, m_right_column_x, get_y_from_preceding(m_ta_players) + 3 * m_padding,
+		(this, right_column_x_, get_y_from_preceding(m_ta_players) + 3 * padding_,
 		 "",
 		 UI::Align_Left),
 	m_ta_win_condition(this,
-							 m_right_column_x + m_indent, get_y_from_preceding(m_label_win_condition) + m_padding,
-							 get_right_column_w(m_right_column_x + m_indent), m_label_height),
+							 right_column_x_ + indent_, get_y_from_preceding(m_label_win_condition) + padding_,
+							 get_right_column_w(right_column_x_ + indent_), m_label_height),
 
 	m_delete
 		(this, "delete",
-		 m_right_column_x, m_buty - m_buth - 2 * m_padding,
-		 m_butw, m_buth,
+		 right_column_x_, m_buty - buth_ - 2 * padding_,
+		 m_butw, buth_,
 		 g_gr->images().get("pics/but0.png"),
 		 _("Delete"), std::string(), false, false),
 
 	m_ta_errormessage
 		(this,
-		 m_right_column_x,
-		 get_y_from_preceding(m_ta_mapname) + 2 * m_padding,
-		 get_right_column_w(m_right_column_x),
-		 m_delete.get_y() - get_y_from_preceding(m_ta_mapname) - 6 * m_padding),
+		 right_column_x_,
+		 get_y_from_preceding(m_ta_mapname) + 2 * padding_,
+		 get_right_column_w(right_column_x_),
+		 m_delete.get_y() - get_y_from_preceding(m_ta_mapname) - 6 * padding_),
 
-	m_minimap_y(get_y_from_preceding(m_ta_win_condition) + 3 * m_padding),
-	m_minimap_w(get_right_column_w(m_right_column_x)),
-	m_minimap_h(m_delete.get_y() - get_y_from_preceding(m_ta_win_condition) - 6 * m_padding),
+	m_minimap_y(get_y_from_preceding(m_ta_win_condition) + 3 * padding_),
+	m_minimap_w(get_right_column_w(right_column_x_)),
+	m_minimap_h(m_delete.get_y() - get_y_from_preceding(m_ta_win_condition) - 6 * padding_),
 	m_minimap_icon(this,
-						m_right_column_x, get_y_from_preceding(m_ta_win_condition) + 3 * m_padding,
+						right_column_x_, get_y_from_preceding(m_ta_win_condition) + 3 * padding_,
 						m_minimap_w, m_minimap_h, nullptr),
 
 	// "Data container" for the savegame information
@@ -150,20 +151,20 @@
 	m_ta_win_condition.set_tooltip(_("The win condition that was set for this game"));
 
 	if (m_is_replay) {
-		m_back.set_tooltip(_("Return to the main menu"));
-		m_ok.set_tooltip(_("Load this replay"));
+		back_.set_tooltip(_("Return to the main menu"));
+		ok_.set_tooltip(_("Load this replay"));
 		m_ta_mapname.set_tooltip(_("The map that this replay is based on"));
 		m_delete.set_tooltip(_("Delete this replay"));
 	} else {
-		m_back.set_tooltip(_("Return to the single player menu"));
-		m_ok.set_tooltip(_("Load this game"));
+		back_.set_tooltip(_("Return to the single player menu"));
+		ok_.set_tooltip(_("Load this game"));
 		m_ta_mapname.set_tooltip(_("The map that this game is based on"));
 		m_delete.set_tooltip(_("Delete this game"));
 	}
 	m_minimap_icon.set_visible(false);
 
-	m_back.sigclicked.connect(boost::bind(&FullscreenMenuLoadGame::clicked_back, boost::ref(*this)));
-	m_ok.sigclicked.connect(boost::bind(&FullscreenMenuLoadGame::clicked_ok, boost::ref(*this)));
+	back_.sigclicked.connect(boost::bind(&FullscreenMenuLoadGame::clicked_back, boost::ref(*this)));
+	ok_.sigclicked.connect(boost::bind(&FullscreenMenuLoadGame::clicked_ok, boost::ref(*this)));
 	m_delete.sigclicked.connect
 		(boost::bind
 			 (&FullscreenMenuLoadGame::clicked_delete, boost::ref(*this)));
@@ -287,7 +288,8 @@
 
 bool FullscreenMenuLoadGame::set_has_selection()
 {
-	bool has_selection = FullscreenMenuLoadMapOrGame::set_has_selection();
+	bool has_selection = m_table.has_selection();
+	ok_.set_enabled(has_selection);
 	m_delete.set_enabled(has_selection);
 
 	if (!has_selection) {
@@ -361,7 +363,7 @@
 					uint16_t h = scale * m_minimap_image->height();
 
 					// Center the minimap in the available space
-					int32_t xpos = m_right_column_x + (get_w() - m_right_column_margin - w - m_right_column_x) / 2;
+					int32_t xpos = right_column_x_ + (get_w() - m_right_column_margin - w - right_column_x_) / 2;
 					int32_t ypos = m_minimap_y;
 
 					// Set small minimaps higher up for a more harmonious look
@@ -396,7 +398,7 @@
 			m_minimap_image.reset();
 
 			m_ta_errormessage.set_visible(true);
-			m_ok.set_enabled(false);
+			ok_.set_enabled(false);
 		}
 	}
 }

=== modified file 'src/ui_fsmenu/loadgame.h'
--- src/ui_fsmenu/loadgame.h	2014-11-13 08:39:14 +0000
+++ src/ui_fsmenu/loadgame.h	2015-03-30 10:39:30 +0000
@@ -84,13 +84,15 @@
 	void clicked_ok() override;
 	void entry_selected() override;
 	void fill_table() override;
-	bool set_has_selection() override;
-
 
 private:
+	/// Updates buttons and text labels and returns whether a table entry is selected.
+	bool set_has_selection();
 	bool compare_date_descending(uint32_t, uint32_t);
 	void clicked_delete();
 
+	UI::Table<uintptr_t const>    m_table;
+
 	bool                          m_is_replay;
 
 	UI::Textarea                  m_title;

=== modified file 'src/ui_fsmenu/mapselect.cc'
--- src/ui_fsmenu/mapselect.cc	2014-12-06 12:22:35 +0000
+++ src/ui_fsmenu/mapselect.cc	2015-03-30 10:39:30 +0000
@@ -27,233 +27,133 @@
 #include "base/log.h"
 #include "base/wexception.h"
 #include "graphic/graphic.h"
-#include "graphic/text_constants.h"
 #include "io/filesystem/layered_filesystem.h"
 #include "logic/game_controller.h"
 #include "logic/game_settings.h"
 #include "map_io/widelands_map_loader.h"
-#include "ui_basic/box.h"
 
 using Widelands::WidelandsMapLoader;
 
 FullscreenMenuMapSelect::FullscreenMenuMapSelect
-		(GameSettingsProvider* const settings, GameController* const ctrl, bool is_editor) :
+		(GameSettingsProvider* const settings, GameController* const ctrl) :
 	FullscreenMenuLoadMapOrGame(),
-
-	m_is_editor(is_editor),
-	m_checkbox_space(25),
-	m_checkboxes_y(m_tabley - 120),
+	checkbox_space_(25),
+	checkboxes_y_(tabley_ - 120),
 
 	// Main title
-	m_title
-		(this, get_w() / 2, m_checkboxes_y / 3,
+	title_
+		(this, get_w() / 2, checkboxes_y_ / 3,
 		 _("Choose a map"),
 		 UI::Align_HCenter),
 
-	// Map description
-	m_label_mapname(this, m_right_column_x, m_tabley, "", UI::Align_Left),
-	m_ta_mapname(this,
-					 m_right_column_x + m_indent, get_y_from_preceding(m_label_mapname) + m_padding,
-					 get_right_column_w(m_right_column_x + m_indent), m_label_height),
-
-	m_label_author
-		(this, m_right_column_x, get_y_from_preceding(m_ta_mapname) + 2 * m_padding,
-		 "",
-		 UI::Align_Left),
-	m_ta_author(this,
-					 m_right_column_x + m_indent, get_y_from_preceding(m_label_author) + m_padding,
-					 get_right_column_w(m_right_column_x + m_indent), m_label_height),
-
-	m_label_description
-		(this, m_right_column_x, get_y_from_preceding(m_ta_author) + 2 * m_padding,
-		 _("Description:"),
-		 UI::Align_Left),
-	m_ta_description
-		(this,
-		 m_right_column_x + m_indent,
-		 get_y_from_preceding(m_label_description) + m_padding,
-		 get_right_column_w(m_right_column_x + m_indent),
-		 m_buty - get_y_from_preceding(m_label_description) - 4 * m_padding),
-
-	m_is_scenario(false),
-
-	// Runtime variables
-	m_curdir("maps"), m_basedir("maps"),
-
-	m_settings(settings),
-	m_ctrl(ctrl)
+	table_(this, tablex_, tabley_, tablew_, tableh_, false),
+	map_details_(this, right_column_x_, tabley_,
+					 get_right_column_w(right_column_x_ + indent_),
+					 tableh_ - buth_ - 4 * padding_),
+
+	basedir_("maps"),
+	settings_(settings),
+	ctrl_(ctrl),
+	has_translated_mapname_(false),
+	is_scenario_(false)
 {
-	m_title.set_textstyle(UI::TextStyle::ui_big());
-	if (m_is_editor) {
-		m_back.set_tooltip(_("Return to the editor menu"));
+	curdir_ = basedir_,
+	title_.set_textstyle(UI::TextStyle::ui_big());
+	if (settings_->settings().multiplayer) {
+		back_.set_tooltip(_("Return to the multiplayer game setup"));
 	} else {
-		if (m_settings->settings().multiplayer) {
-			m_back.set_tooltip(_("Return to the multiplayer game setup"));
-		} else {
-			m_back.set_tooltip(_("Return to the single player menu"));
-		}
+		back_.set_tooltip(_("Return to the single player menu"));
 	}
-	m_ta_description.set_tooltip(_("Story and hints"));
-
-	m_back.sigclicked.connect(boost::bind(&FullscreenMenuMapSelect::clicked_back, boost::ref(*this)));
-	m_ok.sigclicked.connect(boost::bind(&FullscreenMenuMapSelect::clicked_ok, boost::ref(*this)));
-	m_table.selected.connect(boost::bind(&FullscreenMenuMapSelect::entry_selected, this));
-	m_table.double_clicked.connect(boost::bind(&FullscreenMenuMapSelect::clicked_ok, boost::ref(*this)));
-
-	/** TRANSLATORS: Column title for number of players in map list */
-	m_table.add_column(35, _("Pl."), _("Number of players"), UI::Align_HCenter);
-	m_table.add_column(m_table.get_w() - 35 - 115, _("Map Name"), _("The name of the map or scenario"),
-							 UI::Align_Left);
-	m_table.add_column(115, _("Size"), _("The size of the map (Width x Height)"), UI::Align_Left);
-	m_table.set_column_compare
-		(0,
-		 boost::bind(&FullscreenMenuMapSelect::compare_players, this, _1, _2));
-	m_table.set_column_compare
-		(1,
-		 boost::bind(&FullscreenMenuMapSelect::compare_mapnames, this, _1, _2));
-	m_table.set_column_compare
-		(2,
-		 boost::bind(&FullscreenMenuMapSelect::compare_size, this, _1, _2));
-	m_table.set_sort_column(0);
-	m_is_scenario = false;
-
-	// Suggested teams
-	// Y coordinate will be set later, when we know how high this box will get.
-	m_suggested_teams_box = new UI::SuggestedTeamsBox(this, m_right_column_x, 0, UI::Box::Vertical,
-								 m_padding, m_indent, m_label_height,
-								 get_w() - m_right_column_x, 4 * m_label_height);
-
-	UI::Box* vbox = new UI::Box(this, m_tablex, m_checkboxes_y,
-										 UI::Box::Horizontal, m_checkbox_space, get_w());
+
+	back_.sigclicked.connect(boost::bind(&FullscreenMenuMapSelect::clicked_back, boost::ref(*this)));
+	ok_.sigclicked.connect(boost::bind(&FullscreenMenuMapSelect::clicked_ok, boost::ref(*this)));
+	table_.selected.connect(boost::bind(&FullscreenMenuMapSelect::entry_selected, this));
+	table_.double_clicked.connect(boost::bind(&FullscreenMenuMapSelect::clicked_ok, boost::ref(*this)));
+
+	UI::Box* vbox = new UI::Box(this, tablex_, checkboxes_y_,
+										 UI::Box::Horizontal, checkbox_space_, get_w());
 
 	// Must be initialized before tag checkboxes
-	m_cb_dont_localize_mapnames = new UI::Checkbox(vbox, Point(0, 0));
-	m_cb_dont_localize_mapnames->set_state(false);
-	m_cb_dont_localize_mapnames->changedto.connect
+	cb_dont_localize_mapnames_ = new UI::Checkbox(vbox, Point(0, 0));
+	cb_dont_localize_mapnames_->set_state(false);
+	cb_dont_localize_mapnames_->changedto.connect
 			(boost::bind(&FullscreenMenuMapSelect::fill_table, boost::ref(*this)));
 
-	m_cb_show_all_maps = _add_tag_checkbox(vbox, "blumba", _("Show all maps"));
-	m_tags_checkboxes.clear(); // Remove this again, it is a special tag checkbox
-	m_cb_show_all_maps->set_state(true);
+	cb_show_all_maps_ = _add_tag_checkbox(vbox, "blumba", _("Show all maps"));
+	tags_checkboxes_.clear(); // Remove this again, it is a special tag checkbox
+	cb_show_all_maps_->set_state(true);
 
-	vbox->add(m_cb_dont_localize_mapnames, UI::Box::AlignLeft, true);
+	vbox->add(cb_dont_localize_mapnames_, UI::Box::AlignLeft, true);
 	UI::Textarea * ta_dont_localize_mapnames =
 			/** TRANSLATORS: Checkbox title. If this checkbox is enabled, map names aren't translated. */
 			new UI::Textarea(vbox, _("Show original map names"), UI::Align_CenterLeft);
-	vbox->add_space(m_padding);
+	vbox->add_space(padding_);
 	vbox->add(ta_dont_localize_mapnames, UI::Box::AlignLeft);
-	vbox->add_space(m_checkbox_space);
-	vbox->set_size(get_w() - 2 * m_tablex, m_checkbox_space);
+	vbox->add_space(checkbox_space_);
+	vbox->set_size(get_w() - 2 * tablex_, checkbox_space_);
 
 	vbox = new UI::Box(this,
-							 m_tablex, vbox->get_y() + vbox->get_h() + m_padding,
-							 UI::Box::Horizontal, m_checkbox_space, get_w());
+							 tablex_, vbox->get_y() + vbox->get_h() + padding_,
+							 UI::Box::Horizontal, checkbox_space_, get_w());
 	_add_tag_checkbox(vbox, "official", _("Official"));
 	_add_tag_checkbox(vbox, "unbalanced", _("Unbalanced"));
 	_add_tag_checkbox(vbox, "seafaring", _("Seafaring"));
 	_add_tag_checkbox(vbox, "scenario", _("Scenario"));
-	vbox->set_size(get_w() - 2 * m_tablex, m_checkbox_space);
+	vbox->set_size(get_w() - 2 * tablex_, checkbox_space_);
 
 	vbox = new UI::Box(this,
-							 m_tablex, vbox->get_y() + vbox->get_h() + m_padding,
-							 UI::Box::Horizontal, m_checkbox_space, get_w());
+							 tablex_, vbox->get_y() + vbox->get_h() + padding_,
+							 UI::Box::Horizontal, checkbox_space_, get_w());
 	_add_tag_checkbox(vbox, "ffa", _("Free for all"));
 	_add_tag_checkbox(vbox, "1v1", _("1v1"));
 
-	vbox->set_size(get_w() - 2 * m_tablex, m_checkbox_space);
+	vbox->set_size(get_w() - 2 * tablex_, checkbox_space_);
 
 	vbox = new UI::Box(this,
-							 m_tablex, vbox->get_y() + vbox->get_h() + m_padding,
-							 UI::Box::Horizontal, m_checkbox_space, get_w());
+							 tablex_, vbox->get_y() + vbox->get_h() + padding_,
+							 UI::Box::Horizontal, checkbox_space_, get_w());
 	_add_tag_checkbox(vbox, "2teams", _("Teams of 2"));
 	_add_tag_checkbox(vbox, "3teams", _("Teams of 3"));
 	_add_tag_checkbox(vbox, "4teams", _("Teams of 4"));
-	vbox->set_size(get_w() - 2 * m_tablex, m_checkbox_space);
-
-	m_scenario_types = m_settings->settings().multiplayer ? Map::MP_SCENARIO : Map::SP_SCENARIO;
-
-	m_table.focus();
+	vbox->set_size(get_w() - 2 * tablex_, checkbox_space_);
+
+	scenario_types_ = settings_->settings().multiplayer ? Map::MP_SCENARIO : Map::SP_SCENARIO;
+
+	table_.focus();
 	fill_table();
 
 	// We don't need the unlocalizing option if there is nothing to unlocalize.
 	// We know this after the list is filled.
-	m_cb_dont_localize_mapnames->set_visible(m_has_translated_mapname);
-	ta_dont_localize_mapnames->set_visible(m_has_translated_mapname);
+	cb_dont_localize_mapnames_->set_visible(has_translated_mapname_);
+	ta_dont_localize_mapnames->set_visible(has_translated_mapname_);
 }
 
 void FullscreenMenuMapSelect::think()
 {
-	if (m_ctrl) {
-		m_ctrl->think();
-	}
-}
-
-
-bool FullscreenMenuMapSelect::compare_players(uint32_t rowa, uint32_t rowb)
-{
-	const MapData & r1 = m_maps_data[m_table[rowa]];
-	const MapData & r2 = m_maps_data[m_table[rowb]];
-
-	if (r1.nrplayers == r2.nrplayers) {
-		return compare_mapnames(rowa, rowb);
-	}
-	return r1.nrplayers < r2.nrplayers;
-}
-
-
-bool FullscreenMenuMapSelect::compare_mapnames(uint32_t rowa, uint32_t rowb)
-{
-	const MapData & r1 = m_maps_data[m_table[rowa]];
-	const MapData & r2 = m_maps_data[m_table[rowb]];
-
-	if (!r1.width && !r2.width) {
-		return r1.name < r2.name;
-	} else if (!r1.width && r2.width) {
-		return true;
-	} else if (r1.width && !r2.width) {
-		return false;
-	} else if (m_cb_dont_localize_mapnames->get_state()) {
-		return r1.name < r2.name;
-	}
-	return r1.localized_name < r2.localized_name;
-}
-
-
-bool FullscreenMenuMapSelect::compare_size(uint32_t rowa, uint32_t rowb)
-{
-	const MapData & r1 = m_maps_data[m_table[rowa]];
-	const MapData & r2 = m_maps_data[m_table[rowb]];
-
-	if (r1.width != r2.width) {
-		return r1.width < r2.width;
-	} else if (r1.height == r2.height) {
-		return compare_mapnames(rowa, rowb);
-	}
-	return r1.height < r2.height;
-}
-
+	if (ctrl_) {
+		ctrl_->think();
+	}
+}
 
 bool FullscreenMenuMapSelect::is_scenario()
 {
-	return m_is_scenario;
+	return is_scenario_;
 }
 
 
 MapData const * FullscreenMenuMapSelect::get_map() const
 {
-	if (!m_table.has_selection()) {
-		return nullptr;
-	}
-	return &m_maps_data[m_table.get_selected()];
+	return table_.get_map();
 }
 
 
 void FullscreenMenuMapSelect::clicked_ok()
 {
-	const MapData & mapdata = m_maps_data[m_table.get_selected()];
+	assert(table_.has_selection());
+	const MapData& mapdata = *table_.get_map();
 
 	if (!mapdata.width) {
-		m_curdir = mapdata.filename;
+		curdir_ = mapdata.filename;
 		fill_table();
 	} else {
 		end_modal(1 + is_scenario());
@@ -262,19 +162,11 @@
 
 bool FullscreenMenuMapSelect::set_has_selection()
 {
-	bool has_selection = m_table.has_selection();
-	FullscreenMenuLoadMapOrGame::set_has_selection();
+	bool has_selection = table_.has_selection();
+	ok_.set_enabled(has_selection);
 
 	if (!has_selection) {
-		m_label_mapname.set_text(std::string());
-		m_label_author.set_text(std::string());
-		m_label_description.set_text(std::string());
-
-		m_ta_mapname.set_text(std::string());
-		m_ta_author.set_text(std::string());
-		m_ta_description.set_text(std::string());
-
-		m_suggested_teams_box->hide();
+		map_details_.clear();
 	}
 	return has_selection;
 }
@@ -283,78 +175,7 @@
 void FullscreenMenuMapSelect::entry_selected()
 {
 	if (set_has_selection()) {
-		const MapData & map = m_maps_data[m_table.get_selected()];
-
-		if (map.width) {
-			// Show map information
-			if (map.scenario) {
-				m_label_mapname.set_text(_("Scenario:"));
-			} else {
-				m_label_mapname.set_text(_("Map:"));
-			}
-			std::string map_displayname = map.localized_name;
-			if (m_cb_dont_localize_mapnames->get_state()) {
-				map_displayname = map.name;
-			}
-			m_ta_mapname.set_text(map_displayname);
-			if (map.localized_name != map.name) {
-				if (m_cb_dont_localize_mapnames->get_state()) {
-					m_ta_mapname.set_tooltip
-					/** TRANSLATORS: Tooltip in map description when map names are being displayed in English. */
-					/** TRANSLATORS: %s is the localized name of the map. */
-							((boost::format(_("The name of this map in your language: %s"))
-							  % map.localized_name).str());
-				} else {
-					m_ta_mapname.set_tooltip
-					/** TRANSLATORS: Tooltip in map description when translated map names are being displayed. */
-					/** TRANSLATORS: %s is the English name of the map. */
-							((boost::format(_("The original name of this map: %s"))
-							  % map.name).str());
-				}
-			} else {
-				m_ta_mapname.set_tooltip(_("The name of this map"));
-			}
-			m_label_author.set_text(ngettext("Author:", "Authors:", map.authors.get_number()));
-			m_ta_author.set_tooltip(ngettext("The designer of this map", "The designers of this map",
-														map.authors.get_number()));
-			m_ta_author.set_text(map.authors.get_names());
-			m_ta_description.set_text(map.description +
-											  (map.hint.empty() ? "" : (std::string("\n\n") + map.hint)));
-			m_label_author.set_visible(true);
-			m_label_description.set_visible(true);
-			m_ta_description.set_size
-					(m_ta_description.get_w(),
-					 m_buty - get_y_from_preceding(m_label_description) - 4 * m_padding);
-			m_ok.set_tooltip(m_is_editor ? _("Edit this map") : _("Play this map"));
-		} else {
-			// Show directory information
-			m_label_mapname.set_text(_("Directory:"));
-			m_ta_mapname.set_text(map.localized_name);
-			m_ta_mapname.set_tooltip(_("The name of this directory"));
-
-			m_ta_author.set_text(std::string());
-			m_ta_description.set_text(std::string());
-			m_label_author.set_visible(false);
-			m_label_description.set_visible(false);
-			m_ok.set_tooltip(_("Open this directory"));
-		}
-
-		m_is_scenario = map.scenario; // reset
-		m_ta_description.scroll_to_top();
-
-		// Show / hide suggested teams
-		m_suggested_teams_box->hide();
-
-		if (!map.suggested_teams.empty()) {
-			m_suggested_teams_box->show(map.suggested_teams);
-
-			m_suggested_teams_box->set_pos(
-						Point(m_suggested_teams_box->get_x(),
-								m_buty - m_padding - m_suggested_teams_box->get_h() - m_padding));
-
-			m_ta_description.set_size(m_ta_description.get_w(),
-											  m_suggested_teams_box->get_y() - m_ta_description.get_y() - 3 * m_padding);
-		}
+		map_details_.update(*table_.get_map(), !cb_dont_localize_mapnames_->get_state());
 	}
 }
 
@@ -371,7 +192,7 @@
  * be taken to sort uncompressed maps (which look like and really are
  * directories) with the files.
  *
- * The search starts in \ref m_curdir ("..../maps") and there is no possibility
+ * The search starts in \ref curdir_ ("..../maps") and there is no possibility
  * to move further up. If the user moves down into subdirectories, we insert an
  * entry to move back up.
  *
@@ -380,162 +201,81 @@
  */
 void FullscreenMenuMapSelect::fill_table()
 {
-	uint8_t col_players = 0;
-	uint8_t col_name = 1;
-	uint8_t col_size = 2;
-
-	m_maps_data.clear();
-	m_table.clear();
-	m_has_translated_mapname = false;
-
-
-	if (m_settings->settings().maps.empty()) {
+	std::vector<MapData> maps_data;
+	has_translated_mapname_ = false;
+
+	if (settings_->settings().maps.empty()) {
 		// This is the normal case
 
 		//  Fill it with all files we find in all directories.
-		FilenameSet files = g_fs->list_directory(m_curdir);
-
-		int32_t ndirs = 0;
+		FilenameSet files = g_fs->list_directory(curdir_);
 
 		//If we are not at the top of the map directory hierarchy (we're not talking
 		//about the absolute filesystem top!) we manually add ".."
-		if (m_curdir != m_basedir) {
-			MapData mapdata;
-	#ifndef _WIN32
-			mapdata.filename = m_curdir.substr(0, m_curdir.rfind('/'));
-	#else
-			mapdata.filename = m_curdir.substr(0, m_curdir.rfind('\\'));
-	#endif
-			mapdata.localized_name = (boost::format("\\<%s\\>") % _("parent")).str();
-			m_maps_data.push_back(mapdata);
-			UI::Table<uintptr_t const>::EntryRecord & te =
-				m_table.add(m_maps_data.size() - 1);
-
-			te.set_string(col_players, "");
-			te.set_picture
-				(col_name,  g_gr->images().get("pics/ls_dir.png"),
-				mapdata.localized_name);
-			te.set_string(col_size, "");
-
-			++ndirs;
+		if (curdir_ != basedir_) {
+			maps_data.push_back(MapData::create_parent_dir(curdir_));
 		}
 
-		//Add subdirectories to the list (except for uncompressed maps)
+		Widelands::Map map; //  MapLoader needs a place to put its preload data
+
 		for (const std::string& mapfilename : files) {
-			char const * const name = mapfilename.c_str();
-			if (!strcmp(FileSystem::fs_filename(name), "."))
-				continue;
-			// Upsy, appeared again. ignore
-			if (!strcmp(FileSystem::fs_filename(name), ".."))
-				continue;
-			if (!g_fs->is_directory(name))
-				continue;
-			if (WidelandsMapLoader::is_widelands_map(name))
-				continue;
-
-			MapData mapdata;
-			mapdata.filename = name;
-			if (strcmp (name, "maps/MP Scenarios") == 0) {
-				/** TRANSLATORS: Directory name for MP Scenarios in map selection */
-				mapdata.localized_name = _("Multiplayer Scenarios");
-			} else {
-				mapdata.localized_name = FileSystem::fs_filename(name);
-			}
-
-			m_maps_data.push_back(mapdata);
-			UI::Table<uintptr_t const>::EntryRecord & te = m_table.add(m_maps_data.size() - 1);
-
-			te.set_string(col_players, "");
-			te.set_picture(col_name, g_gr->images().get("pics/ls_dir.png"), mapdata.localized_name);
-			te.set_string(col_size, "");
-
-			++ndirs;
-		}
-
-		//Add map files(compressed maps) and directories(uncompressed)
-		{
-			Widelands::Map map; //  MapLoader needs a place to put its preload data
-
-			for (const std::string& mapfilename : files) {
-
+
+			// Add map file (compressed) or map directory (uncompressed)
+			if (Widelands::WidelandsMapLoader::is_widelands_map(mapfilename)) {
 				std::unique_ptr<Widelands::MapLoader> ml = map.get_correct_loader(mapfilename);
-				if (!ml) {
+				if (ml.get() != nullptr) {
+					try {
+						map.set_filename(mapfilename);
+						ml->preload_map(true);
+
+						if (!map.get_width() || !map.get_height()) {
+							continue;
+						}
+
+						MapData::MapType maptype;
+						if (map.scenario_types() & scenario_types_) {
+							maptype = MapData::MapType::kScenario;
+						} else if (dynamic_cast<WidelandsMapLoader*>(ml.get())) {
+							maptype = MapData::MapType::kNormal;
+						} else {
+							maptype = MapData::MapType::kSettlers2;
+						}
+
+						MapData mapdata(map, mapfilename, maptype);
+
+						has_translated_mapname_ =
+								has_translated_mapname_ || (mapdata.name != mapdata.localized_name);
+
+						bool has_all_tags = true;
+						for (std::set<uint32_t>::const_iterator it = req_tags_.begin(); it != req_tags_.end(); ++it)
+							has_all_tags &= mapdata.tags.count(tags_ordered_[*it]);
+						if (!has_all_tags) {
+							continue;
+						}
+						maps_data.push_back(mapdata);
+					} catch (const std::exception & e) {
+						log("Mapselect: Skip %s due to preload error: %s\n", mapfilename.c_str(), e.what());
+					} catch (...) {
+						log("Mapselect: Skip %s due to unknown exception\n", mapfilename.c_str());
+					}
+				}
+			} else if (g_fs->is_directory(mapfilename)) {
+				// Add subdirectory to the list
+				const char* fs_filename = FileSystem::fs_filename(mapfilename.c_str());
+				if (!strcmp(fs_filename, ".") || !strcmp(fs_filename, ".."))
 					continue;
-				}
-
-				try {
-					map.set_filename(mapfilename);
-					ml->preload_map(true);
-
-					i18n::Textdomain td("maps");
-
-					MapData mapdata;
-					mapdata.filename       = mapfilename;
-					mapdata.name           = map.get_name();
-					mapdata.localized_name = mapdata.name.empty() ? "" : _(mapdata.name);
-					mapdata.authors.parse(map.get_author());
-					mapdata.description    = map.get_description().empty() ? "" : _(map.get_description());
-					mapdata.hint           = map.get_hint().empty() ? "" : _(map.get_hint());
-					mapdata.nrplayers      = map.get_nrplayers();
-					mapdata.width          = map.get_width();
-					mapdata.height         = map.get_height();
-					mapdata.scenario       = map.scenario_types() & m_scenario_types
-													 || (m_is_editor && map.scenario_types() > 0);
-					mapdata.tags           = map.get_tags();
-					if (mapdata.scenario) {
-						mapdata.tags.insert("scenario");
-					}
-					mapdata.suggested_teams = map.get_suggested_teams();
-
-					m_has_translated_mapname =
-							m_has_translated_mapname || (mapdata.name != mapdata.localized_name);
-
-					if (!mapdata.width || !mapdata.height) {
-						continue;
-					}
-
-					bool has_all_tags = true;
-					for (std::set<uint32_t>::const_iterator it = m_req_tags.begin(); it != m_req_tags.end(); ++it)
-						has_all_tags &= mapdata.tags.count(m_tags_ordered[*it]);
-					if (!has_all_tags) {
-						continue;
-					}
-
-					m_maps_data.push_back(mapdata);
-					UI::Table<uintptr_t const>::EntryRecord & te = m_table.add(m_maps_data.size() - 1);
-
-					te.set_string(col_players, (boost::format("(%i)") % mapdata.nrplayers).str());
-
-					std::string map_displayname = mapdata.localized_name;
-					if (m_cb_dont_localize_mapnames->get_state()) {
-						map_displayname = mapdata.name;
-					}
-					te.set_picture
-						(col_name,  g_gr->images().get
-						 (dynamic_cast<WidelandsMapLoader*>(ml.get()) ?
-							  (mapdata.scenario ? "pics/ls_wlscenario.png" : "pics/ls_wlmap.png") :
-						"pics/ls_s2map.png"),
-						map_displayname);
-
-					te.set_string(col_size, (boost::format("%u x %u") % mapdata.width % mapdata.height).str());
-				} catch (const std::exception & e) {
-					log("Mapselect: Skip %s due to preload error: %s\n", mapfilename.c_str(), e.what());
-				} catch (...) {
-					log("Mapselect: Skip %s due to unknown exception\n", mapfilename.c_str());
-				}
+				maps_data.push_back(MapData::create_directory(mapfilename));
 			}
 		}
 	} else {
 		//client changing maps on dedicated server
-		for (uint16_t i = 0; i < m_settings->settings().maps.size(); ++i) {
+		for (uint16_t i = 0; i < settings_->settings().maps.size(); ++i) {
 			Widelands::Map map; //  MapLoader needs a place to put its preload data
 
-			const DedicatedMapInfos & dmap = m_settings->settings().maps.at(i);
+			const DedicatedMapInfos & dmap = settings_->settings().maps.at(i);
 			const std::string& mapfilename = dmap.path;
 			std::unique_ptr<Widelands::MapLoader> ml(map.get_correct_loader(mapfilename));
 
-			i18n::Textdomain td("maps");
-			MapData mapdata;
 			try {
 				if (!ml) {
 					throw wexception("Mapselect: No MapLoader");
@@ -544,67 +284,63 @@
 				map.set_filename(mapfilename);
 				ml->preload_map(true);
 
-				mapdata.filename    = mapfilename;
-				mapdata.name        = map.get_name();
-				mapdata.authors.parse(map.get_author());
-				mapdata.description = map.get_description();
-				mapdata.hint        = map.get_hint();
-				mapdata.nrplayers   = map.get_nrplayers();
-				mapdata.width       = map.get_width();
-				mapdata.height      = map.get_height();
-				mapdata.scenario    = map.scenario_types() & m_scenario_types;
-
-				if (mapdata.nrplayers != dmap.players || mapdata.scenario != dmap.scenario) {
+				if (!map.get_width() || !map.get_height()) {
+					throw wexception("Mapselect: Map has no size");
+				}
+
+				MapData::MapType maptype;
+
+				if (map.scenario_types() & scenario_types_) {
+					maptype = MapData::MapType::kScenario;
+				} else if (dynamic_cast<WidelandsMapLoader*>(ml.get())) {
+					maptype = MapData::MapType::kSettlers2;
+				} else {
+					maptype = MapData::MapType::kNormal;
+				}
+
+				if (map.get_nrplayers() != dmap.players ||
+					 (maptype == MapData::MapType::kScenario) != dmap.scenario) {
 					throw wexception("Mapselect: Number of players or scenario doesn't match");
 				}
 
-				if (!mapdata.width || !mapdata.height) {
-					throw wexception("Mapselect: Map has no size");
-				}
+				MapData mapdata(map, mapfilename, maptype);
 
 				// Finally write the entry to the list
-				m_maps_data.push_back(mapdata);
-				UI::Table<uintptr_t const>::EntryRecord & te = m_table.add(m_maps_data.size() - 1);
-
-				te.set_string(col_players, (boost::format("(%i)") % mapdata.nrplayers).str());
-				te.set_picture
-					(col_name,
-					 g_gr->images().get((mapdata.scenario ? "pics/ls_wlscenario.png" : "pics/ls_wlmap.png")),
-					 mapdata.name.c_str());
-				te.set_string(col_size, (boost::format("%u x %u") % mapdata.width % mapdata.height).str());
-
+				maps_data.push_back(mapdata);
 			} catch (...) {
 				log("Mapselect: Skipped reading locale data for file %s - not valid.\n", mapfilename.c_str());
 
+				MapData mapdata;
+
 				// Fill in the data we got from the dedicated server
 				mapdata.filename    = mapfilename;
 				mapdata.name        = mapfilename.substr(5, mapfilename.size() - 1);
-				mapdata.authors.parse(_("Nobody"));
+				mapdata.authors     = MapAuthorData(_("Nobody"));
 				mapdata.description = _("This map file is not present in your filesystem."
 							" The data shown here was sent by the server.");
 				mapdata.hint        = "";
 				mapdata.nrplayers   = dmap.players;
 				mapdata.width       = 1;
 				mapdata.height      = 0;
-				mapdata.scenario    = dmap.scenario;
+
+				if (dmap.scenario) {
+					mapdata.maptype = MapData::MapType::kScenario;
+					mapdata.tags.insert("scenario");
+				} else if (dynamic_cast<WidelandsMapLoader*>(ml.get())) {
+					mapdata.maptype = MapData::MapType::kSettlers2;
+				} else {
+					mapdata.maptype = MapData::MapType::kNormal;
+				}
 
 				// Finally write the entry to the list
-				m_maps_data.push_back(mapdata);
-				UI::Table<uintptr_t const>::EntryRecord & te = m_table.add(m_maps_data.size() - 1);
-
-				te.set_string(col_players, (boost::format("(%i)") % mapdata.nrplayers).str());
-				te.set_picture
-					(col_name, g_gr->images().get
-					 ((mapdata.scenario ? "pics/ls_wlscenario.png" : "pics/ls_wlmap.png")),
-					 mapdata.name.c_str());
-				te.set_string(col_size, (boost::format("%u x %u") % mapdata.width % mapdata.height).str());
+				maps_data.push_back(mapdata);
 			}
 		}
 	}
-	m_table.sort();
-
-	if (m_table.size()) {
-		m_table.select(0);
+	if (cb_dont_localize_mapnames_->get_state()) {
+		table_.fill(maps_data, MapTable::Type::kMapnames);
+	} else {
+		table_.fill(maps_data, MapTable::Type::kMapnamesLocalized);
 	}
 	set_has_selection();
 }
@@ -615,8 +351,8 @@
 UI::Checkbox * FullscreenMenuMapSelect::_add_tag_checkbox
 	(UI::Box * box, std::string tag, std::string displ_name)
 {
-	int32_t id = m_tags_ordered.size();
-	m_tags_ordered.push_back(tag);
+	int32_t id = tags_ordered_.size();
+	tags_ordered_.push_back(tag);
 
 	UI::Checkbox * cb = new UI::Checkbox(box, Point(0, 0));
 	cb->changedto.connect
@@ -624,11 +360,11 @@
 
 	box->add(cb, UI::Box::AlignLeft, true);
 	UI::Textarea * ta = new UI::Textarea(box, displ_name, UI::Align_CenterLeft);
-	box->add_space(m_padding);
+	box->add_space(padding_);
 	box->add(ta, UI::Box::AlignLeft);
-	box->add_space(m_checkbox_space);
+	box->add_space(checkbox_space_);
 
-	m_tags_checkboxes.push_back(cb);
+	tags_checkboxes_.push_back(cb);
 
 	return cb;
 }
@@ -639,23 +375,23 @@
 void FullscreenMenuMapSelect::_tagbox_changed(int32_t id, bool to) {
 	if (id == 0) { // Show all maps checbox
 		if (to) {
-			for (UI::Checkbox * checkbox : m_tags_checkboxes) {
+			for (UI::Checkbox * checkbox : tags_checkboxes_) {
 				checkbox->set_state(false);
 			}
 		}
 	} else { // Any tag
 		if (to) {
-			m_req_tags.insert(id);
+			req_tags_.insert(id);
 		}
 		else {
-			m_req_tags.erase(id);
+			req_tags_.erase(id);
 		}
 	}
-	if (m_req_tags.empty()) {
-		m_cb_show_all_maps->set_state(true);
+	if (req_tags_.empty()) {
+		cb_show_all_maps_->set_state(true);
 	}
 	else {
-		m_cb_show_all_maps->set_state(false);
+		cb_show_all_maps_->set_state(false);
 	}
 
 	fill_table();

=== modified file 'src/ui_fsmenu/mapselect.h'
--- src/ui_fsmenu/mapselect.h	2014-11-13 08:39:14 +0000
+++ src/ui_fsmenu/mapselect.h	2015-03-30 10:39:30 +0000
@@ -20,56 +20,28 @@
 #ifndef WL_UI_FSMENU_MAPSELECT_H
 #define WL_UI_FSMENU_MAPSELECT_H
 
-#include <set>
 #include <string>
+#include <vector>
 
 #include "ui_fsmenu/base.h"
-#include "logic/map.h"
-#include "ui_basic/button.h"
+#include "ui_basic/box.h"
 #include "ui_basic/checkbox.h"
-#include "ui_basic/multilinetextarea.h"
-#include "ui_basic/table.h"
 #include "ui_basic/textarea.h"
 #include "ui_fsmenu/load_map_or_game.h"
-#include "ui_fsmenu/suggested_teams_box.h"
-
+#include "wui/mapdetails.h"
+#include "wui/maptable.h"
 
 using Widelands::Map;
 class GameController;
 struct GameSettingsProvider;
 
-namespace UI {
-	struct Box;
-}
-
-/**
- * Data about a map that we're interested in.
- */
-struct MapData {
-	using Tags = std::set<std::string>;
-
-	std::string filename;
-	std::string name;
-	std::string localized_name;
-	std::string description;
-	std::string hint;
-	Tags tags;
-	std::vector<Map::SuggestedTeamLineup> suggested_teams;
-
-	MapAuthorData authors;
-	uint32_t width = 0;
-	uint32_t height = 0;
-	uint32_t nrplayers = 0;
-	bool scenario = false; // is this a scenario we should list?
-};
-
 
 /**
  * Select a Map in Fullscreen Mode. It's a modal fullscreen menu
  */
 class FullscreenMenuMapSelect : public FullscreenMenuLoadMapOrGame {
 public:
-	FullscreenMenuMapSelect(GameSettingsProvider*, GameController*, bool is_editor = false);
+	FullscreenMenuMapSelect(GameSettingsProvider*, GameController*);
 
 	bool is_scenario();
 	MapData const* get_map() const;
@@ -79,48 +51,38 @@
 	void clicked_ok() override;
 	void entry_selected() override;
 	void fill_table() override;
-	bool set_has_selection() override;
-
 
 private:
-	bool compare_players(uint32_t, uint32_t);
-	bool compare_mapnames(uint32_t, uint32_t);
-	bool compare_size(uint32_t, uint32_t);
-
+	/// Updates buttons and text labels and returns whether a table entry is selected.
+	bool set_has_selection();
 	UI::Checkbox* _add_tag_checkbox(UI::Box*, std::string, std::string);
 	void _tagbox_changed(int32_t, bool);
 
-	bool const                    m_is_editor;
-	int32_t const                 m_checkbox_space;
-	int32_t const                 m_checkboxes_y;
-
-	UI::Textarea                  m_title;
-	UI::Textarea                  m_label_mapname;
-	UI::MultilineTextarea         m_ta_mapname;
-	UI::Textarea                  m_label_author;
-	UI::MultilineTextarea         m_ta_author;
-	UI::Textarea                  m_label_description;
-	UI::MultilineTextarea         m_ta_description;
-
-	UI::Checkbox*                 m_cb_dont_localize_mapnames;
-	bool                          m_has_translated_mapname;
-
-	UI::Checkbox*                 m_cb_show_all_maps;
-	std::vector<UI::Checkbox*>    m_tags_checkboxes;
-
-	UI::SuggestedTeamsBox*        m_suggested_teams_box;
-
-	bool                          m_is_scenario;
-	std::string                   m_curdir, m_basedir;
-	Map::ScenarioTypes            m_scenario_types;
-
-	std::vector<std::string>      m_tags_ordered;
-	std::set<uint32_t>            m_req_tags;
-
-	std::vector<MapData>          m_maps_data;
-
-	GameSettingsProvider*         m_settings;
-	GameController*               m_ctrl;
+	int32_t const                 checkbox_space_;
+	int32_t const                 checkboxes_y_;
+
+	UI::Textarea                  title_;
+
+	MapTable                      table_;
+	MapDetails                    map_details_;
+
+	const std::string             basedir_;
+	std::string                   curdir_;
+
+	GameSettingsProvider*         settings_;
+	GameController*               ctrl_;
+
+	UI::Checkbox*                 cb_dont_localize_mapnames_;
+	bool                          has_translated_mapname_;
+
+	UI::Checkbox*                 cb_show_all_maps_;
+	std::vector<UI::Checkbox*>    tags_checkboxes_;
+
+	bool                          is_scenario_;
+	Map::ScenarioTypes            scenario_types_;
+
+	std::vector<std::string>      tags_ordered_;
+	std::set<uint32_t>            req_tags_;
 };
 
 #endif  // end of include guard: WL_UI_FSMENU_MAPSELECT_H

=== modified file 'src/wlapplication.cc'
--- src/wlapplication.cc	2015-03-01 09:21:20 +0000
+++ src/wlapplication.cc	2015-03-30 10:39:30 +0000
@@ -409,7 +409,6 @@
 
 				// Load the requested map
 				Widelands::Map map;
-				i18n::Textdomain td("maps");
 				map.set_filename(m_filename);
 				std::unique_ptr<Widelands::MapLoader> ml = map.get_correct_loader(m_filename);
 				if (!ml) {
@@ -420,18 +419,8 @@
 				}
 				ml->preload_map(true);
 
-				// fill in the mapdata structure
-				MapData mapdata;
-				mapdata.filename = m_filename;
-				mapdata.name = map.get_name();
-				mapdata.authors.parse(map.get_author());
-				mapdata.description = map.get_description();
-				mapdata.nrplayers = map.get_nrplayers();
-				mapdata.width = map.get_width();
-				mapdata.height = map.get_height();
-
 				// set the map
-				netgame.set_map(mapdata.name, mapdata.filename, mapdata.nrplayers);
+				netgame.set_map(map.get_name(), map.get_filename(), map.get_nrplayers());
 
 				// run the network game
 				// -> autostarts when a player sends "/start" as pm to the server.

=== modified file 'src/wui/CMakeLists.txt'
--- src/wui/CMakeLists.txt	2015-01-31 16:03:59 +0000
+++ src/wui/CMakeLists.txt	2015-03-30 10:39:30 +0000
@@ -43,6 +43,22 @@
     logic_widelands_geometry
 )
 
+wl_library(wui_common
+  SRCS
+    mapdetails.cc
+    mapdetails.h
+    mapdata.h
+    maptable.cc
+    maptable.h
+    suggested_teams_box.cc
+    suggested_teams_box.h
+  DEPENDS
+    base_i18n
+    io_filesystem
+    logic
+    ui_basic
+)
+
 wl_library(wui
   SRCS
     actionconfirm.cc

=== modified file 'src/wui/login_box.cc'
--- src/wui/login_box.cc	2014-09-29 19:25:24 +0000
+++ src/wui/login_box.cc	2015-03-30 10:39:30 +0000
@@ -63,7 +63,7 @@
 		(this, "login",
 		 (get_inner_w() / 2 - 200) / 2, get_inner_h() - 20 - margin,
 		 200, 20,
-		 g_gr->images().get("pics/but0.png"),
+		 g_gr->images().get("pics/but5.png"),
 		 _("Login"));
 	loginbtn->sigclicked.connect(boost::bind(&LoginBox::pressed_login, boost::ref(*this)));
 	UI::Button * cancelbtn = new UI::Button

=== added file 'src/wui/mapdata.h'
--- src/wui/mapdata.h	1970-01-01 00:00:00 +0000
+++ src/wui/mapdata.h	2015-03-30 10:39:30 +0000
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2002, 2006-2009, 2011, 2014-2015 by the Widelands Development Team
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef WL_WUI_MAPDATA_H
+#define WL_WUI_MAPDATA_H
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/format.hpp>
+
+#include "base/i18n.h"
+#include "io/filesystem/filesystem.h"
+#include "logic/map.h"
+
+
+/**
+ * Author data for a map or scenario.
+ */
+struct MapAuthorData {
+	const std::string& get_names() const {return m_names;}
+	size_t get_number()            const {return m_number;}
+
+	// Parses author list string into localized contatenated list
+	// string. Use , as list separator and no whitespaces between
+	// author names.
+	MapAuthorData(const std::string& author_list) {
+		std::vector<std::string> authors;
+		boost::split(authors, author_list, boost::is_any_of(","));
+		m_names = i18n::localize_list(authors, i18n::ConcatenateWith::AMPERSAND);
+		m_number = authors.size();
+	}
+
+private:
+	std::string m_names;
+	size_t      m_number;
+};
+
+/**
+ * Data about a map that we're interested in.
+ */
+struct MapData {
+	using Tags = std::set<std::string>;
+
+	enum class MapType {
+		kNormal,
+		kDirectory,
+		kScenario,
+		kSettlers2
+	};
+
+	/// For incomplete data
+	MapData() : authors(""), nrplayers(0), width(0), height(0), maptype(MapData::MapType::kNormal) {}
+
+	/// For normal maps and scenarios
+	MapData(const Widelands::Map& map, const std::string& init_filename, const MapData::MapType init_maptype) :
+		MapData() {
+		i18n::Textdomain td("maps");
+		filename = init_filename;
+		name = map.get_name();
+		localized_name = name.empty() ? "" : _(name);
+		authors = MapAuthorData(map.get_author());
+		description = map.get_description().empty() ? "" : _(map.get_description());
+		hint = map.get_hint().empty() ? "" : _(map.get_hint());
+		nrplayers = map.get_nrplayers();
+		width = map.get_width();
+		height = map.get_height();
+		suggested_teams = map.get_suggested_teams();
+		tags = map.get_tags();
+		maptype = init_maptype;
+
+		if (maptype == MapData::MapType::kScenario) {
+			tags.insert("scenario");
+		}
+	}
+
+	/// For directories
+	MapData(const std::string& init_filename, const std::string& init_localized_name) :
+		MapData() {
+		filename = init_filename;
+		name = init_localized_name;
+		localized_name = init_localized_name;
+		maptype = MapData::MapType::kDirectory;
+	}
+
+	/// Get the ".." directory
+	static MapData create_parent_dir(const std::string& current_dir) {
+#ifndef _WIN32
+		const std::string filename = current_dir.substr(0, current_dir.rfind('/'));
+#else
+		const std::string filename = current_dir.substr(0, current_dir.rfind('\\'));
+#endif
+		return MapData(filename, (boost::format("\\<%s\\>") % _("parent")).str());
+	}
+
+	/// Create a subdirectory
+	static MapData create_directory(const std::string& directory) {
+		std::string localized_name;
+		if (boost::equals(directory, "maps/MP Scenarios")) {
+			/** TRANSLATORS: Directory name for MP Scenarios in map selection */
+			localized_name = _("Multiplayer Scenarios");
+		} else {
+			localized_name = FileSystem::fs_filename(directory.c_str());
+		}
+		return MapData(directory, localized_name);
+	}
+
+	std::string filename;
+	std::string name;
+	std::string localized_name;
+	MapAuthorData authors;
+	std::string description;
+	std::string hint;
+	uint32_t nrplayers;
+	uint32_t width;
+	uint32_t height;
+	std::vector<Widelands::Map::SuggestedTeamLineup> suggested_teams;
+	Tags tags;
+	MapData::MapType maptype;
+};
+
+#endif  // end of include guard: WL_WUI_MAPDATA_H

=== added file 'src/wui/mapdetails.cc'
--- src/wui/mapdetails.cc	1970-01-01 00:00:00 +0000
+++ src/wui/mapdetails.cc	2015-03-30 10:39:30 +0000
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2002, 2006-2015 by the Widelands Development Team
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "wui/mapdetails.h"
+
+#include <cstdio>
+#include <memory>
+
+#include <boost/format.hpp>
+
+#include "base/i18n.h"
+#include "base/log.h"
+#include "base/wexception.h"
+#include "graphic/graphic.h"
+#include "graphic/text_constants.h"
+#include "io/filesystem/layered_filesystem.h"
+#include "logic/game_controller.h"
+#include "logic/game_settings.h"
+#include "map_io/widelands_map_loader.h"
+#include "ui_basic/box.h"
+
+MapDetails::MapDetails
+		(Panel* parent, int32_t x, int32_t y, int32_t max_x, int32_t max_y) :
+	UI::Panel(parent, x, y, max_x, max_y),
+
+	padding_(4),
+	indent_(10),
+	labelh_(20),
+	max_x_(max_x),
+	max_y_(max_y),
+
+	main_box_(this, 0, 0, UI::Box::Vertical,
+		  max_x_, max_y_, 0),
+
+	name_box_(&main_box_, 0, 0, UI::Box::Horizontal,
+		  max_x_, 3 * labelh_ + padding_, padding_ / 2),
+	name_label_(&main_box_, 0, 0, max_x_ - padding_, labelh_, ""),
+	name_(&name_box_, 0, 0, max_x_ - indent_, 2 * labelh_, ""),
+
+	author_box_(&main_box_, 0, 0, UI::Box::Horizontal,
+		  max_x_, 3 * labelh_ + padding_, padding_ / 2),
+	author_label_(&main_box_, 0, 0, max_x_ - padding_, labelh_, ""),
+	author_(&author_box_, 0, 0, max_x_ - indent_, labelh_, ""),
+
+	descr_box_(&main_box_, 0, 0, UI::Box::Horizontal,
+		  max_x_, 6 * labelh_ + padding_, padding_ / 2),
+	descr_label_(&main_box_, 0, 0, max_x_, labelh_, ""),
+	descr_(&descr_box_, 0, 0, max_x_ - indent_, 5 * labelh_, "")
+{
+	suggested_teams_box_ = new UI::SuggestedTeamsBox(this, 0, 0, UI::Box::Vertical,
+																	 padding_, indent_, labelh_, max_x_, 4 * labelh_);
+
+	main_box_.add(&name_label_, UI::Box::AlignLeft);
+	name_box_.add_space(indent_);
+	name_box_.add(&name_, UI::Box::AlignLeft);
+	main_box_.add(&name_box_, UI::Box::AlignLeft);
+	main_box_.add_space(padding_);
+
+	main_box_.add(&author_label_, UI::Box::AlignLeft);
+	author_box_.add_space(indent_);
+	author_box_.add(&author_, UI::Box::AlignLeft);
+	main_box_.add(&author_box_, UI::Box::AlignLeft);
+	main_box_.add_space(padding_);
+
+	main_box_.add(&descr_label_, UI::Box::AlignLeft);
+	descr_box_.add_space(indent_);
+	descr_box_.add(&descr_, UI::Box::AlignLeft);
+	main_box_.add(&descr_box_, UI::Box::AlignLeft);
+	main_box_.add_space(padding_);
+}
+
+
+void MapDetails::clear() {
+	name_label_.set_text("");
+	author_label_.set_text("");
+	descr_label_.set_text("");
+	name_.set_text("");
+	author_.set_text("");
+	descr_.set_text("");
+	suggested_teams_box_->hide();
+}
+
+void MapDetails::update(const MapData& mapdata, bool localize_mapname) {
+	clear();
+	if (mapdata.maptype == MapData::MapType::kDirectory) {
+		// Show directory information
+		name_label_.set_text(_("Directory:"));
+		name_.set_text(mapdata.localized_name);
+		name_.set_tooltip(_("The name of this directory"));
+		main_box_.set_size(max_x_, max_y_);
+	} else {
+		// Show map information
+		if (mapdata.maptype == MapData::MapType::kScenario) {
+			name_label_.set_text(_("Scenario:"));
+		} else {
+			name_label_.set_text(_("Map:"));
+		}
+		name_.set_text(localize_mapname ? mapdata.localized_name : mapdata.name);
+		if (mapdata.localized_name != mapdata.name) {
+			if (localize_mapname) {
+				name_.set_tooltip
+				/** TRANSLATORS: Tooltip in map description when translated map names are being displayed. */
+				/** TRANSLATORS: %s is the English name of the map. */
+						((boost::format(_("The original name of this map: %s"))
+						  % mapdata.name).str());
+			} else {
+				name_.set_tooltip
+				/** TRANSLATORS: Tooltip in map description when map names are being displayed in English. */
+				/** TRANSLATORS: %s is the localized name of the map. */
+						((boost::format(_("The name of this map in your language: %s"))
+						  % mapdata.localized_name).str());
+			}
+		} else {
+			name_.set_tooltip(_("The name of this map"));
+		}
+		author_label_.set_text(ngettext("Author:", "Authors:", mapdata.authors.get_number()));
+		author_.set_text(mapdata.authors.get_names());
+		descr_label_.set_text(_("Description:"));
+		descr_.set_text(mapdata.description +
+										  (mapdata.hint.empty() ? "" : (std::string("\n\n") + mapdata.hint)));
+
+		// Show / hide suggested teams
+		if (mapdata.suggested_teams.empty()) {
+			main_box_.set_size(max_x_, max_y_);
+			descr_box_.set_size(
+						descr_box_.get_w(),
+						max_y_ - descr_label_.get_y() - descr_label_.get_h() - 2 * padding_);
+		} else {
+			suggested_teams_box_->show(mapdata.suggested_teams);
+			suggested_teams_box_->set_pos(Point(0, max_y_ - suggested_teams_box_->get_h()));
+			main_box_.set_size(max_x_, max_y_ - suggested_teams_box_->get_h());
+			descr_box_.set_size(
+						descr_box_.get_w(),
+						suggested_teams_box_->get_y() - descr_label_.get_y() - descr_label_.get_h() - 4 * padding_);
+		}
+		descr_.set_size(descr_.get_w(), descr_box_.get_h());
+		descr_.scroll_to_top();
+	}
+}

=== added file 'src/wui/mapdetails.h'
--- src/wui/mapdetails.h	1970-01-01 00:00:00 +0000
+++ src/wui/mapdetails.h	2015-03-30 10:39:30 +0000
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2002, 2006-2015, 2011 by the Widelands Development Team
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef WL_WUI_MAPDETAILS_H
+#define WL_WUI_MAPDETAILS_H
+
+#include "ui_basic/box.h"
+#include "ui_basic/multilinetextarea.h"
+#include "ui_basic/panel.h"
+#include "ui_basic/textarea.h"
+#include "wui/mapdata.h"
+#include "wui/suggested_teams_box.h"
+
+
+/**
+ * Show a Panel with information about a map.
+ */
+class MapDetails : public UI::Panel {
+public:
+	MapDetails(Panel * parent,
+				  int32_t x, int32_t y,
+				  int32_t max_x, int32_t max_y);
+
+	void clear();
+	void update(const MapData& mapdata, bool localize_mapname);
+
+private:
+	const int padding_, indent_, labelh_;
+	const int32_t max_x_, max_y_;
+
+	UI::Box main_box_;
+
+	UI::Box name_box_;
+	UI::Textarea name_label_;
+	UI::MultilineTextarea name_;
+
+	UI::Box author_box_;
+	UI::Textarea author_label_;
+	UI::MultilineTextarea author_;
+
+	UI::Box descr_box_;
+	UI::Textarea descr_label_;
+	UI::MultilineTextarea descr_;
+
+	UI::SuggestedTeamsBox* suggested_teams_box_;
+};
+
+#endif  // end of include guard: WL_WUI_MAPDETAILS_H

=== added file 'src/wui/maptable.cc'
--- src/wui/maptable.cc	1970-01-01 00:00:00 +0000
+++ src/wui/maptable.cc	2015-03-30 10:39:30 +0000
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2002, 2006-2013 by the Widelands Development Team
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "wui/maptable.h"
+
+#include <string>
+
+#include <boost/format.hpp>
+
+#include "base/i18n.h"
+#include "graphic/graphic.h"
+#include "io/filesystem/filesystem.h"
+
+MapTable::MapTable
+		(UI::Panel * parent,
+		 int32_t x, int32_t y, uint32_t w, uint32_t h,
+		 const bool descending) :
+	UI::Table<uintptr_t>(parent, x, y, w, h, descending),
+	type_(MapTable::Type::kMapnamesLocalized) {
+
+	/** TRANSLATORS: Column title for number of players in map list */
+	add_column(35, _("Pl."), _("Number of players"), UI::Align_HCenter);
+	add_column(get_w() - 35 - 115, "", _("The name of the map or scenario"), UI::Align_Left);
+	add_column(115, _("Size"), _("The size of the map (Width x Height)"), UI::Align_Left);
+	set_column_compare(0, boost::bind(&MapTable::compare_players, this, _1, _2));
+	set_column_compare(1, boost::bind(&MapTable::compare_mapnames, this, _1, _2));
+	set_column_compare(2, boost::bind(&MapTable::compare_size, this, _1, _2));
+	set_sort_column(0);
+}
+
+// NOCOM fix column sorting
+
+bool MapTable::compare_players(uint32_t rowa, uint32_t rowb) {
+	const MapData & r1 = maps_data_[rowa];
+	const MapData & r2 = maps_data_[rowb];
+
+	if (r1.nrplayers == r2.nrplayers) {
+		return compare_mapnames(rowa, rowb);
+	}
+	return r1.nrplayers < r2.nrplayers;
+}
+
+
+bool MapTable::compare_mapnames(uint32_t rowa, uint32_t rowb) {
+	const MapData & r1 = maps_data_[rowa];
+	const MapData & r2 = maps_data_[rowb];
+
+	if (!r1.width && !r2.width) { // Directories take the localized name
+		return r1.localized_name < r2.localized_name;
+	} else if (!r1.width && r2.width) {
+		return true;
+	} else if (r1.width && !r2.width) {
+		return false;
+	}
+
+	switch (type_) {
+		case MapTable::Type::kFilenames:
+			return r1.filename < r2.filename;
+		case MapTable::Type::kMapnames:
+			return r1.name < r2.name;
+		default:
+			return r1.localized_name < r2.localized_name;
+	}
+}
+
+
+bool MapTable::compare_size(uint32_t rowa, uint32_t rowb) {
+	const MapData & r1 = maps_data_[rowa];
+	const MapData & r2 = maps_data_[rowb];
+
+	if (r1.width != r2.width) {
+		return r1.width < r2.width;
+	} else if (r1.height == r2.height) {
+		return compare_mapnames(rowa, rowb);
+	}
+	return r1.height < r2.height;
+}
+
+const MapData* MapTable::get_map() const {
+	if (!has_selection()) {
+		return nullptr;
+	}
+	return &maps_data_[get_selected()];
+}
+
+
+void MapTable::fill(const std::vector<MapData>& entries, MapTable::Type type) {
+	type_ = type;
+
+	maps_data_ = entries;
+	clear();
+
+	for (size_t i = 0; i < maps_data_.size(); ++i) {
+		const MapData& mapdata = maps_data_[i];
+		UI::Table<uintptr_t const>::EntryRecord& te = add(i);
+
+		if (mapdata.maptype == MapData::MapType::kDirectory) {
+			te.set_string(0, "");
+			te.set_picture(1,  g_gr->images().get("pics/ls_dir.png"), mapdata.localized_name);
+			te.set_string(2, "");
+		} else {
+			te.set_string(0, (boost::format("(%i)") % mapdata.nrplayers).str());
+
+			std::string picture = "pics/ls_wlmap.png";
+			if (mapdata.maptype == MapData::MapType::kScenario) {
+				picture = "pics/ls_wlscenario.png";
+			} else if (mapdata.maptype == MapData::MapType::kSettlers2) {
+				picture = "pics/ls_s2map.png";
+			}
+
+			if (type == MapTable::Type::kFilenames) {
+				set_column_title(1, _("Filename"));
+				te.set_picture(
+							1,
+							g_gr->images().get(picture),
+							FileSystem::filename_without_ext(mapdata.filename.c_str()));
+			} else {
+				set_column_title(1, _("Map Name"));
+				if (type == MapTable::Type::kMapnames) {
+					te.set_picture(1, g_gr->images().get(picture), mapdata.name);
+				} else {
+					te.set_picture(1, g_gr->images().get(picture), mapdata.localized_name);
+				}
+			}
+
+			te.set_string(2, (boost::format("%u x %u") % mapdata.width % mapdata.height).str());
+		}
+	}
+	sort();
+}

=== added file 'src/wui/maptable.h'
--- src/wui/maptable.h	1970-01-01 00:00:00 +0000
+++ src/wui/maptable.h	2015-03-30 10:39:30 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2002, 2006-2009, 2011, 2014-2015 by the Widelands Development Team
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef WL_WUI_MAPTABLE_H
+#define WL_WUI_MAPTABLE_H
+
+#include <vector>
+
+#include "ui_basic/table.h"
+#include "wui/mapdata.h"
+
+
+/**
+ * A table listing all the available maps for saveloading.
+ */
+class MapTable : public UI::Table<uintptr_t> {
+public:
+	enum class Type {
+		kFilenames,
+		kMapnames,
+		kMapnamesLocalized
+	};
+
+	MapTable(UI::Panel * parent,
+				 int32_t x, int32_t y, uint32_t w, uint32_t h,
+				 const bool descending);
+
+	/// Get the current selected map. Returns nullptr if there is nothing selected.
+	const MapData* get_map() const;
+
+	/// Fill the table with maps and directories.
+	void fill(const std::vector<MapData>& entries, MapTable::Type type);
+
+private:
+	bool compare_players(uint32_t, uint32_t);
+	bool compare_mapnames(uint32_t, uint32_t);
+	bool compare_size(uint32_t, uint32_t);
+
+	MapTable::Type type_;
+	std::vector<MapData> maps_data_;
+};
+
+#endif  // end of include guard: WL_WUI_MAPTABLE_H

=== modified file 'src/wui/story_message_box.cc'
--- src/wui/story_message_box.cc	2014-09-10 14:48:40 +0000
+++ src/wui/story_message_box.cc	2015-03-30 10:39:30 +0000
@@ -64,7 +64,7 @@
 	UI::Button * okbtn = new UI::Button
 		(this, "ok",
 		 posx, posy, but_width, 20,
-		 g_gr->images().get("pics/but0.png"),
+		 g_gr->images().get("pics/but5.png"),
 		 button_text);
 	okbtn->sigclicked.connect(boost::bind(&StoryMessageBox::clicked_ok, boost::ref(*this)));
 

=== renamed file 'src/ui_fsmenu/suggested_teams_box.cc' => 'src/wui/suggested_teams_box.cc'
--- src/ui_fsmenu/suggested_teams_box.cc	2015-03-01 09:21:20 +0000
+++ src/wui/suggested_teams_box.cc	2015-03-30 10:39:30 +0000
@@ -17,7 +17,7 @@
  *
  */
 
-#include "ui_fsmenu/suggested_teams_box.h"
+#include "wui/suggested_teams_box.h"
 
 #include <set>
 #include <string>
@@ -95,7 +95,7 @@
 		for (const Widelands::Map::SuggestedTeamLineup& lineup : m_suggested_teams) {
 
 			m_lineup_box =
-					new UI::Box(this, m_indent, teamlist_offset + lineup_counter * m_label_height,
+					new UI::Box(this, m_indent, teamlist_offset + lineup_counter * (m_label_height + m_padding),
 									UI::Box::Horizontal, get_w() - m_indent);
 
 			m_lineup_box->set_size(get_w(), m_label_height + m_padding);
@@ -105,7 +105,7 @@
 
 				if (!is_first) {
 					m_lineup_box->add_space(m_padding);
-					vs_label = new UI::Textarea(m_lineup_box, "x", UI::Align_CenterLeft);
+					vs_label = new UI::Textarea(m_lineup_box, "x", UI::Align_BottomCenter);
 					m_lineup_box->add(vs_label, UI::Box::AlignLeft);
 					vs_label->set_visible(true);
 					m_vs_labels.push_back(vs_label);
@@ -129,7 +129,7 @@
 		} // All lineups
 
 		// Adjust size to content
-		set_size(get_w(), teamlist_offset + lineup_counter * m_label_height);
+		set_size(get_w(), teamlist_offset + lineup_counter * (m_label_height + m_padding));
 	}
 }
 

=== renamed file 'src/ui_fsmenu/suggested_teams_box.h' => 'src/wui/suggested_teams_box.h'
--- src/ui_fsmenu/suggested_teams_box.h	2015-03-01 09:21:20 +0000
+++ src/wui/suggested_teams_box.h	2015-03-30 10:39:30 +0000
@@ -17,8 +17,8 @@
  *
  */
 
-#ifndef WL_UI_FSMENU_SUGGESTED_TEAMS_BOX_H
-#define WL_UI_FSMENU_SUGGESTED_TEAMS_BOX_H
+#ifndef WL_WUI_SUGGESTED_TEAMS_BOX_H
+#define WL_WUI_SUGGESTED_TEAMS_BOX_H
 
 #include <set>
 #include <string>
@@ -57,4 +57,4 @@
 
 }
 
-#endif  // end of include guard: WL_UI_FSMENU_SUGGESTED_TEAMS_BOX_H
+#endif  // end of include guard: WL_WUI_SUGGESTED_TEAMS_BOX_H


Follow ups