← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/toolbar-dropdown-menus into lp:widelands

 

GunChleoc has proposed merging lp:~widelands-dev/widelands/toolbar-dropdown-menus into lp:widelands with lp:~widelands-dev/widelands/toolbar-dropdown-scripting-review-only as a prerequisite.

Commit message:
Convert toolbars to dropdowns
- All toolbar menus are converted to dropdowns
- Toolbar menus have tribe-dependent frame graphics
- Add entries to menus that were previously only accessible by hotkey
- Add minimal UI test
- Overhaul Tutorial 1 & 4
  - Adapt to UI changes
  - Make Tutorial 1 more robust against user not following instructions
  - Add pretty pictures to messages

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #1570713 in widelands: "Editor Info Tool can't be accessed via the UI"
  https://bugs.launchpad.net/widelands/+bug/1570713
  Bug #1643563 in widelands: "Toolbar redesign"
  https://bugs.launchpad.net/widelands/+bug/1643563
  Bug #1703570 in widelands: "Add a toolbar button for game speed"
  https://bugs.launchpad.net/widelands/+bug/1703570
  Bug #1823466 in widelands: "Update Tutorial for new tribes and  features"
  https://bugs.launchpad.net/widelands/+bug/1823466

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/toolbar-dropdown-menus/+merge/368230

I have filtered the tutorial changes away from view, because the diff got truncated.

Tutorial code can be reviewed via

https://code.launchpad.net/~widelands-dev/widelands/toolbar-dropdown-scripting-review-only/+merge/368228

-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/toolbar-dropdown-menus into lp:widelands.
=== added directory 'data/images/wui/editor/menus'
=== added file 'data/images/wui/editor/menus/load_map.png'
Binary files data/images/wui/editor/menus/load_map.png	1970-01-01 00:00:00 +0000 and data/images/wui/editor/menus/load_map.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/images/wui/editor/menus/main_menu.png'
Binary files data/images/wui/editor/menus/main_menu.png	1970-01-01 00:00:00 +0000 and data/images/wui/editor/menus/main_menu.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/images/wui/editor/menus/map_options.png'
Binary files data/images/wui/editor/menus/map_options.png	1970-01-01 00:00:00 +0000 and data/images/wui/editor/menus/map_options.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/images/wui/editor/menus/new_map.png'
Binary files data/images/wui/editor/menus/new_map.png	1970-01-01 00:00:00 +0000 and data/images/wui/editor/menus/new_map.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/images/wui/editor/menus/new_random_map.png'
Binary files data/images/wui/editor/menus/new_random_map.png	1970-01-01 00:00:00 +0000 and data/images/wui/editor/menus/new_random_map.png	2019-06-01 16:05:47 +0000 differ
=== renamed file 'data/images/wui/editor/editor_redo.png' => 'data/images/wui/editor/menus/redo.png'
=== added file 'data/images/wui/editor/menus/save_map.png'
Binary files data/images/wui/editor/menus/save_map.png	1970-01-01 00:00:00 +0000 and data/images/wui/editor/menus/save_map.png	2019-06-01 16:05:47 +0000 differ
=== renamed file 'data/images/wui/editor/editor_menu_toggle_tool_menu.png' => 'data/images/wui/editor/menus/tools.png'
=== renamed file 'data/images/wui/editor/editor_menu_set_toolsize_menu.png' => 'data/images/wui/editor/menus/toolsize.png'
=== renamed file 'data/images/wui/editor/editor_undo.png' => 'data/images/wui/editor/menus/undo.png'
=== added directory 'data/images/wui/editor/tools'
=== renamed file 'data/images/wui/editor/editor_menu_tool_place_bob.png' => 'data/images/wui/editor/tools/critters.png'
=== renamed file 'data/images/wui/editor/editor_menu_tool_change_height.png' => 'data/images/wui/editor/tools/height.png'
=== renamed file 'data/images/wui/editor/editor_menu_tool_place_immovable.png' => 'data/images/wui/editor/tools/immovables.png'
=== renamed file 'data/images/wui/editor/editor_menu_tool_set_origin.png' => 'data/images/wui/editor/tools/map_origin.png'
=== renamed file 'data/images/wui/editor/editor_menu_tool_noise_height.png' => 'data/images/wui/editor/tools/noise_height.png'
=== renamed file 'data/images/wui/editor/editor_menu_player_menu.png' => 'data/images/wui/editor/tools/players.png'
=== renamed file 'data/images/wui/editor/editor_menu_tool_set_port_space.png' => 'data/images/wui/editor/tools/port_spaces.png'
=== renamed file 'data/images/wui/editor/editor_menu_tool_resize.png' => 'data/images/wui/editor/tools/resize_map.png'
=== renamed file 'data/images/wui/editor/editor_menu_tool_change_resources.png' => 'data/images/wui/editor/tools/resources.png'
=== renamed file 'data/images/wui/editor/editor_menu_tool_set_terrain.png' => 'data/images/wui/editor/tools/terrain.png'
=== added file 'data/images/wui/menus/CREDITS.txt'
--- data/images/wui/menus/CREDITS.txt	1970-01-01 00:00:00 +0000
+++ data/images/wui/menus/CREDITS.txt	2019-06-01 16:05:47 +0000
@@ -0,0 +1,1 @@
+lua.png Copyright © 1998 Lua.org. Graphic design by Alexandre Nakonechnyj.

=== renamed file 'data/images/wui/menus/menu_chat.png' => 'data/images/wui/menus/chat.png'
=== renamed file 'data/images/wui/menus/menu_exit_game.png' => 'data/images/wui/menus/exit.png'
=== added file 'data/images/wui/menus/gamespeed.png'
Binary files data/images/wui/menus/gamespeed.png	1970-01-01 00:00:00 +0000 and data/images/wui/menus/gamespeed.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/images/wui/menus/gamespeed_decrease.png'
Binary files data/images/wui/menus/gamespeed_decrease.png	1970-01-01 00:00:00 +0000 and data/images/wui/menus/gamespeed_decrease.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/images/wui/menus/gamespeed_increase.png'
Binary files data/images/wui/menus/gamespeed_increase.png	1970-01-01 00:00:00 +0000 and data/images/wui/menus/gamespeed_increase.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/images/wui/menus/gamespeed_pause.png'
Binary files data/images/wui/menus/gamespeed_pause.png	1970-01-01 00:00:00 +0000 and data/images/wui/menus/gamespeed_pause.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/images/wui/menus/gamespeed_resume.png'
Binary files data/images/wui/menus/gamespeed_resume.png	1970-01-01 00:00:00 +0000 and data/images/wui/menus/gamespeed_resume.png	2019-06-01 16:05:47 +0000 differ
=== renamed file 'data/images/wui/menus/menu_goto.png' => 'data/images/wui/menus/goto.png'
=== added file 'data/images/wui/menus/lua.png'
Binary files data/images/wui/menus/lua.png	1970-01-01 00:00:00 +0000 and data/images/wui/menus/lua.png	2019-06-01 16:05:47 +0000 differ
=== renamed file 'data/images/wui/menus/menu_options_menu.png' => 'data/images/wui/menus/main_menu.png'
=== modified file 'data/images/wui/menus/menu_toggle_grid.png'
Binary files data/images/wui/menus/menu_toggle_grid.png	2019-03-14 10:30:55 +0000 and data/images/wui/menus/menu_toggle_grid.png	2019-06-01 16:05:47 +0000 differ
=== renamed file 'data/images/wui/menus/menu_toggle_newmessage_menu.png' => 'data/images/wui/menus/message_new.png'
=== renamed file 'data/images/wui/menus/menu_toggle_oldmessage_menu.png' => 'data/images/wui/menus/message_old.png'
=== renamed file 'data/images/wui/menus/menu_objectives.png' => 'data/images/wui/menus/objectives.png'
=== added file 'data/images/wui/menus/options.png'
Binary files data/images/wui/menus/options.png	1970-01-01 00:00:00 +0000 and data/images/wui/menus/options.png	2019-06-01 16:05:47 +0000 differ
=== renamed file 'data/images/wui/menus/menu_save_game.png' => 'data/images/wui/menus/save_game.png'
=== renamed file 'data/images/wui/fieldaction/menu_show_workarea_overlap.png' => 'data/images/wui/menus/show_workarea_overlap.png'
=== added file 'data/images/wui/menus/showhide.png'
Binary files data/images/wui/menus/showhide.png	1970-01-01 00:00:00 +0000 and data/images/wui/menus/showhide.png	2019-06-01 16:05:47 +0000 differ
=== renamed file 'data/images/wui/menus/menu_toggle_menu.png' => 'data/images/wui/menus/statistics.png'
=== renamed file 'data/images/wui/menus/menu_building_stats.png' => 'data/images/wui/menus/statistics_buildings.png'
=== renamed file 'data/images/wui/menus/menu_general_stats.png' => 'data/images/wui/menus/statistics_general.png'
=== added file 'data/images/wui/menus/statistics_seafaring.png'
Binary files data/images/wui/menus/statistics_seafaring.png	1970-01-01 00:00:00 +0000 and data/images/wui/menus/statistics_seafaring.png	2019-06-01 16:05:47 +0000 differ
=== renamed file 'data/images/wui/menus/menu_stock.png' => 'data/images/wui/menus/statistics_stock.png'
=== renamed file 'data/images/wui/menus/menu_ware_stats.png' => 'data/images/wui/menus/statistics_wares.png'
=== renamed file 'data/images/wui/menus/menu_toggle_bobs.png' => 'data/images/wui/menus/toggle_bobs.png'
=== renamed file 'data/images/wui/menus/menu_toggle_buildhelp.png' => 'data/images/wui/menus/toggle_buildhelp.png'
=== renamed file 'data/images/wui/fieldaction/menu_show_census.png' => 'data/images/wui/menus/toggle_census.png'
=== renamed file 'data/images/wui/menus/menu_toggle_immovables.png' => 'data/images/wui/menus/toggle_immovables.png'
=== renamed file 'data/images/wui/menus/menu_toggle_minimap.png' => 'data/images/wui/menus/toggle_minimap.png'
=== renamed file 'data/images/wui/menus/menu_toggle_resources.png' => 'data/images/wui/menus/toggle_resources.png'
=== renamed file 'data/images/wui/fieldaction/menu_show_statistics.png' => 'data/images/wui/menus/toggle_statistics.png'
=== renamed file 'data/images/wui/menus/menu_watch_follow.png' => 'data/images/wui/menus/watch_follow.png'
=== added file 'data/images/wui/menus/zoom_decrease.png'
Binary files data/images/wui/menus/zoom_decrease.png	1970-01-01 00:00:00 +0000 and data/images/wui/menus/zoom_decrease.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/images/wui/menus/zoom_increase.png'
Binary files data/images/wui/menus/zoom_increase.png	1970-01-01 00:00:00 +0000 and data/images/wui/menus/zoom_increase.png	2019-06-01 16:05:47 +0000 differ
=== renamed file 'data/images/wui/menus/menu_reset_zoom.png' => 'data/images/wui/menus/zoom_reset.png'
=== added directory 'data/images/wui/toolbar'
=== added file 'data/images/wui/toolbar/center.png'
Binary files data/images/wui/toolbar/center.png	1970-01-01 00:00:00 +0000 and data/images/wui/toolbar/center.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/images/wui/toolbar/left.png'
Binary files data/images/wui/toolbar/left.png	1970-01-01 00:00:00 +0000 and data/images/wui/toolbar/left.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/images/wui/toolbar/left_corner.png'
Binary files data/images/wui/toolbar/left_corner.png	1970-01-01 00:00:00 +0000 and data/images/wui/toolbar/left_corner.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/images/wui/toolbar/right.png'
Binary files data/images/wui/toolbar/right.png	1970-01-01 00:00:00 +0000 and data/images/wui/toolbar/right.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/images/wui/toolbar/right_corner.png'
Binary files data/images/wui/toolbar/right_corner.png	1970-01-01 00:00:00 +0000 and data/images/wui/toolbar/right_corner.png	2019-06-01 16:05:47 +0000 differ
=== modified file 'data/tribes/atlanteans.lua'
--- data/tribes/atlanteans.lua	2019-05-25 08:51:42 +0000
+++ data/tribes/atlanteans.lua	2019-06-01 16:05:47 +0000
@@ -44,6 +44,19 @@
 --    **ship**: The internal name of the tribe's ship.
 --
 --    **port**: The internal name of the tribe's port building. This unit needs to be defined in the ``buildings`` table too.
+--
+--    **toolbar**: *Optional*. Replace the default toolbar images with these custom images. Example:
+--
+--    .. code-block:: lua
+--
+--       toolbar = {
+--          left_corner = dirname .. "images/atlanteans/toolbar_left_corner.png",
+--          left = dirname .. "images/atlanteans/toolbar_left.png", -- Will be tiled
+--          center = dirname .. "images/atlanteans/toolbar_center.png",
+--          right = dirname .. "images/atlanteans/toolbar_right.png", -- Will be tiled
+--          right_corner = dirname .. "images/atlanteans/toolbar_right_corner.png"
+--       }
+--
 
 image_dirname = path.dirname(__file__) .. "images/atlanteans/"
 
@@ -370,4 +383,12 @@
    rawlog = "log",
    refinedlog = "planks",
    granite = "granite",
+
+   toolbar = {
+      left_corner = image_dirname .. "toolbar_left_corner.png",
+      left = image_dirname .. "toolbar_left.png",
+      center = image_dirname .. "toolbar_center.png",
+      right = image_dirname .. "toolbar_right.png",
+      right_corner = image_dirname .. "toolbar_right_corner.png"
+   }
 }

=== added file 'data/tribes/images/atlanteans/toolbar_center.png'
Binary files data/tribes/images/atlanteans/toolbar_center.png	1970-01-01 00:00:00 +0000 and data/tribes/images/atlanteans/toolbar_center.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/tribes/images/atlanteans/toolbar_left.png'
Binary files data/tribes/images/atlanteans/toolbar_left.png	1970-01-01 00:00:00 +0000 and data/tribes/images/atlanteans/toolbar_left.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/tribes/images/atlanteans/toolbar_left_corner.png'
Binary files data/tribes/images/atlanteans/toolbar_left_corner.png	1970-01-01 00:00:00 +0000 and data/tribes/images/atlanteans/toolbar_left_corner.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/tribes/images/atlanteans/toolbar_right.png'
Binary files data/tribes/images/atlanteans/toolbar_right.png	1970-01-01 00:00:00 +0000 and data/tribes/images/atlanteans/toolbar_right.png	2019-06-01 16:05:47 +0000 differ
=== added file 'data/tribes/images/atlanteans/toolbar_right_corner.png'
Binary files data/tribes/images/atlanteans/toolbar_right_corner.png	1970-01-01 00:00:00 +0000 and data/tribes/images/atlanteans/toolbar_right_corner.png	2019-06-01 16:05:47 +0000 differ
=== modified file 'regression_test.py'
--- regression_test.py	2019-03-15 19:37:37 +0000
+++ regression_test.py	2019-06-01 16:05:47 +0000
@@ -137,6 +137,9 @@
         self.assertTrue("All Tests passed" in stdout,
             "Not all tests pass. {}.".format(common_msg)
         )
+        self.assertFalse("lua_errors.cc" in stdout,
+            "Not all tests pass. {}.".format(common_msg)
+        )
         out("done.\n")
         if self.keep_output_around:
             out("    stdout: {}\n".format(stdout_filename))

=== modified file 'src/editor/CMakeLists.txt'
--- src/editor/CMakeLists.txt	2019-06-01 16:05:46 +0000
+++ src/editor/CMakeLists.txt	2019-06-01 16:05:47 +0000
@@ -49,8 +49,6 @@
     ui_menus/categorized_item_selection_menu.h
     ui_menus/help.cc
     ui_menus/help.h
-    ui_menus/main_menu.cc
-    ui_menus/main_menu.h
     ui_menus/main_menu_load_map.cc
     ui_menus/main_menu_load_map.h
     ui_menus/main_menu_load_or_save_map.cc
@@ -73,8 +71,6 @@
     ui_menus/tool_change_height_options_menu.h
     ui_menus/tool_change_resources_options_menu.cc
     ui_menus/tool_change_resources_options_menu.h
-    ui_menus/tool_menu.cc
-    ui_menus/tool_menu.h
     ui_menus/tool_noise_height_options_menu.cc
     ui_menus/tool_noise_height_options_menu.h
     ui_menus/tool_options_menu.cc

=== modified file 'src/editor/editorinteractive.cc'
--- src/editor/editorinteractive.cc	2019-04-26 05:52:49 +0000
+++ src/editor/editorinteractive.cc	2019-06-01 16:05:47 +0000
@@ -29,13 +29,29 @@
 #include "base/i18n.h"
 #include "base/scoped_timer.h"
 #include "base/warning.h"
-#include "editor/tools/delete_immovable_tool.h"
+#include "editor/tools/decrease_height_tool.h"
+#include "editor/tools/decrease_resources_tool.h"
+#include "editor/tools/increase_height_tool.h"
+#include "editor/tools/increase_resources_tool.h"
+#include "editor/tools/noise_height_tool.h"
+#include "editor/tools/place_critter_tool.h"
+#include "editor/tools/place_immovable_tool.h"
+#include "editor/tools/set_port_space_tool.h"
+#include "editor/tools/set_terrain_tool.h"
 #include "editor/ui_menus/help.h"
-#include "editor/ui_menus/main_menu.h"
 #include "editor/ui_menus/main_menu_load_map.h"
+#include "editor/ui_menus/main_menu_map_options.h"
+#include "editor/ui_menus/main_menu_new_map.h"
+#include "editor/ui_menus/main_menu_random_map.h"
 #include "editor/ui_menus/main_menu_save_map.h"
 #include "editor/ui_menus/player_menu.h"
-#include "editor/ui_menus/tool_menu.h"
+#include "editor/ui_menus/tool_change_height_options_menu.h"
+#include "editor/ui_menus/tool_change_resources_options_menu.h"
+#include "editor/ui_menus/tool_noise_height_options_menu.h"
+#include "editor/ui_menus/tool_place_critter_options_menu.h"
+#include "editor/ui_menus/tool_place_immovable_options_menu.h"
+#include "editor/ui_menus/tool_resize_options_menu.h"
+#include "editor/ui_menus/tool_set_terrain_options_menu.h"
 #include "editor/ui_menus/toolsize_menu.h"
 #include "graphic/graphic.h"
 #include "graphic/playercolor.h"
@@ -70,66 +86,45 @@
      need_save_(false),
      realtime_(SDL_GetTicks()),
      is_painting_(false),
+	 mainmenu_(
+		toolbar(), "dropdown_menu_main", 0, 0, 34U, 10, 34U,
+		 /** TRANSLATORS: Title for the main menu button in the editor */
+		 as_tooltip_text_with_hotkey(_("Main Menu"), "h"),
+		 UI::DropdownType::kPictorialMenu,
+		 UI::PanelStyle::kWui, UI::ButtonStyle::kWuiPrimary),
+	 toolmenu_(
+		toolbar(), "dropdown_menu_tools", 0, 0, 34U, 12, 34U,
+		 /** TRANSLATORS: Title for the tool menu button in the editor */
+		 as_tooltip_text_with_hotkey(_("Tools"), "t"),
+		 UI::DropdownType::kPictorialMenu,
+		 UI::PanelStyle::kWui, UI::ButtonStyle::kWuiPrimary),
+	 showhidemenu_(
+		toolbar(), "dropdown_menu_showhide", 0, 0, 34U, 10, 34U,
+		 /** TRANSLATORS: Title for a menu button in the editor. This menu will show/hide building spaces, animals, immovables, resources */
+		 _("Show / Hide"),
+		 UI::DropdownType::kPictorialMenu,
+		 UI::PanelStyle::kWui, UI::ButtonStyle::kWuiPrimary),
      undo_(nullptr),
      redo_(nullptr),
      tools_(new Tools(e.map())),
      history_(nullptr)  // history needs the undo/redo buttons
 {
-	add_toolbar_button("wui/menus/menu_toggle_menu", "menu", _("Main menu"), &mainmenu_, true);
-	mainmenu_.open_window = [this] { new EditorMainMenu(*this, mainmenu_); };
-
-	add_toolbar_button(
-	   "wui/editor/editor_menu_toggle_tool_menu", "tools", _("Tools"), &toolmenu_, true);
-	toolmenu_.open_window = [this] { new EditorToolMenu(*this, toolmenu_); };
-
-	add_toolbar_button(
-	   "wui/editor/editor_menu_set_toolsize_menu", "toolsize", _("Tool size"), &toolsizemenu_, true);
-	toolsizemenu_.open_window = [this] { new EditorToolsizeMenu(*this, toolsizemenu_); };
-
-	add_toolbar_button(
-	   "wui/editor/editor_menu_player_menu", "players", _("Players"), &playermenu_, true);
-	playermenu_.open_window = [this] {
-		select_tool(tools_->set_starting_pos, EditorTool::First);
-		new EditorPlayerMenu(*this, playermenu_);
-	};
-
-	toolbar()->add_space(15);
-
-	toggle_buildhelp_ = add_toolbar_button(
-	   "wui/menus/menu_toggle_buildhelp", "buildhelp", _("Show building spaces (on/off)"));
-	toggle_buildhelp_->sigclicked.connect(boost::bind(&EditorInteractive::toggle_buildhelp, this));
-	toggle_grid_ = add_toolbar_button("wui/menus/menu_toggle_grid", "grid", _("Show grid (on/off)"));
-	toggle_grid_->set_perm_pressed(true);
-	toggle_grid_->sigclicked.connect([this]() { toggle_grid(); });
-	toggle_immovables_ = add_toolbar_button(
-	   "wui/menus/menu_toggle_immovables", "immovables", _("Show immovables (on/off)"));
-	toggle_immovables_->set_perm_pressed(true);
-	toggle_immovables_->sigclicked.connect([this]() { toggle_immovables(); });
-	toggle_bobs_ =
-	   add_toolbar_button("wui/menus/menu_toggle_bobs", "animals", _("Show animals (on/off)"));
-	toggle_bobs_->set_perm_pressed(true);
-	toggle_bobs_->sigclicked.connect([this]() { toggle_bobs(); });
-	toggle_resources_ = add_toolbar_button(
-	   "wui/menus/menu_toggle_resources", "resources", _("Show resources (on/off)"));
-	toggle_resources_->set_perm_pressed(true);
-	toggle_resources_->sigclicked.connect([this]() { toggle_resources(); });
-
-	toolbar()->add_space(15);
-
-	add_toolbar_button(
-	   "wui/menus/menu_toggle_minimap", "minimap", _("Minimap"), &minimap_registry(), true);
-	minimap_registry().open_window = [this] { toggle_minimap(); };
-
-	auto zoom = add_toolbar_button("wui/menus/menu_reset_zoom", "reset_zoom", _("Reset zoom"));
-	zoom->sigclicked.connect([this] {
-		map_view()->zoom_around(
-		   1.f, Vector2f(get_w() / 2.f, get_h() / 2.f), MapView::Transition::Smooth);
-	});
-
-	toolbar()->add_space(15);
-
-	undo_ = add_toolbar_button("wui/editor/editor_undo", "undo", _("Undo"));
-	redo_ = add_toolbar_button("wui/editor/editor_redo", "redo", _("Redo"));
+	add_main_menu();
+	add_tool_menu();
+
+	add_toolbar_button(
+	   "wui/editor/menus/toolsize", "toolsize", _("Tool size"), &menu_windows_.toolsize, true);
+	menu_windows_.toolsize.open_window = [this] { new EditorToolsizeMenu(*this, menu_windows_.toolsize); };
+
+	toolbar()->add_space(15);
+
+	add_mapview_menu(MiniMapType::kStaticMap);
+	add_showhide_menu();
+
+	toolbar()->add_space(15);
+
+	undo_ = add_toolbar_button("wui/editor/menus/undo", "undo", _("Undo"));
+	redo_ = add_toolbar_button("wui/editor/menus/redo", "redo", _("Redo"));
 
 	history_.reset(new EditorHistory(*undo_, *redo_));
 
@@ -138,10 +133,10 @@
 
 	toolbar()->add_space(15);
 
-	add_toolbar_button("ui_basic/menu_help", "help", _("Help"), &helpmenu_, true);
-	helpmenu_.open_window = [this] { new EditorHelp(*this, helpmenu_, &egbase().lua()); };
+	add_toolbar_button("ui_basic/menu_help", "help", _("Help"), &menu_windows_.help, true);
+	menu_windows_.help.open_window = [this] { new EditorHelp(*this, menu_windows_.help, &egbase().lua()); };
 
-	adjust_toolbar_position();
+	finalize_toolbar();
 
 #ifndef NDEBUG
 	set_display_flag(InteractiveBase::dfDebug, true);
@@ -152,8 +147,269 @@
 	map_view()->field_clicked.connect([this](const Widelands::NodeAndTriangle<>& node_and_triangle) {
 		map_clicked(node_and_triangle, false);
 	});
-
-	minimap_registry().minimap_type = MiniMapType::kStaticMap;
+}
+
+
+void EditorInteractive::add_main_menu() {
+	mainmenu_.set_image(g_gr->images().get("images/wui/editor/menus/main_menu.png"));
+
+	menu_windows_.newmap.open_window = [this] {
+		new MainMenuNewMap(*this, menu_windows_.newmap);
+	};
+	/** TRANSLATORS: An entry in the editor's main menu */
+	mainmenu_.add(_("New Map"), MainMenuEntry::kNewMap,
+				  g_gr->images().get("images/wui/editor/menus/new_map.png"));
+
+	menu_windows_.newrandommap.open_window = [this] {
+		new MainMenuNewRandomMap(*this, menu_windows_.newrandommap);
+	};
+	/** TRANSLATORS: An entry in the editor's main menu */
+	mainmenu_.add(_("New Random Map"), MainMenuEntry::kNewRandomMap,
+				  g_gr->images().get("images/wui/editor/menus/new_random_map.png"));
+
+	menu_windows_.loadmap.open_window = [this] {
+		new MainMenuLoadMap(*this, menu_windows_.loadmap);
+	};
+	/** TRANSLATORS: An entry in the editor's main menu */
+	mainmenu_.add(_("Load Map"), MainMenuEntry::kLoadMap,
+				  g_gr->images().get("images/wui/editor/menus/load_map.png"),
+				  false, "", pgettext("hotkey", "Ctrl+l"));
+
+	menu_windows_.savemap.open_window = [this] {
+		new MainMenuSaveMap(*this, menu_windows_.savemap, menu_windows_.mapoptions);
+	};
+	/** TRANSLATORS: An entry in the editor's main menu */
+	mainmenu_.add(_("Save Map"), MainMenuEntry::kSaveMap,
+				  g_gr->images().get("images/wui/editor/menus/save_map.png"),
+				  false, "", pgettext("hotkey", "Ctrl+s"));
+
+	menu_windows_.mapoptions.open_window = [this] {
+		new MainMenuMapOptions(*this, menu_windows_.mapoptions);
+	};
+	/** TRANSLATORS: An entry in the editor's main menu */
+	mainmenu_.add(_("Map Options"), MainMenuEntry::kMapOptions,
+				  g_gr->images().get("images/wui/editor/menus/map_options.png"));
+
+	/** TRANSLATORS: An entry in the editor's main menu */
+	mainmenu_.add(_("Exit Editor"), MainMenuEntry::kExitEditor,
+				  g_gr->images().get("images/wui/menus/exit.png"));
+	mainmenu_.selected.connect([this] { main_menu_selected(mainmenu_.get_selected()); });
+	toolbar()->add(&mainmenu_);
+}
+
+void EditorInteractive::main_menu_selected(MainMenuEntry entry) {
+	switch (entry) {
+	case MainMenuEntry::kNewMap: {
+		menu_windows_.newmap.toggle();
+	} break;
+	case MainMenuEntry::kNewRandomMap: {
+		menu_windows_.newrandommap.toggle();
+	} break;
+	case MainMenuEntry::kLoadMap: {
+		menu_windows_.loadmap.toggle();
+	} break;
+	case MainMenuEntry::kSaveMap: {
+		menu_windows_.savemap.toggle();
+	} break;
+	case MainMenuEntry::kMapOptions: {
+		menu_windows_.mapoptions.toggle();
+	} break;
+	case MainMenuEntry::kExitEditor: {
+		exit();
+	}
+	}
+}
+
+void EditorInteractive::add_tool_menu() {
+	toolmenu_.set_image(g_gr->images().get("images/wui/editor/menus/tools.png"));
+
+	tool_windows_.height.open_window = [this] {
+		new EditorToolChangeHeightOptionsMenu(*this, tools()->increase_height, tool_windows_.height);
+	};
+	/** TRANSLATORS: An entry in the editor's tool menu */
+	toolmenu_.add(_("Change height"), ToolMenuEntry::kChangeHeight,
+				  g_gr->images().get("images/wui/editor/tools/height.png"), false,
+				  /** TRANSLATORS: Tooltip for the change height tool in the editor */
+				  _("Change the terrain height"));
+
+	tool_windows_.noiseheight.open_window = [this] {
+		new EditorToolNoiseHeightOptionsMenu(*this, tools()->noise_height, tool_windows_.noiseheight);
+	};
+	/** TRANSLATORS: An entry in the editor's tool menu */
+	toolmenu_.add(_("Random height"), ToolMenuEntry::kRandomHeight,
+				  g_gr->images().get("images/wui/editor/tools/noise_height.png"), false,
+				  /** TRANSLATORS: Tooltip for the random height tool in the editor */
+				  _("Set the terrain height to random values"));
+
+	tool_windows_.terrain.open_window = [this] {
+		new EditorToolSetTerrainOptionsMenu(*this, tools()->set_terrain, tool_windows_.terrain);
+	};
+	/** TRANSLATORS: An entry in the editor's tool menu */
+	toolmenu_.add(_("Terrain"), ToolMenuEntry::kTerrain,
+				  g_gr->images().get("images/wui/editor/tools/terrain.png"), false,
+				  /** TRANSLATORS: Tooltip for the terrain tool in the editor */
+				  _("Change the map’s terrain"));
+
+	tool_windows_.immovables.open_window = [this] {
+		new EditorToolPlaceImmovableOptionsMenu(*this, tools()->place_immovable, tool_windows_.immovables);
+	};
+	/** TRANSLATORS: An entry in the editor's tool menu */
+	toolmenu_.add(_("Immovables"), ToolMenuEntry::kImmovables,
+				  g_gr->images().get("images/wui/editor/tools/immovables.png"), false,
+				  /** TRANSLATORS: Tooltip for the immovables tool in the editor */
+				  _("Add or remove immovables"));
+
+	tool_windows_.critters.open_window = [this] {
+		new EditorToolPlaceCritterOptionsMenu(*this, tools()->place_critter, tool_windows_.critters);
+	};
+	/** TRANSLATORS: An entry in the editor's tool menu */
+	toolmenu_.add(_("Animals"), ToolMenuEntry::kAnimals,
+				  g_gr->images().get("images/wui/editor/tools/critters.png"), false,
+				  /** TRANSLATORS: Tooltip for the animals tool in the editor */
+				  _("Add or remove animals"));
+
+	tool_windows_.resources.open_window = [this] {
+		new EditorToolChangeResourcesOptionsMenu(*this, tools()->increase_resources, tool_windows_.resources);
+	};
+	/** TRANSLATORS: An entry in the editor's tool menu */
+	toolmenu_.add(_("Resources"), ToolMenuEntry::kResources,
+				  g_gr->images().get("images/wui/editor/tools/resources.png"), false,
+				  /** TRANSLATORS: Tooltip for the resources tool in the editor */
+				  _("Set or change resources"));
+
+	/** TRANSLATORS: An entry in the editor's tool menu */
+	toolmenu_.add(_("Port spaces"), ToolMenuEntry::kPortSpace,
+				  g_gr->images().get("images/wui/editor/tools/port_spaces.png"), false,
+				  /** TRANSLATORS: Tooltip for the port spaces tool in the editor */
+				  _("Add or remove port spaces"));
+
+	tool_windows_.players.open_window = [this] {
+		new EditorPlayerMenu(*this, tools()->set_starting_pos, tool_windows_.players);
+	};
+	/** TRANSLATORS: An entry in the editor's tool menu */
+	toolmenu_.add(_("Players"), ToolMenuEntry::kPlayers,
+				  g_gr->images().get("images/wui/editor/tools/players.png"), false,
+				  /** TRANSLATORS: Tooltip for the map size tool in the editor */
+				  _("Set number of players and their names, tribes and starting positions"), "p");
+
+	/** TRANSLATORS: An entry in the editor's tool menu */
+	toolmenu_.add(_("Map origin"), ToolMenuEntry::kMapOrigin,
+				  g_gr->images().get("images/wui/editor/tools/map_origin.png"), false,
+				  /** TRANSLATORS: Tooltip for the map origin tool in the editor */
+				  _("Set the position that will have the coordinates (0, 0). This will be the top-left corner of a generated minimap."));
+
+	tool_windows_.resizemap.open_window = [this] {
+		new EditorToolResizeOptionsMenu(*this, tools()->resize, tool_windows_.resizemap);
+	};
+	/** TRANSLATORS: An entry in the editor's tool menu */
+	toolmenu_.add(_("Map size"), ToolMenuEntry::kMapSize,
+				  g_gr->images().get("images/wui/editor/tools/resize_map.png"), false,
+				  /** TRANSLATORS: Tooltip for the map size tool in the editor */
+				  _("Change the map’s size"));
+
+	/** TRANSLATORS: An entry in the editor's tool menu */
+	toolmenu_.add(_("Information"), ToolMenuEntry::kFieldInfo,
+				  g_gr->images().get("images/wui/editor/fsel_editor_info.png"), false,
+				  /** TRANSLATORS: Tooltip for the map information tool in the editor */
+				  _("Click on a field to show information about it"), "i");
+	toolmenu_.selected.connect([this] { tool_menu_selected(toolmenu_.get_selected()); });
+	toolbar()->add(&toolmenu_);
+}
+
+void EditorInteractive::tool_menu_selected(ToolMenuEntry entry) {
+	switch (entry) {
+	case ToolMenuEntry::kChangeHeight:
+		tool_windows_.height.toggle();
+		break;
+	case ToolMenuEntry::kRandomHeight:
+		tool_windows_.noiseheight.toggle();
+		break;
+	case ToolMenuEntry::kTerrain:
+		tool_windows_.terrain.toggle();
+		break;
+	case ToolMenuEntry::kImmovables:
+		tool_windows_.immovables.toggle();
+		break;
+	case ToolMenuEntry::kAnimals:
+		tool_windows_.critters.toggle();
+		break;
+	case ToolMenuEntry::kResources:
+		tool_windows_.resources.toggle();
+		break;
+	case ToolMenuEntry::kPortSpace:
+		select_tool(tools()->set_port_space, EditorTool::First);
+		break;
+	case ToolMenuEntry::kPlayers:
+		tool_windows_.players.toggle();
+		break;
+	case ToolMenuEntry::kMapOrigin:
+		select_tool(tools()->set_origin, EditorTool::First);
+		break;
+	case ToolMenuEntry::kMapSize:
+		tool_windows_.resizemap.toggle();
+		break;
+	case ToolMenuEntry::kFieldInfo:
+		select_tool(tools()->info, EditorTool::First);
+		break;
+	}
+	toolmenu_.toggle();
+}
+
+void EditorInteractive::add_showhide_menu() {
+	showhidemenu_.set_image(g_gr->images().get("images/wui/menus/showhide.png"));
+	toolbar()->add(&showhidemenu_);
+
+	rebuild_showhide_menu();
+
+	showhidemenu_.selected.connect([this] { showhide_menu_selected(showhidemenu_.get_selected()); });
+}
+
+void EditorInteractive::rebuild_showhide_menu() {
+	showhidemenu_.clear();
+
+	/** TRANSLATORS: An entry in the editor's show/hide menu to toggle whether building spaces are shown */
+	showhidemenu_.add(buildhelp() ? _("Hide Building Spaces") : _("Show Building Spaces"),
+					  ShowHideEntry::kBuildingSpaces, g_gr->images().get("images/wui/menus/toggle_buildhelp.png"),
+					  false, "", pgettext("hotkey", "Space"));
+
+	/** TRANSLATORS: An entry in the editor's show/hide menu to toggle whether the map grid is shown */
+	showhidemenu_.add(draw_grid_ ? _("Hide Grid") : _("Show Grid"),
+					  ShowHideEntry::kGrid, g_gr->images().get("images/wui/menus/menu_toggle_grid.png"),
+					  false, "", "G");
+
+	/** TRANSLATORS: An entry in the editor's show/hide menu to toggle whether immovables (trees, rocks etc.) are shown */
+	showhidemenu_.add(draw_immovables_ ? _("Hide Immovables") : _("Show Immovables"), ShowHideEntry::kImmovables,
+					  g_gr->images().get("images/wui/menus/toggle_immovables.png"));
+
+	/** TRANSLATORS: An entry in the editor's show/hide menu to toggle whether animals are shown */
+	showhidemenu_.add(draw_bobs_ ? _("Hide Animals") : _("Show Animals"), ShowHideEntry::kAnimals,
+					  g_gr->images().get("images/wui/menus/toggle_bobs.png"));
+
+	/** TRANSLATORS: An entry in the editor's show/hide menu to toggle whether resources are shown */
+	showhidemenu_.add(draw_resources_ ? _("Hide Resources") : _("Show Resources"), ShowHideEntry::kResources,
+					  g_gr->images().get("images/wui/menus/toggle_resources.png"));
+
+}
+
+void EditorInteractive::showhide_menu_selected(ShowHideEntry entry) {
+	switch (entry) {
+	case ShowHideEntry::kBuildingSpaces: {
+		toggle_buildhelp();
+	} break;
+	case ShowHideEntry::kGrid: {
+		toggle_grid();
+	} break;
+	case ShowHideEntry::kImmovables: {
+		toggle_immovables();
+	} break;
+	case ShowHideEntry::kAnimals: {
+		toggle_bobs();
+	} break;
+	case ShowHideEntry::kResources: {
+		toggle_resources();
+	} break;
+	}
+	rebuild_showhide_menu();
 }
 
 void EditorInteractive::load(const std::string& filename) {
@@ -399,7 +655,7 @@
 		set_sel_radius(0);
 		return;
 	}
-	if (UI::UniqueWindow* const w = toolsizemenu_.window) {
+	if (UI::UniqueWindow* const w = menu_windows_.toolsize.window) {
 		dynamic_cast<EditorToolsizeMenu&>(*w).update(val);
 	} else {
 		set_sel_radius(val);
@@ -414,28 +670,20 @@
 	return true;
 }
 
-void EditorInteractive::on_buildhelp_changed(const bool value) {
-	toggle_buildhelp_->set_perm_pressed(value);
-}
-
 void EditorInteractive::toggle_resources() {
 	draw_resources_ = !draw_resources_;
-	toggle_resources_->set_perm_pressed(draw_resources_);
 }
 
 void EditorInteractive::toggle_immovables() {
 	draw_immovables_ = !draw_immovables_;
-	toggle_immovables_->set_perm_pressed(draw_immovables_);
 }
 
 void EditorInteractive::toggle_bobs() {
 	draw_bobs_ = !draw_bobs_;
-	toggle_bobs_->set_perm_pressed(draw_bobs_);
 }
 
 void EditorInteractive::toggle_grid() {
 	draw_grid_ = !draw_grid_;
-	toggle_grid_->set_perm_pressed(draw_grid_);
 }
 
 bool EditorInteractive::handle_key(bool const down, SDL_Keysym const code) {
@@ -530,21 +778,19 @@
 			return true;
 
 		case SDLK_l:
-			if (code.mod & (KMOD_LCTRL | KMOD_RCTRL))
-				new MainMenuLoadMap(*this);
-			return true;
-
-		case SDLK_m:
-			minimap_registry().toggle();
+			if (code.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
+				menu_windows_.loadmap.toggle();
+			}
 			return true;
 
 		case SDLK_p:
-			playermenu_.toggle();
+			tool_windows_.players.toggle();
 			return true;
 
 		case SDLK_s:
-			if (code.mod & (KMOD_LCTRL | KMOD_RCTRL))
-				new MainMenuSaveMap(*this);
+			if (code.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
+				menu_windows_.savemap.toggle();
+			}
 			return true;
 
 		case SDLK_t:
@@ -564,7 +810,7 @@
 			return true;
 
 		case SDLK_F1:
-			helpmenu_.toggle();
+			menu_windows_.help.toggle();
 			return true;
 
 		default:
@@ -595,12 +841,12 @@
 	if (which == EditorTool::First && &primary != tools_->current_pointer) {
 		if (primary.has_size_one()) {
 			set_sel_radius(0);
-			if (UI::UniqueWindow* const w = toolsizemenu_.window) {
+			if (UI::UniqueWindow* const w = menu_windows_.toolsize.window) {
 				EditorToolsizeMenu& toolsize_menu = dynamic_cast<EditorToolsizeMenu&>(*w);
 				toolsize_menu.set_buttons_enabled(false);
 			}
 		} else {
-			if (UI::UniqueWindow* const w = toolsizemenu_.window) {
+			if (UI::UniqueWindow* const w = menu_windows_.toolsize.window) {
 				EditorToolsizeMenu& toolsize_menu = dynamic_cast<EditorToolsizeMenu&>(*w);
 				toolsize_menu.update(toolsize_menu.value());
 			}

=== modified file 'src/editor/editorinteractive.h'
--- src/editor/editorinteractive.h	2019-04-24 16:59:23 +0000
+++ src/editor/editorinteractive.h	2019-06-01 16:05:47 +0000
@@ -37,10 +37,10 @@
 #include "logic/map.h"
 #include "notifications/notifications.h"
 #include "ui_basic/button.h"
+#include "ui_basic/dropdown.h"
 #include "ui_basic/unique_window.h"
 #include "wui/interactive_base.h"
 
-class Editor;
 class EditorTool;
 
 /**
@@ -138,16 +138,63 @@
 	// Access to the tools.
 	Tools* tools();
 
-	UI::UniqueWindow::Registry window_help;
-
 private:
-	friend struct EditorToolMenu;
+	// For referencing the items in mainmenu_
+	enum class MainMenuEntry {
+		kNewMap,
+		kNewRandomMap,
+		kLoadMap,
+		kSaveMap,
+		kMapOptions,
+		kExitEditor,
+	};
+
+	// For referencing the items in toolmenu_
+	enum class ToolMenuEntry {
+		kChangeHeight,
+		kRandomHeight,
+		kTerrain,
+		kImmovables,
+		kAnimals,
+		kResources,
+		kPortSpace,
+		kPlayers,
+		kMapOrigin,
+		kMapSize,
+		kFieldInfo
+	};
+
+	// For referencing the items in showhidemenu_
+	enum class ShowHideEntry {
+		kBuildingSpaces,
+		kGrid,
+		kAnimals,
+		kImmovables,
+		kResources
+	};
+
+	// Adds the mainmenu_ to the toolbar
+	void add_main_menu();
+	// Takes the appropriate action when an item in the mainmenu_ is selected
+	void main_menu_selected(MainMenuEntry entry);
+	// Adds the toolmenu_ to the toolbar
+	void add_tool_menu();
+	// Takes the appropriate action when an item in the toolmenu_ is selected
+	void tool_menu_selected(ToolMenuEntry entry);
+
+	// Adds the showhidemenu_ to the toolbar
+	void add_showhide_menu();
+	void rebuild_showhide_menu() override;
+	// Takes the appropriate action when an item in the showhidemenu_ is selected
+	void showhide_menu_selected(ShowHideEntry entry);
 
 	bool player_hears_field(const Widelands::Coords& coords) const override;
-	void on_buildhelp_changed(const bool value) override;
 
+	// Show / hide the resources overlays in the mapview
 	void toggle_resources();
+	// Show / hide the immovables in the mapview
 	void toggle_immovables();
+	// Show / hide the bobs in the mapview
 	void toggle_bobs();
 	void toggle_grid();
 
@@ -156,25 +203,38 @@
 	uint32_t realtime_;
 	bool is_painting_;
 
-	UI::UniqueWindow::Registry toolmenu_;
-
-	UI::UniqueWindow::Registry toolsizemenu_;
-	UI::UniqueWindow::Registry playermenu_;
-	UI::UniqueWindow::Registry mainmenu_;
-	UI::UniqueWindow::Registry heightmenu_;
-	UI::UniqueWindow::Registry noise_heightmenu_;
-	UI::UniqueWindow::Registry terrainmenu_;
-	UI::UniqueWindow::Registry immovablemenu_;
-	UI::UniqueWindow::Registry crittermenu_;
-	UI::UniqueWindow::Registry resourcesmenu_;
-	UI::UniqueWindow::Registry resizemenu_;
-	UI::UniqueWindow::Registry helpmenu_;
-
-	UI::Button* toggle_buildhelp_;
-	UI::Button* toggle_grid_;
-	UI::Button* toggle_resources_;
-	UI::Button* toggle_immovables_;
-	UI::Button* toggle_bobs_;
+	// All unique menu windows
+	struct EditorMenuWindows {
+		UI::UniqueWindow::Registry newmap;
+		UI::UniqueWindow::Registry newrandommap;
+		UI::UniqueWindow::Registry savemap;
+		UI::UniqueWindow::Registry loadmap;
+		UI::UniqueWindow::Registry mapoptions;
+
+		UI::UniqueWindow::Registry toolsize;
+
+		UI::UniqueWindow::Registry help;
+	} menu_windows_;
+
+	// All unique tool windows for those tools that have them
+	struct EditorToolWindows {
+		UI::UniqueWindow::Registry height;
+		UI::UniqueWindow::Registry noiseheight;
+		UI::UniqueWindow::Registry terrain;
+		UI::UniqueWindow::Registry immovables;
+		UI::UniqueWindow::Registry critters;
+		UI::UniqueWindow::Registry resources;
+		UI::UniqueWindow::Registry players;
+		UI::UniqueWindow::Registry resizemap;
+	} tool_windows_;
+
+	// Main menu on the toolbar
+	UI::Dropdown<MainMenuEntry> mainmenu_;
+	// Tools menu on the toolbar
+	UI::Dropdown<ToolMenuEntry> toolmenu_;
+	// Show / Hide menu on the toolbar
+	UI::Dropdown<ShowHideEntry> showhidemenu_;
+
 	UI::Button* undo_;
 	UI::Button* redo_;
 

=== removed file 'src/editor/ui_menus/main_menu.cc'
--- src/editor/ui_menus/main_menu.cc	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/main_menu.cc	1970-01-01 00:00:00 +0000
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2002-2019 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/main_menu.h"
-
-#include "base/i18n.h"
-#include "editor/editorinteractive.h"
-#include "editor/ui_menus/main_menu_load_map.h"
-#include "editor/ui_menus/main_menu_map_options.h"
-#include "editor/ui_menus/main_menu_new_map.h"
-#include "editor/ui_menus/main_menu_random_map.h"
-#include "editor/ui_menus/main_menu_save_map.h"
-
-// TODO(unknown): these should be defined globally for the whole UI
-#define width 200
-#define margin 15
-#define vspacing 15
-
-inline EditorInteractive& EditorMainMenu::eia() {
-	return dynamic_cast<EditorInteractive&>(*get_parent());
-}
-
-/**
- * Create all the buttons etc...
- */
-EditorMainMenu::EditorMainMenu(EditorInteractive& parent, UI::UniqueWindow::Registry& registry)
-   : UI::UniqueWindow(&parent, "main_menu", &registry, 2 * margin + width, 0, _("Main Menu")),
-     box_(this, margin, margin, UI::Box::Vertical, width, get_h() - 2 * margin, vspacing),
-     button_new_map_(
-        &box_, "new_map", 0, 0, width, 0, UI::ButtonStyle::kWuiSecondary, _("New Map")),
-     button_new_random_map_(&box_,
-                            "new_random_map",
-                            0,
-                            0,
-                            width,
-                            0,
-                            UI::ButtonStyle::kWuiSecondary,
-                            _("New Random Map")),
-     button_load_map_(
-        &box_, "load_map", 0, 0, width, 0, UI::ButtonStyle::kWuiSecondary, _("Load Map")),
-     button_save_map_(
-        &box_, "save_map", 0, 0, width, 0, UI::ButtonStyle::kWuiSecondary, _("Save Map")),
-     button_map_options_(
-        &box_, "map_options", 0, 0, width, 0, UI::ButtonStyle::kWuiSecondary, _("Map Options")),
-     button_exit_editor_(
-        &box_, "exit", 0, 0, width, 0, UI::ButtonStyle::kWuiPrimary, _("Exit Editor")) {
-	box_.add(&button_new_map_);
-	box_.add(&button_new_random_map_);
-	box_.add(&button_load_map_);
-	box_.add(&button_save_map_);
-	box_.add(&button_map_options_);
-	box_.add(&button_exit_editor_);
-	box_.set_size(width, 6 * button_new_map_.get_h() + 5 * vspacing);
-	set_inner_size(get_inner_w(), box_.get_h() + 2 * margin);
-
-	button_new_map_.sigclicked.connect(boost::bind(&EditorMainMenu::new_map_btn, this));
-	button_new_random_map_.sigclicked.connect(
-	   boost::bind(&EditorMainMenu::new_random_map_btn, this));
-	button_load_map_.sigclicked.connect(boost::bind(&EditorMainMenu::load_btn, this));
-	button_save_map_.sigclicked.connect(boost::bind(&EditorMainMenu::save_btn, this));
-	button_map_options_.sigclicked.connect(boost::bind(&EditorMainMenu::map_options_btn, this));
-	button_exit_editor_.sigclicked.connect(boost::bind(&EditorMainMenu::exit_btn, this));
-
-	// Put in the default position, if necessary
-	if (get_usedefaultpos())
-		center_to_parent();
-}
-
-void EditorMainMenu::new_map_btn() {
-	new MainMenuNewMap(eia());
-	die();
-}
-
-void EditorMainMenu::new_random_map_btn() {
-	new MainMenuNewRandomMap(eia());
-	die();
-}
-
-void EditorMainMenu::load_btn() {
-	new MainMenuLoadMap(eia());
-	die();
-}
-
-void EditorMainMenu::save_btn() {
-	new MainMenuSaveMap(eia());
-	die();
-}
-void EditorMainMenu::map_options_btn() {
-	new MainMenuMapOptions(eia());
-	die();
-}
-void EditorMainMenu::exit_btn() {
-	eia().exit();
-}

=== removed file 'src/editor/ui_menus/main_menu.h'
--- src/editor/ui_menus/main_menu.h	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/main_menu.h	1970-01-01 00:00:00 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2002-2019 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_MAIN_MENU_H
-#define WL_EDITOR_UI_MENUS_MAIN_MENU_H
-
-#include "ui_basic/box.h"
-#include "ui_basic/button.h"
-#include "ui_basic/unique_window.h"
-
-class EditorInteractive;
-
-/**
- * This represents the main menu
- */
-struct EditorMainMenu : public UI::UniqueWindow {
-	EditorMainMenu(EditorInteractive&, UI::UniqueWindow::Registry&);
-
-private:
-	EditorInteractive& eia();
-	UI::Box box_;
-	UI::Button button_new_map_;
-	UI::Button button_new_random_map_;
-	UI::Button button_load_map_;
-	UI::Button button_save_map_;
-	UI::Button button_map_options_;
-	UI::Button button_exit_editor_;
-
-	void exit_btn();
-	void load_btn();
-	void save_btn();
-	void new_map_btn();
-	void new_random_map_btn();
-	void map_options_btn();
-};
-
-#endif  // end of include guard: WL_EDITOR_UI_MENUS_MAIN_MENU_H

=== modified file 'src/editor/ui_menus/main_menu_load_map.cc'
--- src/editor/ui_menus/main_menu_load_map.cc	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/main_menu_load_map.cc	2019-06-01 16:05:47 +0000
@@ -32,8 +32,8 @@
 /**
  * Create all the buttons etc...
  */
-MainMenuLoadMap::MainMenuLoadMap(EditorInteractive& parent)
-   : MainMenuLoadOrSaveMap(parent, 2, "load_map_menu", _("Load Map")) {
+MainMenuLoadMap::MainMenuLoadMap(EditorInteractive& parent, UI::UniqueWindow::Registry& registry)
+   : MainMenuLoadOrSaveMap(parent, registry, 2, "load_map_menu", _("Load Map")) {
 	set_current_directory(curdir_);
 
 	table_.selected.connect(boost::bind(&MainMenuLoadMap::entry_selected, this));

=== modified file 'src/editor/ui_menus/main_menu_load_map.h'
--- src/editor/ui_menus/main_menu_load_map.h	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/main_menu_load_map.h	2019-06-01 16:05:47 +0000
@@ -29,7 +29,7 @@
  * Choose a filename and save your brand new created map
  */
 struct MainMenuLoadMap : public MainMenuLoadOrSaveMap {
-	explicit MainMenuLoadMap(EditorInteractive& parent);
+	explicit MainMenuLoadMap(EditorInteractive& parent, UI::UniqueWindow::Registry& registry);
 
 protected:
 	void clicked_ok() override;

=== modified file 'src/editor/ui_menus/main_menu_load_or_save_map.cc'
--- src/editor/ui_menus/main_menu_load_or_save_map.cc	2019-04-19 05:13:02 +0000
+++ src/editor/ui_menus/main_menu_load_or_save_map.cc	2019-06-01 16:05:47 +0000
@@ -30,12 +30,12 @@
 #include "io/filesystem/layered_filesystem.h"
 #include "map_io/widelands_map_loader.h"
 
-MainMenuLoadOrSaveMap::MainMenuLoadOrSaveMap(EditorInteractive& parent,
+MainMenuLoadOrSaveMap::MainMenuLoadOrSaveMap(EditorInteractive& parent, Registry& registry,
                                              int no_of_bottom_rows,
                                              const std::string& name,
                                              const std::string& title,
                                              const std::string& basedir)
-   : UI::Window(&parent, name, 0, 0, parent.get_inner_w() - 40, parent.get_inner_h() - 40, title),
+   : UI::UniqueWindow(&parent, name, &registry, parent.get_inner_w() - 40, parent.get_inner_h() - 40, title),
 
      // Values for alignment and size
      padding_(4),

=== modified file 'src/editor/ui_menus/main_menu_load_or_save_map.h'
--- src/editor/ui_menus/main_menu_load_or_save_map.h	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/main_menu_load_or_save_map.h	2019-06-01 16:05:47 +0000
@@ -27,15 +27,16 @@
 #include "ui_basic/button.h"
 #include "ui_basic/checkbox.h"
 #include "ui_basic/textarea.h"
-#include "ui_basic/window.h"
+#include "ui_basic/unique_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 {
+struct MainMenuLoadOrSaveMap : public UI::UniqueWindow {
 	MainMenuLoadOrSaveMap(EditorInteractive& parent,
+						  UI::UniqueWindow::Registry& registry,
 	                      int no_of_bottom_rows,
 	                      const std::string& name,
 	                      const std::string& title,

=== modified file 'src/editor/ui_menus/main_menu_map_options.cc'
--- src/editor/ui_menus/main_menu_map_options.cc	2019-04-18 08:32:25 +0000
+++ src/editor/ui_menus/main_menu_map_options.cc	2019-06-01 16:05:47 +0000
@@ -42,8 +42,8 @@
 /**
  * Create all the buttons etc...
  */
-MainMenuMapOptions::MainMenuMapOptions(EditorInteractive& parent, bool modal)
-   : UI::Window(&parent, "map_options", 0, 0, 350, parent.get_inner_h() - 80, _("Map Options")),
+MainMenuMapOptions::MainMenuMapOptions(EditorInteractive& parent, Registry& registry)
+   : UI::UniqueWindow(&parent, "map_options", &registry, 350, parent.get_inner_h() - 80, _("Map Options")),
      padding_(4),
      indent_(10),
      labelh_(text_height(UI::FontStyle::kLabel) + 4),
@@ -80,7 +80,7 @@
      teams_list_(
         &teams_box_, 0, 0, max_w_, 60, UI::PanelStyle::kWui, UI::ListselectLayout::kShowCheck),
 
-     modal_(modal) {
+	 registry_(registry) {
 
 	tab_box_.set_size(max_w_, get_inner_h() - labelh_ - 2 * padding_);
 	tabs_.set_size(max_w_, tab_box_.get_inner_h());
@@ -139,11 +139,11 @@
 	teams_box_.add(new UI::Textarea(&teams_box_, 0, 0, max_w_, labelh_, players));
 
 	tab_box_.add(&tabs_, UI::Box::Resizing::kFullSize);
-	tabs_.add("main_map_options", g_gr->images().get("images/wui/menus/menu_toggle_minimap.png"),
+	tabs_.add("main_map_options", g_gr->images().get("images/wui/menus/toggle_minimap.png"),
 	          &main_box_, _("Main Options"));
 	tabs_.add("map_tags", g_gr->images().get("images/ui_basic/checkbox_checked.png"), &tags_box_,
 	          _("Tags"));
-	tabs_.add("map_teams", g_gr->images().get("images/wui/editor/editor_menu_player_menu.png"),
+	tabs_.add("map_teams", g_gr->images().get("images/wui/editor/tools/players.png"),
 	          &teams_box_, _("Teams"));
 
 	name_.changed.connect(boost::bind(&MainMenuMapOptions::changed, this));
@@ -203,20 +203,12 @@
 			eia().egbase().mutable_map()->add_tag(tag.first);
 		}
 	}
-
-	if (modal_) {
-		end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kOk);
-	} else {
-		die();
-	}
+	Notifications::publish(NoteMapOptions());
+	registry_.destroy();
 }
 
 void MainMenuMapOptions::clicked_cancel() {
-	if (modal_) {
-		end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack);
-	} else {
-		die();
-	}
+	registry_.destroy();
 }
 
 /*

=== modified file 'src/editor/ui_menus/main_menu_map_options.h'
--- src/editor/ui_menus/main_menu_map_options.h	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/main_menu_map_options.h	2019-06-01 16:05:47 +0000
@@ -20,6 +20,7 @@
 #ifndef WL_EDITOR_UI_MENUS_MAIN_MENU_MAP_OPTIONS_H
 #define WL_EDITOR_UI_MENUS_MAIN_MENU_MAP_OPTIONS_H
 
+#include "logic/note_map_options.h"
 #include "ui_basic/box.h"
 #include "ui_basic/button.h"
 #include "ui_basic/checkbox.h"
@@ -28,7 +29,7 @@
 #include "ui_basic/multilineeditbox.h"
 #include "ui_basic/tabpanel.h"
 #include "ui_basic/textarea.h"
-#include "ui_basic/window.h"
+#include "ui_basic/unique_window.h"
 
 class EditorInteractive;
 
@@ -37,8 +38,8 @@
  * about the current map are displayed and you can change
  * author, name and description
  */
-struct MainMenuMapOptions : public UI::Window {
-	MainMenuMapOptions(EditorInteractive&, bool modal = false);
+struct MainMenuMapOptions : public UI::UniqueWindow {
+	MainMenuMapOptions(EditorInteractive&, UI::UniqueWindow::Registry& registry);
 
 private:
 	EditorInteractive& eia();
@@ -66,7 +67,7 @@
 
 	// Tag, Checkbox
 	std::map<std::string, UI::Checkbox*> tags_checkboxes_;
-	bool modal_;
+	UI::UniqueWindow::Registry& registry_;
 };
 
 #endif  // end of include guard: WL_EDITOR_UI_MENUS_MAIN_MENU_MAP_OPTIONS_H

=== modified file 'src/editor/ui_menus/main_menu_new_map.cc'
--- src/editor/ui_menus/main_menu_new_map.cc	2019-06-01 16:05:46 +0000
+++ src/editor/ui_menus/main_menu_new_map.cc	2019-06-01 16:05:47 +0000
@@ -41,8 +41,8 @@
 	return dynamic_cast<EditorInteractive&>(*get_parent());
 }
 
-MainMenuNewMap::MainMenuNewMap(EditorInteractive& parent)
-   : UI::Window(&parent, "new_map_menu", 0, 0, 360, 150, _("New Map")),
+MainMenuNewMap::MainMenuNewMap(EditorInteractive& parent, Registry& registry)
+   : UI::UniqueWindow(&parent, "new_map_menu", &registry, 360, 150, _("New Map")),
      margin_(4),
      box_width_(get_inner_w() - 2 * margin_),
      box_(this, margin_, margin_, UI::Box::Vertical, 0, 0, margin_),

=== modified file 'src/editor/ui_menus/main_menu_new_map.h'
--- src/editor/ui_menus/main_menu_new_map.h	2019-06-01 16:05:46 +0000
+++ src/editor/ui_menus/main_menu_new_map.h	2019-06-01 16:05:47 +0000
@@ -25,7 +25,7 @@
 #include "ui_basic/box.h"
 #include "ui_basic/button.h"
 #include "ui_basic/listselect.h"
-#include "ui_basic/window.h"
+#include "ui_basic/unique_window.h"
 
 class EditorInteractive;
 
@@ -34,8 +34,8 @@
  * the user to choose the new world and a few other
  * things like size, world ....
  */
-struct MainMenuNewMap : public UI::Window {
-	explicit MainMenuNewMap(EditorInteractive&);
+struct MainMenuNewMap : public UI::UniqueWindow {
+	explicit MainMenuNewMap(EditorInteractive&, UI::UniqueWindow::Registry&);
 
 private:
 	EditorInteractive& eia();

=== modified file 'src/editor/ui_menus/main_menu_random_map.cc'
--- src/editor/ui_menus/main_menu_random_map.cc	2019-06-01 16:05:46 +0000
+++ src/editor/ui_menus/main_menu_random_map.cc	2019-06-01 16:05:47 +0000
@@ -47,8 +47,8 @@
 
 using namespace Widelands;
 
-MainMenuNewRandomMap::MainMenuNewRandomMap(EditorInteractive& parent)
-   : UI::Window(&parent, "random_map_menu", 0, 0, 400, 500, _("New Random Map")),
+MainMenuNewRandomMap::MainMenuNewRandomMap(EditorInteractive& parent, UI::UniqueWindow::Registry& registry)
+   : UI::UniqueWindow(&parent, "random_map_menu", &registry, 400, 500, _("New Random Map")),
      // UI elements
      margin_(4),
      box_width_(get_inner_w() - 2 * margin_),

=== modified file 'src/editor/ui_menus/main_menu_random_map.h'
--- src/editor/ui_menus/main_menu_random_map.h	2019-06-01 16:05:46 +0000
+++ src/editor/ui_menus/main_menu_random_map.h	2019-06-01 16:05:47 +0000
@@ -30,7 +30,7 @@
 #include "ui_basic/editbox.h"
 #include "ui_basic/spinbox.h"
 #include "ui_basic/textarea.h"
-#include "ui_basic/window.h"
+#include "ui_basic/unique_window.h"
 
 namespace Widelands {
 struct UniqueRandomMapInfo;
@@ -46,8 +46,8 @@
  * the user to choose the new world and a few other
  * things like size, world ....
  */
-struct MainMenuNewRandomMap : public UI::Window {
-	explicit MainMenuNewRandomMap(EditorInteractive&);
+struct MainMenuNewRandomMap : public UI::UniqueWindow {
+	explicit MainMenuNewRandomMap(EditorInteractive&, UI::UniqueWindow::Registry&);
 
 	enum class ButtonId : uint8_t {
 		kNone,

=== modified file 'src/editor/ui_menus/main_menu_save_map.cc'
--- src/editor/ui_menus/main_menu_save_map.cc	2019-04-18 08:32:25 +0000
+++ src/editor/ui_menus/main_menu_save_map.cc	2019-06-01 16:05:47 +0000
@@ -31,7 +31,6 @@
 #include "base/macros.h"
 #include "base/wexception.h"
 #include "editor/editorinteractive.h"
-#include "editor/ui_menus/main_menu_map_options.h"
 #include "editor/ui_menus/main_menu_save_map_make_directory.h"
 #include "io/filesystem/filesystem.h"
 #include "io/filesystem/layered_filesystem.h"
@@ -49,9 +48,9 @@
 }
 
 // TODO(GunChleoc): Arabic: Make directory dialog: buttons need more height for Arabic.
-MainMenuSaveMap::MainMenuSaveMap(EditorInteractive& parent)
-   : MainMenuLoadOrSaveMap(parent, 3, "save_map_menu", _("Save Map"), "maps/My_Maps"),
-
+MainMenuSaveMap::MainMenuSaveMap(EditorInteractive& parent, UI::UniqueWindow::Registry& registry, Registry& map_options_registry)
+   : MainMenuLoadOrSaveMap(parent, registry, 3, "save_map_menu", _("Save Map"), "maps/My_Maps"),
+	 map_options_registry_(map_options_registry),
      make_directory_(this,
                      "make_directory",
                      right_column_x_,
@@ -114,6 +113,10 @@
 	MapData mapdata(map, "", maptype, MapData::DisplayType::kMapnames);
 
 	map_details_.update(mapdata, false);
+
+	subscriber_ = Notifications::subscribe<NoteMapOptions>([this](const NoteMapOptions&) {
+		update_map_options();
+	});
 }
 
 /**
@@ -196,24 +199,29 @@
 }
 
 void MainMenuSaveMap::clicked_edit_options() {
-	MainMenuMapOptions mo(eia(), true);
-	if (mo.run<UI::Panel::Returncodes>() == UI::Panel::Returncodes::kOk) {
-		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, MapData::DisplayType::kMapnames);
-
-		map_details_.update(mapdata, false);
-	}
-}
-
+	map_options_registry_.create();
+}
+
+void MainMenuSaveMap::update_map_options() {
+	const Widelands::Map& map = eia().egbase().map();
+	MapData::MapType maptype;
+
+	const std::string old_name = map_details_.name();
+
+	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, MapData::DisplayType::kMapnames);
+
+	map_details_.update(mapdata, false);
+	if (old_name == editbox_->text()) {
+		editbox_->set_text(map_details_.name());
+	}
+}
 /**
  * called when an item was selected
  */

=== modified file 'src/editor/ui_menus/main_menu_save_map.h'
--- src/editor/ui_menus/main_menu_save_map.h	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/main_menu_save_map.h	2019-06-01 16:05:47 +0000
@@ -20,10 +20,12 @@
 #ifndef WL_EDITOR_UI_MENUS_MAIN_MENU_SAVE_MAP_H
 #define WL_EDITOR_UI_MENUS_MAIN_MENU_SAVE_MAP_H
 
+#include <memory>
 #include <string>
 
 #include "editor/editorinteractive.h"
 #include "editor/ui_menus/main_menu_load_or_save_map.h"
+#include "editor/ui_menus/main_menu_map_options.h"
 #include "ui_basic/button.h"
 #include "ui_basic/editbox.h"
 #include "ui_basic/textarea.h"
@@ -32,7 +34,7 @@
  * Choose a filename and save your brand new created map
  */
 struct MainMenuSaveMap : public MainMenuLoadOrSaveMap {
-	explicit MainMenuSaveMap(EditorInteractive& parent);
+	explicit MainMenuSaveMap(EditorInteractive& parent, UI::UniqueWindow::Registry& registry, UI::UniqueWindow::Registry& map_options_registry);
 
 protected:
 	// Sets the current dir and updates labels.
@@ -40,6 +42,8 @@
 
 private:
 	EditorInteractive& eia();
+	Registry& map_options_registry_;
+
 	void clicked_ok() override;
 	void clicked_make_directory();
 	void clicked_edit_options();
@@ -49,6 +53,8 @@
 	/// Resets the map's filename in the editbox. If mapname didn't change, die().
 	void reset_editbox_or_die(const std::string& current_filename);
 
+	void update_map_options();
+
 	bool save_map(std::string, bool);
 
 	UI::Button make_directory_, edit_options_;
@@ -56,6 +62,8 @@
 	UI::Textarea editbox_label_;
 	UI::EditBox* editbox_;
 	const std::string illegal_filename_tooltip_;
+
+	std::unique_ptr<Notifications::Subscriber<NoteMapOptions>> subscriber_;
 };
 
 #endif  // end of include guard: WL_EDITOR_UI_MENUS_MAIN_MENU_SAVE_MAP_H

=== modified file 'src/editor/ui_menus/player_menu.cc'
--- src/editor/ui_menus/player_menu.cc	2019-06-01 16:05:46 +0000
+++ src/editor/ui_menus/player_menu.cc	2019-06-01 16:05:47 +0000
@@ -119,8 +119,8 @@
 	return dynamic_cast<EditorInteractive&>(*get_parent());
 }
 
-EditorPlayerMenu::EditorPlayerMenu(EditorInteractive& parent, UI::UniqueWindow::Registry& registry)
-   : UI::UniqueWindow(&parent, "players_menu", &registry, 100, 100, _("Player Options")),
+EditorPlayerMenu::EditorPlayerMenu(EditorInteractive& parent, EditorSetStartingPosTool& tool, UI::UniqueWindow::Registry& registry)
+   : EditorToolOptionsMenu(parent, registry, 0, 0, _("Player Options"), tool),
      box_(this, kMargin, kMargin, UI::Box::Vertical),
      no_of_players_(&box_,
 					"dropdown_map_players",

=== modified file 'src/editor/ui_menus/player_menu.h'
--- src/editor/ui_menus/player_menu.h	2019-02-27 19:00:36 +0000
+++ src/editor/ui_menus/player_menu.h	2019-06-01 16:05:47 +0000
@@ -24,6 +24,7 @@
 #include <string>
 #include <vector>
 
+#include "editor/ui_menus/tool_options_menu.h"
 #include "ui_basic/box.h"
 #include "ui_basic/button.h"
 #include "ui_basic/dropdown.h"
@@ -32,9 +33,9 @@
 
 class EditorInteractive;
 
-class EditorPlayerMenu : public UI::UniqueWindow {
+class EditorPlayerMenu : public EditorToolOptionsMenu {
 public:
-	EditorPlayerMenu(EditorInteractive&, UI::UniqueWindow::Registry&);
+	EditorPlayerMenu(EditorInteractive&, EditorSetStartingPosTool& tool, UI::UniqueWindow::Registry&);
 	~EditorPlayerMenu() override {
 	}
 

=== modified file 'src/editor/ui_menus/tool_change_height_options_menu.cc'
--- src/editor/ui_menus/tool_change_height_options_menu.cc	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/tool_change_height_options_menu.cc	2019-06-01 16:05:47 +0000
@@ -32,7 +32,7 @@
    EditorInteractive& parent,
    EditorIncreaseHeightTool& increase_tool,
    UI::UniqueWindow::Registry& registry)
-   : EditorToolOptionsMenu(parent, registry, 350, 100, _("Height Tools Options")),
+   : EditorToolOptionsMenu(parent, registry, 350, 100, _("Height Tools Options"), increase_tool),
      increase_tool_(increase_tool),
      box_(this, hmargin(), vmargin(), UI::Box::Vertical, 0, 0, vspacing()),
      change_by_(&box_,

=== modified file 'src/editor/ui_menus/tool_change_resources_options_menu.cc'
--- src/editor/ui_menus/tool_change_resources_options_menu.cc	2019-05-12 07:45:59 +0000
+++ src/editor/ui_menus/tool_change_resources_options_menu.cc	2019-06-01 16:05:47 +0000
@@ -45,7 +45,7 @@
    EditorInteractive& parent,
    EditorIncreaseResourcesTool& increase_tool,
    UI::UniqueWindow::Registry& registry)
-   : EditorToolOptionsMenu(parent, registry, 370, 120, _("Resources")),
+   : EditorToolOptionsMenu(parent, registry, 370, 120, _("Resources"), increase_tool),
      increase_tool_(increase_tool),
      box_(this, hmargin(), vmargin(), UI::Box::Vertical, 0, 0, vspacing()),
      change_by_(&box_,

=== removed file 'src/editor/ui_menus/tool_menu.cc'
--- src/editor/ui_menus/tool_menu.cc	2019-04-24 07:09:29 +0000
+++ src/editor/ui_menus/tool_menu.cc	1970-01-01 00:00:00 +0000
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2002-2019 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/tool_menu.h"
-
-#include "base/i18n.h"
-#include "base/wexception.h"
-#include "editor/editorinteractive.h"
-#include "editor/tools/decrease_height_tool.h"
-#include "editor/tools/decrease_resources_tool.h"
-#include "editor/tools/increase_height_tool.h"
-#include "editor/tools/increase_resources_tool.h"
-#include "editor/tools/noise_height_tool.h"
-#include "editor/tools/place_critter_tool.h"
-#include "editor/tools/place_immovable_tool.h"
-#include "editor/tools/set_port_space_tool.h"
-#include "editor/tools/set_terrain_tool.h"
-#include "editor/ui_menus/tool_change_height_options_menu.h"
-#include "editor/ui_menus/tool_change_resources_options_menu.h"
-#include "editor/ui_menus/tool_noise_height_options_menu.h"
-#include "editor/ui_menus/tool_place_critter_options_menu.h"
-#include "editor/ui_menus/tool_place_immovable_options_menu.h"
-#include "editor/ui_menus/tool_resize_options_menu.h"
-#include "editor/ui_menus/tool_set_terrain_options_menu.h"
-#include "graphic/graphic.h"
-#include "ui_basic/radiobutton.h"
-#include "ui_basic/textarea.h"
-
-EditorToolMenu::EditorToolMenu(EditorInteractive& parent, UI::UniqueWindow::Registry& registry)
-   : UI::UniqueWindow(&parent, "tool_menu", &registry, 350, 400, _("Tools")) {
-
-#define spacing 5
-	Vector2i const offs(spacing, spacing);
-	Vector2i pos = offs;
-	int32_t const width = 34;
-	int32_t const height = 34;
-
-	int32_t const num_tools = 9;
-#define ADD_BUTTON(pic, tooltip)                                                                   \
-	radioselect_.add_button(                                                                        \
-	   this, pos, g_gr->images().get("images/wui/editor/editor_menu_tool_" pic ".png"), tooltip);   \
-	pos.x += width + spacing;
-
-	ADD_BUTTON("change_height", _("Change height"))
-	ADD_BUTTON("noise_height", _("Random height"))
-	ADD_BUTTON("set_terrain", _("Terrain"))
-	ADD_BUTTON("place_immovable", _("Immovables"))
-	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."));
-	ADD_BUTTON("resize", _("Change the map’s size"));
-
-	set_inner_size(offs.x + (width + spacing) * num_tools, offs.y + (height + spacing));
-
-	{
-		const EditorTool* current = &parent.tools()->current();
-		radioselect_.set_state(current == &parent.tools()->noise_height ?
-		                          1 :
-		                          current == &parent.tools()->set_terrain ?
-		                          2 :
-		                          current == &parent.tools()->place_immovable ?
-		                          3 :
-		                          current == &parent.tools()->place_critter ?
-		                          4 :
-		                          current == &parent.tools()->increase_resources ?
-		                          5 :
-		                          current == &parent.tools()->set_port_space ?
-		                          6 :
-		                          current == &parent.tools()->set_origin ?
-		                          7 :
-		                          current == &parent.tools()->resize ? 8 : 0);
-	}
-
-	radioselect_.changed.connect(boost::bind(&EditorToolMenu::changed_to, this));
-	radioselect_.clicked.connect(boost::bind(&EditorToolMenu::changed_to, this));
-
-	if (get_usedefaultpos())
-		center_to_parent();
-}
-
-/**
- * Called when the radiogroup changes or is reclicked
- */
-void EditorToolMenu::changed_to() {
-	const int32_t n = radioselect_.get_state();
-
-	EditorInteractive& parent = dynamic_cast<EditorInteractive&>(*get_parent());
-
-	EditorTool* current_tool_pointer = nullptr;
-	UI::UniqueWindow::Registry* current_registry_pointer = nullptr;
-	switch (n) {
-	case 0:
-		current_tool_pointer = &parent.tools()->increase_height;
-		current_registry_pointer = &parent.heightmenu_;
-		break;
-	case 1:
-		current_tool_pointer = &parent.tools()->noise_height;
-		current_registry_pointer = &parent.noise_heightmenu_;
-		break;
-	case 2:
-		current_tool_pointer = &parent.tools()->set_terrain;
-		current_registry_pointer = &parent.terrainmenu_;
-		break;
-	case 3:
-		current_tool_pointer = &parent.tools()->place_immovable;
-		current_registry_pointer = &parent.immovablemenu_;
-		break;
-	case 4:
-		current_tool_pointer = &parent.tools()->place_critter;
-		current_registry_pointer = &parent.crittermenu_;
-		break;
-	case 5:
-		current_tool_pointer = &parent.tools()->increase_resources;
-		current_registry_pointer = &parent.resourcesmenu_;
-		break;
-	case 6:
-		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;
-	case 8:
-		current_tool_pointer = &parent.tools()->resize;
-		current_registry_pointer = &parent.resizemenu_;
-		break;
-	default:
-		NEVER_HERE();
-	}
-
-	parent.select_tool(*current_tool_pointer, EditorTool::First);
-
-	if (current_registry_pointer) {
-		if (UI::Window* const window = current_registry_pointer->window) {
-			// There is already a window. If it is minimal, restore it.
-			if (window->is_minimal())
-				window->restore();
-			else
-				delete window;
-		} else
-			switch (n) {  //  create window
-			case 0:
-				new EditorToolChangeHeightOptionsMenu(
-				   parent, parent.tools()->increase_height, *current_registry_pointer);
-				break;
-			case 1:
-				new EditorToolNoiseHeightOptionsMenu(
-				   parent, parent.tools()->noise_height, *current_registry_pointer);
-				break;
-			case 2:
-				new EditorToolSetTerrainOptionsMenu(
-				   parent, parent.tools()->set_terrain, *current_registry_pointer);
-				break;
-			case 3:
-				new EditorToolPlaceImmovableOptionsMenu(
-				   parent, parent.tools()->place_immovable, *current_registry_pointer);
-				break;
-			case 4:
-				new EditorToolPlaceCritterOptionsMenu(
-				   parent, parent.tools()->place_critter, *current_registry_pointer);
-				break;
-			case 5:
-				new EditorToolChangeResourcesOptionsMenu(
-				   parent, parent.tools()->increase_resources, *current_registry_pointer);
-				break;
-			case 8:
-				new EditorToolResizeOptionsMenu(
-				   parent, parent.tools()->resize, *current_registry_pointer);
-				break;
-			default:
-				NEVER_HERE();
-			}
-	}
-}

=== removed file 'src/editor/ui_menus/tool_menu.h'
--- src/editor/ui_menus/tool_menu.h	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/tool_menu.h	1970-01-01 00:00:00 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2002-2019 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_TOOL_MENU_H
-#define WL_EDITOR_UI_MENUS_TOOL_MENU_H
-
-#include "editor/editorinteractive.h"
-#include "ui_basic/radiobutton.h"
-#include "ui_basic/unique_window.h"
-
-/// The tool selection window/menu.
-struct EditorToolMenu : public UI::UniqueWindow {
-	EditorToolMenu(EditorInteractive&, UI::UniqueWindow::Registry&);
-
-private:
-	UI::Radiogroup radioselect_;
-
-	void changed_to();
-};
-
-#endif  // end of include guard: WL_EDITOR_UI_MENUS_TOOL_MENU_H

=== modified file 'src/editor/ui_menus/tool_noise_height_options_menu.cc'
--- src/editor/ui_menus/tool_noise_height_options_menu.cc	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/tool_noise_height_options_menu.cc	2019-06-01 16:05:47 +0000
@@ -35,7 +35,7 @@
    EditorInteractive& parent,
    EditorNoiseHeightTool& noise_tool,
    UI::UniqueWindow::Registry& registry)
-   : EditorToolOptionsMenu(parent, registry, 300, 120, _("Random Height Options")),
+   : EditorToolOptionsMenu(parent, registry, 300, 120, _("Random Height Options"), noise_tool),
      noise_tool_(noise_tool),
      box_(this, hmargin(), vmargin(), UI::Box::Vertical, 0, 0, vspacing()),
      lower_(&box_,

=== modified file 'src/editor/ui_menus/tool_options_menu.cc'
--- src/editor/ui_menus/tool_options_menu.cc	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/tool_options_menu.cc	2019-06-01 16:05:47 +0000
@@ -23,14 +23,14 @@
                                              UI::UniqueWindow::Registry& registry,
                                              uint32_t const width,
                                              uint32_t const height,
-                                             char const* const title)
+                                             const std::string& title, EditorTool& tool)
    : UI::UniqueWindow(&parent, "tool_options_menu", &registry, width, height, title),
-     current_pointer_(parent.tools()->current_pointer) {
-	if (get_usedefaultpos())
-		center_to_parent();
+	 parent_(parent),
+     current_tool_(tool) {
+	select_correct_tool();
+	clicked.connect([this] { select_correct_tool(); });
 }
 
 void EditorToolOptionsMenu::select_correct_tool() {
-	dynamic_cast<EditorInteractive&>(*get_parent())
-	   .select_tool(*current_pointer_, EditorTool::First);
+	parent_.select_tool(current_tool_, EditorTool::First);
 }

=== modified file 'src/editor/ui_menus/tool_options_menu.h'
--- src/editor/ui_menus/tool_options_menu.h	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/tool_options_menu.h	2019-06-01 16:05:47 +0000
@@ -28,7 +28,8 @@
 	                      UI::UniqueWindow::Registry&,
 	                      const uint32_t width,
 	                      const uint32_t height,
-	                      char const* title);
+	                      const std::string& title,
+						  EditorTool& tool);
 
 	/**
 	 * Selects the correct tool from the parent.
@@ -53,7 +54,8 @@
 	}
 
 private:
-	EditorTool* current_pointer_;
+	EditorInteractive& parent_;
+	EditorTool& current_tool_;
 };
 
 #endif  // end of include guard: WL_EDITOR_UI_MENUS_TOOL_OPTIONS_MENU_H

=== modified file 'src/editor/ui_menus/tool_place_critter_options_menu.cc'
--- src/editor/ui_menus/tool_place_critter_options_menu.cc	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/tool_place_critter_options_menu.cc	2019-06-01 16:05:47 +0000
@@ -47,7 +47,7 @@
 
 EditorToolPlaceCritterOptionsMenu::EditorToolPlaceCritterOptionsMenu(
    EditorInteractive& parent, EditorPlaceCritterTool& tool, UI::UniqueWindow::Registry& registry)
-   : EditorToolOptionsMenu(parent, registry, 0, 0, _("Animals")) {
+   : EditorToolOptionsMenu(parent, registry, 0, 0, _("Animals"), tool) {
 	const Widelands::World& world = parent.egbase().world();
 	multi_select_menu_.reset(
 	   new CategorizedItemSelectionMenu<Widelands::CritterDescr, EditorPlaceCritterTool>(

=== modified file 'src/editor/ui_menus/tool_place_immovable_options_menu.cc'
--- src/editor/ui_menus/tool_place_immovable_options_menu.cc	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/tool_place_immovable_options_menu.cc	2019-06-01 16:05:47 +0000
@@ -48,7 +48,7 @@
 
 EditorToolPlaceImmovableOptionsMenu::EditorToolPlaceImmovableOptionsMenu(
    EditorInteractive& parent, EditorPlaceImmovableTool& tool, UI::UniqueWindow::Registry& registry)
-   : EditorToolOptionsMenu(parent, registry, 0, 0, _("Immovables")) {
+   : EditorToolOptionsMenu(parent, registry, 0, 0, _("Immovables"), tool) {
 	const Widelands::World& world = parent.egbase().world();
 	multi_select_menu_.reset(
 	   new CategorizedItemSelectionMenu<Widelands::ImmovableDescr, EditorPlaceImmovableTool>(

=== modified file 'src/editor/ui_menus/tool_resize_options_menu.cc'
--- src/editor/ui_menus/tool_resize_options_menu.cc	2019-06-01 16:05:46 +0000
+++ src/editor/ui_menus/tool_resize_options_menu.cc	2019-06-01 16:05:47 +0000
@@ -33,10 +33,11 @@
 	return dynamic_cast<EditorInteractive&>(*get_parent());
 }
 
-EditorToolResizeOptionsMenu::EditorToolResizeOptionsMenu(EditorInteractive& parent,
-                                                         EditorResizeTool& resize_tool,
-                                                         UI::UniqueWindow::Registry& registry)
-   : EditorToolOptionsMenu(parent, registry, 260, 200, _("Resize")),
+EditorToolResizeOptionsMenu::EditorToolResizeOptionsMenu(
+   EditorInteractive& parent,
+   EditorResizeTool& resize_tool,
+   UI::UniqueWindow::Registry& registry)
+   : EditorToolOptionsMenu(parent, registry, 260, 200, _("Resize"), resize_tool),
      resize_tool_(resize_tool),
      box_(this, hmargin(), vmargin(), UI::Box::Vertical, 0, 0, vspacing()),
      map_size_box_(box_, "tool_resize_map", 4, parent.egbase().map().get_width(), parent.egbase().map().get_height()),

=== modified file 'src/editor/ui_menus/tool_set_terrain_options_menu.cc'
--- src/editor/ui_menus/tool_set_terrain_options_menu.cc	2019-02-23 11:00:49 +0000
+++ src/editor/ui_menus/tool_set_terrain_options_menu.cc	2019-06-01 16:05:47 +0000
@@ -86,7 +86,7 @@
 
 EditorToolSetTerrainOptionsMenu::EditorToolSetTerrainOptionsMenu(
    EditorInteractive& parent, EditorSetTerrainTool& tool, UI::UniqueWindow::Registry& registry)
-   : EditorToolOptionsMenu(parent, registry, 0, 0, _("Terrain")) {
+   : EditorToolOptionsMenu(parent, registry, 0, 0, _("Terrain"), tool) {
 	const Widelands::World& world = parent.egbase().world();
 	multi_select_menu_.reset(
 	   new CategorizedItemSelectionMenu<Widelands::TerrainDescription, EditorSetTerrainTool>(

=== modified file 'src/graphic/CMakeLists.txt'
--- src/graphic/CMakeLists.txt	2019-05-31 07:39:22 +0000
+++ src/graphic/CMakeLists.txt	2019-06-01 16:05:47 +0000
@@ -6,6 +6,16 @@
 
 # Align and color
 
+wl_library(graphic_toolbar_imageset
+  SRCS
+    toolbar_imageset.cc
+    toolbar_imageset.h
+  DEPENDS
+    graphic
+    graphic_surface
+    scripting_lua_table
+)
+
 wl_library(graphic_align
   SRCS
     align.h

=== added file 'src/graphic/toolbar_imageset.cc'
--- src/graphic/toolbar_imageset.cc	1970-01-01 00:00:00 +0000
+++ src/graphic/toolbar_imageset.cc	2019-06-01 16:05:47 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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 "graphic/toolbar_imageset.h"
+
+#include "graphic/graphic.h"
+
+ToolbarImageset::ToolbarImageset() :
+	left_corner(g_gr->images().get("images/wui/toolbar/left_corner.png")),
+	left(g_gr->images().get("images/wui/toolbar/left.png")),
+	center(g_gr->images().get("images/wui/toolbar/center.png")),
+	right(g_gr->images().get("images/wui/toolbar/right.png")),
+	right_corner(g_gr->images().get("images/wui/toolbar/right_corner.png")) {
+}
+
+ToolbarImageset::ToolbarImageset(const LuaTable& table) :
+	left_corner(g_gr->images().get(table.get_string("left_corner"))),
+	left(g_gr->images().get(table.get_string("left"))),
+	center(g_gr->images().get(table.get_string("center"))),
+	right(g_gr->images().get(table.get_string("right"))),
+	right_corner(g_gr->images().get(table.get_string("right_corner"))) {
+}

=== added file 'src/graphic/toolbar_imageset.h'
--- src/graphic/toolbar_imageset.h	1970-01-01 00:00:00 +0000
+++ src/graphic/toolbar_imageset.h	2019-06-01 16:05:47 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 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_GRAPHIC_TOOLBAR_IMAGESET_H
+#define WL_GRAPHIC_TOOLBAR_IMAGESET_H
+
+#include "graphic/image.h"
+#include "scripting/lua_table.h"
+
+/// An imageset for a horizontal toolbar
+struct ToolbarImageset {
+	ToolbarImageset();
+	ToolbarImageset(const LuaTable& table);
+
+	/// Will be painted beyond the left corner of the toolbar
+	const Image* left_corner;
+	/// Will be repeated between the left corner and the center
+	const Image* left;
+	/// Will be painted at the center
+	const Image* center;
+	/// Will be repeated between the right corner and the center
+	const Image* right;
+	/// Will be painted beyond the right corner of the toolbar
+	const Image* right_corner;
+};
+
+#endif  // end of include guard: WL_GRAPHIC_TOOLBAR_IMAGESET_H

=== modified file 'src/logic/CMakeLists.txt'
--- src/logic/CMakeLists.txt	2019-05-26 01:58:59 +0000
+++ src/logic/CMakeLists.txt	2019-06-01 16:05:47 +0000
@@ -124,6 +124,7 @@
     maptriangleregion.cc
     maptriangleregion.h
     nodecaps.h
+    note_map_options.h
     path.cc
     path.h
     pathfield.cc
@@ -231,6 +232,8 @@
     graphic
     graphic_color
     graphic_playercolor
+    graphic_toolbar_imageset
+    helper
     io_fileread
     io_filesystem
     io_stream

=== modified file 'src/logic/map.cc'
--- src/logic/map.cc	2019-05-16 09:15:03 +0000
+++ src/logic/map.cc	2019-06-01 16:05:47 +0000
@@ -46,6 +46,7 @@
 #include "logic/mapfringeregion.h"
 #include "logic/maphollowregion.h"
 #include "logic/mapregion.h"
+#include "logic/note_map_options.h"
 #include "logic/objective.h"
 #include "logic/pathfield.h"
 #include "map_io/s2map.h"
@@ -2299,6 +2300,7 @@
 	// There need to be at least 2 port spaces for seafaring to make sense
 	if (get_port_spaces().size() < 2) {
 		allows_seafaring_ = false;
+		Notifications::publish(NoteMapOptions());
 		return;
 	}
 
@@ -2324,6 +2326,7 @@
 			// Found one
 			if (reachable_from_previous_ports.count(current_position) > 0) {
 				allows_seafaring_ = true;
+				Notifications::publish(NoteMapOptions());
 				return;
 			}
 
@@ -2346,6 +2349,7 @@
 		}
 	}
 	allows_seafaring_ = false;
+	Notifications::publish(NoteMapOptions());
 }
 
 void Map::cleanup_port_spaces(const World& world) {

=== modified file 'src/logic/map.h'
--- src/logic/map.h	2019-05-16 09:15:03 +0000
+++ src/logic/map.h	2019-06-01 16:05:47 +0000
@@ -131,7 +131,6 @@
  */
 class Map : public ITransportCostCalculator {
 public:
-	friend class Editor;
 	friend class EditorGameBase;
 	friend class MapLoader;
 	friend class MapVersionPacket;

=== modified file 'src/logic/map_objects/tribes/tribe_descr.cc'
--- src/logic/map_objects/tribes/tribe_descr.cc	2019-05-29 06:24:42 +0000
+++ src/logic/map_objects/tribes/tribe_descr.cc	2019-06-01 16:05:47 +0000
@@ -203,6 +203,9 @@
 		refinedlog_ = add_special_ware(table.get_string("refinedlog"));
 		granite_ = add_special_ware(table.get_string("granite"));
 
+		if (table.has_key<std::string>("toolbar")) {
+			toolbar_image_set_.reset(new ToolbarImageset(*table.get_table("toolbar")));
+		}
 	} catch (const GameDataError& e) {
 		throw GameDataError("tribe %s: %s", name_.c_str(), e.what());
 	}
@@ -445,6 +448,10 @@
 	}
 }
 
+ToolbarImageset* TribeDescr::toolbar_image_set() const {
+	return toolbar_image_set_.get();
+}
+
 /**
  * Helper functions
  */

=== modified file 'src/logic/map_objects/tribes/tribe_descr.h'
--- src/logic/map_objects/tribes/tribe_descr.h	2019-05-29 06:24:42 +0000
+++ src/logic/map_objects/tribes/tribe_descr.h	2019-06-01 16:05:47 +0000
@@ -26,6 +26,7 @@
 
 #include "base/macros.h"
 #include "graphic/animation.h"
+#include "graphic/toolbar_imageset.h"
 #include "logic/map_objects/immovable.h"
 #include "logic/map_objects/tribes/building.h"
 #include "logic/map_objects/tribes/road_textures.h"
@@ -162,6 +163,9 @@
 
 	void add_building(const std::string& buildingname);
 
+	// The custom toolbar imageset if any. Can be nullptr.
+	ToolbarImageset* toolbar_image_set() const;
+
 private:
 	// Helper function for adding a special worker type (carriers etc.)
 	DescriptionIndex add_special_worker(const std::string& workername);
@@ -206,6 +210,9 @@
 	WaresOrder wares_order_;
 	WaresOrder workers_order_;
 
+	// An optional custom imageset for the in-game menu toolbar
+	std::unique_ptr<ToolbarImageset> toolbar_image_set_;
+
 	std::vector<Widelands::TribeBasicInfo::Initialization> initializations_;
 
 	DISALLOW_COPY_AND_ASSIGN(TribeDescr);

=== added file 'src/logic/note_map_options.h'
--- src/logic/note_map_options.h	1970-01-01 00:00:00 +0000
+++ src/logic/note_map_options.h	2019-06-01 16:05:47 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 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_LOGIC_NOTE_MAP_OPTIONS_H
+#define WL_LOGIC_NOTE_MAP_OPTIONS_H
+
+#include "notifications/note_ids.h"
+#include "notifications/notifications.h"
+
+struct NoteMapOptions {
+	CAN_BE_SENT_AS_NOTE(NoteId::MapOptions)
+
+	NoteMapOptions() = default;
+};
+
+#endif  // end of include guard: WL_LOGIC_NOTE_MAP_OPTIONS_H

=== modified file 'src/notifications/note_ids.h'
--- src/notifications/note_ids.h	2019-05-10 17:43:19 +0000
+++ src/notifications/note_ids.h	2019-06-01 16:05:47 +0000
@@ -41,7 +41,8 @@
 	NoteExpeditionCanceled,
 	Sound,
 	Dropdown,
-	GameSettings
+	GameSettings,
+	MapOptions
 };
 
 #endif  // end of include guard: WL_NOTIFICATIONS_NOTE_IDS_H

=== modified file 'src/scripting/lua_game.cc'
--- src/scripting/lua_game.cc	2019-04-26 16:52:39 +0000
+++ src/scripting/lua_game.cc	2019-06-01 16:05:47 +0000
@@ -108,7 +108,7 @@
    PROP_RO(LuaPlayer, name),       PROP_RO(LuaPlayer, allowed_buildings),
    PROP_RO(LuaPlayer, objectives), PROP_RO(LuaPlayer, defeated),
    PROP_RO(LuaPlayer, messages),   PROP_RO(LuaPlayer, inbox),
-   PROP_RW(LuaPlayer, team),       PROP_RO(LuaPlayer, tribe),
+   PROP_RO(LuaPlayer, color), PROP_RW(LuaPlayer, team),       PROP_RO(LuaPlayer, tribe),
    PROP_RW(LuaPlayer, see_all),    {nullptr, nullptr, nullptr},
 };
 
@@ -222,6 +222,17 @@
 }
 
 /* RST
+   .. attribute:: color
+
+      (RO) The playercolor assigned to this player, in hex notation.
+*/
+int LuaPlayer::get_color(lua_State* L) {
+	const PlayerNumber pnumber = get(L, get_egbase(L)).player_number();
+	lua_pushstring(L, kPlayerColors[pnumber - 1].hex_value());
+	return 1;
+}
+
+/* RST
    .. attribute:: team
 
       (RW) The team number of this player (0 means player is not in a team)

=== modified file 'src/scripting/lua_game.h'
--- src/scripting/lua_game.h	2019-04-26 16:52:39 +0000
+++ src/scripting/lua_game.h	2019-06-01 16:05:47 +0000
@@ -71,6 +71,7 @@
 	int get_defeated(lua_State* L);
 	int get_messages(lua_State* L);
 	int get_inbox(lua_State* L);
+	int get_color(lua_State* L);
 	int get_team(lua_State* L);
 	int get_tribe(lua_State* L);
 	int set_team(lua_State* L);

=== modified file 'src/ui_fsmenu/internet_lobby.cc'
--- src/ui_fsmenu/internet_lobby.cc	2019-05-29 13:23:54 +0000
+++ src/ui_fsmenu/internet_lobby.cc	2019-06-01 16:05:47 +0000
@@ -241,17 +241,14 @@
 
 	if (games != nullptr) {  // If no communication error occurred, fill the list.
 		for (const InternetGame& game : *games) {
-			const Image* pic;
 			if (game.connectable == INTERNET_GAME_SETUP && game.build_id == localbuildid) {
 				// only clients with the same build number are displayed
-				pic = g_gr->images().get("images/ui_basic/continue.png");
-				opengames_list_.add(game.name, game, pic, false, game.build_id);
+				opengames_list_.add(richtext_escape(game.name), game, g_gr->images().get("images/ui_basic/continue.png"), false, game.build_id);
 			} else if (game.connectable == INTERNET_GAME_SETUP &&
 			           game.build_id.compare(0, 6, "build-") != 0 &&
 			           localbuildid.compare(0, 6, "build-") != 0) {
 				// only development clients are allowed to see games openend by such
-				pic = g_gr->images().get("images/ui_basic/different.png");
-				opengames_list_.add(game.name, game, pic, false, game.build_id);
+				opengames_list_.add(richtext_escape(game.name), game, g_gr->images().get("images/ui_basic/different.png"), false, game.build_id);
 			}
 		}
 	}

=== modified file 'src/ui_fsmenu/launch_mpg.cc'
--- src/ui_fsmenu/launch_mpg.cc	2019-05-26 17:21:15 +0000
+++ src/ui_fsmenu/launch_mpg.cc	2019-06-01 16:05:47 +0000
@@ -113,7 +113,7 @@
                          buth_,
                          buth_,
                          UI::ButtonStyle::kFsMenuSecondary,
-                         g_gr->images().get("images/wui/menus/menu_toggle_minimap.png"),
+                         g_gr->images().get("images/wui/menus/toggle_minimap.png"),
                          _("Change map or saved game")),
      help_button_(this,
                   "help",

=== modified file 'src/wui/CMakeLists.txt'
--- src/wui/CMakeLists.txt	2019-05-29 06:24:42 +0000
+++ src/wui/CMakeLists.txt	2019-06-01 16:05:47 +0000
@@ -200,16 +200,12 @@
     game_debug_ui.h
     game_exit_confirm_box.cc
     game_exit_confirm_box.h
-    game_statistics_menu.cc
-    game_statistics_menu.h
     game_main_menu_save_game.cc
     game_main_menu_save_game.h
     game_message_menu.cc
     game_message_menu.h
     game_objectives_menu.cc
     game_objectives_menu.h
-    game_options_menu.cc
-    game_options_menu.h
     game_options_sound_menu.cc
     game_options_sound_menu.h
     game_summary.cc
@@ -296,6 +292,7 @@
     graphic_surface
     graphic_text
     graphic_text_layout
+    graphic_toolbar_imageset
     io_fileread
     io_filesystem
     logic

=== modified file 'src/wui/buildingwindow.cc'
--- src/wui/buildingwindow.cc	2019-05-26 17:21:15 +0000
+++ src/wui/buildingwindow.cc	2019-06-01 16:05:47 +0000
@@ -348,7 +348,7 @@
 
 		UI::Button* gotobtn = new UI::Button(
 		   capsbuttons, "goto", 0, 0, 34, 34, UI::ButtonStyle::kWuiMenu,
-		   g_gr->images().get("images/wui/menus/menu_goto.png"), _("Center view on this"));
+		   g_gr->images().get("images/wui/menus/goto.png"), _("Center view on this"));
 		gotobtn->sigclicked.connect(boost::bind(&BuildingWindow::clicked_goto, boost::ref(*this)));
 		capsbuttons->add(gotobtn);
 

=== modified file 'src/wui/economy_options_window.cc'
--- src/wui/economy_options_window.cc	2019-06-01 16:05:46 +0000
+++ src/wui/economy_options_window.cc	2019-06-01 16:05:47 +0000
@@ -52,7 +52,7 @@
         &tabpanel_, this, serial_, player_, can_act, Widelands::wwWORKER, kDesiredWidth)),
      dropdown_box_(this, 0, 0, UI::Box::Horizontal),
      dropdown_(
-        &dropdown_box_, "economy_profiles", 0, 0, 174, 10, 34, "", UI::DropdownType::kTextual, UI::PanelStyle::kWui, UI::ButtonStyle::kWuiSecondary), // NOCOM test if this is the correct button style. heap-use-after-free somewhere too.
+        &dropdown_box_, "economy_profiles", 0, 0, 174, 10, 34, "", UI::DropdownType::kTextual, UI::PanelStyle::kWui, UI::ButtonStyle::kWuiSecondary),
      time_last_thought_(0),
      save_profile_dialog_(nullptr) {
 	set_center_panel(&main_box_);
@@ -95,7 +95,7 @@
 	dropdown_.selected.connect([this] { reset_target(); });
 
 	b = new UI::Button(&dropdown_box_, "save_targets", 0, 0, 34, 34, UI::ButtonStyle::kWuiMenu,
-	                   g_gr->images().get("images/wui/menus/menu_save_game.png"),
+	                   g_gr->images().get("images/wui/menus/save_game.png"),
 	                   _("Save target settings"));
 	b->sigclicked.connect([this] { create_target(); });
 	dropdown_box_.add_space(8);

=== modified file 'src/wui/fieldaction.cc'
--- src/wui/fieldaction.cc	2019-06-01 16:05:46 +0000
+++ src/wui/fieldaction.cc	2019-06-01 16:05:47 +0000
@@ -163,9 +163,6 @@
 	void add_buttons_attack();
 
 	void act_watch();
-	void act_show_census();
-	void act_show_statistics();
-	void act_show_workarea_overlap();
 	void act_debug();
 	void act_buildflag();
 	void act_configure_economy();
@@ -231,10 +228,6 @@
 static const char* const pic_buildflag = "images/wui/fieldaction/menu_build_flag.png";
 static const char* const pic_ripflag = "images/wui/fieldaction/menu_rip_flag.png";
 static const char* const pic_watchfield = "images/wui/fieldaction/menu_watch_field.png";
-static const char* const pic_showcensus = "images/wui/fieldaction/menu_show_census.png";
-static const char* const pic_showstatistics = "images/wui/fieldaction/menu_show_statistics.png";
-static const char* const pic_showworkareaoverlap =
-   "images/wui/fieldaction/menu_show_workarea_overlap.png";
 static const char* const pic_debug = "images/wui/fieldaction/menu_debug.png";
 static const char* const pic_abort = "images/wui/menu_abort.png";
 static const char* const pic_geologist = "images/wui/fieldaction/menu_geologist.png";
@@ -382,21 +375,10 @@
 	                             node_, ibase().egbase().map().get_width())))
 		add_buttons_attack();
 
-	//  Watch actions, only when game (no use in editor) same for statistics.
-	//  census is ok
+	//  Watch actions, only when in game (no use in editor).
 	if (dynamic_cast<const Game*>(&ibase().egbase())) {
 		add_button(&watchbox, "watch", pic_watchfield, &FieldActionWindow::act_watch,
 		           _("Watch field in a separate window"));
-		add_button(&watchbox, "statistics", pic_showstatistics,
-		           &FieldActionWindow::act_show_statistics, _("Toggle building statistics display"));
-	}
-	add_button(&watchbox, "census", pic_showcensus, &FieldActionWindow::act_show_census,
-	           _("Toggle building label display"));
-	if (is_a(InteractivePlayer, &ibase())) {
-		add_button(
-		   &watchbox, "workarea_overlap", pic_showworkareaoverlap,
-		   &FieldActionWindow::act_show_workarea_overlap,
-		   _("Toggle whether overlapping workareas are indicated when placing a constructionsite"));
 	}
 
 	if (ibase().get_display_flag(InteractiveBase::dfDebug))
@@ -581,29 +563,6 @@
 
 /*
 ===============
-Toggle display of census and statistics for buildings, respectively.
-===============
-*/
-void FieldActionWindow::act_show_census() {
-	ibase().set_display_flag(
-	   InteractiveBase::dfShowCensus, !ibase().get_display_flag(InteractiveBase::dfShowCensus));
-	reset_mouse_and_die();
-}
-
-void FieldActionWindow::act_show_statistics() {
-	ibase().set_display_flag(InteractiveBase::dfShowStatistics,
-	                         !ibase().get_display_flag(InteractiveBase::dfShowStatistics));
-	reset_mouse_and_die();
-}
-
-void FieldActionWindow::act_show_workarea_overlap() {
-	ibase().set_display_flag(InteractiveBase::dfShowWorkareaOverlap,
-	                         !ibase().get_display_flag(InteractiveBase::dfShowWorkareaOverlap));
-	reset_mouse_and_die();
-}
-
-/*
-===============
 Show a debug widow for this field.
 ===============
 */

=== modified file 'src/wui/game_chat_menu.cc'
--- src/wui/game_chat_menu.cc	2019-02-23 11:00:49 +0000
+++ src/wui/game_chat_menu.cc	2019-06-01 16:05:47 +0000
@@ -53,11 +53,13 @@
 	return new GameChatMenu(parent, registry, chat, _("Chat"));
 }
 
+#ifndef NDEBUG  //  only in debug builds
 GameChatMenu* GameChatMenu::create_script_console(UI::Panel* parent,
                                                   UI::UniqueWindow::Registry& registry,
                                                   ChatProvider& chat) {
-	return new GameChatMenu(parent, registry, chat, _("Script console"));
+	return new GameChatMenu(parent, registry, chat, _("Script Console"));
 }
+#endif
 
 bool GameChatMenu::enter_chat_message(bool close_on_send) {
 	if (is_minimal()) {

=== modified file 'src/wui/game_chat_menu.h'
--- src/wui/game_chat_menu.h	2019-02-23 11:00:49 +0000
+++ src/wui/game_chat_menu.h	2019-06-01 16:05:47 +0000
@@ -34,11 +34,13 @@
 	 */
 	static GameChatMenu* create_chat_console(UI::Panel*, UI::UniqueWindow::Registry&, ChatProvider&);
 
+#ifndef NDEBUG  //  only in debug builds
 	/**
 	 * Creates a chat window only for scripting in debug mode
 	 */
 	static GameChatMenu*
 	create_script_console(UI::Panel*, UI::UniqueWindow::Registry&, ChatProvider&);
+#endif
 
 	/**
 	 * Configure the menu so that it is useful for writing chat messages.

=== modified file 'src/wui/game_client_disconnected.cc'
--- src/wui/game_client_disconnected.cc	2019-06-01 16:05:46 +0000
+++ src/wui/game_client_disconnected.cc	2019-06-01 16:05:47 +0000
@@ -92,7 +92,7 @@
                 width,
                 35,
                 UI::ButtonStyle::kWuiMenu,
-                g_gr->images().get("images/wui/menus/menu_exit_game.png"),
+                g_gr->images().get("images/wui/menus/exit.png"),
                 /** TRANSLATORS: Button tooltip */
                 _("Exit Game")) {
 

=== modified file 'src/wui/game_message_menu.cc'
--- src/wui/game_message_menu.cc	2019-06-01 16:05:46 +0000
+++ src/wui/game_message_menu.cc	2019-06-01 16:05:47 +0000
@@ -104,7 +104,7 @@
 
 	scenariobtn_ = new UI::Button(this, "filter_scenario_messages", 5 * kPadding + 4 * kButtonSize,
 	                              kPadding, kButtonSize, kButtonSize, UI::ButtonStyle::kWuiSecondary,
-	                              g_gr->images().get("images/wui/menus/menu_objectives.png"));
+	                              g_gr->images().get("images/wui/menus/objectives.png"));
 	scenariobtn_->sigclicked.connect(
 	   boost::bind(&GameMessageMenu::filter_messages, this, Widelands::Message::Type::kScenario));
 
@@ -129,7 +129,7 @@
 	centerviewbtn_ =
 	   new UI::Button(this, "center_main_mapview_on_location", kWindowWidth - kPadding - kButtonSize,
 	                  archivebtn_->get_y(), kButtonSize, kButtonSize, UI::ButtonStyle::kWuiPrimary,
-	                  g_gr->images().get("images/wui/menus/menu_goto.png"),
+	                  g_gr->images().get("images/wui/menus/goto.png"),
 	                  as_tooltip_text_with_hotkey(
 	                   /** TRANSLATORS: Tooltip in the messages window */
 	                   _("Center main mapview on location"), "g"));
@@ -564,7 +564,7 @@
 	case Widelands::Message::Type::kWarfare:
 		return "images/wui/messages/messages_warfare.png";
 	case Widelands::Message::Type::kScenario:
-		return "images/wui/menus/menu_objectives.png";
+		return "images/wui/menus/objectives.png";
 	case Widelands::Message::Type::kGameLogic:
 		return "images/ui_basic/menu_help.png";
 	case Widelands::Message::Type::kNoMessages:

=== removed file 'src/wui/game_options_menu.cc'
--- src/wui/game_options_menu.cc	2019-03-18 07:11:02 +0000
+++ src/wui/game_options_menu.cc	1970-01-01 00:00:00 +0000
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2002-2019 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/game_options_menu.h"
-
-#include <boost/bind.hpp>
-#include <boost/lambda/bind.hpp>
-#include <boost/lambda/construct.hpp>
-#include <boost/type_traits.hpp>
-
-#include "base/i18n.h"
-#include "graphic/graphic.h"
-#include "wui/game_exit_confirm_box.h"
-#include "wui/game_main_menu_save_game.h"
-#include "wui/game_options_sound_menu.h"
-#include "wui/unique_window_handler.h"
-
-#define width 200
-#define margin 10
-#define vspacing 5
-#define vgap 3
-
-GameOptionsMenu::GameOptionsMenu(InteractiveGameBase& gb,
-                                 UI::UniqueWindow::Registry& registry,
-                                 InteractiveGameBase::GameMainMenuWindows& windows)
-   : UI::UniqueWindow(&gb, "options", &registry, 2 * margin + width, 0, _("Main Menu")),
-     igb_(gb),
-     windows_(windows),
-     box_(this, margin, margin, UI::Box::Vertical, width, get_h() - 2 * margin, vspacing),
-     sound_(&box_,
-            "sound_options",
-            0,
-            0,
-            width,
-            0,
-            UI::ButtonStyle::kWuiMenu,
-            _("Sound Options"),
-            /** TRANSLATORS: Button tooltip */
-            _("Set sound effect and music options")),
-     save_game_(&box_,
-                "save_game",
-                0,
-                0,
-                width,
-                35,
-                UI::ButtonStyle::kWuiMenu,
-                g_gr->images().get("images/wui/menus/menu_save_game.png"),
-                /** TRANSLATORS: Button tooltip */
-                _("Save Game")),
-     exit_game_(&box_,
-                "exit_game",
-                0,
-                0,
-                width,
-                35,
-                UI::ButtonStyle::kWuiMenu,
-                g_gr->images().get("images/wui/menus/menu_exit_game.png"),
-                /** TRANSLATORS: Button tooltip */
-                _("Exit Game")) {
-	box_.add(&sound_);
-	box_.add_space(vgap);
-	box_.add(&save_game_);
-	box_.add(&exit_game_);
-	box_.set_size(width, sound_.get_h() + 2 * save_game_.get_h() + vgap + 3 * vspacing);
-	set_inner_size(get_inner_w(), box_.get_h() + 2 * margin);
-
-	windows_.sound_options.open_window = [this] {
-		new GameOptionsSoundMenu(igb_, windows_.sound_options);
-	};
-	sound_.sigclicked.connect(
-	   boost::bind(&UI::UniqueWindow::Registry::toggle, boost::ref(windows_.sound_options)));
-	save_game_.sigclicked.connect(
-	   boost::bind(&GameOptionsMenu::clicked_save_game, boost::ref(*this)));
-	exit_game_.sigclicked.connect(
-	   boost::bind(&GameOptionsMenu::clicked_exit_game, boost::ref(*this)));
-
-	if (windows_.sound_options.window) {
-		sound_.set_perm_pressed(true);
-	}
-	windows_.sound_options.opened.connect(boost::bind(&UI::Button::set_perm_pressed, &sound_, true));
-	windows_.sound_options.closed.connect(
-	   boost::bind(&UI::Button::set_perm_pressed, &sound_, false));
-
-	if (get_usedefaultpos())
-		center_to_parent();
-}
-
-GameOptionsMenu::~GameOptionsMenu() {
-}
-
-void GameOptionsMenu::clicked_save_game() {
-	new GameMainMenuSaveGame(igb_, windows_.savegame);
-	die();
-}
-
-void GameOptionsMenu::clicked_exit_game() {
-	if (SDL_GetModState() & KMOD_CTRL) {
-		igb_.end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack);
-	} else {
-		new GameExitConfirmBox(*get_parent(), igb_);
-		die();
-	}
-}

=== removed file 'src/wui/game_options_menu.h'
--- src/wui/game_options_menu.h	2019-02-23 11:00:49 +0000
+++ src/wui/game_options_menu.h	1970-01-01 00:00:00 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2002-2019 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_GAME_OPTIONS_MENU_H
-#define WL_WUI_GAME_OPTIONS_MENU_H
-
-#include "ui_basic/box.h"
-#include "ui_basic/button.h"
-#include "ui_basic/messagebox.h"
-#include "ui_basic/textarea.h"
-#include "ui_basic/unique_window.h"
-#include "wui/interactive_gamebase.h"
-
-// The GameOptionsMenu is a rather dumb window with lots of buttons
-struct GameOptionsMenu : public UI::UniqueWindow {
-	GameOptionsMenu(InteractiveGameBase&,
-	                UI::UniqueWindow::Registry&,
-	                InteractiveGameBase::GameMainMenuWindows&);
-	~GameOptionsMenu();
-
-private:
-	InteractiveGameBase& igb_;
-	InteractiveGameBase::GameMainMenuWindows& windows_;
-	UI::Box box_;
-	UI::Button sound_;
-	UI::Button save_game_;
-	UI::Button exit_game_;
-
-	void clicked_save_game();
-	void clicked_exit_game();
-};
-
-#endif  // end of include guard: WL_WUI_GAME_OPTIONS_MENU_H

=== removed file 'src/wui/game_statistics_menu.cc'
--- src/wui/game_statistics_menu.cc	2019-02-23 11:00:49 +0000
+++ src/wui/game_statistics_menu.cc	1970-01-01 00:00:00 +0000
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2002-2019 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/game_statistics_menu.h"
-
-#include <boost/bind.hpp>
-
-#include "base/i18n.h"
-#include "graphic/graphic.h"
-#include "ui_basic/unique_window.h"
-#include "wui/building_statistics_menu.h"
-#include "wui/general_statistics_menu.h"
-#include "wui/interactive_player.h"
-#include "wui/seafaring_statistics_menu.h"
-#include "wui/stock_menu.h"
-#include "wui/ware_statistics_menu.h"
-
-GameStatisticsMenu::GameStatisticsMenu(InteractivePlayer& plr,
-                                       UI::UniqueWindow::Registry& registry,
-                                       InteractivePlayer::GameMainMenuWindows& windows)
-   : UI::UniqueWindow(&plr, "main_menu", &registry, 0, 0, _("Statistics Menu")),
-     player_(plr),
-     windows_(windows),
-     box_(this, 0, 0, UI::Box::Horizontal, 0, 0, 5) {
-	const bool is_seafaring = plr.egbase().mutable_map()->allows_seafaring();
-	add_button("wui/menus/menu_general_stats", "general_stats", _("General statistics"),
-	           &windows_.general_stats);
-	add_button(
-	   "wui/menus/menu_ware_stats", "ware_stats", _("Ware statistics"), &windows_.ware_stats);
-	add_button("wui/menus/menu_building_stats", "building_stats", _("Building statistics"),
-	           &windows_.building_stats);
-	add_button("wui/menus/menu_stock", "stock", _("Stock"), &windows_.stock);
-	if (is_seafaring) {
-		add_button("wui/buildings/start_expedition", "seafaring_stats", _("Seafaring Statistics"),
-		           &windows_.seafaring_stats);
-	}
-	box_.set_pos(Vector2i(10, 10));
-	box_.set_size((34 + 5) * (is_seafaring ? 5 : 4), 34);
-	set_inner_size(box_.get_w() + 20, box_.get_h() + 20);
-
-	windows_.general_stats.open_window = [this] {
-		new GeneralStatisticsMenu(player_, windows_.general_stats);
-	};
-	windows_.ware_stats.open_window = [this] {
-		new WareStatisticsMenu(player_, windows_.ware_stats);
-	};
-	windows_.building_stats.open_window = [this] {
-		new BuildingStatisticsMenu(player_, windows_.building_stats);
-	};
-	// The stock window is defined in InteractivePlayer because of the keyboard shortcut.
-	if (is_seafaring) {
-		windows_.seafaring_stats.open_window = [this] {
-			new SeafaringStatisticsMenu(player_, windows_.seafaring_stats);
-		};
-	}
-
-	if (get_usedefaultpos())
-		center_to_parent();
-}
-
-UI::Button* GameStatisticsMenu::add_button(const std::string& image_basename,
-                                           const std::string& name,
-                                           const std::string& tooltip_text,
-                                           UI::UniqueWindow::Registry* window) {
-	UI::Button* button =
-	   new UI::Button(&box_, name, 0, 0, 34U, 34U, UI::ButtonStyle::kWuiMenu,
-	                  g_gr->images().get("images/" + image_basename + ".png"), tooltip_text);
-	box_.add(button);
-	if (window) {
-		if (window->window) {
-			button->set_perm_pressed(true);
-		}
-		window->opened.connect(boost::bind(&UI::Button::set_perm_pressed, button, true));
-		window->closed.connect(boost::bind(&UI::Button::set_perm_pressed, button, false));
-		button->sigclicked.connect(
-		   boost::bind(&UI::UniqueWindow::Registry::toggle, boost::ref(*window)));
-	}
-	return button;
-}
-
-GameStatisticsMenu::~GameStatisticsMenu() {
-}

=== removed file 'src/wui/game_statistics_menu.h'
--- src/wui/game_statistics_menu.h	2019-02-23 11:00:49 +0000
+++ src/wui/game_statistics_menu.h	1970-01-01 00:00:00 +0000
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2002-2019 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_GAME_STATISTICS_MENU_H
-#define WL_WUI_GAME_STATISTICS_MENU_H
-
-#include "ui_basic/box.h"
-#include "ui_basic/button.h"
-#include "wui/interactive_player.h"
-
-// The GameStatisticsMenu is a row of buttons that will toggle unique windows
-struct GameStatisticsMenu : public UI::UniqueWindow {
-	GameStatisticsMenu(InteractivePlayer&,
-	                   UI::UniqueWindow::Registry&,
-	                   InteractivePlayer::GameMainMenuWindows&);
-
-	~GameStatisticsMenu();
-
-private:
-	/// Adds a button to the menu that will toggle its window
-	/// \param image_basename:      File path for button image starting from 'images' and without
-	///                             file extension
-	/// \param name:                Internal name of the button
-	/// \param tooltip_text:        The button tooltip
-	/// \param window:              The window that's associated with this button.
-	UI::Button* add_button(const std::string& image_basename,
-	                       const std::string& name,
-	                       const std::string& tooltip_text,
-	                       UI::UniqueWindow::Registry* window);
-
-	InteractivePlayer& player_;
-	InteractivePlayer::GameMainMenuWindows& windows_;
-	UI::Box box_;
-};
-
-#endif  // end of include guard: WL_WUI_GAME_STATISTICS_MENU_H

=== modified file 'src/wui/game_summary.cc'
--- src/wui/game_summary.cc	2019-05-26 17:21:15 +0000
+++ src/wui/game_summary.cc	2019-06-01 16:05:47 +0000
@@ -91,7 +91,7 @@
 	bottom_box->add_space(PADDING);
 	stop_button_ =
 	   new UI::Button(bottom_box, "stop_button", 0, 0, 35, 35, UI::ButtonStyle::kWuiMenu,
-	                  g_gr->images().get("images/wui/menus/menu_exit_game.png"), _("Exit Game"));
+	                  g_gr->images().get("images/wui/menus/exit.png"), _("Exit Game"));
 	bottom_box->add(stop_button_);
 	bottom_box->add_space(PADDING);
 

=== modified file 'src/wui/interactive_base.cc'
--- src/wui/interactive_base.cc	2019-05-29 15:43:40 +0000
+++ src/wui/interactive_base.cc	2019-06-01 16:05:47 +0000
@@ -91,13 +91,82 @@
 
 }  // namespace
 
+InteractiveBase::Toolbar::Toolbar(Panel* parent) : UI::Panel(parent, 0, 0, parent->get_inner_w(), parent->get_inner_h()), box(this, 0, 0, UI::Box::Horizontal),
+	repeat(0)
+{
+}
+
+void InteractiveBase::Toolbar::change_imageset(const ToolbarImageset& images) {
+	imageset = images;
+	finalize();
+}
+
+void InteractiveBase::Toolbar::finalize() {
+	// Set box size and get minimum height
+	int box_width, height;
+	box.get_desired_size(&box_width, &height);
+	box.set_size(box_width, height);
+
+	// Calculate repetition and width
+	repeat = 1;
+	int width = imageset.left->width() + imageset.center->width() + imageset.right->width();
+	while (width < box.get_w()) {
+		++repeat;
+		width += imageset.left->width() + imageset.right->width();
+	}
+	width += imageset.left_corner->width() + imageset.right_corner->width();
+
+	// Find the highest image
+	height = std::max(height, imageset.left_corner->height());
+	height = std::max(height, imageset.left->height());
+	height = std::max(height, imageset.center->height());
+	height = std::max(height, imageset.right->height());
+	height = std::max(height, imageset.right_corner->height());
+
+	// Set size and position
+	set_size(width, height);
+	set_pos(Vector2i((get_parent()->get_inner_w() - width) >> 1, get_parent()->get_inner_h() - height));
+	box.set_pos(Vector2i((get_w() - box.get_w()) / 2, get_h() - box.get_h()));
+
+	// Notify dropdowns
+	box.position_changed();
+}
+
+void InteractiveBase::Toolbar::draw(RenderTarget& dst) {
+	int x = 0;
+	// Left corner
+	dst.blit(Vector2i(x, get_h() - imageset.left_corner->height()), imageset.left_corner);
+	x += imageset.left_corner->width();
+	// Repeat left
+	for (int i = 0; i < repeat; ++i) {
+		dst.blit(Vector2i(x, get_h() - imageset.left->height()), imageset.left);
+		x += imageset.left->width();
+	}
+	// Center
+	dst.blit(Vector2i(x, get_h() - imageset.center->height()), imageset.center);
+	x += imageset.center->width();
+	// Repeat right
+	for (int i = 0; i < repeat; ++i) {
+		dst.blit(Vector2i(x, get_h() - imageset.right->height()), imageset.right);
+		x += imageset.right->width();
+	}
+	// Right corner
+	dst.blit(Vector2i(x, get_h() - imageset.right_corner->height()), imageset.right_corner);
+}
+
 InteractiveBase::InteractiveBase(EditorGameBase& the_egbase, Section& global_s)
    : UI::Panel(nullptr, 0, 0, g_gr->get_xres(), g_gr->get_yres()),
      buildhelp_(false),
      map_view_(this, the_egbase.map(), 0, 0, g_gr->get_xres(), g_gr->get_yres()),
      // Initialize chatoveraly before the toolbar so it is below
      chat_overlay_(new ChatOverlay(this, 10, 25, get_w() / 2, get_h() - 25)),
-     toolbar_(this, 0, 0, UI::Box::Horizontal),
+     toolbar_(this),
+	 mapviewmenu_(
+		toolbar(), "dropdown_menu_mapview", 0, 0, 34U, 10, 34U,
+		 /** TRANSLATORS: Title for the map view menu button in the game */
+		 _("Map View"),
+		 UI::DropdownType::kPictorialMenu,
+		 UI::PanelStyle::kWui, UI::ButtonStyle::kWuiPrimary),
      quick_navigation_(&map_view_),
      workareas_cache_(nullptr),
      egbase_(the_egbase),
@@ -147,7 +216,7 @@
 		   set_size(message.width, message.height);
 		   map_view_.set_size(message.width, message.height);
 		   resize_chat_overlay();
-		   adjust_toolbar_position();
+		   finalize_toolbar();
 	   });
 	sound_subscriber_ = Notifications::subscribe<NoteSound>(
 	   [this](const NoteSound& note) { play_sound_effect(note); });
@@ -191,6 +260,68 @@
 	}
 }
 
+
+void InteractiveBase::add_mapview_menu(MiniMapType minimap_type) {
+	mapviewmenu_.set_image(g_gr->images().get("images/wui/menus/toggle_minimap.png"));
+	toolbar()->add(&mapviewmenu_);
+
+	minimap_registry_.open_window = [this] { toggle_minimap(); };
+	minimap_registry_.minimap_type = minimap_type;
+	minimap_registry_.closed.connect([this] { rebuild_mapview_menu(); });
+
+	rebuild_mapview_menu();
+	mapviewmenu_.selected.connect([this] { mapview_menu_selected(mapviewmenu_.get_selected()); });
+}
+
+void InteractiveBase::rebuild_mapview_menu() {
+	mapviewmenu_.clear();
+
+	/** TRANSLATORS: An entry in the game's map view menu */
+	mapviewmenu_.add(minimap_registry_.window != nullptr ? _("Hide Minimap") : _("Show Minimap"),
+					 MapviewMenuEntry::kMinimap,
+					 g_gr->images().get("images/wui/menus/toggle_minimap.png"),
+					 false, "", "m");
+
+	/** TRANSLATORS: An entry in the game's map view menu */
+	mapviewmenu_.add(_("Zoom +"),
+					 MapviewMenuEntry::kIncreaseZoom,
+					 g_gr->images().get("images/wui/menus/zoom_increase.png"),
+					 false, "", pgettext("hotkey", "Ctrl++"));
+
+	/** TRANSLATORS: An entry in the game's map view menu */
+	mapviewmenu_.add(_("Reset zoom"),
+					 MapviewMenuEntry::kResetZoom,
+					 g_gr->images().get("images/wui/menus/zoom_reset.png"),
+					 false, "", pgettext("hotkey", "Ctrl+0"));
+
+	/** TRANSLATORS: An entry in the game's map view menu */
+	mapviewmenu_.add(_("Zoom -"),
+					 MapviewMenuEntry::kDecreaseZoom,
+					 g_gr->images().get("images/wui/menus/zoom_decrease.png"),
+					 false, "", pgettext("hotkey", "Ctrl+-"));
+}
+
+void InteractiveBase::mapview_menu_selected(MapviewMenuEntry entry) {
+	switch (entry) {
+	case MapviewMenuEntry::kMinimap : {
+		toggle_minimap();
+	} break;
+	case MapviewMenuEntry::kDecreaseZoom : {
+		map_view()->decrease_zoom();
+		mapviewmenu_.toggle();
+	} break;
+	case MapviewMenuEntry::kIncreaseZoom : {
+		map_view()->increase_zoom();
+		mapviewmenu_.toggle();
+	} break;
+
+	case MapviewMenuEntry::kResetZoom : {
+		map_view()->reset_zoom();
+		mapviewmenu_.toggle();
+	} break;
+	}
+}
+
 const InteractiveBase::BuildhelpOverlay*
 InteractiveBase::get_buildhelp_overlay(const Widelands::NodeCaps caps) const {
 	const int buildhelp_overlay_index = caps_to_buildhelp(caps);
@@ -222,6 +353,11 @@
 	return false;
 }
 
+
+void InteractiveBase::set_toolbar_imageset(const ToolbarImageset& imageset) {
+	toolbar_.change_imageset(imageset);
+}
+
 UniqueWindowHandler& InteractiveBase::unique_windows() {
 	return *unique_window_handler_;
 }
@@ -230,6 +366,10 @@
 	sel_.pos = center;
 }
 
+void InteractiveBase::finalize_toolbar() {
+	toolbar_.finalize();
+}
+
 /*
  * Set the current sel selection radius.
  */
@@ -269,8 +409,11 @@
 }
 
 void InteractiveBase::show_buildhelp(bool t) {
+	const bool old_value = buildhelp_;
 	buildhelp_ = t;
-	on_buildhelp_changed(t);
+	if (old_value != t) {
+		rebuild_showhide_menu();
+	}
 }
 
 void InteractiveBase::toggle_buildhelp() {
@@ -283,9 +426,9 @@
                                                 UI::UniqueWindow::Registry* window,
                                                 bool bind_default_toggle) {
 	UI::Button* button =
-	   new UI::Button(&toolbar_, name, 0, 0, 34U, 34U, UI::ButtonStyle::kWuiPrimary,
+	   new UI::Button(&toolbar_.box, name, 0, 0, 34U, 34U, UI::ButtonStyle::kWuiPrimary,
 	                  g_gr->images().get("images/" + image_basename + ".png"), tooltip_text);
-	toolbar_.add(button);
+	toolbar_.box.add(button);
 	if (window) {
 		window->opened.connect([button] { button->set_perm_pressed(true); });
 		window->closed.connect([button] { button->set_perm_pressed(false); });
@@ -298,9 +441,6 @@
 	return button;
 }
 
-void InteractiveBase::on_buildhelp_changed(bool /* value */) {
-}
-
 bool InteractiveBase::has_expedition_port_space(const Widelands::Coords& coords) const {
 	for (const auto& pair : expedition_port_spaces_) {
 		if (pair.second == coords) {
@@ -659,6 +799,7 @@
 		});
 		mainview_move();
 	}
+	rebuild_mapview_menu();
 }
 
 const std::vector<QuickNavigation::Landmark>& InteractiveBase::landmarks() {
@@ -676,17 +817,6 @@
 	minimap_registry_.destroy();
 }
 
-/**
-===========
-InteractiveBase::minimap_registry()
-
-Exposes the Registry object of the minimap to derived classes
-===========
-*/
-MiniMap::Registry& InteractiveBase::minimap_registry() {
-	return minimap_registry_;
-}
-
 /*
 ===============
 Return display flags (dfXXX) that modify the view of the map.
@@ -1016,46 +1146,15 @@
 
 	if (down) {
 		switch (code.sym) {
-		case SDLK_KP_9:
-			if (code.mod & KMOD_NUM) {
-				break;
-			}
-			FALLS_THROUGH;
-		case SDLK_PAGEUP:
-			if (upcast(Game, game, &egbase_)) {
-				if (GameController* const ctrl = game->game_controller()) {
-					ctrl->set_desired_speed(ctrl->desired_speed() + 1000);
-				}
-			}
-			return true;
-
-		case SDLK_PAUSE:
-			if (upcast(Game, game, &egbase_)) {
-				if (GameController* const ctrl = game->game_controller()) {
-					ctrl->toggle_paused();
-				}
-			}
-			return true;
-
-		case SDLK_KP_3:
-			if (code.mod & KMOD_NUM) {
-				break;
-			}
-			FALLS_THROUGH;
-		case SDLK_PAGEDOWN:
-			if (upcast(Widelands::Game, game, &egbase_)) {
-				if (GameController* const ctrl = game->game_controller()) {
-					uint32_t const speed = ctrl->desired_speed();
-					ctrl->set_desired_speed(1000 < speed ? speed - 1000 : 0);
-				}
-			}
-			return true;
 #ifndef NDEBUG  //  only in debug builds
 		case SDLK_F6:
 			GameChatMenu::create_script_console(
 			   this, debugconsole_, *DebugConsole::get_chat_provider());
 			return true;
 #endif
+		case SDLK_m:
+			toggle_minimap();
+			return true;
 		default:
 			break;
 		}

=== modified file 'src/wui/interactive_base.h'
--- src/wui/interactive_base.h	2019-05-31 19:31:45 +0000
+++ src/wui/interactive_base.h	2019-06-01 16:05:47 +0000
@@ -25,12 +25,14 @@
 
 #include <SDL_keycode.h>
 
+#include "graphic/toolbar_imageset.h"
 #include "logic/editor_game_base.h"
 #include "logic/map.h"
 #include "notifications/notifications.h"
 #include "profile/profile.h"
 #include "sound/note_sound.h"
 #include "ui_basic/box.h"
+#include "ui_basic/dropdown.h"
 #include "ui_basic/textarea.h"
 #include "ui_basic/unique_window.h"
 #include "wui/chat_overlay.h"
@@ -116,7 +118,7 @@
 	// Returns true if the buildhelp is currently displayed.
 	bool buildhelp() const;
 
-	// Sets if the buildhelp should be displayed. Will also call on_buildhelp_changed().
+	// Sets if the buildhelp should be displayed and then calls rebuild_showhide_menu
 	void show_buildhelp(bool t);
 
 	/**
@@ -171,6 +173,7 @@
 	}
 
 	void toggle_minimap();
+	// Toggles the buildhelp and calls rebuild_showhide_menu
 	void toggle_buildhelp();
 
 	// Returns the list of landmarks that have been mapped to the keys 0-9
@@ -184,6 +187,21 @@
 	}
 
 protected:
+	// For referencing the items in mapviewmenu_
+	enum class MapviewMenuEntry {
+		kMinimap,
+		kIncreaseZoom,
+		kDecreaseZoom,
+		kResetZoom
+	};
+
+	// Adds the mapviewmenu_ to the toolbar
+	void add_mapview_menu(MiniMapType minimap_type);
+	// Rebuilds the mapviewmenu_ according to current view settings
+	void rebuild_mapview_menu();
+	// Takes the appropriate action when an item in the mapviewmenu_ is selected
+	void mapview_menu_selected(MapviewMenuEntry entry);
+
 	/// Adds a toolbar button to the toolbar
 	/// \param image_basename:      File path for button image starting from 'images' and without
 	///                             file extension
@@ -197,13 +215,8 @@
 	                               UI::UniqueWindow::Registry* window = nullptr,
 	                               bool bind_default_toggle = false);
 
-	// Will be called whenever the buildhelp is changed with the new 'value'.
-	virtual void on_buildhelp_changed(bool value);
-
 	void hide_minimap();
 
-	MiniMap::Registry& minimap_registry();
-
 	void mainview_move();
 
 	void draw_overlay(RenderTarget&) override;
@@ -231,16 +244,16 @@
 	const Image* get_sel_picture() {
 		return sel_.pic;
 	}
-	void adjust_toolbar_position() {
-		toolbar_.set_pos(Vector2i((get_inner_w() - toolbar_.get_w()) >> 1, get_inner_h() - 34));
-	}
+
+	// Sets the toolbar's position to the bottom middle and configures its background images
+	void finalize_toolbar();
 
 	ChatOverlay* chat_overlay() {
 		return chat_overlay_;
 	}
 
 	UI::Box* toolbar() {
-		return &toolbar_;
+		return &toolbar_.box;
 	}
 
 	// Returns the information which overlay text should currently be drawn.
@@ -267,6 +280,12 @@
 	/// Returns true if the current player is allowed to hear sounds from map objects on this field
 	virtual bool player_hears_field(const Widelands::Coords& coords) const = 0;
 
+	void set_toolbar_imageset(const ToolbarImageset& imageset);
+
+#ifndef NDEBUG  //  only in debug builds
+	UI::UniqueWindow::Registry debugconsole_;
+#endif
+
 private:
 	void play_sound_effect(const NoteSound& note) const;
 	void resize_chat_overlay();
@@ -275,6 +294,9 @@
 	void cmd_map_object(const std::vector<std::string>& args);
 	void cmd_lua(const std::vector<std::string>& args);
 
+	// Rebuilds the subclass' showhidemenu_ according to current map settings
+	virtual void rebuild_showhide_menu() = 0;
+
 	struct SelData {
 		SelData(const bool Freeze = false,
 		        const bool Triangles = false,
@@ -297,7 +319,26 @@
 	MapView map_view_;
 	ChatOverlay* chat_overlay_;
 
-	UI::Box toolbar_;
+	/// A horizontal menu bar embellished with background graphics
+	struct Toolbar : UI::Panel {
+		Toolbar(UI::Panel* parent);
+
+		/// Sets the actual size and position of the toolbar
+		void finalize();
+		void draw(RenderTarget& dst) override;
+		void change_imageset(const ToolbarImageset& images);
+
+		/// A row of buttons and dropdown menus
+		UI::Box box;
+	private:
+		/// The set of background images
+		ToolbarImageset imageset;
+		/// How often the left and right images get repeated, calculated from the width of the box
+		int repeat;
+	} toolbar_;
+
+	// Map View menu on the toolbar
+	UI::Dropdown<MapviewMenuEntry> mapviewmenu_;
 	// No unique_ptr on purpose: 'minimap_' is a UniqueWindow, its parent will
 	// delete it.
 	MiniMap* minimap_;
@@ -325,7 +366,6 @@
 	Widelands::CoordPath* buildroad_;  //  path for the new road
 	Widelands::PlayerNumber road_build_player_;
 
-	UI::UniqueWindow::Registry debugconsole_;
 	std::unique_ptr<UniqueWindowHandler> unique_window_handler_;
 	BuildhelpOverlay buildhelp_overlays_[Widelands::Field::Buildhelp_None];
 };

=== modified file 'src/wui/interactive_gamebase.cc'
--- src/wui/interactive_gamebase.cc	2019-05-26 17:21:15 +0000
+++ src/wui/interactive_gamebase.cc	2019-06-01 16:05:47 +0000
@@ -37,7 +37,11 @@
 #include "profile/profile.h"
 #include "wui/constructionsitewindow.h"
 #include "wui/dismantlesitewindow.h"
+#include "wui/game_chat_menu.h"
 #include "wui/game_client_disconnected.h"
+#include "wui/game_exit_confirm_box.h"
+#include "wui/game_main_menu_save_game.h"
+#include "wui/game_options_sound_menu.h"
 #include "wui/game_summary.h"
 #include "wui/interactive_player.h"
 #include "wui/militarysitewindow.h"
@@ -65,7 +69,25 @@
    : InteractiveBase(g, global_s),
      chat_provider_(nullptr),
      multiplayer_(multiplayer),
-     playertype_(pt) {
+     playertype_(pt),
+	 showhidemenu_(
+		toolbar(), "dropdown_menu_showhide", 0, 0, 34U, 10, 34U,
+		 /** TRANSLATORS: Title for a menu button in the game. This menu will show/hide building spaces, census, statistics */
+		 _("Show / Hide"),
+		 UI::DropdownType::kPictorialMenu,
+		 UI::PanelStyle::kWui, UI::ButtonStyle::kWuiPrimary),
+	 mainmenu_(
+		toolbar(), "dropdown_menu_main", 0, 0, 34U, 10, 34U,
+		 /** TRANSLATORS: Title for the main menu button in the game */
+		 _("Main Menu"),
+		 UI::DropdownType::kPictorialMenu,
+		 UI::PanelStyle::kWui, UI::ButtonStyle::kWuiPrimary),
+	 gamespeedmenu_(
+		toolbar(), "dropdown_menu_gamespeed", 0, 0, 34U, 10, 34U,
+		 /** TRANSLATORS: Title for a menu button in the game. This menu will show options o increase/decrease the gamespeed, and to pause the game */
+		 _("Game Speed"),
+		 UI::DropdownType::kPictorialMenu,
+		 UI::PanelStyle::kWui, UI::ButtonStyle::kWuiPrimary) {
 	buildingnotes_subscriber_ = Notifications::subscribe<Widelands::NoteBuilding>(
 	   [this](const Widelands::NoteBuilding& note) {
 		   switch (note.action) {
@@ -93,6 +115,211 @@
 	   });
 }
 
+void InteractiveGameBase::add_main_menu() {
+	mainmenu_.set_image(g_gr->images().get("images/wui/menus/main_menu.png"));
+	toolbar()->add(&mainmenu_);
+
+#ifndef NDEBUG  //  only in debug builds
+	/** TRANSLATORS: An entry in the game's main menu */
+	mainmenu_.add(_("Script Console"), MainMenuEntry::kScriptConsole, g_gr->images().get("images/wui/menus/lua.png"), false,
+				  /** TRANSLATORS: Tooltip for Script Console in the game's main menu */
+				  "", pgettext("hotkey", "F6"));
+#endif
+
+	menu_windows_.sound_options.open_window = [this] {
+		new GameOptionsSoundMenu(*this, menu_windows_.sound_options);
+	};
+	/** TRANSLATORS: An entry in the game's main menu */
+	mainmenu_.add(_("Sound Options"), MainMenuEntry::kOptions, g_gr->images().get("images/wui/menus/options.png"), false,
+				  /** TRANSLATORS: Tooltip for Sound Options in the game's main menu */
+				  _("Set sound effect and music options"));
+
+	menu_windows_.savegame.open_window = [this] {
+		new GameMainMenuSaveGame(*this, menu_windows_.savegame);
+	};
+	/** TRANSLATORS: An entry in the game's main menu */
+	mainmenu_.add(_("Save Game"), MainMenuEntry::kSaveMap, g_gr->images().get("images/wui/menus/save_game.png"));
+
+	/** TRANSLATORS: An entry in the game's main menu */
+	mainmenu_.add(_("Exit Game"), MainMenuEntry::kExitGame, g_gr->images().get("images/wui/menus/exit.png"));
+
+	mainmenu_.selected.connect([this] { main_menu_selected(mainmenu_.get_selected()); });
+}
+
+void InteractiveGameBase::main_menu_selected(MainMenuEntry entry) {
+	switch (entry) {
+#ifndef NDEBUG  //  only in debug builds
+	case MainMenuEntry::kScriptConsole: {
+		GameChatMenu::create_script_console(
+		   this, debugconsole_, *DebugConsole::get_chat_provider());
+	} break;
+#endif
+	case MainMenuEntry::kOptions: {
+		menu_windows_.sound_options.toggle();
+	} break;
+	case MainMenuEntry::kSaveMap: {
+		menu_windows_.savegame.toggle();
+	} break;
+	case MainMenuEntry::kExitGame: {
+		if (SDL_GetModState() & KMOD_CTRL) {
+			end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack);
+		} else {
+			new GameExitConfirmBox(*this, *this);
+		}
+	} break;
+	}
+}
+
+void InteractiveGameBase::add_showhide_menu() {
+	showhidemenu_.set_image(g_gr->images().get("images/wui/menus/showhide.png"));
+	toolbar()->add(&showhidemenu_);
+
+	rebuild_showhide_menu();
+	showhidemenu_.selected.connect([this] { showhide_menu_selected(showhidemenu_.get_selected()); });
+}
+
+void InteractiveGameBase::rebuild_showhide_menu() {
+	showhidemenu_.clear();
+
+	/** TRANSLATORS: An entry in the game's show/hide menu to toggle whether building spaces are shown */
+	showhidemenu_.add(buildhelp() ? _("Hide Building Spaces") : _("Show Building Spaces"),
+					  ShowHideEntry::kBuildingSpaces, g_gr->images().get("images/wui/menus/toggle_buildhelp.png"),
+					  false, "", pgettext("hotkey", "Space"));
+
+	/** TRANSLATORS: An entry in the game's show/hide menu to toggle whether building names are shown */
+	showhidemenu_.add(get_display_flag(dfShowCensus) ? _("Hide Census") : _("Show Census"),
+					  ShowHideEntry::kCensus, g_gr->images().get("images/wui/menus/toggle_census.png"),
+					  false, "", "c");
+
+	/** TRANSLATORS: An entry in the game's show/hide menu to toggle whether building staristics are shown */
+	showhidemenu_.add(get_display_flag(dfShowStatistics) ? _("Hide Statistics") : _("Show Statistics"),
+					  ShowHideEntry::kStatistics, g_gr->images().get("images/wui/menus/toggle_statistics.png"),
+					  false, "", "s");
+}
+
+void InteractiveGameBase::showhide_menu_selected(ShowHideEntry entry) {
+	switch (entry) {
+	case ShowHideEntry::kBuildingSpaces: {
+		toggle_buildhelp();
+	} break;
+	case ShowHideEntry::kCensus: {
+		set_display_flag(dfShowCensus, !get_display_flag(dfShowCensus));
+	} break;
+	case ShowHideEntry::kStatistics: {
+		set_display_flag(dfShowStatistics, !get_display_flag(dfShowStatistics));
+	} break;
+	case ShowHideEntry::kWorkareaOverlap: {
+		set_display_flag(dfShowWorkareaOverlap, !get_display_flag(dfShowWorkareaOverlap));
+	} break;
+	}
+	rebuild_showhide_menu();
+}
+
+
+void InteractiveGameBase::add_gamespeed_menu() {
+	gamespeedmenu_.set_image(g_gr->images().get("images/wui/menus/gamespeed.png"));
+	toolbar()->add(&gamespeedmenu_);
+	rebuild_gamespeed_menu();
+	gamespeedmenu_.selected.connect([this] { gamespeed_menu_selected(gamespeedmenu_.get_selected()); });
+}
+
+
+void InteractiveGameBase::rebuild_gamespeed_menu() {
+	gamespeedmenu_.clear();
+
+	gamespeedmenu_.add(_("Speed +"), GameSpeedEntry::kIncrease, g_gr->images().get("images/wui/menus/gamespeed_increase.png"), false,
+				  /** TRANSLATORS: Tooltip for Speed + in the game's game speed menu */
+				  _("Increase the game speed"), pgettext("hotkey", "Page Up"));
+
+	gamespeedmenu_.add(_("Speed -"), GameSpeedEntry::kDecrease, g_gr->images().get("images/wui/menus/gamespeed_decrease.png"), false,
+				  /** TRANSLATORS: Tooltip for Speed - in the game's game speed menu */
+				  _("Decrease the game speed"), pgettext("hotkey", "Page Down"));
+
+	if (get_game()->game_controller() && get_game()->game_controller()->is_paused()) {
+		gamespeedmenu_.add(_("Resume"), GameSpeedEntry::kPause, g_gr->images().get("images/wui/menus/gamespeed_resume.png"), false,
+					  /** TRANSLATORS: Tooltip for Pause in the game's game speed menu */
+					  _("Resume the Game"), pgettext("hotkey", "Pause"));
+	} else {
+		gamespeedmenu_.add(_("Pause"), GameSpeedEntry::kPause, g_gr->images().get("images/wui/menus/gamespeed_pause.png"), false,
+					  /** TRANSLATORS: Tooltip for Pause in the game's game speed menu */
+					  _("Pause the Game"), pgettext("hotkey", "Pause"));
+	}
+}
+
+void InteractiveGameBase::gamespeed_menu_selected(GameSpeedEntry entry) {
+	switch (entry) {
+	case GameSpeedEntry::kIncrease: {
+		increase_gamespeed();
+		// Keep the window open so that the player can click this multiple times
+		gamespeedmenu_.toggle();
+	} break;
+	case GameSpeedEntry::kDecrease: {
+		decrease_gamespeed();
+		// Keep the window open so that the player can click this multiple times
+		gamespeedmenu_.toggle();
+	} break;
+	case GameSpeedEntry::kPause: {
+		toggle_game_paused();
+	} break;
+	}
+}
+
+void InteractiveGameBase::increase_gamespeed() {
+	if (GameController* const ctrl = get_game()->game_controller()) {
+		ctrl->set_desired_speed(ctrl->desired_speed() + 1000);
+	}
+}
+
+void InteractiveGameBase::decrease_gamespeed() {
+	if (GameController* const ctrl = get_game()->game_controller()) {
+		uint32_t const speed = ctrl->desired_speed();
+		ctrl->set_desired_speed(1000 < speed ? speed - 1000 : 0);
+	}
+}
+
+void InteractiveGameBase::toggle_game_paused() {
+	if (GameController* const ctrl = get_game()->game_controller()) {
+		ctrl->toggle_paused();
+		// Toggle Pause / Resume in the menu
+		rebuild_gamespeed_menu();
+	}
+}
+
+bool InteractiveGameBase::handle_key(bool down, SDL_Keysym code) {
+	if (InteractiveBase::handle_key(down, code)) {
+		return true;
+	}
+
+	if (down) {
+		switch (code.sym) {
+		case SDLK_KP_9:
+			if (code.mod & KMOD_NUM) {
+				break;
+			}
+			FALLS_THROUGH;
+		case SDLK_PAGEUP:
+			increase_gamespeed();
+			return true;
+
+		case SDLK_PAUSE:
+			toggle_game_paused();
+			return true;
+
+		case SDLK_KP_3:
+			if (code.mod & KMOD_NUM) {
+				break;
+			}
+			FALLS_THROUGH;
+		case SDLK_PAGEDOWN:
+			decrease_gamespeed();
+			return true;
+		default:
+			break;
+		}
+	}
+	return false;
+}
+
 /// \return a pointer to the running \ref Game instance.
 Widelands::Game* InteractiveGameBase::get_game() const {
 	return dynamic_cast<Widelands::Game*>(&egbase());
@@ -180,7 +407,6 @@
  */
 void InteractiveGameBase::postload() {
 	show_buildhelp(false);
-	on_buildhelp_changed(buildhelp());
 
 	// Recalc whole map for changed owner stuff
 	egbase().mutable_map()->recalc_whole_map(egbase().world());
@@ -210,10 +436,6 @@
 	}
 }
 
-void InteractiveGameBase::on_buildhelp_changed(const bool value) {
-	toggle_buildhelp_->set_perm_pressed(value);
-}
-
 void InteractiveGameBase::add_wanted_building_window(const Widelands::Coords& coords,
                                                      const Vector2i point,
                                                      bool was_minimal) {

=== modified file 'src/wui/interactive_gamebase.h'
--- src/wui/interactive_gamebase.h	2019-05-12 16:28:27 +0000
+++ src/wui/interactive_gamebase.h	2019-06-01 16:05:47 +0000
@@ -25,6 +25,7 @@
 
 #include "logic/game.h"
 #include "profile/profile.h"
+#include "ui_basic/dropdown.h"
 #include "ui_basic/unique_window.h"
 #include "wui/general_statistics_menu.h"
 #include "wui/interactive_base.h"
@@ -35,22 +36,6 @@
 
 class InteractiveGameBase : public InteractiveBase {
 public:
-	struct GameMainMenuWindows {
-		UI::UniqueWindow::Registry loadgame;
-		UI::UniqueWindow::Registry savegame;
-		UI::UniqueWindow::Registry readme;
-		UI::UniqueWindow::Registry keys;
-		UI::UniqueWindow::Registry help;
-		UI::UniqueWindow::Registry license;
-		UI::UniqueWindow::Registry sound_options;
-
-		UI::UniqueWindow::Registry building_stats;
-		GeneralStatisticsMenu::Registry general_stats;
-		UI::UniqueWindow::Registry ware_stats;
-		UI::UniqueWindow::Registry stock;
-		UI::UniqueWindow::Registry seafaring_stats;
-	};
-
 	InteractiveGameBase(Widelands::Game&,
 	                    Section& global_s,
 	                    PlayerType pt = NONE,
@@ -104,20 +89,85 @@
 	void start() override;
 
 protected:
+	// For referencing the items in showhidemenu_
+	enum class ShowHideEntry {
+		kBuildingSpaces,
+		kCensus,
+		kStatistics,
+		kWorkareaOverlap
+	};
+
+	// Adds the mapviewmenu_ to the toolbar
+	void add_main_menu();
+	// Adds the showhidemenu_ to the toolbar
+	void add_showhide_menu();
+	void rebuild_showhide_menu() override;
+	// Adds the gamespeedmenu_ to the toolbar
+	void add_gamespeed_menu();
+
+	bool handle_key(bool down, SDL_Keysym code) override;
+
 	void draw_overlay(RenderTarget&) override;
 
-	GameMainMenuWindows main_windows_;
+	// All unique menu windows
+	struct GameMenuWindows {
+		UI::UniqueWindow::Registry sound_options;
+		UI::UniqueWindow::Registry savegame;
+
+		GeneralStatisticsMenu::Registry stats_general;
+		UI::UniqueWindow::Registry stats_wares;
+		UI::UniqueWindow::Registry stats_stock;
+		UI::UniqueWindow::Registry stats_buildings;
+		UI::UniqueWindow::Registry stats_seafaring;
+
+		UI::UniqueWindow::Registry help;
+	} menu_windows_;
+
 	ChatProvider* chat_provider_;
 	bool multiplayer_;
 	PlayerType playertype_;
+
+	// Show / Hide menu on the toolbar
+	UI::Dropdown<ShowHideEntry> showhidemenu_;
+
 	UI::UniqueWindow::Registry fieldaction_;
 	UI::UniqueWindow::Registry game_summary_;
 	UI::UniqueWindow::Registry client_disconnected_;
-	UI::Button* toggle_buildhelp_;
-	UI::Button* reset_zoom_;
 
 private:
-	void on_buildhelp_changed(const bool value) override;
+	// For referencing the items in mainmenu_
+	enum class MainMenuEntry {
+#ifndef NDEBUG  //  only in debug builds
+		kScriptConsole,
+#endif
+		kOptions,
+		kSaveMap,
+		kExitGame
+	};
+
+	// For referencing the items in gamespeedmenu_
+	enum class GameSpeedEntry {
+		kIncrease,
+		kDecrease,
+		kPause
+	};
+
+	// Takes the appropriate action when an item in the mainmenu_ is selected
+	void main_menu_selected(MainMenuEntry entry);
+	// Takes the appropriate action when an item in the showhidemenu_ is selected
+	void showhide_menu_selected(ShowHideEntry entry);
+	// Takes the appropriate action when an item in the gamespeedmenu_ is selected
+	void gamespeed_menu_selected(GameSpeedEntry entry);
+	// Rebuilds the gamespeedmenu_ according to current game settings
+	void rebuild_gamespeed_menu();
+
+	// Increases the gamespeed
+	void increase_gamespeed();
+	// Decreases the gamespeed
+	void decrease_gamespeed();
+	// Pauses / Unpauses the game and calls rebuild_gamespeed_menu
+	void toggle_game_paused();
+
 	struct WantedBuildingWindow {
 		explicit WantedBuildingWindow(const Vector2i& pos,
 		                              bool was_minimized,
@@ -128,6 +178,12 @@
 		const bool minimize;
 		const bool show_workarea;
 	};
+
+	// Main menu on the toolbar
+	UI::Dropdown<MainMenuEntry> mainmenu_;
+	// Game speed menu on the toolbar
+	UI::Dropdown<GameSpeedEntry> gamespeedmenu_;
+
 	// Building coordinates, window position, whether the window was minimized
 	std::map<uint32_t, std::unique_ptr<const WantedBuildingWindow>> wanted_building_windows_;
 	std::unique_ptr<Notifications::Subscriber<Widelands::NoteBuilding>> buildingnotes_subscriber_;

=== modified file 'src/wui/interactive_player.cc'
--- src/wui/interactive_player.cc	2019-05-31 19:31:45 +0000
+++ src/wui/interactive_player.cc	2019-06-01 16:05:47 +0000
@@ -48,8 +48,6 @@
 #include "wui/game_main_menu_save_game.h"
 #include "wui/game_message_menu.h"
 #include "wui/game_objectives_menu.h"
-#include "wui/game_options_menu.h"
-#include "wui/game_statistics_menu.h"
 #include "wui/general_statistics_menu.h"
 #include "wui/seafaring_statistics_menu.h"
 #include "wui/stock_menu.h"
@@ -161,36 +159,26 @@
    : InteractiveGameBase(g, global_s, NONE, multiplayer),
      auto_roadbuild_mode_(global_s.get_bool("auto_roadbuild_mode", true)),
      flag_to_connect_(Widelands::Coords::null()),
-     grid_marker_pic_(g_gr->images().get("images/wui/overlays/grid_marker.png")) {
-	add_toolbar_button(
-	   "wui/menus/menu_options_menu", "options_menu", _("Main menu"), &options_, true);
-	options_.open_window = [this] { new GameOptionsMenu(*this, options_, main_windows_); };
-
-	add_toolbar_button(
-	   "wui/menus/menu_toggle_menu", "statistics_menu", _("Statistics"), &statisticsmenu_, true);
-	statisticsmenu_.open_window = [this] {
-		new GameStatisticsMenu(*this, statisticsmenu_, main_windows_);
-	};
+	 statisticsmenu_(
+		toolbar(), "dropdown_menu_statistics", 0, 0, 34U, 10, 34U,
+		 /** TRANSLATORS: Title for the statistics menu button in the game */
+		 _("Statistics"),
+		 UI::DropdownType::kPictorialMenu,
+		 UI::PanelStyle::kWui, UI::ButtonStyle::kWuiPrimary),
+	 grid_marker_pic_(g_gr->images().get("images/wui/overlays/grid_marker.png")) {
+	add_main_menu();
 
 	set_display_flag(InteractiveBase::dfShowWorkareaOverlap, true);  // enable by default
 
 	toolbar()->add_space(15);
 
-	add_toolbar_button(
-	   "wui/menus/menu_toggle_minimap", "minimap", _("Minimap"), &minimap_registry(), true);
-	minimap_registry().open_window = [this] { toggle_minimap(); };
+	add_mapview_menu(MiniMapType::kStaticViewWindow);
+	add_showhide_menu();
+	add_gamespeed_menu();
 
-	toggle_buildhelp_ = add_toolbar_button(
-	   "wui/menus/menu_toggle_buildhelp", "buildhelp", _("Show building spaces (on/off)"));
-	toggle_buildhelp_->sigclicked.connect(boost::bind(&InteractiveBase::toggle_buildhelp, this));
-	reset_zoom_ = add_toolbar_button("wui/menus/menu_reset_zoom", "reset_zoom", _("Reset zoom"));
-	reset_zoom_->sigclicked.connect([this] {
-		map_view()->zoom_around(
-		   1.f, Vector2f(get_w() / 2.f, get_h() / 2.f), MapView::Transition::Smooth);
-	});
 	toolbar()->add_space(15);
 	if (multiplayer) {
-		toggle_chat_ = add_toolbar_button("wui/menus/menu_chat", "chat", _("Chat"), &chat_, true);
+		toggle_chat_ = add_toolbar_button("wui/menus/chat", "chat", _("Chat"), &chat_, true);
 		chat_.open_window = [this] {
 			if (chat_provider_) {
 				GameChatMenu::create_chat_console(this, chat_, *chat_provider_);
@@ -199,14 +187,18 @@
 		toolbar()->add_space(15);
 	}
 
+	add_statistics_menu();
+
 	add_toolbar_button(
-	   "wui/menus/menu_objectives", "objectives", _("Objectives"), &objectives_, true);
+	   "wui/menus/objectives", "objectives", _("Objectives"), &objectives_, true);
 	objectives_.open_window = [this] { new GameObjectivesMenu(this, objectives_); };
 
 	toggle_message_menu_ = add_toolbar_button(
-	   "wui/menus/menu_toggle_oldmessage_menu", "messages", _("Messages"), &message_menu_, true);
+	   "wui/menus/message_old", "messages", _("Messages"), &message_menu_, true);
 	message_menu_.open_window = [this] { new GameMessageMenu(*this, message_menu_); };
 
+	toolbar()->add_space(15);
+
 	add_toolbar_button("ui_basic/menu_help", "help", _("Help"), &encyclopedia_, true);
 	encyclopedia_.open_window = [this] {
 		new TribalEncyclopedia(*this, encyclopedia_, &game().lua());
@@ -217,13 +209,106 @@
 		node_action(node_and_triangle);
 	});
 
-	adjust_toolbar_position();
-
-	main_windows_.stock.open_window = [this] { new StockMenu(*this, main_windows_.stock); };
+	finalize_toolbar();
 
 #ifndef NDEBUG  //  only in debug builds
 	addCommand("switchplayer", boost::bind(&InteractivePlayer::cmdSwitchPlayer, this, _1));
 #endif
+
+	map_options_subscriber_ =
+	   Notifications::subscribe<NoteMapOptions>([this](const NoteMapOptions&) {
+		   rebuild_statistics_menu();
+	   });
+}
+
+
+void InteractivePlayer::add_statistics_menu() {
+	statisticsmenu_.set_image(g_gr->images().get("images/wui/menus/statistics.png"));
+	toolbar()->add(&statisticsmenu_);
+
+	menu_windows_.stats_seafaring.open_window = [this] {
+		new SeafaringStatisticsMenu(*this, menu_windows_.stats_seafaring);
+	};
+
+	menu_windows_.stats_stock.open_window = [this] { new StockMenu(*this, menu_windows_.stats_stock); };
+
+	menu_windows_.stats_buildings.open_window = [this] {
+		new BuildingStatisticsMenu(*this, menu_windows_.stats_buildings);
+	};
+
+
+	menu_windows_.stats_wares.open_window = [this] {
+		new WareStatisticsMenu(*this, menu_windows_.stats_wares);
+	};
+
+	menu_windows_.stats_general.open_window = [this] {
+		new GeneralStatisticsMenu(*this, menu_windows_.stats_general);
+	};
+
+	// NoteMapOptions takes care of the rebuilding
+
+	statisticsmenu_.selected.connect([this] { statistics_menu_selected(statisticsmenu_.get_selected()); });
+}
+
+void InteractivePlayer::rebuild_statistics_menu() {
+	statisticsmenu_.clear();
+
+	if (egbase().map().allows_seafaring()) {
+		/** TRANSLATORS: An entry in the game's statistics menu */
+		statisticsmenu_.add(_("Seafaring"), StatisticsMenuEntry::kSeafaring,
+							g_gr->images().get("images/wui/menus/statistics_seafaring.png"),
+							false, "", "e");
+	}
+
+	/** TRANSLATORS: An entry in the game's statistics menu */
+	statisticsmenu_.add(_("Stock"), StatisticsMenuEntry::kStock,
+						g_gr->images().get("images/wui/menus/statistics_stock.png"),
+						false, "", "i");
+
+	/** TRANSLATORS: An entry in the game's statistics menu */
+	statisticsmenu_.add(_("Buildings"), StatisticsMenuEntry::kBuildings,
+						g_gr->images().get("images/wui/menus/statistics_buildings.png"),
+						false, "", "b");
+
+	/** TRANSLATORS: An entry in the game's statistics menu */
+	statisticsmenu_.add(_("Wares"), StatisticsMenuEntry::kWare, g_gr->images().get("images/wui/menus/statistics_wares.png"));
+
+
+	/** TRANSLATORS: An entry in the game's statistics menu */
+	statisticsmenu_.add(_("General"), StatisticsMenuEntry::kGeneral, g_gr->images().get("images/wui/menus/statistics_general.png"));
+}
+
+void InteractivePlayer::statistics_menu_selected(StatisticsMenuEntry entry) {
+	switch (entry) {
+	case StatisticsMenuEntry::kGeneral: {
+		menu_windows_.stats_general.toggle();
+	} break;
+	case StatisticsMenuEntry::kWare: {
+		menu_windows_.stats_wares.toggle();
+	} break;
+	case StatisticsMenuEntry::kBuildings: {
+		menu_windows_.stats_buildings.toggle();
+	} break;
+	case StatisticsMenuEntry::kStock: {
+		menu_windows_.stats_stock.toggle();
+	} break;
+	case StatisticsMenuEntry::kSeafaring: {
+		if (egbase().map().allows_seafaring()) {
+			menu_windows_.stats_seafaring.toggle();
+		}
+	} break;
+	}
+	statisticsmenu_.toggle();
+}
+
+void InteractivePlayer::rebuild_showhide_menu() {
+	InteractiveGameBase::rebuild_showhide_menu();
+
+	/** TRANSLATORS: An entry in the game's show/hide menu to toggle whether workarea overlaps are highlighted */
+	showhidemenu_.add(get_display_flag(dfShowWorkareaOverlap) ? _("Hide Workarea Overlaps") : _("Show Workarea Overlaps"),
+					  ShowHideEntry::kWorkareaOverlap, g_gr->images().get("images/wui/menus/show_workarea_overlap.png"),
+					  false, _("Toggle whether overlapping workareas are indicated when placing a constructionsite"),
+					  "w");
 }
 
 void InteractivePlayer::think() {
@@ -255,11 +340,11 @@
 		toggle_chat_->set_enabled(chat_provider_);
 	}
 	{
-		char const* msg_icon = "images/wui/menus/menu_toggle_oldmessage_menu.png";
+		char const* msg_icon = "images/wui/menus/message_old.png";
 		std::string msg_tooltip = _("Messages");
 		if (uint32_t const nr_new_messages =
 		       player().messages().nr_messages(Widelands::Message::Status::kNew)) {
-			msg_icon = "images/wui/menus/menu_toggle_newmessage_menu.png";
+			msg_icon = "images/wui/menus/message_new.png";
 			msg_tooltip =
 			   (boost::format(ngettext("%u new message", "%u new messages", nr_new_messages)) %
 			    nr_new_messages)
@@ -427,11 +512,7 @@
 			return true;
 
 		case SDLK_i:
-			main_windows_.stock.toggle();
-			return true;
-
-		case SDLK_m:
-			minimap_registry().toggle();
+			menu_windows_.stats_stock.toggle();
 			return true;
 
 		case SDLK_n:
@@ -451,26 +532,26 @@
 			return true;
 
 		case SDLK_b:
-			if (main_windows_.building_stats.window == nullptr) {
-				new BuildingStatisticsMenu(*this, main_windows_.building_stats);
+			if (menu_windows_.stats_buildings.window == nullptr) {
+				new BuildingStatisticsMenu(*this, menu_windows_.stats_buildings);
 			} else {
-				main_windows_.building_stats.toggle();
+				menu_windows_.stats_buildings.toggle();
 			}
 			return true;
 
 		case SDLK_e:
 			if (game().map().allows_seafaring()) {
-				if (main_windows_.seafaring_stats.window == nullptr) {
-					new SeafaringStatisticsMenu(*this, main_windows_.seafaring_stats);
+				if (menu_windows_.stats_seafaring.window == nullptr) {
+					new SeafaringStatisticsMenu(*this, menu_windows_.stats_seafaring);
 				} else {
-					main_windows_.seafaring_stats.toggle();
+					menu_windows_.stats_seafaring.toggle();
 				}
 			}
 			return true;
 
 		case SDLK_s:
 			if (code.mod & (KMOD_LCTRL | KMOD_RCTRL))
-				new GameMainMenuSaveGame(*this, main_windows_.savegame);
+				new GameMainMenuSaveGame(*this, menu_windows_.savegame);
 			else
 				set_display_flag(dfShowStatistics, !get_display_flag(dfShowStatistics));
 			return true;
@@ -520,12 +601,20 @@
 void InteractivePlayer::cleanup_for_load() {
 }
 
+void InteractivePlayer::postload() {
+	InteractiveGameBase::postload();
+
+	ToolbarImageset* imageset = player().tribe().toolbar_image_set();
+	if (imageset != nullptr) {
+		set_toolbar_imageset(*imageset);
+	}
+}
+
 bool InteractivePlayer::player_hears_field(const Widelands::Coords& coords) const {
 	const Widelands::Player& plr = player();
 	if (plr.see_all()) {
 		return true;
 	}
-
 	const Widelands::Map& map = egbase().map();
 	const Widelands::Player::Field& player_field =
 	   plr.fields()[map.get_index(coords, map.get_width())];
@@ -548,7 +637,7 @@
 	   str(boost::format("Switching from #%1% to #%2%.") % static_cast<int>(player_number_) % n));
 	player_number_ = n;
 
-	if (UI::UniqueWindow* const building_statistics_window = main_windows_.building_stats.window) {
+	if (UI::UniqueWindow* const building_statistics_window = menu_windows_.stats_buildings.window) {
 		dynamic_cast<BuildingStatisticsMenu&>(*building_statistics_window).update();
 	}
 }

=== modified file 'src/wui/interactive_player.h'
--- src/wui/interactive_player.h	2019-04-25 06:31:33 +0000
+++ src/wui/interactive_player.h	2019-06-01 16:05:47 +0000
@@ -20,11 +20,13 @@
 #ifndef WL_WUI_INTERACTIVE_PLAYER_H
 #define WL_WUI_INTERACTIVE_PLAYER_H
 
+#include <memory>
 #include <vector>
 
 #include <SDL_keyboard.h>
 
 #include "logic/message_id.h"
+#include "logic/note_map_options.h"
 #include "profile/profile.h"
 #include "ui_basic/button.h"
 #include "wui/interactive_gamebase.h"
@@ -64,6 +66,7 @@
 
 	// For load
 	void cleanup_for_load() override;
+	void postload() override;
 	void think() override;
 	void draw(RenderTarget& dst) override;
 
@@ -74,6 +77,23 @@
 	void popup_message(Widelands::MessageId, const Widelands::Message&);
 
 private:
+	// For referencing the items in statisticsmenu_
+	enum class StatisticsMenuEntry {
+		kGeneral,
+		kWare,
+		kBuildings,
+		kStock,
+		kSeafaring
+	};
+
+	// Adds the statisticsmenu_ to the toolbar
+	void add_statistics_menu();
+	// Rebuilds the statisticsmenu_ according to current map settings
+	void rebuild_statistics_menu();
+	// Takes the appropriate action when an item in the statisticsmenu_ is selected
+	void statistics_menu_selected(StatisticsMenuEntry entry);
+	void rebuild_showhide_menu() override;
+
 	bool player_hears_field(const Widelands::Coords& coords) const override;
 
 	void cmdSwitchPlayer(const std::vector<std::string>& args);
@@ -85,14 +105,16 @@
 	UI::Button* toggle_chat_;
 	UI::Button* toggle_message_menu_;
 
+	// Statistics menu on the toolbar
+	UI::Dropdown<StatisticsMenuEntry> statisticsmenu_;
 	UI::UniqueWindow::Registry chat_;
-	UI::UniqueWindow::Registry options_;
-	UI::UniqueWindow::Registry statisticsmenu_;
 	UI::UniqueWindow::Registry objectives_;
 	UI::UniqueWindow::Registry encyclopedia_;
 	UI::UniqueWindow::Registry message_menu_;
 
 	const Image* grid_marker_pic_;
+
+	std::unique_ptr<Notifications::Subscriber<NoteMapOptions>> map_options_subscriber_;
 };
 
 #endif  // end of include guard: WL_WUI_INTERACTIVE_PLAYER_H

=== modified file 'src/wui/interactive_spectator.cc'
--- src/wui/interactive_spectator.cc	2019-04-25 21:48:17 +0000
+++ src/wui/interactive_spectator.cc	2019-06-01 16:05:47 +0000
@@ -30,7 +30,6 @@
 #include "wui/fieldaction.h"
 #include "wui/game_chat_menu.h"
 #include "wui/game_main_menu_save_game.h"
-#include "wui/game_options_menu.h"
 #include "wui/general_statistics_menu.h"
 
 /**
@@ -40,48 +39,24 @@
                                            Section& global_s,
                                            bool const multiplayer)
    : InteractiveGameBase(g, global_s, OBSERVER, multiplayer) {
-	if (is_multiplayer()) {
-		add_toolbar_button(
-		   "wui/menus/menu_options_menu", "options_menu", _("Main menu"), &options_, true);
-		options_.open_window = [this] { new GameOptionsMenu(*this, options_, main_windows_); };
-
-	} else {
-		UI::Button* button =
-		   add_toolbar_button("wui/menus/menu_exit_game", "exit_replay", _("Exit replay"));
-		button->sigclicked.connect(boost::bind(&InteractiveSpectator::exit_btn, this));
-
-		add_toolbar_button(
-		   "wui/menus/menu_save_game", "save_game", _("Save game"), &main_windows_.savegame, true);
-		main_windows_.savegame.open_window = [this] {
-			new GameMainMenuSaveGame(*this, main_windows_.savegame);
-		};
-	}
-	add_toolbar_button("wui/menus/menu_general_stats", "general_stats", _("Statistics"),
-	                   &main_windows_.general_stats, true);
-	main_windows_.general_stats.open_window = [this] {
-		new GeneralStatisticsMenu(*this, main_windows_.general_stats);
+	add_main_menu();
+
+	add_toolbar_button("wui/menus/statistics_general", "general_stats", _("Statistics"),
+	                   &menu_windows_.stats_general, true);
+	menu_windows_.stats_general.open_window = [this] {
+		new GeneralStatisticsMenu(*this, menu_windows_.stats_general);
 	};
 
 	toolbar()->add_space(15);
 
-	add_toolbar_button(
-	   "wui/menus/menu_toggle_minimap", "minimap", _("Minimap"), &minimap_registry(), true);
-	minimap_registry().open_window = [this] { toggle_minimap(); };
-
-	toggle_buildhelp_ = add_toolbar_button(
-	   "wui/menus/menu_toggle_buildhelp", "buildhelp", _("Show building spaces (on/off)"));
-	toggle_buildhelp_->sigclicked.connect(boost::bind(&InteractiveBase::toggle_buildhelp, this));
-
-	reset_zoom_ = add_toolbar_button("wui/menus/menu_reset_zoom", "reset_zoom", _("Reset zoom"));
-	reset_zoom_->sigclicked.connect([this] {
-		map_view()->zoom_around(
-		   1.f, Vector2f(get_w() / 2.f, get_h() / 2.f), MapView::Transition::Smooth);
-	});
+	add_mapview_menu(MiniMapType::kStaticViewWindow);
+	add_showhide_menu();
+	add_gamespeed_menu();
 
 	toolbar()->add_space(15);
 
 	if (is_multiplayer()) {
-		add_toolbar_button("wui/menus/menu_chat", "chat", _("Chat"), &chat_, true);
+		add_toolbar_button("wui/menus/chat", "chat", _("Chat"), &chat_, true);
 		chat_.open_window = [this] {
 			if (chat_provider_) {
 				GameChatMenu::create_chat_console(this, chat_, *chat_provider_);
@@ -89,7 +64,7 @@
 		};
 	}
 
-	adjust_toolbar_position();
+	finalize_toolbar();
 
 	// Setup all screen elements
 	map_view()->field_clicked.connect([this](const Widelands::NodeAndTriangle<>& node_and_triangle) {
@@ -222,17 +197,13 @@
 			toggle_buildhelp();
 			return true;
 
-		case SDLK_m:
-			minimap_registry().toggle();
-			return true;
-
 		case SDLK_c:
 			set_display_flag(dfShowCensus, !get_display_flag(dfShowCensus));
 			return true;
 
 		case SDLK_s:
 			if (code.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
-				new GameMainMenuSaveGame(*this, main_windows_.savegame);
+				new GameMainMenuSaveGame(*this, menu_windows_.savegame);
 			} else
 				set_display_flag(dfShowStatistics, !get_display_flag(dfShowStatistics));
 			return true;

=== modified file 'src/wui/interactive_spectator.h'
--- src/wui/interactive_spectator.h	2019-03-14 23:06:02 +0000
+++ src/wui/interactive_spectator.h	2019-06-01 16:05:47 +0000
@@ -56,7 +56,6 @@
 	void node_action(const Widelands::NodeAndTriangle<>& node_and_triangle) override;
 
 	UI::UniqueWindow::Registry chat_;
-	UI::UniqueWindow::Registry options_;
 };
 
 #endif  // end of include guard: WL_WUI_INTERACTIVE_SPECTATOR_H

=== modified file 'src/wui/mapdetails.cc'
--- src/wui/mapdetails.cc	2019-05-25 09:33:17 +0000
+++ src/wui/mapdetails.cc	2019-06-01 16:05:47 +0000
@@ -42,6 +42,7 @@
      style_(style),
      padding_(4),
      main_box_(this, 0, 0, UI::Box::Vertical, 0, 0, 0),
+	 name_(""),
      name_label_(&main_box_,
                  0,
                  0,
@@ -86,6 +87,7 @@
 
 void MapDetails::update(const MapData& mapdata, bool localize_mapname) {
 	clear();
+	name_= mapdata.name;
 	// Show directory information
 	if (mapdata.maptype == MapData::MapType::kDirectory) {
 		name_label_.set_text(

=== modified file 'src/wui/mapdetails.h'
--- src/wui/mapdetails.h	2019-04-18 16:50:35 +0000
+++ src/wui/mapdetails.h	2019-06-01 16:05:47 +0000
@@ -36,6 +36,9 @@
 
 	void clear();
 	void update(const MapData& mapdata, bool localize_mapname);
+	std::string name() {
+		return name_;
+	}
 
 private:
 	void layout() override;
@@ -43,6 +46,7 @@
 	const int padding_;
 
 	UI::Box main_box_;
+	std::string name_;
 	UI::MultilineTextarea name_label_;
 	UI::MultilineTextarea descr_;
 	UI::SuggestedTeamsBox* suggested_teams_box_;

=== modified file 'src/wui/mapview.cc'
--- src/wui/mapview.cc	2019-04-25 06:31:33 +0000
+++ src/wui/mapview.cc	2019-06-01 16:05:47 +0000
@@ -40,6 +40,9 @@
 // value is used for automatic movements and for user controlled zoom.
 constexpr float kMaxZoom = 4.f;
 
+// Step size for zooming by keypress or UI button
+constexpr float kZoomPercentPerKeyPress = 0.10f;
+
 // The time used for panning automated map movement only.
 constexpr float kShortAnimationMs = 500.f;
 
@@ -556,6 +559,19 @@
 	NEVER_HERE();
 }
 
+
+void MapView::reset_zoom() {
+	zoom_around(1.f, Vector2f(get_w() / 2.f, get_h() / 2.f), Transition::Smooth);
+}
+void MapView::increase_zoom() {
+	zoom_around(animation_target_view().view.zoom - kZoomPercentPerKeyPress,
+				Vector2f(get_w() / 2.f, get_h() / 2.f), Transition::Smooth);
+}
+void MapView::decrease_zoom() {
+	zoom_around(animation_target_view().view.zoom + kZoomPercentPerKeyPress,
+				Vector2f(get_w() / 2.f, get_h() / 2.f), Transition::Smooth);
+}
+
 bool MapView::is_dragging() const {
 	return dragging_;
 }
@@ -580,18 +596,15 @@
 		return false;
 	}
 
-	constexpr float kPercentPerKeyPress = 0.10f;
 	switch (code.sym) {
 	case SDLK_PLUS:
-		zoom_around(animation_target_view().view.zoom - kPercentPerKeyPress,
-		            Vector2f(get_w() / 2.f, get_h() / 2.f), Transition::Smooth);
+		increase_zoom();
 		return true;
 	case SDLK_MINUS:
-		zoom_around(animation_target_view().view.zoom + kPercentPerKeyPress,
-		            Vector2f(get_w() / 2.f, get_h() / 2.f), Transition::Smooth);
+		decrease_zoom();
 		return true;
 	case SDLK_0:
-		zoom_around(1.f, Vector2f(get_w() / 2.f, get_h() / 2.f), Transition::Smooth);
+		reset_zoom();
 		return true;
 	default:
 		return false;

=== modified file 'src/wui/mapview.h'
--- src/wui/mapview.h	2019-04-25 06:31:33 +0000
+++ src/wui/mapview.h	2019-06-01 16:05:47 +0000
@@ -163,6 +163,13 @@
 	// displayed at 'panel_pixel' unchanging, i.e. the center of the zoom.
 	void zoom_around(float new_zoom, const Vector2f& panel_pixel, const Transition& transition);
 
+	// Reset the zoom to 1.0f
+	void reset_zoom();
+	// Zoom in a bit
+	void increase_zoom();
+	// Zoom out a bit
+	void decrease_zoom();
+
 	// True if the user is currently dragging the map.
 	bool is_dragging() const;
 

=== modified file 'src/wui/seafaring_statistics_menu.cc'
--- src/wui/seafaring_statistics_menu.cc	2019-06-01 16:05:46 +0000
+++ src/wui/seafaring_statistics_menu.cc	2019-06-01 16:05:47 +0000
@@ -98,7 +98,7 @@
                kButtonSize,
                kButtonSize,
                UI::ButtonStyle::kWuiPrimary,
-               g_gr->images().get("images/wui/menus/menu_watch_follow.png"),
+               g_gr->images().get("images/wui/menus/watch_follow.png"),
                 /** TRANSLATORS: Tooltip in the seafaring statistics window */
                 as_tooltip_text_with_hotkey(_("Watch the selected ship"), "w")),
      openwindowbtn_(

=== modified file 'src/wui/watchwindow.cc'
--- src/wui/watchwindow.cc	2019-03-15 21:36:00 +0000
+++ src/wui/watchwindow.cc	2019-06-01 16:05:47 +0000
@@ -59,12 +59,12 @@
      cur_index_(0) {
 	UI::Button* followbtn =
 	   new UI::Button(this, "follow", 0, h - 34, 34, 34, UI::ButtonStyle::kWuiSecondary,
-	                  g_gr->images().get("images/wui/menus/menu_watch_follow.png"), _("Follow"));
+	                  g_gr->images().get("images/wui/menus/watch_follow.png"), _("Follow"));
 	followbtn->sigclicked.connect(boost::bind(&WatchWindow::do_follow, this));
 
 	UI::Button* gotobtn = new UI::Button(
 	   this, "center_mainview_here", 34, h - 34, 34, 34, UI::ButtonStyle::kWuiSecondary,
-	   g_gr->images().get("images/wui/menus/menu_goto.png"), _("Center the main view on this"));
+	   g_gr->images().get("images/wui/menus/goto.png"), _("Center the main view on this"));
 	gotobtn->sigclicked.connect(boost::bind(&WatchWindow::do_goto, this));
 
 	if (init_single_window) {

=== added file 'test/maps/plain.wmf/scripting/test_ui.lua'
--- test/maps/plain.wmf/scripting/test_ui.lua	1970-01-01 00:00:00 +0000
+++ test/maps/plain.wmf/scripting/test_ui.lua	2019-06-01 16:05:47 +0000
@@ -0,0 +1,74 @@
+local function open_and_close_sound_options(dropdown)
+   sleep(100)
+
+   -- Test out-of-range selection in dropdown
+   assert_error("Highlighting item 0 should have been out of range", function()
+      dropdown:highlight_item(0)
+   end)
+   assert_error("Highlighting item 2000 should have been out of range", function()
+      dropdown:highlight_item(2000)
+   end)
+
+   -- Test selecting an item in the dropdown
+   dropdown:highlight_item(1)
+   assert_nil(wl.ui.MapView().windows.sound_options_menu, "Sound options window should not have been there yet")
+
+   dropdown:select()
+   sleep(100)
+
+   window = wl.ui.MapView().windows.sound_options_menu
+   assert_not_nil(window, "Failed to open sound options window")
+   window:close()
+
+   sleep(100)
+   assert_nil(wl.ui.MapView().windows.sound_options_menu, "Failed to close sound options window")
+end
+
+run(function()
+   sleep(100)
+
+   -- Validate listing dropdowns
+   local dropdowns = wl.ui.MapView().dropdowns
+   for name,dropdown in pairs(dropdowns) do
+      assert_equal(name, dropdown.name)
+   end
+
+   -- Validate dropdown functions
+   local dropdown = dropdowns["dropdown_menu_main"]
+   assert_not_nil(dropdown, "Failed to find main menu dropdown")
+
+   -- Selecting from closed dropdown should fail silently
+   dropdown:select()
+
+   -- Validate selection without opening
+   open_and_close_sound_options(dropdown);
+
+   -- Validate selection with opening
+   dropdown:open()
+   sleep(100)
+   open_and_close_sound_options(dropdown);
+
+   -- Exit by dropdown
+   local dropdown = dropdowns["dropdown_menu_main"]
+   dropdown:highlight_item(3)
+   dropdown:select()
+
+   local message_box = wl.ui.MapView().windows["message_box"]
+   assert_not_nil(message_box, "Failed to find exit confirm message box")
+   local ok_button = message_box.buttons["ok"]
+   assert_not_nil(ok_button, "Exit confirm message box has no 'ok' button")
+
+   -- We have to print this before closing the main view, otherwise the test suite
+   -- will fail this test, because printing to console won't work.
+   print("# All Tests passed.")
+
+   ok_button:click()
+
+   -- Give Widelands some time to close the map view
+   sleep(10000)
+   assert_nil(wl.ui.MapView(), "Exiting by main menu did not close the map view")
+
+   if (wl.ui.MapView() ~= nil) then
+      wl.ui.MapView():close()
+   end
+end)

=== modified file 'utils/buildcat.py'
--- utils/buildcat.py	2019-01-12 09:44:33 +0000
+++ utils/buildcat.py	2019-06-01 16:05:47 +0000
@@ -110,7 +110,7 @@
      ['../../data/campaigns/%(name)s/extra_data',
       '../../data/campaigns/%(name)s/objective',
       '../../data/campaigns/%(name)s/scripting/*.lua',
-      '../../data/scripting/format_scenario.lua'
+      '../../data/scripting/richtext_scenarios.lua'
       ]
      ),
     ('map_%(name)s/map_%(name)s', 'data/maps/',


Follow ups