← 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
- 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/368229
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/toolbar-dropdown-menus into lp:widelands.
=== modified file 'data/campaigns/tutorial01_basic_control.wmf/elemental'
--- data/campaigns/tutorial01_basic_control.wmf/elemental	2014-10-28 09:24:36 +0000
+++ data/campaigns/tutorial01_basic_control.wmf/elemental	2019-06-01 15:41:38 +0000
@@ -6,5 +6,5 @@
 map_h="64"
 nr_players="1"
 name=_"Basic Control"
-author="Winterwind,SirVer,Nasenbaer,wl-zocker"
+author="Winterwind,SirVer,Nasenbaer,wl-zocker,GunChleoc"
 descr=_"In this tutorial, you will learn how to navigate in Widelands and how to build buildings and roads."

=== modified file 'data/campaigns/tutorial01_basic_control.wmf/scripting/helper_functions_demonstration.lua'
--- data/campaigns/tutorial01_basic_control.wmf/scripting/helper_functions_demonstration.lua	2016-12-28 22:11:45 +0000
+++ data/campaigns/tutorial01_basic_control.wmf/scripting/helper_functions_demonstration.lua	2019-06-01 15:41:38 +0000
@@ -68,6 +68,18 @@
    blocker:lift_blocks()
 end
 
+
+function select_item_from_dropdown(name, item)
+   local blocker = UserInputDisabler:new()
+
+   wl.ui.MapView().dropdowns[name]:highlight_item(item)
+   sleep(5000)
+   wl.ui.MapView().dropdowns[name]:select()
+   sleep(3000)
+
+   blocker:lift_blocks()
+end
+
 -- Make sure the user is in road building mode starting from the given flag
 function enter_road_building_mode(flag)
    local mv = wl.ui.MapView()

=== modified file 'data/campaigns/tutorial01_basic_control.wmf/scripting/mission_thread.lua'
--- data/campaigns/tutorial01_basic_control.wmf/scripting/mission_thread.lua	2017-06-25 12:53:48 +0000
+++ data/campaigns/tutorial01_basic_control.wmf/scripting/mission_thread.lua	2019-06-01 15:41:38 +0000
@@ -2,17 +2,61 @@
 -- Mission thread
 -- ================
 
+local objective_to_explain_objectives = add_campaign_objective(obj_initial_close_objectives_window)
+
+local function wait_for_quarry_road_connection(field, cs, objective)
+   -- Wait till the construction site is connected to the headquarters
+   sleep(10 * wl.Game().desired_speed)
+   while not field.immovable or field.brn.immovable.debug_economy ~= sf.brn.immovable.debug_economy do
+      if not field.immovable then
+         campaign_message_box(quarry_illegally_destroyed)
+         scroll_to_field(field)
+         mouse_to_field(field)
+
+         cs = nil
+         immovable_is_legal = function(i)
+            -- only allow quarry and flag at this position because the road building below relies on this
+            if (i.fields[1] == field) or (i.fields[1] == field.brn) then
+               cs = allow_constructionsite(i, {"barbarians_quarry"})
+               return cs
+            elseif(i.descr.type_name == "flag") or (i.descr.type_name == "road") then
+               register_immovable_as_allowed(i)
+               return true
+            else return false end
+         end
+
+         -- Wait for a new constructionsite to be placed
+         while not cs do sleep(200) end
+         register_immovable_as_allowed(cs)
+      else
+         campaign_message_box(quarry_not_connected)
+      end
+      sleep(60*1000)
+   end
+   set_objective_done(objective, 0)
+   register_immovable_as_allowed(cs)
+end
+
 function starting_infos()
+   -- So that the player cannot build anything here
+   map:place_immovable("debris00", second_quarry_field, "world")
    reveal_concentric(plr, sf, 13, true, 80)
-   map:place_immovable("debris00",second_quarry_field, "world")
-   -- so that the player cannot build anything here
-
    sleep(1000)
 
-   message_box_objective(plr, initial_message_01)
+   -- Welcome and teach objectives
+   local o = campaign_message_with_objective(initial_message_01, obj_initial_close_story_window)
+   set_objective_done(o, 100)
+
+   wl.ui.MapView().buttons.objectives:click()
+   while not wl.ui.MapView().windows.objectives do sleep(100) end
+   while wl.ui.MapView().windows.objectives do sleep(100) end
    sleep(500)
 
-   local o = message_box_objective(plr, initial_message_02)
+   -- Teach building spaces
+   campaign_message_box(initial_message_02, 200)
+   select_item_from_dropdown("dropdown_menu_showhide", 1)
+   select_item_from_dropdown("dropdown_menu_showhide", 1)
+   local o = campaign_message_with_objective(initial_message_03, obj_initial_toggle_building_spaces)
 
    -- Wait for buildhelp to come on
    while not wl.ui.MapView().buildhelp do
@@ -30,7 +74,7 @@
    -- We take control, everything that we build is legal
    immovable_is_legal = function(i) return true end
 
-   message_box_objective(plr, lumberjack_message_01)
+   campaign_message_box(lumberjack_message_01)
 
    local blocker = UserInputDisabler:new()
    close_windows()
@@ -38,7 +82,7 @@
    scroll_to_field(first_lumberjack_field)
    mouse_to_field(first_lumberjack_field)
    sleep(500)
-   message_box_objective(plr, lumberjack_message_02)
+   campaign_message_box(lumberjack_message_02)
    sleep(500)
 
    click_on_field(first_lumberjack_field)
@@ -48,16 +92,16 @@
    sleep(500)
 
    if wl.ui.MapView().is_building_road then
-      message_box_objective(plr, lumberjack_message_03a)
+      campaign_message_box(lumberjack_message_03a)
    else
       enter_road_building_mode(first_lumberjack_field.brn.immovable)
-      message_box_objective(plr, lumberjack_message_03b)
+      campaign_message_box(lumberjack_message_03b)
    end
    sleep(500)
 
    click_on_field(sf.brn)
 
-   message_box_objective(plr, lumberjack_message_04)
+   campaign_message_box(lumberjack_message_04)
 
    register_immovable_as_allowed(first_lumberjack_field.immovable) -- hut + flag
 
@@ -72,7 +116,7 @@
 
    if not (f.immovable and f.immovable.descr.type_name == "flag") then
       -- only show this if the user has not already built a flag
-      local o = message_box_objective(plr, lumberjack_message_05)
+      local o = campaign_message_with_objective(lumberjack_message_05, obj_lumberjack_place_flag)
 
       local blocker = UserInputDisabler:new()
       close_windows()
@@ -85,27 +129,35 @@
 
       -- Wait for flag
       while not (f.immovable and f.immovable.descr.type_name == "flag") do sleep(300) end
-      set_objective_done(o, 300)
-
-      message_box_objective(plr, lumberjack_message_06)
+      set_objective_done(o, 16 * 1000)
    else
       -- if the flag is already built, show the player a different message box
-      message_box_objective(plr, flag_built)
+      campaign_message_box(lumberjack_message_06, 3 * 1000)
    end
 
-   sleep(30*1000) -- let the player experiment a bit with the speed
-   message_box_objective(plr, construction_site_window)
+   local o = campaign_message_with_objective(lumberjack_message_07, obj_lumberjack_progress)
+   scroll_to_field(first_lumberjack_field)
+   mouse_to_field(first_lumberjack_field)
+
+   while not wl.ui.MapView().windows.building_window do sleep(100) end
+   while wl.ui.MapView().windows.building_window do sleep(100) end
+   set_objective_done(o)
+
+   campaign_message_box(lumberjack_message_08)
+   wl.ui.MapView().dropdowns["dropdown_menu_gamespeed"]:open()
+
+   sleep(20*1000) -- let the player experiment a bit with the window
 
    while #plr:get_buildings("barbarians_lumberjacks_hut") < 1 do sleep(300) end
 
-   message_box_objective(plr, lumberjack_message_07)
+   campaign_message_box(lumberjack_message_09)
 
    learn_to_move()
 end
 
 function learn_to_move()
    -- Teaching the user how to scroll on the map
-   local o = message_box_objective(plr, inform_about_rocks)
+   local o = campaign_message_with_objective(tell_about_keyboard_move, obj_moving_keyboard)
 
    function _wait_for_move()
       local center_map_pixel = wl.ui.MapView().center_map_pixel
@@ -118,12 +170,17 @@
    _wait_for_move()
    set_objective_done(o)
 
-   o = message_box_objective(plr, tell_about_right_drag_move)
+   o = campaign_message_with_objective(tell_about_right_drag_move, obj_moving_right_drag)
 
    _wait_for_move()
    set_objective_done(o)
 
-   o = message_box_objective(plr, tell_about_minimap)
+   -- Teach the minimap
+   campaign_message_box(tell_about_minimap_1)
+
+   -- Open the minimap
+   select_item_from_dropdown("dropdown_menu_mapview", 1)
+   o = campaign_message_with_objective(tell_about_minimap_2, obj_moving_minimap)
 
    -- Wait until the minimap has been opened and closed again
    while not wl.ui.MapView().windows.minimap do sleep(100) end
@@ -131,7 +188,7 @@
 
    set_objective_done(o, 500)
 
-   message_box_objective(plr, congratulate_and_on_to_quarry)
+   campaign_message_box(congratulate_and_on_to_quarry)
 
    build_a_quarry()
 end
@@ -140,7 +197,7 @@
    sleep(200)
 
    -- Teaching how to build a quarry and the nits and knacks of road building.
-   local o = message_box_objective(plr, order_quarry_recap_how_to_build)
+   local o = campaign_message_with_objective(order_quarry_recap_how_to_build, obj_build_a_quarry)
 
    local cs = nil
    immovable_is_legal = function(i)
@@ -174,12 +231,12 @@
 
    immovable_is_legal = function() return true end
 
-   sleep(3000) -- give the game some time to enter road building mode
+   sleep(wl.Game().desired_speed) -- give the game some time to enter road building mode
    if wl.ui.MapView().is_building_road then
-      message_box_objective(plr, talk_about_roadbuilding_00a)
+      campaign_message_box(talk_about_roadbuilding_00a)
    else
       -- show the user how to enter road building mode manually
-      message_box_objective(plr, talk_about_roadbuilding_00b)
+      campaign_message_box(talk_about_roadbuilding_00b)
       click_on_field(first_quarry_field.brn)
       click_on_panel(wl.ui.MapView().windows.field_action.buttons.build_road, 300)
    end
@@ -195,7 +252,7 @@
 
    _rip_road()
 
-   message_box_objective(plr, talk_about_roadbuilding_01)
+   campaign_message_box(talk_about_roadbuilding_01)
    -- Showoff direct roadbuilding
    click_on_field(first_quarry_field.brn)
    click_on_panel(wl.ui.MapView().windows.field_action.buttons.build_road, 300)
@@ -207,7 +264,7 @@
 
    blocker:lift_blocks()
 
-   local o = message_box_objective(plr, talk_about_roadbuilding_02)
+   local o = campaign_message_with_objective(talk_about_roadbuilding_02, obj_build_road_to_quarry)
 
    -- The player is allowed to build roads and flags at will
    immovable_is_legal = function(i)
@@ -217,13 +274,7 @@
       else return false end
    end
 
-   -- Wait till the construction site is connected to the headquarters
-   sleep(20*1000)
-   while first_quarry_field.brn.immovable.debug_economy ~= sf.brn.immovable.debug_economy do
-      message_box_objective(plr,quarry_not_connected)
-      sleep(60*1000)
-      if not first_quarry_field.immovable then message_box_objective(plr,quarry_illegally_destroyed) return end
-   end
+   wait_for_quarry_road_connection(first_quarry_field, cs, o)
 
    second_quarry()
 
@@ -231,7 +282,6 @@
    census_and_statistics()
 
    while #plr:get_buildings("barbarians_quarry") < 2 do sleep(1400) end
-   set_objective_done(o, 0)
 
    messages()
 end
@@ -239,9 +289,11 @@
 function second_quarry()
    sleep(2000)
 
-   local o = message_box_objective(plr, build_second_quarry)
+   local o = campaign_message_with_objective(build_second_quarry, obj_build_the_second_quarry)
+   -- Remove this immovable (debris)
    second_quarry_field.immovable:remove()
-   -- remove this immovable (debris)
+   scroll_to_field(first_quarry_field)
+   mouse_to_field(second_quarry_field)
 
    local cs = nil
    immovable_is_legal = function(i)
@@ -257,18 +309,9 @@
    -- Wait for the constructionsite to be placed
    while not cs do sleep(200) end
 
-   sleep(60*1000)
-   while second_quarry_field.brn.immovable.debug_economy ~= sf.brn.immovable.debug_economy do
-      message_box_objective(plr,quarry_not_connected)
-      sleep(60*1000)
-      if not second_quarry_field.immovable then message_box_objective(plr,quarry_illegally_destroyed) return end
-   end
-
-   set_objective_done(o, 0)
-   register_immovable_as_allowed(cs)
+   wait_for_quarry_road_connection(second_quarry_field, cs, o)
 end
 
-
 function census_and_statistics()
    sleep(15000)
 
@@ -280,40 +323,45 @@
 
    wl.ui.MapView():abort_road_building()
 
-   message_box_objective(plr, census_and_statistics_00)
-
-   click_on_field(first_quarry_field.bln)
-   click_on_panel(wl.ui.MapView().windows.field_action.tabs.watch)
-   click_on_panel(wl.ui.MapView().windows.field_action.buttons.census)
-   sleep(300)
-   click_on_field(first_quarry_field.brn)
-   click_on_panel(wl.ui.MapView().windows.field_action.tabs.watch)
-   click_on_panel(wl.ui.MapView().windows.field_action.buttons.statistics)
-
-   message_box_objective(plr, census_and_statistics_01)
+   campaign_message_box(census_and_statistics_00)
+
+   select_item_from_dropdown("dropdown_menu_showhide", 2)
+   sleep(200)
 
    blocker:lift_blocks()
+
+   local o = campaign_message_with_objective(census_and_statistics_01, obj_show_statistics)
+
+   -- Wait for statistics to come on
+   while not wl.ui.MapView().statistics do sleep(200) end
+   set_objective_done(o, 5 * wl.Game().desired_speed)
+
+   if (#plr:get_buildings("barbarians_quarry") < 2) then
+      campaign_message_box(census_and_statistics_02, 200)
+   end
 end
 
 function messages()
    -- Teach the player about receiving messages
    sleep(10)
+   local old_gamespeed = wl.Game().desired_speed
+   wl.Game().desired_speed = 1000
 
    send_message(plr, teaching_about_messages.title, teaching_about_messages.body, teaching_about_messages, {heading = teaching_about_messages.heading})
-   local o = add_campaign_objective(teaching_about_messages)
+   local o = add_campaign_objective(obj_archive_all_messages)
 
    while #plr.inbox > 0 do sleep(200) end
    set_objective_done(o, 500)
 
-   local o = message_box_objective(plr, closing_msg_window_00)
+   local o = campaign_message_with_objective(closing_msg_window_00, obj_close_message_window)
 
    -- Wait for messages window to close
    while wl.ui.MapView().windows.messages do sleep(300) end
-   set_objective_done(o, 0)
-
-   message_box_objective(plr, closing_msg_window_01)
-
-   sleep(800)
+   set_objective_done(o, 300)
+
+   campaign_message_box(closing_msg_window_01, 800)
+
+   if (wl.Game().desired_speed == 1000) then wl.Game().desired_speed = old_gamespeed end
 
    destroy_quarries()
 end
@@ -336,10 +384,7 @@
    -- Wait for messages to arrive
    while count_quarry_messages() < 2 do sleep(300) end
 
-   local o = message_box_objective(plr, destroy_quarries_message)
-
-   -- From now on, the player can build whatever he wants
-   terminate_bad_boy_sentinel = true
+   local o = campaign_message_with_objective(destroy_quarries_message, obj_destroy_quarries)
 
    while #plr:get_buildings("barbarians_quarry") > 0 do sleep(200) end
    set_objective_done(o)
@@ -351,7 +396,10 @@
    -- Teach about expanding the territory
    sleep(10)
 
-   local o = message_box_objective(plr, introduce_expansion)
+   -- From now on, the player can build whatever he wants
+   terminate_bad_boy_sentinel = true
+
+   local o = campaign_message_with_objective(introduce_expansion, obj_expand_territory)
 
    -- wait until there are soldiers inside so that the player sees the expansion
    local soldier_inside = false
@@ -371,19 +419,20 @@
       sleep(500)
    end
 
-   set_objective_done(o)
-   message_box_objective(plr, military_building_finished)
+   set_objective_done(o, 4 * wl.Game().desired_speed)
+   campaign_message_box(military_building_finished)
 
    conclusion()
 end
 
 function conclusion()
+   set_objective_done(objective_to_explain_objectives)
+
    sleep(5000) -- to give the player time to see his expanded area
 
    -- Conclude the tutorial with final words and information
    -- on how to quit
-   message_box_objective(plr, conclude_tutorial)
-
+   campaign_message_box(conclude_tutorial)
 end
 
 run(bad_boy_sentry)

=== modified file 'data/campaigns/tutorial01_basic_control.wmf/scripting/texts.lua'
--- data/campaigns/tutorial01_basic_control.wmf/scripting/texts.lua	2019-02-03 12:02:57 +0000
+++ data/campaigns/tutorial01_basic_control.wmf/scripting/texts.lua	2019-06-01 15:41:38 +0000
@@ -2,15 +2,14 @@
 --                      Texts for the tutorial mission
 -- =======================================================================
 
--- =========================
--- Some formating functions
--- =========================
-
 include "scripting/richtext_scenarios.lua"
 
--- =============
--- Texts below
--- =============
+-- ================
+-- General messages
+-- ================
+
+local close_story_window_instructions = _[[Click on the ‘OK’ button or press the ‘Enter ⏎’ key on the keyboard to close this window.]]
+
 scold_player = {
    title = _"Nice And Easy Does It All the Time",
    body = (
@@ -21,50 +20,93 @@
    show_instantly = true
 }
 
+-- Teaching basic UI controls
+
+-- ==============
+-- Starting Infos
+-- ==============
+
+obj_initial_close_story_window = {
+   name = "initial_close_story_window",
+   title=_"Close this window",
+   number = 1,
+   body = objective_text(_"Close this window",
+      li(close_story_window_instructions)
+   )
+}
 initial_message_01 = {
    title = _"Welcome to the Widelands Tutorial!",
    body = (
       h1(_"Welcome to Widelands!") ..
-      p(_[[Widelands is a slow-paced build-up strategy game with an emphasis on construction rather than destruction. This tutorial will guide you through the basics of the game.]]) ..
-      li(_[[Dismiss this box by left-clicking on the button below.]])
-   ),
-   h = 300,
-   w = 400
-}
+      li_image("images/logos/wl-ico-64.png",
+         _[[Widelands is a slow-paced build-up strategy game with an emphasis on construction rather than destruction. This tutorial will guide you through the basics of the game.]]) ..
+      li_arrow(_[[You will be guided through this tutorial by objectives]]) ..
+      li(_[[Follow the intructions in the objective below so that I can show you where to find them.]])
+   )
+}
+
+obj_initial_close_objectives_window = {
+   name = "obj_initial_close_objectives_window",
+   title=_"Objectives and how to close this window",
+   number = 1,
+   body = objective_text(_"Closing this window",
+      p(_[[This is the ‘Objectives’ window. You can return to this window for instructions at any time.]]) ..
+      li_image("images/wui/menus/objectives.png", _[[ You can open and close this window by clicking on the ‘Objectives’ button in the toolbar on the bottom of the screen.]]) ..
+      li_arrow(_[[Like any other window, you can also close the ‘Objectives’ window by right-clicking on it.]]) ..
+      li_arrow(_[[When you have accomplished an objective, it will disappear from the list above.]]) ..
+      li(_[[Try it out.]])
+   )
+}
+
+obj_initial_toggle_building_spaces = {
+   name = "initial_toggle_building_spaces",
+   title=_"Show building spaces",
+   number = 1,
+   body = objective_text(_"Show building spaces",
+      p(_[[We need to find a nice place for the lumberjack’s hut. To make this easier, we can activate ‘Show Building Spaces’. There are two ways you can do this:]]) ..
+      li_image("images/wui/menus/showhide.png", _[[Press the Space bar to toggle them, or select ‘Show Building Spaces’ in the ‘Show / Hide’ menu.]]) ..
+      li(_[[Show the building spaces now.]])
+   )
+}
+
 initial_message_02 = {
-   title = _"Diving In",
-   position = "topright",
-   field = sf,
-   body = (
-      h1(_"Let’s dive right in!") ..
-      p(_[[There are three different tribes in Widelands: the Barbarians, the Empire and the Atlanteans. All tribes have a different economy, strength and weaknesses, but the general gameplay is the same for all. We will play the Barbarians for now.]]) ..
-      p(_[[You will usually start the game with one headquarters. This is the big building with the blue flag in front of it. The headquarters is a warehouse that stores wares, workers and soldiers. Some wares are needed for building houses, others for making other wares. Obviously, the wares in the headquarters will not last forever, so you must make sure to replace them. The most important wares in the early game are the basic construction wares: logs and granite. Let’s make sure that we do not run out of logs. For this, we need a lumberjack and a hut for him to stay in.]]) ..
-      p(_[[We need to find a nice place for the lumberjack’s hut. To make this easier, we can activate ‘Show building spaces’. There are two ways you can do this:]]) ..
-      li_arrow(_[[Press the Space bar to toggle them, or]]) ..
-      -- TRANSLATORS: List item. Has an image of the button next to it.
-      li_image("images/wui/menus/menu_toggle_buildhelp.png", _[[click the ‘Show building spaces’ button on the bottom of the screen.]]) ..
-      li(_[[Left-click the ‘OK’ button to close this box and then try it.]])
-   ),
-   obj_name = "enable_buildhelp",
-   obj_title = _"Enable the showing of building spaces",
-   obj_body = (
-      h1(_"Show Building Spaces") ..
-      p(_[[It is easier to understand what type of buildings can be built on which field when the symbols for the building spaces are enabled.]]) ..
-      li_arrow(_[[Press the Space bar to toggle them, or]]) ..
-      -- TRANSLATORS: List item. Has an image of the button next to it.
-      li_image("images/wui/menus/menu_toggle_buildhelp.png", _[[click the ‘Show building spaces’ button on the bottom of the screen.]]) ..
-      li(_[[Right-click on this window now and then give it a try.]])
-   )
-}
+   title = _"Building Spaces",
+   position = "topright",
+   field = sf,
+   body = (
+      h1(_"Let’s dive right in!") ..
+      li_image("tribes/images/barbarians/icon.png",
+         _[[There are four different tribes in Widelands: the Barbarians, the Empire, the Atlanteans and the Frisians. All tribes have a different economy, strength and weaknesses, but the general gameplay is the same for all. We will play the Barbarians for now.]]) ..
+      li_object("barbarians_headquarters", _[[You will usually start the game with one headquarters. This is the big building with the blue flag in front of it. The headquarters is a warehouse that stores wares, workers and soldiers. Some wares are needed for building houses, others for making other wares. Obviously, the wares in the headquarters will not last forever, so you must make sure to replace them. The most important wares in the early game are the basic construction wares: logs and granite. Let’s make sure that we do not run out of logs. For this, we need a lumberjack and a hut for him to stay in.]], plr.color) ..
+      p(_[[We need to find a nice place for the lumberjack’s hut. To make this easier, we can activate ‘Show Building Spaces’.]]) ..
+      li(_[[Left-click the ‘OK’ button to close this window so that I can show you how.]]) ..
+      li_arrow(_[[Note that you cannot close this window by right-clicking on it. I have blocked this so that you will not close it by accident and miss important information.]])
+   )
+}
+
+initial_message_03 = {
+   title = _"Building Spaces",
+   position = "topright",
+   field = sf,
+   body = (
+      h1(_"Let’s dive right in!") ..
+      li_object("barbarians_lumberjacks_hut", _[[Now that I have shown you how to show and hide the building spaces, please switch them on again so that we can place our first building.]], plr.color)
+   )
+}
+
+-- ==========
+-- Lumberjack
+-- ==========
 
 lumberjack_message_01 = {
    title = _"Lumberjack’s Spot",
    position = "topright",
    field = first_lumberjack_field,
    body = (
-      p(_[[There you go. I will explain about all those symbols in a minute. First, let me show you how to make a lumberjack’s hut and how to connect it with a road. There is a sweet spot for a lumberjack right next to those trees. I’ll describe the steps I will take and then ask you to click on the ‘OK’ button for me to demonstrate.]])
+      li_object("barbarians_lumberjacks_hut",
+         _[[There you go. I will explain about all those symbols in a minute. First, let me show you how to make a lumberjack’s hut and how to connect it with a road. There is a sweet spot for a lumberjack right next to those trees. I’ll describe the steps I will take and then ask you to click on the ‘OK’ button for me to demonstrate.]], plr.color)
    ),
-   h = 300,
+   h = 250,
    w = 350
 }
 
@@ -72,20 +114,23 @@
    title = _"Building the Lumberjack",
    position = "topright",
    body = (
-      p(_[[First, I’ll left-click on the symbol where I want the lumberjack’s hut to be built. A window will appear where I can choose between buildings. Because I’ll click a yellow house symbol – which means that its field can house medium and small buildings – I am presented with all the medium buildings that I can build. The lumberjack’s hut is a small building, so I will go on to select the small buildings tab. Then I’ll choose the lumberjack’s hut.]]) ..
+      li_object("barbarians_lumberjacks_hut",
+         _[[First, I’ll left-click on the symbol where I want the lumberjack’s hut to be built. A window will appear where I can choose between buildings. Because I’ll click a yellow house symbol – which means that its field can house medium and small buildings – I am presented with all the medium buildings that I can build. The lumberjack’s hut is a small building, so I will go on to select the small buildings tab. Then I’ll choose the lumberjack’s hut.]], plr.color) ..
       li(_[[Click the ‘OK’ button to watch me. I’ll go really slowly: I will click – then select the tab – and finally I’ll choose the building.]])
    ),
-   h = 300
+   h = 300,
+   w = 350
 }
 
 lumberjack_message_03a = {
    title = _"Building a Connecting Road",
    position = "topright",
    body = (
-      p(_[[That won’t do yet. I still need to connect the lumberjack’s hut to the rest of my road network. After ordering the construction site, I was automatically put into road building mode, so all I have to do is click on the blue flag in front of my headquarters.]])
+      li_image("images/wui/fieldaction/menu_tab_buildroad.png", _[[That won’t do yet. I still need to connect the lumberjack’s hut to the rest of my road network. After ordering the construction site, I was automatically put into road building mode, so all I have to do is click on the blue flag in front of my headquarters.]]) ..
+      li(close_story_window_instructions)
    ),
    show_instantly = true,
-   h = 300,
+   h = 200,
    w = 350
 }
 
@@ -93,10 +138,12 @@
    title = _"Building a Connecting Road",
    position = "topright",
    body = (
-      p(_[[That won’t do yet. I still need to connect the lumberjack’s hut to the rest of my road network. You have disabled the option ‘Start building road after placing a flag’ (to change that, choose ‘Options’ in the Widelands main menu). Therefore, I have entered the road building mode manually. I will tell you later how to do that. To build the road, all I have to do now is click on the blue flag in front of my headquarters.]])
+      li_image("images/wui/fieldaction/menu_tab_buildroad.png",
+         _[[That won’t do yet. I still need to connect the lumberjack’s hut to the rest of my road network. You have disabled the option ‘Start building road after placing a flag’ (to change that, choose ‘Options’ in the Widelands main menu). Therefore, I have entered the road building mode manually. I will tell you later how to do that. To build the road, all I have to do now is click on the blue flag in front of my headquarters.]]) ..
+         li(close_story_window_instructions)
    ),
    show_instantly = true,
-   h = 300,
+   h = 250,
    w = 350
 }
 
@@ -104,169 +151,230 @@
    title = _"Waiting for the Lumberjack to Go Up",
    position = "topright",
    body = (
-      p(_[[Now watch closely while a builder leaves the headquarters and goes to the construction site. Also, a carrier will take position in between the two blue flags and carry wares from one blue flag to the other.]])
+      li_object("barbarians_builder",
+         _[[Now watch closely while a builder leaves the headquarters and goes to the construction site. Also, a carrier will take position in between the two blue flags and carry wares from one blue flag to the other.]], plr.color) ..
+         li(close_story_window_instructions)
+   ),
+   h = 200,
+   w = 350
+}
+
+obj_lumberjack_place_flag = {
+   name = "obj_lumberjack_place_flag",
+   title=_"Build a flag to divide the road to the lumberjack",
+   number = 1,
+   body = objective_text(_"Build a Flag on the Road",
+      p(_[[The shorter your road segments are, the faster your wares will be transported. You should therefore make sure that your roads have as many flags as possible.]]) ..
+      li(_[[Build a blue flag now in the middle of the road that connects your headquarters to your lumberjack’s hut.]]) ..
+      li_image("images/wui/fieldaction/menu_build_flag.png",_[[To build the flag, click on the yellow flag symbol in between the two blue flags we just placed and then click on the build flag symbol.]])
    ),
    h = 300,
    w = 350
 }
-
 lumberjack_message_05 = {
    title = _"Placing Another Flag",
    position = "topright",
    body = (
-      p(_[[Nice how they are working, isn’t it? But the poor carrier has a very long way to go. We can make it easier for him (and more efficient for us) by placing another blue flag on the road.]]) ..
-      li(_[[You try it this time: click on the yellow flag symbol in between the two blue flags we just placed and then click on the]]) ..
-      li_image("images/wui/fieldaction/menu_build_flag.png", _"build flag symbol.")
+      li_object("barbarians_carrier",
+         _[[Nice how they are working, isn’t it? But the poor carrier has a very long way to go. We can make it easier for him (and more efficient for us) by placing another blue flag on the road. You try it this time.]], plr.color)
    ),
-   h = 300,
-   obj_name = "build_flag_on_road_to_lumberjack",
-   obj_title = _"Build a flag to divide the road to the lumberjack",
-   obj_body = (
-      h1(_"Build a Flag on the Road") ..
-      p(_[[The shorter your road segments are, the faster your wares will be transported. You should therefore make sure that your roads have as many flags as possible.]]) ..
-      li(_[[Build a blue flag now in the middle of the road that connects your headquarters to your lumberjack’s hut.]])
-   )
+   h = 450,
+   w = 350
 }
 
 lumberjack_message_06 = {
-   title = _"Waiting For the Hut to be Finished",
-   position = "topright",
-   body = (
-      p(_[[Well done! Let’s wait till the hut is finished.]]) ..
-      p(_[[If you want things to go faster, simply use the Page Up key on your keyboard to increase the game speed. You can use Page Down to make the game slower again.]])
-   ),
-   h = 300,
-   w = 350
-}
-
-flag_built = {
-   title = _"Waiting for the Hut to be Finished",
-   position = "topright",
-   body = (
-      p(_[[I wanted to teach you how to build new flags, but it seems you have already found out on your own. Well done!]]) ..
+   title = _"Waiting for the Lumberjack to Go Up",
+   position = "topright",
+   body = (
+      li_image("images/wui/fieldaction/menu_tab_buildroad.png",
+         _[[I wanted to teach you how to build new flags, but it seems you have already found out on your own. Well done!]]) ..
       p(_[[Now you have split the road in two parts with a carrier each. This means less work for him and higher efficiency for us. You should therefore always place as many flags as possible on your roads.]]) ..
-      p(_[[Now we only have to wait till the hut is finished.]]) ..
-      p(_[[If you want things to go faster, simply use the Page Up key on your keyboard to increase the game speed. You can use Page Down to make the game slower again.]])
+      li(close_story_window_instructions)
    ),
-   h = 350
+   h = 250,
+   w = 350
 }
 
-construction_site_window = {
+obj_lumberjack_progress = {
+   name = "obj_lumberjack_progress",
+   title=_"Let’s see the progress",
+   number = 1,
+   body = objective_text(_"Let’s see the progress",
+      li(_[[Click on the construction site to have a look at it, then close it again when you have seen enough.]]) ..
+      li_arrow(_[[To close the construction site’s window, simply right-click on it.]])
+   ),
+   h = 300,
+   w = 350
+}
+lumberjack_message_07 = {
    title = _"The Construction Site",
-   body = (
-      h1(_"Let's see the progress") ..
-      p(_[[If you click on the construction site, a window will open. You can see the wares that are still missing grayed out. You can also see the progress of this construction site.]]) ..
-      -- The player doesn't know about the statistics yet. First things first.
-      p(_[[To close the window, simply right-click on it. All windows in Widelands can be closed that way, except the ones with instructions, like this one. Try it out!]])
-   ),
-   h = 300,
-   w = 350
-}
-
-lumberjack_message_07 = {
+   position = "topright",
+   body = (
+      h1(_"Let’s see the progress") ..
+      li_object("barbarians_builder", _[[If you click on the construction site, a window will open. You can see the wares that are still missing grayed out. You can also see the progress of this construction site.]], plr.color)
+   ),
+   h = 450,
+   w = 350
+}
+
+lumberjack_message_08 = {
+   title = _"Waiting for the Lumberjack to Go Up",
+   position = "topright",
+   body = (
+      p(_[[Well done! Let’s wait till the hut is finished.]]) ..
+      li_image("images/wui/menus/gamespeed.png",
+   _[[If you want things to go faster, simply use the Page Up key on your keyboard to increase the game speed. You can use Page Down to make the game slower again.]])
+   ),
+   h = 200,
+   w = 350
+}
+
+lumberjack_message_09 = {
    title = _"The Lumberjack’s Hut is Done",
    position = "topright",
    body = (
-      p(_[[Excellent. The lumberjack’s hut is done. A lumberjack will now move in and start chopping down trees, so our log income is secured for now. Now on to the granite.]])
+      li_object("barbarians_lumberjacks_hut", _[[Excellent. The lumberjack’s hut is done. A lumberjack will now move in and start chopping down trees, so our log income is secured for now. Now on to the granite.]], plr.color)
    ),
-   h = 300,
+   h = 200,
    w = 350
 }
 
-inform_about_rocks = {
+-- ==================
+-- Moving the mapview
+-- ==================
+
+local moving_view_instructions =
+   h2(_"Moving Your View") ..
+   p(_[[Moving your view is essential to get a complete overview of your whole economy. There are three ways to move your view in Widelands.]]) ..
+   li_arrow(_[[The first one is to use the cursor keys on your keyboard.]]) ..
+   li_arrow(_[[The second one is the more common and faster one: press-and-hold the right mouse button anywhere on the map, then move your mouse around and you’ll see the view scroll.]]) ..
+   li_arrow(_[[The third one is to use the minimap. It is especially useful for traveling big distances.]])
+
+
+obj_moving_keyboard = {
+   name = "move_view_with_cursor_keys",
+   title=_"Move your view with the cursor keys",
+   number = 1,
+   body = objective_text(_"Move your view with the cursor keys",
+      li(_[[There are three ways to move your view. The first one is using the cursor keys on your keyboard. Go ahead and try this out.]]) .. moving_view_instructions
+   ),
+}
+tell_about_keyboard_move = {
    title = _"Some Rocks Were Found",
    body = (
       h1(_"Getting a Quarry Up") ..
-      p(_[[Granite can be mined in granite mines, but the easier way is to build a quarry next to some rocks lying around. As it happens, there is a pile of them just to the west (left) of your headquarters. I will teach you now how to move your view over there.]]) ..
-      li(_[[There are three ways to move your view. The first one is using the cursor keys on your keyboard. Go ahead and try this out.]]) ..
-      li(_[[Click the ‘OK’ button and then move the view using the cursor keys.]])
+      li_object("greenland_rocks6",
+         _[[Granite can be mined in granite mines, but the easier way is to build a quarry next to some rocks lying around. As it happens, there is a pile of them just to the west (left) of your headquarters. I will teach you now how to move your view over there.]])
    ),
-   h = 350,
-   obj_name = "move_view_with_cursor_keys",
-   obj_title = _"Move your view with the cursor keys",
-   obj_body = (
-      h1(_"Moving Your View") ..
-      p(_[[Moving your view is essential to get a complete overview of your whole economy. There are three ways to move your view in Widelands.]]) ..
-      li(_[[The first one is to use the cursor keys on your keyboard.]]) ..
-      li(_[[The second one is the more common and faster one: press-and-hold the right mouse button anywhere on the map, then move your mouse around and you’ll see the view scroll.]]) ..
-      li(_[[The third one is to use the minimap. It is especially useful for traveling big distances.]])
-   )
+   h = 450,
 }
 
+obj_moving_right_drag = {
+   name = "move_view_with_mouse",
+   title=_"Move your view with the mouse",
+   number = 1,
+   body = objective_text(_"Move your view with the mouse",
+      li(_[[Simply right-click-and-hold anywhere on the map, then drag the mouse and instead of the cursor, the view will be moved. Try it.]]) .. moving_view_instructions
+   ),
+}
 tell_about_right_drag_move = {
-   title = _"Other Ways to Move the View",
+   title = _"Moving Your View",
    body = (
-      p(_[[Excellent. Now there is a faster way to move, using the mouse instead:]]) ..
-      li(_[[Simply right-click-and-hold anywhere on the map, then drag the mouse and instead of the cursor, the view will be moved. Try it.]])
+      h1(_"Other Ways to Move the View") ..
+      li_image("images/ui_basic/cursor_click.png",
+         _[[Excellent. Now there is a faster way to move, using the mouse instead.]])
    ),
-   h = 300,
-   w = 350,
-   obj_name = "move_view_with_mouse",
-   obj_title = _"Move your view with the mouse",
-   obj_body = inform_about_rocks.obj_body,
+   h = 450,
 }
 
-tell_about_minimap = {
-   title = _"Use the minimap",
-   body = (
-      p(_[[Very good. And now about the minimap. You can open it by clicking on the]]) ..
-      li_image("images/wui/menus/menu_toggle_minimap.png", _[[minimap button at the bottom of the screen or simply by using the keyboard shortcut ‘m’.]]) ..
-      p(_[[The minimap shows the complete map in miniature. You can directly jump to any field by left-clicking on it. You can also toggle buildings, roads, flags and player indicators on and off inside the minimap.]]) ..
-      li(_[[Try it out. Open the minimap, click on a few buttons and try moving around. Close it when you have experimented enough.]])
-   ),
-   h = 350,
-   obj_name = "use_minimap",
-   obj_title = _"Learn to use the minimap",
-   obj_body = (
-      li(_[[Open the minimap by using the third button from the left on the bottom of your screen or the ‘m’ key.]]) ..
+obj_moving_minimap = {
+   name = "use_minimap",
+   title=_"Learn to use the minimap",
+   number = 1,
+   body = objective_text(_"Learn to use the minimap",
+      li(_[[Try moving around by clicking on the minimap]]) ..
       li(_[[Play around a bit with the different overlays (roads, flags, etc.)]]) ..
-      li(_[[Close the minimap when you are ready to continue by using the same button or ‘m’ again. Of course, a right-click also works.]])
-   )
+      li(_[[When you are ready to continue, close the minimap by selecting ‘Hide Minimap’ in the ‘Map View’ menu or by pressing ‘m’. Of course, a right-click also works.]])
+   ),
+}
+tell_about_minimap_1 = {
+   title = _"Moving Your View",
+   body = (
+      h1(_"Using the Minimap") ..
+      li_image("images/wui/menus/toggle_minimap.png",
+         p(_[[Very good. And now about the minimap. ]]) ..
+         -- TRANSLATORS it = the minimap
+         p(_[[You can open it by selecting the ‘Show Minimap’ entry in the ‘Map View’ menu at the bottom of the screen or simply by using the keyboard shortcut ‘m’.]])) ..
+      -- TRANSLATORS it = the minimap
+      li_arrow(_[[I will open it for you.]])
+   ),
+   w = 350,
+   h = 250,
+}
+
+tell_about_minimap_2 = {
+   title = _"Moving Your View",
+   body = (
+   h1(_"Using the Minimap") ..
+      li_image("images/wui/menus/toggle_minimap.png",
+         _([[The minimap shows the complete map in miniature. ]]
+         .. [[You can directly jump to any field by left-clicking on it. ]]
+         .. [[You can also toggle buildings, roads, flags and player indicators on and off inside the minimap.]]))
+   ),
+   h = 450,
 }
 
 congratulate_and_on_to_quarry = {
    title = _"Onward to the Quarry",
-   body = p(_[[Great. Now about that quarry…]]),
+   body = li_object("greenland_rocks6",_[[Great. Now about that quarry…]]),
    h = 200,
    w = 250
 }
 
+-- ======
+-- Quarry
+-- ======
+
+obj_build_a_quarry = {
+   name = "build_a_quarry",
+   title=_"Build a quarry next to the rocks",
+   number = 1,
+   body = objective_text(_"Build a Quarry",
+      li(_[[There are some rocks to the west of your headquarters. Build a quarry right next to them.]]) ..
+      li_image("images/wui/overlays/small.png", _[[The quarry is a small building like the lumberjack’s hut. You can therefore build it on any field that shows a red, yellow or green house when the building spaces symbols are enabled (Press Space for that).]]) ..
+      li_arrow(_[[Just click on any house symbol next to the rocks, select the small buildings tab in the window that opens up, then click on the quarry symbol.]])
+   ),
+}
 order_quarry_recap_how_to_build = {
    field = first_quarry_field,
    position = "topright",
    title = _"How to Build a Quarry",
    body = (
-      p(_[[Build a quarry next to those rocks here. Remember how I did it earlier?]]) ..
-      p(_[[Make sure that you are showing the building spaces, then just click on the space where you want the building to be, choose it from the window that appears, and it is placed. Maybe this is a good time to explain about all those building space symbols we activated earlier.]]) ..
-      p(_[[You can build four things on fields in Widelands: flags, small houses, medium houses and big houses. But not every field can hold everything. The build space symbols ease recognition:]]) ..
+      li_object("barbarians_quarry",
+         p(_[[Build a quarry next to those rocks here. Remember how I did it earlier?]]) ..
+         p(_[[Make sure that you are showing the building spaces, then just click on the space where you want the building to be, choose it from the window that appears, and it is placed. Maybe this is a good time to explain about all those building space symbols we activated earlier.]]) ..
+         p(_[[You can build four things on fields in Widelands: flags, small houses, medium houses and big houses. But not every field can hold everything. The build space symbols ease recognition:]]), plr.color) ..
       li_image("images/wui/overlays/big.png", _[[Everything can be built on the green house symbol.]]) ..
       li_image("images/wui/overlays/medium.png", _[[Everything except for big buildings can be built on a yellow house symbol.]]) ..
       li_image("images/wui/overlays/small.png", _[[Red building symbols can only hold small buildings and flags.]]) ..
       li_image("images/wui/overlays/set_flag.png", _[[And finally, the yellow flag symbol only allows for flags.]]) ..
-      p(_[[If you place something on a field, the surrounding fields might have less space for holding buildings, so choose your fields wisely.]]) ..
-      li(_[[Now go ahead, try it. The quarry is a small building, so if you click on a medium or big building symbol, you will have to select the small buildings tab first to find it. Go on, check it out!]])
-   ),
-   obj_name = "build_a_quarry",
-   obj_title = _"Build a quarry next to the rocks",
-   obj_body = (
-      h1(_"Build a Quarry") ..
-      li(_[[There are some rocks to the west of your headquarters. Build a quarry right next to them.]]) ..
-      li(_[[The quarry is a small building like the lumberjack’s hut. You can therefore build it on any field that shows a red, yellow or green house when the building spaces symbols are enabled (Press Space for that).]]) ..
-      li(_[[Just click on any house symbol next to the rocks, select the small buildings tab in the window that opens up, then click on the quarry symbol.]])
+      p(_[[If you place something on a field, the surrounding fields might have less space for holding buildings, so choose your fields wisely.]])
    )
 }
 
+local explain_abort_roadbuilding = li_image("images/wui/menu_abort.png", _[[If you decide you do not want to build a road at this time, you can cancel road building by clicking on the starting flag of the road and selecting the abort symbol.]])
+
 talk_about_roadbuilding_00a = {
    position = "topright",
    field = wl.Game().map:get_field(9,12),
    title = _"Road Building",
    body = (
-      p(_[[Excellent! Directly after placing the building, you have been switched into road building mode. The new road will start at the flag in front of your newly placed construction site. You can enter road building mode for any flag by left-clicking on a flag and selecting]]) ..
-      li_image("images/wui/fieldaction/menu_build_way.png", _[[the road building symbol.]]) ..
-      p(_[[If you decide you do not want to build a road at this time, you can cancel road building by clicking on the starting flag of the road and selecting]]) ..
-      li_image("images/wui/menu_abort.png", _[[the abort symbol.]]) ..
+      li_image("images/wui/fieldaction/menu_tab_buildroad.png", _[[Excellent! Directly after placing the building, you have been switched into road building mode. The new road will start at the flag in front of your newly placed construction site.]]) ..
+      li_image("images/wui/fieldaction/menu_build_way.png", _[[You can enter road building mode for any flag by left-clicking on a flag and selecting the road building symbol.]]) ..
+      explain_abort_roadbuilding ..
       p(_[[Now, about this road. Remember: we are already in road building mode since you just ordered the quarry. You can either make it longer by one field at a time by left-clicking multiple times on neighboring fields for perfect control over the route the road takes, like so:]])
    ),
+   h = 300,
    show_instantly = true
 }
 
@@ -275,12 +383,11 @@
    field = road_building_field,
    title = _"Road Building",
    body = (
-      p(_[[Excellent! To enter road building mode for any flag, left-click on a flag and select]]) ..
-      li_image("images/wui/fieldaction/menu_build_way.png", _[[the road building symbol.]]) ..
-      p(_[[If you decide that you do not want to build a road at this time, you can cancel road building by clicking on the starting flag of the road and selecting]]) ..
-      li_image("images/wui/menu_abort.png", _[[the abort symbol.]]) ..
+      li_image("images/wui/fieldaction/menu_build_way.png", _[[ Excellent! To enter road building mode for any flag, left-click on a flag and select the road building symbol.]]) ..
+      explain_abort_roadbuilding ..
       p(_[[Now, about this road. I’ll enter the road building mode and then make it longer by one field at a time by left-clicking multiple times on neighboring fields for perfect control over the route the road takes, like so:]])
    ),
+   h = 300,
    show_instantly = true
 }
 
@@ -288,38 +395,38 @@
    position = "topright",
    field = road_building_field,
    title = _"Road Building",
-   body = p(_[[Or, you can directly click the flag where the road should end, like so:]]),
+   body = li_object("barbarians_flag", _[[Or, you can directly click the flag where the road should end, like so:]], plr.color),
    h = 200,
    w = 250
 }
 
+obj_build_road_to_quarry = {
+   name = "build_road_to_quarry",
+   title=_"Connect the quarry to the headquarters",
+   number = 1,
+   body = objective_text(_"Connect Your Construction Site",
+      li(_[[Connect your quarry construction site to your headquarters with a road. You would have been put directly into road building mode after ordering a new site. But now, you aren’t.]]) ..
+      li_arrow(_[[To build a completely new road, just click on the flag in front of your construction site, click on the build road icon and then click on the flag in front of your headquarters. Wait for the completion of the quarry.]]) ..
+      li_arrow(_[[If you hold Ctrl or Shift+Ctrl while you finish the road, flags are placed automatically.]])
+   ),
+}
 talk_about_roadbuilding_02 = {
    position = "topright",
    title = _"Road Building",
    body = (
-      p(_[[One more thing: around the field where your road would end, you can see different markers. They have the following meaning:]]) ..
+      li_image("images/wui/fieldaction/menu_tab_buildroad.png", _[[One more thing: around the field where your road would end, you can see different markers. They have the following meaning:]]) ..
       li_image("images/wui/overlays/roadb_green.png", _[[The terrain is flat here. Your carriers will be very swift on this terrain.]]) ..
       li_image("images/wui/overlays/roadb_yellow.png", _[[There is a small slope to climb to reach this field. This means that your workers will be faster walking downhill than they will be walking uphill.]]) ..
       li_image("images/wui/overlays/roadb_red.png", _[[The connection between the fields is extremely steep. The speed increase in one direction is huge while the slowdown in the other is also substantial.]]) ..
-      p(_[[Keep the slopes in mind while placing roads and use them to your advantage. Also, try to keep roads as short as possible and always remember to place as many flags as you can on road segments to share the load better.]]) ..
-      li_arrow(_[[If you hold Ctrl or Shift+Ctrl while you finish the road, flags are placed automatically.]]) ..
-      li(_[[Now please rebuild the road between your quarry and your headquarters.]])
+      p(_[[Keep the slopes in mind while placing roads and use them to your advantage. Also, try to keep roads as short as possible and always remember to place as many flags as you can on road segments to share the load better.]])
    ),
-   h = 450,
-   obj_name = "build_road_to_quarry",
-   obj_title = _"Connect the quarry to the headquarters",
-   obj_body = (
-      h1(_"Connect Your Construction Site") ..
-      p(_[[Connect your quarry construction site to your headquarters with a road. You would have been put directly into road building mode after ordering a new site. But now, you aren’t.]]) ..
-      li_arrow(_[[To build a completely new road, just click on the flag in front of your construction site, click on the build road icon and then click on the flag in front of your headquarters. Wait for the completion of the quarry.]]) ..
-      li_arrow(_[[If you hold Ctrl or Shift+Ctrl while you finish the road, flags are placed automatically.]])
-   )
+   h = 450
 }
 
 quarry_not_connected = {
    title = _"Quarry not Connected",
    body = (
-      p(_[[Your workers do not like to walk across country. You have to build a road from your headquarters to the construction site so that carriers can transport wares. The simplest way is to click on the construction site’s flag, choose ‘Build road’, and then click on the destination flag (the one in front of your headquarters), just like I’ve demonstrated.]])
+      li_object("barbarians_carrier", _[[Your workers do not like to walk across country. You have to build a road from your headquarters to the construction site so that carriers can transport wares. The simplest way is to click on the construction site’s flag, choose ‘Build road’, and then click on the destination flag (the one in front of your headquarters), just like I’ve demonstrated.]], plr.color)
    ),
    w = 350,
    h = 250
@@ -328,87 +435,125 @@
 quarry_illegally_destroyed = {
    title = _"You Destroyed the Construction Site!",
    body = (
-      p(_[[It seems like you destroyed a construction site for a quarry we wanted to build. Since we need the granite, I suggest you reload the game from a previous savegame. Luckily, these are created from time to time. To do so, you have to go back to the main menu and choose ‘Single Player’ → ‘Load Game’. And please be a bit more careful next time.]])
+      li_object("barbarians_quarry", _[[It seems like you destroyed a construction site for a quarry we wanted to build. Luckily, we still have enough logs left this time, so you can simply build another one.]], plr.color) ..
+      li_arrow(_[[You can also reload the game from a previous savegame. Luckily, these are created from time to time. To do so, you will have to go back to the main menu and choose ‘Single Player’ → ‘Load Game’. And please be a bit more careful next time.]])
    ),
    w = 350,
    h = 250
 }
 
+obj_build_the_second_quarry = {
+   name = "build_the_second_quarry",
+   title=_"Build another quarry",
+   number = 1,
+   body = objective_text(_"Build another quarry",
+      li(_[[Build a second quarry near the rocks and connect it to your road network.]]) ..
+      li_arrow(_[[You can connect the new road to any flag of your existing road network. You can create junctions everywhere, not only in front of buildings.]])
+   ),
+}
 build_second_quarry = {
    position = "topright",
    title = _"Build a second quarry",
    body = (
-      p(_[[When there are many rocks, you can consider building another quarry. This will make the granite production faster.]]) ..
-      li(_[[Build a second quarry near the rocks and connect it to your road network.]])
-   ),
-   obj_name = "build_the_second_quarry",
-   obj_title = _"Build another quarry",
-   obj_body = (
-      h1(_"Build another quarry") ..
-      p(_[[Build a second quarry next to the rocks. Do not forget to connect it to another flag.]]) ..
-      li(_[[You can connect the new road to any flag of your existing road network. You can create junctions everywhere, not only in front of buildings.]])
-   ),
-   h = 300,
-   w = 350
+      li_object("barbarians_quarry", _[[When there are many rocks, you can consider building another quarry. This will make the granite production faster.]], plr.color)
+   ),
+   h = 300
 }
 
+-- ===================
+-- Census & Statistics
+-- ===================
+
 census_and_statistics_00 = {
    title = _"Census and Statistics",
    body = (
-      p(_[[While we wait, I’ll quickly show you another useful feature. All construction sites look the same, and some buildings look alike. It is sometimes hard to tell them apart. Widelands offers a feature to show label texts over the buildings. They are called the ‘census’ and you can toggle them via the ‘c’ key or via the button on the ‘Watch’ tab of any field.]]) ..
-      p(_[[Similar to this are the building statistics, which are also toggled via a button on the ‘Watch’ tab of any field. The hotkey for it is ‘s’. This will display information about the productivity of buildings or the progress of construction sites.]]) ..
-      p(_[[Let me quickly enable these two for you. Remember: ‘c’ and ‘s’ are the keys. Alternatively, you can click on any field without a building on it, select the watch tab and then click on the corresponding buttons.]])
+      li_image("images/wui/menus/toggle_census.png", _[[While we wait, I’ll quickly show you another useful feature. All construction sites look the same, and some buildings look alike. It is sometimes hard to tell them apart. Widelands offers a feature to show label texts over the buildings. They are called the ‘census’.]]) ..
+      li_arrow(_[[In order to show or hide the building census labels, you can select the ‘Show Census’ / ‘Hide Census’ entry from the ‘Show / Hide’ menu on the bottom, or press the ‘c’ key on the keyboard.]]) ..
+      p(_[[Let me enable the census for you.]])
+   ),
+   position = "topright",
+   h = 300,
+   w = 350
+}
+
+obj_show_statistics = {
+   name = "show_statistics",
+   title=_"Show the building statistics",
+   number = 1,
+   body = objective_text(_"Show the building statistics",
+      li(_[[Show the building statistics labels, so that we can check the progress of our quarry construction more easily.]]) ..
+      li_arrow(_[[In order to show or hide the building statistics labels, you can select the ‘Show Statistics’ entry from the ‘Show / Hide’ menu on the bottom, or press the ‘s’ key on the keyboard.]])
    )
 }
-
 census_and_statistics_01 = {
    title = _"Census and Statistics",
-   body = (p(_[[Now we know what’s going on. Let’s wait for the quarries to finish.]])),
-   h = 200,
+   body = (
+      li_image("images/wui/menus/toggle_statistics.png",
+         p(_[[Now, wouldn’t it be nice to check on our quarries’ progress without having to open their windows?]]) ..
+         p(_[[In addition to the buildings’ census, you can also activate statictics labels on them. This will display information about the productivity of buildings or the progress of construction sites.]]))
+   ),
+   position = "topright",
+   h = 400,
+   w = 350
+}
+
+census_and_statistics_02 = {
+   title = _"Census and Statistics",
+   body = (
+      li_object("barbarians_quarry", _[[Now we know what’s going on. Let’s wait for the quarries to finish.]], plr.color)
+   ),
+   position = "topright",
+   h = 150,
    w = 250
 }
 
+-- ========
+-- Messages
+-- ========
+
+obj_archive_all_messages = {
+   name = "archive_all_messages",
+   title=_"Archive all messages in your inbox",
+   number = 1,
+   body = objective_text(_"Archive Your Inbox Messages",
+      li(_[[Archive all your messages in your inbox now.]]) ..
+      li_image("images/wui/messages/message_archive.png", _[[Keep clicking the ‘Archive selected message’ button until all messages have been archived and the list is empty.]]) ..
+      li_arrow(_[[Once you have archived a message, another message will be selected automatically from the list.]]) ..
+      li_arrow(_[[You can also hold down the Ctrl or Shift key to select multiple messages, or press Ctrl + A to select them all.]]) ..
+      li_arrow(_[[You can toggle the message window by pressing ‘n’ or clicking the second button from the right at the very bottom of the screen. The newest message will be marked for you automatically.]]) ..
+      li_arrow(_[[The message window is central to fully controlling your tribe’s fortune. However, you will get a lot of messages in a real game. To keep your head straight, you should try to keep the inbox empty.]])
+   )
+}
 teaching_about_messages = {
    popup = true,
    title = _"Messages",
    heading = _"Introducing Messages",
    body = (
-      p(_[[Hi, it’s me again! This time, I have sent you a message. Messages are sent to you by Widelands to inform you about important events: empty mines, attacks on your tribe, won or lost military buildings, resources found…]]) ..
+      li_image("images/wui/menus/message_new.png",_[[Hi, it’s me again! This time, I have sent you a message. Messages are sent to you by Widelands to inform you about important events: empty mines, attacks on your tribe, won or lost military buildings, resources found…]]) ..
       p(_[[The message window can be toggled by the second button from the right at the bottom of the screen. This button will also change appearance whenever new messages are available, but there is also a bell sound played whenever you receive a new message.]]) ..
-      p(_[[You have two messages at the moment. This one, which you are currently reading, and the one that informed you that a new headquarters was added to your economy. Let’s learn how to archive messages: first, select the message that you wish to archive by clicking on it in the list. Then, click the]]) ..
-      li_image("images/wui/messages/message_archive.png", _[[‘Archive selected message’ button to move it into your archive.]]) ..
-      p(_[[Once you have archived a message, another message will be selected automatically from the list.]]) ..
-      li_arrow(_[[You can also hold down the Ctrl or Shift key to select multiple messages, or press Ctrl + A to select them all.]]) ..
-      li(_[[Archive all messages that you currently have in your inbox, including this one.]])
-   ),
-   obj_name = "archive_all_messages",
-   obj_title = _"Archive all messages in your inbox",
-   obj_body = (
-      h1(_"Archive Your Inbox Messages") ..
-      p(_[[The message window is central to fully controlling your tribe’s fortune. However, you will get a lot of messages in a real game. To keep your head straight, you should try to keep the inbox empty.]]) ..
-      li(_[[Archive all your messages in your inbox now.]]) ..
-      li_arrow(_[[To do so, open the message window by pressing ‘n’ or clicking the second button from the right at the very bottom of the screen. The newest message will be marked for you automatically. Keep clicking the ‘Archive selected message’ button until all messages have been archived and the list is empty.]]) ..
-      li_arrow(_[[You can also hold down the Ctrl or Shift key to select multiple messages, or press Ctrl + A to select them all.]])
+      p(_[[You have two messages at the moment. This one, which you are currently reading, and the one that informed you that a new headquarters was added to your economy. Let’s learn how to archive messages:]]) ..
+      new_objectives(obj_archive_all_messages)
    )
 }
 
+obj_close_message_window = {
+   name = "close_message_window",
+   title=_"Close the messages window",
+   number = 1,
+   body = objective_text(_"Close the Messages Window",
+      p(_[[All windows in Widelands can be closed by right-clicking into them. Some windows can also be toggled with the buttons and menus at the very bottom of the screen.]]) ..
+      li(_[[Close the messages window now by right-clicking into it.]])
+   )
+}
 closing_msg_window_00 = {
    position = "topright",
    field = first_quarry_field,
    title = _"Closing Windows",
    body = (
-      p(_[[Excellent. Do you remember how to close windows? You simply have to right-click on them. This will work with all windows except for story message windows like this one. Go ahead and try it.]]) ..
-      li(_[[First, close this window by pressing the button below, then right-click into the messages window to close it.]])
+      li_image("images/wui/menus/message_old.png",_[[Excellent. Do you remember how to close windows? You simply have to right-click on them. This will work with all windows except for story message windows like this one. Go ahead and try it.]])
    ),
-   h = 300,
-   w = 350,
-   obj_name = "close_message_window",
-   obj_title = _"Close the messages window",
-   obj_body = (
-      h1(_"Close the Messages Window") ..
-      p(_[[All windows in Widelands can be closed by right-clicking into them. Some windows can also be toggled with the buttons at the very bottom of the screen.]]) ..
-      li(_[[Close the messages window now by right-clicking into it.]])
-   )
+   h = 400,
+   w = 350
 }
 
 closing_msg_window_01 = {
@@ -416,71 +561,85 @@
    field = first_quarry_field,
    title = _"Closing Windows",
    body = (
-      p(_[[Well done! Let’s see how messages work in a real game, shall we? For this, I’ll take all rocks away from the poor stonemasons in the quarries. They will then send a message each that they can’t find any in their work areas the next time they try to do some work.]])
+      li_object("barbarians_quarry", _[[Well done! Let’s see how messages work in a real game, shall we? For this, I’ll take all rocks away from the poor stonemasons in the quarries. They will then send a message each that they can’t find any in their work areas the next time they try to do some work.]], plr.color)
    ),
-   h = 300,
+   h = 250,
    w = 350
 }
 
+obj_destroy_quarries = {
+   name = "destroy_quarries",
+   title=_"Destroy the two quarries",
+   number = 1,
+   body = objective_text(_"Destroy the Quarries",
+      li(_[[Since our quarries are useless now, you can destroy them and reuse the space later on.]]) ..
+      p(_[[There are two different ways of destroying a building: burning down and dismantling. Try them both out on your quarries.]]) ..
+      li_image("images/wui/buildings/menu_bld_bulldoze.png", _[[Burning down the quarry: This is the fastest way of clearing the space. While the worker abandons the building, the wares are lost.]]) ..
+      li_image("images/wui/buildings/menu_bld_dismantle.png", _[[Dismantling the quarry: A builder will walk from the headquarters to dismantle the quarry piece by piece. Thereby, you regain some of the resources you used for the construction.]])
+   )
+}
 destroy_quarries_message = {
    position = "topright",
    title = _"Messages Arrived!",
    body = (
-      p(_[[You received some messages. See how the button at the bottom of the screen has changed appearance? You can destroy the quarries now as they are no longer of any use and just blocking space. To do so, there are two possibilities:]]) ..
-      li_image("images/wui/buildings/menu_bld_bulldoze.png", _[[Burning down the quarry: this is the fastest way of clearing the space. While the worker abandons the building, the wares are lost.]]) ..
-      li_image("images/wui/buildings/menu_bld_dismantle.png", _[[Dismantling the quarry: a builder will walk from the headquarters to dismantle the quarry piece by piece. Thereby, you regain some of the resources you used for the construction.]])
+      li_image("images/wui/menus/message_new.png", _[[You received some messages. See how the button at the bottom of the screen has changed appearance?]])
    ),
-   h = 300,
-   obj_name = "destroy_quarries",
-   obj_title = _"Destroy the two quarries",
-   obj_body = (
-      p(_[[Since our quarries are useless now, you can destroy them and reuse the space later on.]]) ..
-      li_arrow(_[[There are two different ways of destroying a building: burning down and dismantling. Try them both out on your quarries.]]) ..
-      li_image("images/wui/buildings/menu_bld_bulldoze.png", _[[Burning down the quarry: This is the fastest way of clearing the space. While the worker abandons the building, the wares are lost.]]) ..
-      li_image("images/wui/buildings/menu_bld_dismantle.png", _[[Dismantling the quarry: A builder will walk from the headquarters to dismantle the quarry piece by piece. Thereby, you regain some of the resources you used for the construction.]])
+   h = 400,
+   w = 350
+}
+
+-- =========
+-- Expansion
+-- =========
+
+obj_expand_territory = {
+   name = "expand_territory",
+   title=_"Expand your territory",
+   number = 1,
+   body = objective_text(_"Make your Territory Grow",
+      li(_[[Build a military building on your border.]]) ..
+      li_arrow(_[[In Widelands, it is necessary to build many buildings, which take up a lot of space. To expand your territory, you have to build military buildings next to your border. Every tribe has several military buildings.]]) ..
+      li_arrow(_[[The Barbarians have four different military buildings you can build: the sentry (small), the barrier and the tower (both medium) and the fortress (big). Just choose the one you like most.]]) ..
+      li_arrow(_[[The sentry is the only military site that fits on a small building plot. If your lumberjack has cleared enough space, you can also build another military building.]]) ..
+      li_arrow(_[[Remember that big buildings (green icon) cannot be built on small (red) or medium (yellow) building plots, but buildings can be built on a building plot that provides more space than they need. You should always keep that in mind when you search for a suitable place.]])
    )
 }
-
 introduce_expansion = {
    title = _"Expanding Your Territory!",
    body = (
-      p(_[[There is one more thing I’d like to teach you now: Expanding your territory. The place that we started with around our headquarters is barely enough for a basic building infrastructure, and we do not have access to mountains, which we need to mine minerals and coal. So, we have to expand our territory.]]) ..
-      p(_[[Expanding is as simple as building a military building at the edge of your territory. The Barbarians have a selection of different military buildings: sentries, barriers, towers, fortresses and citadels. The bigger the building, the more expensive it is to build, but the more land it will conquer around itself and the more soldiers can be stationed there. The buildings also vary in their vision range: buildings with a tower see farther than others.]]) ..
-      p(_[[As soon as a military building is manned, it will extend your land. I will tell your more about military buildings in another tutorial.]]) ..
-      li(_[[Let’s try it out now: build a military building on your border.]]) ..
-      li_arrow(_[[The sentry is the only military site that fits on a small building plot. If your lumberjack has cleared enough space, you can also build another military building.]])
-   ),
-   obj_name = "expand_territory",
-   obj_title = _"Expand your territory",
-   obj_body = (
-      h1(_"Make your territory grow") ..
-      p(_[[In Widelands, it is necessary to build many buildings, which take up a lot of space. To expand your territory, you have to build military buildings next to your border. Every tribe has several military buildings.]]) ..
-      li(_[[The Barbarians have four different military buildings you can build: the sentry (small), the barrier and the tower (both medium) and the fortress (big). Just choose the one you like most.]]) ..
-      li_arrow(_[[Remember that big buildings (green icon) cannot be built on small (red) or medium (yellow) building plots, but buildings can be built on a building plot that provides more space than they need. You should always keep that in mind when you search for a suitable place.]])
+      li_object("barbarians_sentry",
+         p(_[[There is one more thing I’d like to teach you now: Expanding your territory. The place that we started with around our headquarters is barely enough for a basic building infrastructure, and we do not have access to mountains, which we need to mine minerals and coal. So, we have to expand our territory.]]) ..
+         p(_[[Expanding is as simple as building a military building at the edge of your territory. The Barbarians have a selection of different military buildings: sentries, barriers, towers, fortresses and citadels. The bigger the building, the more expensive it is to build, but the more land it will conquer around itself and the more soldiers can be stationed there. The buildings also vary in their vision range: buildings with a tower see farther than others.]]) ..
+         p(_[[As soon as a military building is manned, it will extend your land. I will tell you more about military buildings in another tutorial.]]), plr.color)
    )
 }
 
-
 military_building_finished = {
    title = _"Military Site Occupied",
    body = (
       h1(_"Your territory has just grown!") ..
-      p(_[[Great. Do you see how your territory has grown since your soldiers entered your new military building?]]) ..
-      p(_[[Every military building has a certain conquer area – the more expensive the building, the more land it conquers.]])
+      li_object("barbarians_tower",
+         p(_[[Great. Do you see how your territory has grown since your soldiers entered your new military building?]]) ..
+         p(_[[Every military building has a certain conquer area – the more expensive the building, the more land it conquers.]]), plr.color)
    ),
    h = 300,
    w = 350
 }
 
+-- ==========
+-- Conclusion
+-- ==========
+
 conclude_tutorial = {
    title = _"Conclusion",
    body = (
       h1(_"Conclusion") ..
-      p(_[[This concludes the first tutorial. In order to learn more about the game, I suggest to play one of the other tutorials. Each of them covers a different topic.]]) ..
-      p(_[[However, since you now know how to control Widelands, you can also start a game (or continue this one) and discover more by yourself.]]) ..
-      p(_[[To leave this game and return to the main menu, click on the]]) ..
-      li_image("images/wui/menus/menu_options_menu.png", _[[‘Main Menu’ button on the very left at the bottom of the screen. Then click the]]) ..
-      li_image("images/wui/menus/menu_exit_game.png", _[[‘Exit Game’ button.]]) ..
+      li_image("images/logos/wl-ico-64.png",
+         p(_[[This concludes the first tutorial. In order to learn more about the game, I suggest to play one of the other tutorials. Each of them covers a different topic.]]) ..
+         p(_[[However, since you now know how to control Widelands, you can also start a game (or continue this one) and discover more by yourself.]])) ..
+      p(_[[To leave this game and return to the main menu:]]) ..
+      li_image("images/wui/menus/main_menu.png", _[[Click on the ‘Main Menu’ button on the very left at the bottom of the screen.]]) ..
+      li_image("images/wui/menus/exit.png", _[[Then click on the ‘Exit Game’ entry.]]) ..
       p(_[[Thanks for playing this tutorial. Enjoy Widelands and remember to visit us at]]) ..
       h1(p("align=center", u("widelands.org")))
    ),

=== modified file 'data/campaigns/tutorial04_economy.wmf/scripting/mission_thread.lua'
--- data/campaigns/tutorial04_economy.wmf/scripting/mission_thread.lua	2018-07-07 10:53:30 +0000
+++ data/campaigns/tutorial04_economy.wmf/scripting/mission_thread.lua	2019-06-01 15:41:38 +0000
@@ -10,8 +10,8 @@
 
    sleep(1000)
 
-   message_box_objective(plr, intro1)
-   message_box_objective(plr, intro2)
+   campaign_message_box(intro1)
+   campaign_message_box(intro2)
 
    burn_tavern_down()
 end
@@ -19,15 +19,19 @@
 function wait_for_window_and_tab_or_complain(
    window_name,
    tab_name,
-   objective, complain_msg
-)
+   complain_msg,
+   objective)
+
+   local obj_open_window = add_campaign_objective(objective)
+   obj_open_window.visible = false
+
    while true do
       -- This waits for the window to be opened.
       if not mv.windows[window_name] then
-         objective.visible = true
-         message_box_objective(plr, complain_msg)
+         obj_open_window.visible = true
+         campaign_message_box(complain_msg)
          while not mv.windows[window_name] do sleep(200) end
-         objective.visible = false
+         obj_open_window.visible = false
       end
 
       -- But it might be closed at any point in time. If it is open and the
@@ -39,21 +43,20 @@
       end
       sleep(200)
    end
+   set_objective_done(obj_open_window)
 end
 
 function encyclopedia_tutorial()
    sleep(100*1000)
-   local o = message_box_objective(plr, ware_encyclopedia) -- where to get help
+   local o = campaign_message_with_objective(ware_encyclopedia, obj_open_encyclopedia) -- where to get help
    while not mv.windows.encyclopedia do sleep(200) end
    set_objective_done(o, wl.Game().real_speed)
 
-   o = message_box_objective(plr, explain_encyclopedia) -- what information is available
-   local o2 = add_campaign_objective(reopen_encyclopedia_obj)
-   o2.visible = false
+   o = campaign_message_with_objective(explain_encyclopedia, obj_lookup_wares) -- what information is available
    wait_for_window_and_tab_or_complain(
       "encyclopedia",
       "encyclopedia_wares",
-      o2, reopen_encyclopedia
+      reopen_encyclopedia, obj_reopen_encyclopedia
    )
    while mv.windows.encyclopedia do sleep(200) end
    set_objective_done(o, wl.Game().real_speed)
@@ -65,44 +68,38 @@
    sleep(1000)
    tavern_field.immovable:destroy()
    sleep(1000)
-   message_box_objective(plr, tavern_burnt_down)
+   campaign_message_box(tavern_burnt_down)
    sleep(500)
-   local o = message_box_objective(plr, building_stat)
+   local o = campaign_message_with_objective(building_stats, obj_open_building_stats)
+   wl.ui.MapView().dropdowns["dropdown_menu_statistics"]:open()
+
    while not mv.windows.building_statistics do sleep(100) end
    set_objective_done(o, wl.Game().real_speed)
 
-   o = message_box_objective(plr,explain_building_stat)
-   -- We cannot create several objectives with the same name. Therefore, we create o2 here once and change its visibility
-   local o2 = add_campaign_objective(reopen_building_stat_obj)
-   o2.visible = false
+   o = campaign_message_with_objective(explain_building_stats, obj_check_taverns)
    wait_for_window_and_tab_or_complain(
       "building_statistics",
       "building_stats_medium",
-      o2, reopen_building_stat
+      reopen_building_stats, obj_reopen_building_stats
    )
    while mv.windows.building_statistics do sleep(100) end
    set_objective_done(o, 0)
 
-   o = message_box_objective(plr, inventory1)
+   o = campaign_message_with_objective(inventory1, obj_open_inventory)
    while not mv.windows.stock_menu do sleep(200) end
    set_objective_done(o, wl.Game().real_speed)
 
-   o = message_box_objective(plr, inventory2)
-   -- We cannot create several objectives with the same name. Therefore, we
-   -- create o2 here once and change its visibility
-   o2 = add_campaign_objective(reopen_stock_menu_obj)
-   o2.visible = false
-
+   o = campaign_message_with_objective(inventory2, obj_switch_stock_tab)
    wait_for_window_and_tab_or_complain(
       "stock_menu",
       "wares_in_warehouses",
-      o2, reopen_stock_menu
+      reopen_stock_menu, obj_reopen_stock_menu
    )
    set_objective_done(o, 0)
-   message_box_objective(plr, inventory3)
+   campaign_message_box(inventory3)
 
    sleep(2000)
-   o = message_box_objective(plr, build_taverns)
+   o = campaign_message_with_objective(build_taverns, obj_build_taverns)
 
    encyclopedia_tutorial()
 
@@ -113,44 +110,38 @@
 end
 
 function plan_the_future()
-   message_box_objective(plr, building_priority_settings)
+   campaign_message_box(building_priority_settings)
    sleep(30*1000) -- give the user time to try it out
 
-   local o = message_box_objective(plr, ware_stats1)
+   local o = campaign_message_with_objective(ware_stats1, obj_open_ware_stats)
    while not mv.windows.ware_statistics do sleep(200) end
    set_objective_done(o, 0)
 
-   o = message_box_objective(plr, ware_stats2)
-   local o2 = add_campaign_objective(reopen_ware_stats1_obj)
-   o2.visible = false
-
+   o = campaign_message_with_objective(ware_stats2, obj_switch_ware_stats_tab_to_third)
    wait_for_window_and_tab_or_complain(
       "ware_statistics",
       "economy_health",
-      o2, reopen_ware_stats1
+      reopen_ware_stats1, obj_reopen_ware_stats1
    )
    set_objective_done(o, 0)
 
-   o = message_box_objective(plr, ware_stats3)
-   o2 = add_campaign_objective(reopen_ware_stats2_obj)
-   o2.visible = false
-
+   o = campaign_message_with_objective(ware_stats3, obj_switch_ware_stats_tab_to_fourth)
    wait_for_window_and_tab_or_complain(
       "ware_statistics",
       "stock",
-      o2, reopen_ware_stats2
+      reopen_ware_stats2, obj_reopen_ware_stats2
    )
    set_objective_done(o, 0)
 
-   o = message_box_objective(plr, ware_stats4)
+   o = campaign_message_with_objective(ware_stats4, obj_close_ware_stats)
    while mv.windows.ware_statistics do sleep(500) end
    set_objective_done(o)
 
-   o = message_box_objective(plr, economy_settings1)
+   o = campaign_message_with_objective(economy_settings1, obj_open_economy_settings)
    while not mv.windows.economy_options do sleep(200) end
    set_objective_done(o, 0)
-   message_box_objective(plr, economy_settings2)
-   o = message_box_objective(plr, economy_settings3)
+   campaign_message_box(economy_settings2)
+   o = campaign_message_with_objective(economy_settings3, obj_produce_marble_columns)
 
    while sf.brn.immovable.economy:ware_target_quantity("marble_column") ~= 20 do
       sleep(200)
@@ -159,7 +150,7 @@
    set_objective_done(o)
 
    -- new objective all has to be transported to the front
-   o = message_box_objective(plr, warehouse_preference_settings)
+   o = campaign_message_with_objective(warehouse_preference_settings, obj_bring_marble_columns_to_front)
 
    local enough_wares = false
    while not enough_wares do
@@ -178,7 +169,7 @@
 end
 
 function conclude()
-   message_box_objective(plr, conclusion)
+   campaign_message_box(conclusion)
 end
 
 run(introduction)

=== modified file 'data/campaigns/tutorial04_economy.wmf/scripting/texts.lua'
--- data/campaigns/tutorial04_economy.wmf/scripting/texts.lua	2018-09-12 15:58:07 +0000
+++ data/campaigns/tutorial04_economy.wmf/scripting/texts.lua	2019-06-01 15:41:38 +0000
@@ -8,7 +8,6 @@
 
 include "scripting/richtext_scenarios.lua"
 
-
 -- =============
 -- Texts below
 -- =============
@@ -17,7 +16,7 @@
    title = _"Your Economy and its Settings",
    body = (
       h1(_[[Economy]]) ..
-      p(_[[Welcome back. In this tutorial, I’ll tell you what you can do to check how well your economy works.]]) ..
+      li_image("images/wui/stats/genstats_nrwares.png", _[[Welcome back. In this tutorial, I’ll tell you what you can do to check how well your economy works.]]) ..
       p(_[[Building your economy up and making it work well and grow is the main part of Widelands. But you can’t control the workers directly – they will follow the general conditions you set.]]) ..
       p(_[[This is what I’ll show you in this tutorial: what actions can you take to define those general conditions?]])
    ),
@@ -29,49 +28,65 @@
    field = field_near_border,
    title = _"A Peaceful Land",
    body = (
-      p(_[[Now about the map: you have settled in a nice valley between two mountains, rich in marble, iron ore and coal. All were hoping for a peaceful life.]]) ..
-      p(_[[But one day, you discovered a barren wasteland with abandoned buildings in the east. A strange aura came from there, and no one wanted to set foot there. But the border could not be left undefended, and so you constructed three castles.]]) ..
-      p(_[[You had not been prepared for war, and you have to hurry now to build up an army.]])
+      li_object("empire_fortress",
+         p(_[[Now about the map: you have settled in a nice valley between two mountains, rich in marble, iron ore and coal. All were hoping for a peaceful life.]]) ..
+         p(_[[But one day, you discovered a barren wasteland with abandoned buildings in the east. A strange aura came from there, and no one wanted to set foot there. But the border could not be left undefended, and so you constructed three fortresses.]]) ..
+         p(_[[You had not been prepared for war, and you have to hurry now to build up an army.]]), plr.color)
    ),
    h = 300
 }
 
 tavern_burnt_down = {
    position = "topright",
-   title = _"The Tavern is Burning!",
+   title = _"An accident",
    body = (
-      h1(_[[An accident]]) ..
-      p(_[[Oh no, look at this: our tavern is burning! In all the hurry, our innkeeper accidentally dropped a torch. She is fine, but we could not extinguish the fire in time.]])
+      h1(_[[The Tavern is Burning!]]) ..
+      li_object("destroyed_building",
+         _[[Oh no, look at this: our tavern is burning! In all the hurry, our innkeeper accidentally dropped a torch. She is fine, but we could not extinguish the fire in time.]], plr.color)
    ),
    w = 300,
    h = 250
 }
 
-building_stat = {
+obj_open_building_stats = {
+   name = "open_building_stats",
+   title=_"Open the building statistics window",
+   number = 1,
+   body = objective_text(_"Open the building statistics window",
+      li(_[[Open the building statistics window for an overview over the buildings you have.]]) ..
+      li_image("images/wui/menus/statistics.png", _[[First, you will have to open the ‘Statistics’ menu at the bottom of the screen.]]) ..
+      li_image("images/wui/menus/statistics_buildings.png", _[[Afterwards, choose ‘Buildings’.]]) ..
+      li_arrow(_[[You can also use the hotkey ‘b’.]])
+   )
+}
+building_stats = {
    position = "topright",
    title = _"Building statistics",
    body = (
       h1(_[[Check out your taverns]]) ..
-      p(_[[At first, we should find out how many taverns we currently have. Widelands offers you a window where you can easily check this.]]) ..
-      li_image("images/wui/menus/menu_toggle_menu.png", _[[First, you will have to open the statistics menu (you can find the corresponding button at the bottom). We will need this menu several times.]]) ..
-      li_image("images/wui/menus/menu_building_stats.png", _[[Afterwards, choose the ‘Building statistics’.]]) ..
-      li(_[[Open the building statistics window.]]) ..
-      li_arrow(_[[You can also use the hotkey ‘b’.]])
-   ),
-   h = 350,
-   obj_name = "open_building_stat",
-   obj_title = _"Open the building statistics window",
-   obj_body =
-      li_image("images/wui/menus/menu_building_stats.png", _[[The building statistics window gives you an overview over the buildings you have.]]) ..
-      -- TRANSLATORS: "it" refers to the building statistics window
-      li(_[[Open it. You can access it from the statistics menu.]]) ..
-      li_arrow(_[[The statistics menu is accessed via the second button at the bottom. It provides several windows that give you information about the game.]])
+      p(_[[At first, we should find out how many taverns we currently have. Widelands offers you a window where you can easily check this.]])
+   )
 }
 
-explain_building_stat = {
+obj_check_taverns = {
+   name = "check_taverns",
+   title=_"Look up how many taverns you have",
+   number = 1,
+   body = objective_text(_"Look up how many taverns you have",
+      p(_[[We want to know whether we still have taverns.]]) ..
+      li_image("images/wui/fieldaction/menu_tab_buildmedium.png",
+         _[[Choose the ‘Medium buildings’ tab in the building statistics window.]]) ..
+      li(_[[Look up how many taverns you have.]]) ..
+      li_arrow(_[[Below every building, there are two lines. The first one shows the number of buildings you own and how many are under construction. The second line shows the average productivity if it is a production site or training site, or the stationed and desired soldiers in military buildings.]]) ..
+      li(_[[Close the building statistics window when you are done.]])
+   )
+}
+explain_building_stats = {
+   position = "topright",
    title = _"Building Statistics",
    body = (
-      p(_[[This is the building statistics window. It shows you all buildings you can own, sorted by their size.]]) ..
+      li_image("images/wui/menus/statistics_buildings.png",
+         _[[This is the building statistics window. It shows you all buildings you can own, sorted by their size.]]) ..
       p(_[[Let me now explain what all those numbers mean:]]) ..
       li(_[[‘2/1’ below the quarry: This means that you have two quarries, plus another one which is under construction.]]) ..
       li(_[[‘0%’: This indicates the average productivity of all buildings of that type. You have just started this game, therefore none of your buildings has done any work yet, but they are going to start working soon.]]) ..
@@ -79,149 +94,170 @@
       li_arrow(_[[In both cases, the color (green - yellow - red) signals you how good the value is.]]) ..
       li(_[[If you click on a building, you can scroll through the buildings of the selected type.]]) ..
       li(_[[If you don’t have any building of a particular building type, it will be shown greyed out.]]) ..
-      h2(_[[Now it’s your turn]]) ..
-      p(_[[This is enough explanation for now. Now try it out yourself. We want to know whether we still have taverns, so you have to choose the ‘Medium buildings’ tab. Close the building statistics menu afterwards.]])
+      p(_[[This is enough explanation for now. Now try it out yourself.]])
    ),
-   obj_name = "check_taverns",
-   obj_title = _"Look up how many taverns you have",
-   obj_body = (
-      li(_[[Choose the ‘Medium buildings’ tab in the building statistics window.]]) ..
-      li(_[[Look up how many taverns you have.]]) ..
-      li_arrow(_[[Below every building, there are two lines. The first one shows the number of buildings you own and how many are under construction. The second line shows the average productivity if it is a production site or training site, or the stationed and desired soldiers in military buildings.]]) ..
-      li(_[[Close the building statistics window when you are done.]])
-   )
+   h = 500,
 }
 
-reopen_building_stat = {
+reopen_building_stats = {
    title = _"You closed the building statistics window!",
    body = (
-      p(_[[You have closed the building statistics window. I didn’t notice that you switched to the medium buildings to look up the number of taverns. Would you please be so nice and show it to me?]])
+      li_image("images/wui/menus/statistics_buildings.png",
+         _[[You have closed the building statistics window. I didn’t notice that you switched to the medium buildings to look up the number of taverns. Would you please be so nice and show it to me?]])
    ),
    show_instantly = true,
    w = 300,
    h = 250
 }
 
-reopen_building_stat_obj = {
-   obj_name = "open_building_stat_again",
-   obj_title = _"Open the building statistics window again",
-   obj_body = (
-      p(_[[You closed the building statistics window, although you have not yet looked up the number of taverns.]]) ..
+obj_reopen_building_stats = {
+   name = "reopen_building_stats",
+   title = _"Open the building statistics window again",
+   number = 1,
+   body = objective_text(_"Open the building statistics window again",
+      li_image("images/wui/menus/statistics_buildings.png",
+         _[[You closed the building statistics window, although you have not yet looked up the number of taverns.]]) ..
       -- TRANSLATORS: "it" refers to the building statistics window.
       li(_[[Please reopen it and choose the second tab (medium buildings).]])
-   ),
-   h = 250
+   )
 }
 
+obj_open_inventory = {
+   name = "open_inventory",
+   title=_"Open your stock window",
+   number = 1,
+   body = objective_text(_"Open your stock window",
+      p(_[[The stock window gives you an overview over the wares you currently have.]]) ..
+      li_image("images/wui/menus/statistics.png", _[[First, you will have to open the ‘Statistics’ menu at the bottom of the screen.]]) ..
+      li_image("images/wui/menus/statistics_stock.png", _[[Afterwards, choose ‘Stock’.]]) ..
+      li_arrow(_[[You can also use the hotkey ‘i’ (as in ‘inventory’) to access this window quickly.]])
+   )
+}
 inventory1 = {
    position = "topright",
    title = _"Stock",
    body = (
       h1(_[[Check for rations]]) ..
-      p(_[[OK. In the list, you’ve seen that you have no more taverns or inns. That means that you’re not producing any rations. But let’s see what we still have in stock.]]) ..
-      li_image("images/wui/menus/menu_stock.png", _[[Click on the ‘Stock’ button.]]) ..
-      li_arrow(_[[You can also use the hotkey ‘i’ (as in ‘inventory’) to access this window quickly.]])
-   ),
-   h = 300,
-   obj_name = "open_inventory",
-   obj_title = _"Open your stock window",
-   obj_body = (
-      p(_[[The stock menu window gives you an overview over the wares you currently have.]]) ..
-      -- TRANSLATORS: "it" refers to the stock menu window
-      li(_[[Open it. You can access it from the statistics menu.]]) ..
-      li_arrow(_[[The statistics menu is accessed via the second button at the bottom. It provides several windows that give you information about the game.]])
+      li_image(wl.Game():get_ware_description("ration").icon_name,
+         _[[OK. In the list, you’ve seen that you have no more taverns or inns. That means that you’re not producing any rations. But let’s see what we still have in stock.]])
    )
 }
 
+obj_switch_stock_tab = {
+   name = "switch_stock_tab",
+   title=_"Examine the first two tabs in the stock window",
+   number = 1,
+   body = objective_text(_"Examine the first two tabs in the stock window",
+      p(_[[Have a look at the first two tabs in the stock window. They show all the wares and workers you have.]]) ..
+      li_image("images/wui/stats/menu_tab_wares_warehouse.png",
+         _[[When you have seen enough, switch to the third tab (‘Wares in warehouses’).]])
+   )
+}
 inventory2 = {
+   position = "topright",
    title = _"Stock",
    body = (
-      p(_[[The stock menu window has four tabs. The first (and currently selected) one shows you all your current wares, including those on roads, at flags and inside buildings waiting for processing.]]) ..
+      li_image("images/wui/buildings/menu_tab_wares.png",
+         _[[The stock window has four tabs. The first (and currently selected) one shows you all your current wares, including those on roads, at flags and inside buildings waiting for processing.]]) ..
       p(_[[Looking at the rations, there are currently only five in total, probably on their way to somewhere. Five rations are not much for such a big economy.]]) ..
-      p(_[[The second tab shows you all your workers, again those on roads and in buildings summed up.]]) ..
-      p(_[[Now have a look at these two tabs. When you click on the]]) ..
-      li_image("images/wui/stats/menu_tab_wares_warehouse.png", _[[third tab (‘Wares in warehouses’), I’ll continue.]])
-   ),
-   h = 350,
-   show_instantly = true,
-   obj_name = "switch_stock_tab",
-   obj_title = _"Switch to the third tab in the stock menu window",
-   obj_body = (
-      p(_[[Have a look at the first two tabs in the stock menu window. They show all the wares and workers you have.]]) ..
-      li(_[[When you have seen enough, switch to the third tab.]])
-   ),
+      li_image("images/wui/buildings/menu_tab_workers.png",
+         _[[The second tab shows you all your workers, again those on roads and in buildings summed up.]])
+   ),
+   show_instantly = true
 }
 
 inventory3 = {
+position = "topright",
    title = _"Stock",
    body = (
-      p(_[[The third tab shows you the wares that are stored in your headquarters, your warehouses and ports. They are not needed anywhere and are therefore your reserve.]]) ..
-      p(_[[The fourth tab shows the same thing for workers.]]) ..
+      li_image("images/wui/stats/menu_tab_wares_warehouse.png",
+         _[[The third tab shows you the wares that are stored in your headquarters, your warehouses and ports. They are not needed anywhere and are therefore your reserve.]]) ..
+      li_image("images/wui/stats/menu_tab_workers_warehouse.png", _[[The fourth tab shows the same thing for workers.]]) ..
       p(_[[The third tab tells you that there are no rations left in your headquarters – that’s not good!]])
    ),
    show_instantly = true,
-   h = 300
+   h = 250
 }
 
 reopen_stock_menu = {
    title = _"You closed the stock window!",
    body = (
-      p(_[[You have closed the stock menu window, but I have not yet finished with my explanation. Would you please reopen it and choose the third tab?]])
+      li_image("images/wui/menus/statistics_stock.png",
+         _[[You have closed the stock window, but I have not yet finished with my explanation. Would you please reopen it and choose the third tab?]])
    ),
    show_instantly = true,
    w = 300,
    h = 250
 }
 
-reopen_stock_menu_obj = {
-   obj_name = "open_stock_menu_again",
-   obj_title = _"Open the stock window again",
-   obj_body = (
-      p(_[[You closed the stock menu window before I finished telling you everything about it. If you already know everything, please feel free to leave this tutorial at any time.]]) ..
-      -- TRANSLATORS: "it" refers to the stock menu window.
+obj_reopen_stock_menu = {
+   name = "open_stock_menu_again",
+   title = _"Open the stock window again",
+   number = 1,
+   body = objective_text(_"Open the stock window again",
+      li_image("images/wui/menus/statistics_stock.png",
+         _[[You closed the stock window before I finished telling you everything about it. If you already know everything, please feel free to leave this tutorial at any time.]]) ..
+      -- TRANSLATORS: "it" refers to the "Stock" window.
       li(_[[Otherwise, please reopen it and choose the third tab.]])
-   ),
-   h = 250
+   )
 }
 
+obj_build_taverns = {
+   name = "build_taverns",
+   title=_"Build new taverns",
+   number = 1,
+   body = objective_text(_"Build new taverns",
+      li(_[[Build at least two taverns.]]) ..
+      li_arrow(_[[As long as we don’t produce rations, our miners won’t dig for ore. And without iron, we cannot forge a single helm.]])
+   )
+}
 build_taverns = {
    position = "topright",
    title = _"New taverns",
    body = (
       h1(_[[We need new taverns]]) ..
-      p(_[[Now that you have an overview, you should act. I think we should build more than one tavern – two or three are better. Remember: as long as we don’t produce rations, our miners won’t dig for ore. And without iron, we cannot forge a single helm.]]) ..
-      li(_[[Build at least two taverns.]])
-   ),
-   h = 300,
-   obj_name = "build_taverns",
-   obj_title = _"Build new taverns",
-   obj_body = (
-      p(_[[To make our mines work, we need rations again – the more, the better.]]) ..
-      li(_[[Build at least two taverns.]])
+      li_object("empire_tavern",
+         _[[Now that you have an overview, you should act. I think we should build more than one tavern – two or three are better.]],
+         plr.color)
    )
 }
 
-ware_encyclopedia = {
-   title = _"Encyclopedia",
-   body = (
-      h1(_[[How to get help]]) ..
-      p(_[[Of course, it is difficult to remember all of my remarks and advice. For example, you might ask yourself: ‘Why do we need rations to get soldiers?’]]) ..
-      p(_[[When you’ve played a lot, you will know all these things by heart. But until then or if you’re unsure about your tribe’s needs and abilities and how its buildings and workers operate, you can look it up easily in our tribe-specific in-game help and encyclopedia.]]) ..
-      p(_[[This encyclopedia can be accessed via the help button at the bottom right.]])..
-      li_image("images/ui_basic/menu_help.png", _[[Please open the in-game help, and I’ll explain its contents to you.]])
-   ),
-   h = 350,
-   show_instantly = true,
-   obj_name = "open_encyclopedia",
-   obj_title = _"Open the in-game help window",
-   obj_body = (
+obj_open_encyclopedia = {
+   name = "open_encyclopedia",
+   title=_"Open the in-game help window",
+   number = 1,
+   body = objective_text(_"Open the in-game help window",
       li_image("images/ui_basic/menu_help.png", _[[The encyclopedia window contains the in-game help and an encyclopedia of the tribe you’re currently playing.]]) ..
       -- TRANSLATORS: "it" refers to the encyclopedia window
       li(_[[Open it. You can access it via the button at the bottom of the screen.]]) ..
       li_arrow(_[[Alternatively, you can access it directly with the ‘F1’ key.]])
+   )
+}
+ware_encyclopedia = {
+   title = _"Encyclopedia",
+   body = (
+      h1(_[[How to get help]]) ..
+      li_object("empire_soldier",
+         _[[Of course, it is difficult to remember all of my remarks and advice. For example, you might ask yourself: ‘Why do we need rations to get soldiers?’]], plr.color) ..
+      p(_[[When you’ve played a lot, you will know all these things by heart. But until then or if you’re unsure about your tribe’s needs and abilities and how its buildings and workers operate, you can look it up easily in our tribe-specific in-game help and encyclopedia.]])
    ),
+   h = 450,
+   show_instantly = true,
 }
 
+obj_lookup_wares = {
+   name = "lookup_wares",
+   title=_"Look up which wares are needed to recruit soldiers",
+   number = 1,
+   body = objective_text(_"Look up which wares are needed to recruit soldiers",
+      p(_[[A soldier needs a wooden spear and a helmet – from there on out, you can search backwards to find the wares and the buildings you need to supply your barracks where the soldier is recruited. When you are finished, just close the encyclopedia window.]]) ..
+      li(_[[Use the encyclopedia to find out how to create new soldiers.]]) ..
+      li_arrow(_[[Choose the ‘Wares’ tab in the encyclopedia window.]]) ..
+      li_arrow(_[[Look up what is needed to produce a helmet and what is needed to produce a wooden spear.]]) ..
+      li_arrow(_[[If you want, you may further look up what is needed to produce the wares you just looked up.]]) ..
+      li(_[[Close the encyclopedia window when you are done.]])
+   )
+}
 explain_encyclopedia = {
    position = "topright",
    title = _"Encyclopedia details",
@@ -232,140 +268,143 @@
       div("width=100%", div("float=left padding_r=18 padding_t=15 padding_b=15 padding_l=4",p(img("images/wui/buildings/menu_tab_wares.png"))) .. p(_[[The ‘Wares’ tab shows information about the wares that your tribe needs, including a short help text, a list of buildings that produce each ware, the needed wares to produce it and where the ware is consumed.]])) ..
       div("width=100%", div("float=left padding_r=16",p(img("images/wui/buildings/menu_tab_workers.png"))) .. p(_[[The ‘Workers’ tab shows information about your tribe’s workers in a similar manner to the wares in the second tab.]])) ..
       div("width=100%", div("float=left padding_r=18 padding_t=5 padding_l=4",p(img("images/wui/stats/genstats_nrbuildings.png"))) .. p(_[[The ‘Buildings’ tab contains all the necessary information about the buildings of your tribe.]])) ..
-      li_image("tribes/immovables/field_harvested/idle_00.png", _[[Finally, the ‘Immovables’ tab shows information about the specific immovables that your tribe’s workers can place on the map.]]) ..
-      li(_[[Now use the encyclopedia to find out how to create new soldiers.]]) ..
-      li_arrow(_[[A soldier needs a wooden spear and a helmet – from there on out, you can search backwards to find the wares and the buildings you need to supply your barracks where the soldier is recruited. When you are finished, just close the encyclopedia window.]])
+      div("width=100%", div("float=left padding_r=18 padding_t=5 padding_l=4",p(img("tribes/immovables/field_ripe/idle_00.png"))) .. p(_[[Finally, the ‘Immovables’ tab shows information about the specific immovables that your tribe’s workers can place on the map.]]))
    ),
-   h = 450,
+   h = 500,
    show_instantly = true,
-   obj_name = "check_wares",
-   obj_title = _"Look up which wares are needed to recruit soldiers",
-   obj_body = (
-      li(_[[Choose the ‘Wares’ tab in the encyclopedia window.]]) ..
-      li(_[[Look up what is needed to produce a helmet and what is needed to produce a wooden spear.]]) ..
-      li_arrow(_[[If you want, you may further look up what is needed to produce the wares you just looked up.]]) ..
-      li(_[[Close the encyclopedia window when you are done.]])
-   )
 }
 
 reopen_encyclopedia = {
    title = _"You closed the encyclopedia!",
    body = (
-      p(_[[You have closed the encyclopedia window, but I didn’t notice that you were trying to find out which wares are needed to recruit a soldier. Would you please reopen it and do so?]])
+      li_image("images/ui_basic/menu_help.png",
+         _[[You have closed the encyclopedia window, but I didn’t notice that you were trying to find out which wares are needed to recruit a soldier. Would you please reopen it and do so?]])
    ),
    show_instantly = true,
    w = 300,
    h = 250
 }
 
-reopen_encyclopedia_obj = {
-   obj_name = "open_encyclopedia_again",
-   obj_title = _"Open the encyclopedia window again",
-   obj_body = (
-      p(_[[You closed the encyclopedia window without searching for the information we need. If you already know everything, please feel free to leave this tutorial at any time.]]) ..
+obj_reopen_encyclopedia = {
+   name = "reopen_encyclopedia",
+   title = _"Open the encyclopedia window again",
+   number = 1,
+   body = objective_text(_"Open the encyclopedia window again",
+      li_image("images/ui_basic/menu_help.png",
+         _[[You closed the encyclopedia window without searching for the information we need. If you already know everything, please feel free to leave this tutorial at any time.]]) ..
       li(_[[Otherwise, please reopen the encyclopedia window and choose the second tab.]])
-   ),
-   h = 250
+   )
 }
-
 building_priority_settings = {
    position = "topright",
    title = _"Priority Settings",
    body = (
       h1(_[[Send the wares where they’re needed]]) ..
-      p(_[[Great. Our taverns have now been built up and are supplying us with rations.]]) ..
-      p(_[[At the moment, all mines are supplied with rations. If you want to prioritize a special mine, you simply have to open its window. In the wares tab, behind every ware, you can see ‘traffic lights’.]]) ..
-      p(_[[When you click on the red dot (low priority), the corresponding ware gets delivered less frequently. Green means that as many wares as possible should be delivered to this building, maybe because it produces something important.]]) ..
-      p(_[[In our situation, you might want to work the bakeries as fast as possible because they supply our taverns, so you could set water to the highest priority for them. The other buildings (for example the donkey farm) would then get less water, but the bakery could work faster.]])
+      li_object("empire_marblemine", p(_[[Great. Our taverns have now been built up and are supplying us with rations.]]) ..
+         p(_[[At the moment, all mines are supplied with rations. If you want to prioritize a special mine, you simply have to open its window. In the wares tab, behind every ware, you can see ‘traffic lights’.]]) ..
+         p(_[[When you click on the red dot (low priority), the corresponding ware gets delivered less frequently. Green means that as many wares as possible should be delivered to this building, maybe because it produces something important.]]) ..
+         p(_[[In our situation, you might want to work the bakeries as fast as possible because they supply our taverns, so you could set water to the highest priority for them. The other buildings (for example the donkey farm) would then get less water, but the bakery could work faster.]]), plr.color)
       -- we cannot check whether the user does this, so no objective
       -- see bug https://bugs.launchpad.net/widelands/+bug/1380288
    )
 }
 
+obj_open_ware_stats = {
+   name = "open_ware_stats",
+   title = _"Open the ware statistics window",
+   number = 1,
+   body = objective_text(_"Open the ware statistics window",
+      li(_[[Select the ‘Wares’ entry from the ‘Statistics’ menu.]])
+   )
+}
 ware_stats1 = {
-   position = "top",
    title = _"Ware Statistics",
    body = (
-      p(_[[In the statistics menu, there is also a]]) ..
-      li_image("images/wui/menus/menu_ware_stats.png", _[[‘Ware statistics’ button.]]) ..
-      -- TRANSLATORS: "it" refers to the ware statistics button
-      li(_[[Click on it.]])
+      li_image("images/wui/menus/statistics_wares.png", _[[Let’s have a look at how our wares production is doing.]])
    ),
-   w = 200,
-   h = 200,
-   obj_name = "open_ware_stat",
-   obj_title = _"Open the ware statistics window",
-   obj_body = (
-      li(_[[Open the ‘Ware statistics’ window, accessed via the statistics menu.]])
+   h = 250
+}
+
+obj_switch_ware_stats_tab_to_third = {
+   name = "switch_ware_stats_tab_to_third",
+   title = _"Examine your ware production and consumption",
+   number = 1,
+   body = objective_text(_"Examine your ware production and consumption",
+      p(_[[The first two tabs show you the production and consumption of any ware. You can toggle them by simply clicking on them.]]) ..
+      li(_[[When you have seen enough, switch to the third tab (‘Economy health’).]])
    )
 }
-
 ware_stats2 = {
+   position = "topright",
    title = _"Ware Statistics",
    body = (
-      p(_[[In this menu window, you can select wares to see how their production or consumption has changed over time. Try it out with some wares.]]) ..
-      li(_[[I’ll continue as soon as you click on the]]) ..
-      li_image("images/wui/stats/menu_tab_wares_econ_health.png", _[[third tab (‘Economy health’).]])
+      p(_[[In this window, you can select wares to see how their production or consumption has changed over time. Try it out with some wares.]]) ..
+      li_image("images/wui/stats/menu_tab_wares_econ_health.png", _[[I’ll continue as soon as you click on the third tab (‘Economy health’).]])
    ),
-   h = 250,
-   show_instantly = true,
-   obj_name = "switch_ware_stat_tab_to_third",
-   obj_title = _"Switch to the third tab in the ware statistics menu window",
-   obj_body = (
-      p(_[[The first two tabs show you the production and consumption of any ware. You can toggle them by simply clicking on them.]]) ..
-      li(_[[When you have seen enough, switch to the third tab.]])
+   h = 350,
+   show_instantly = true
+}
+
+obj_switch_ware_stats_tab_to_fourth = {
+   name = "switch_ware_stats_tab_to_fourth",
+   title = _"Examine your economy’s health",
+   number = 1,
+   body = objective_text(_"Examine your economy’s health",
+      p(_[[The third tab shows you the economy health of the ware. When the value is positive, this means your stock is growing.]]) ..
+      p(_[[Now try this out. You can also compare it with the two previous tabs.]]) ..
+      li(_[[When you have seen enough, switch to the fourth tab (‘Stock’).]])
    )
 }
-
 ware_stats3 = {
+   position = "topright",
    title = _"Ware Statistics",
    body = (
-      p(_[[In this tab, you can see the difference between production and consumption, called ‘economy health’. You can see at one glance which one of those two is higher for the selected ware, that means whether the amount increases or decreases.]]) ..
-      p(_[[Now try this out. You can also compare it with the two previous tabs.]]) ..
-      li(_[[Click on the last tab when I should continue.]])
+      li_image("images/wui/stats/menu_tab_wares_econ_health.png",
+         _[[In this tab, you can see the difference between production and consumption, called ‘economy health’. You can see at one glance which one of those two is higher for the selected ware, that means whether the amount increases or decreases.]])
    ),
-   h = 250,
-   show_instantly = true,
-   obj_name = "switch_ware_stat_tab_to_forth",
-   obj_title = _"Switch to the last tab in the ware statistics menu window",
-   obj_body = (
-      p(_[[The third tab shows you the economy health of the ware. When the value is positive, this means your stock is growing.]]) ..
-      li(_[[When you have seen enough, switch to the fourth tab.]])
-   )
+   h = 350,
+   show_instantly = true
 }
 
+obj_close_ware_stats = {
+   name = "close_ware_stats",
+   title = _"Examine your stock",
+   number = 1,
+   body = objective_text(_"Examine your stock",
+      li_arrow(_[[The stock tab shows you how many wares you have. Compare the information from the four tabs to understand the correlation.]]) ..
+      li(_[[When you have finished, close the ware statistics window.]])
+   ),
+   h = 250
+}
 ware_stats4 = {
+   position = "topright",
    title = _"Ware Statistics",
    body = (
-      p(_[[In the last tab, you can also see your absolute stock. It will increase when the economy health is positive, and decrease otherwise. Compare the two graphs!]]) ..
-      p(_[[The last two tabs are good indicators to see whether shortages are about to come. Don’t forget to check them regularly!]]) ..
-      li(_[[Close this window when you’re done.]])
-   ),
-   h = 250,
-   show_instantly = true,
-   obj_name = "close_ware_stats",
-   obj_title = _"Close the ware statistics window",
-   obj_body = (
-      p(_[[The stock tab shows you how many wares you have. Compare the information from the four tabs to understand the correlation.]]) ..
-      li(_[[When you have finished, close the ware statistics window.]])
-   ),
+      li_image("images/wui/stats/menu_tab_wares_stock.png",
+         p(_[[In the last tab, you can also see your absolute stock. It will increase when the economy health is positive, and decrease otherwise. Compare the two graphs!]]) ..
+         p(_[[The last two tabs are good indicators to see whether shortages are about to come. Don’t forget to check them regularly!]]))
+   ),
+   show_instantly = true
 }
 
 reopen_ware_stats1 = {
    title = _"You closed the ware statistics window!",
    body = (
-      p(_[[You have closed the ware statistics menu window, but I have not yet finished with my explanation. Would you please reopen it and choose the third tab?]])
+      li_image("images/wui/menus/statistics_wares.png",
+         _[[You have closed the ware statistics window, but I have not yet finished with my explanation. Would you please reopen it and choose the third tab?]])
    ),
    show_instantly = true,
    w = 300,
    h = 250
 }
 
-reopen_ware_stats1_obj = {
-   obj_name = "open_ware_stats_menu_again1",
+obj_reopen_ware_stats1 = {
+   obj_name = "reopen_ware_stats1",
    obj_title = _"Open the ware statistics window again",
+   number = 1,
    obj_body = (
-      p(_[[You closed the ware statistics menu window before I finished telling you everything about it. If you already know everything, please feel free to leave this tutorial at any time.]]) ..
+      li_image("images/wui/menus/statistics_wares.png",
+         _[[You closed the ware statistics window before I finished telling you everything about it. If you already know everything, please feel free to leave this tutorial at any time.]]) ..
       -- TRANSLATORS: "it" refers to the ware statistics window.
       li(_[[Otherwise, please reopen it and choose the third tab.]])
    )
@@ -374,102 +413,122 @@
 reopen_ware_stats2 = {
    title = _"You closed the ware statistics window!",
    body = (
-      p(_[[You have closed the ware statistics menu window, but I have not yet finished with my explanation. Would you please reopen it and choose the fourth tab?]])
+      li_image("images/wui/menus/statistics_wares.png",
+         _[[You have closed the ware statistics window, but I have not yet finished with my explanation. Would you please reopen it and choose the fourth tab?]])
    ),
    show_instantly = true,
    w = 300,
    h = 250
 }
 
-reopen_ware_stats2_obj = {
-   obj_name = "open_ware_stats_menu_again2",
-   obj_title = _"Open the ware statistics window again",
-   obj_body = (
-      p(_[[You closed the ware statistics menu window before I finished telling you everything about it. If you already know everything, please feel free to leave this tutorial at any time.]]) ..
+obj_reopen_ware_stats2 = {
+   name = "open_ware_stats_menu_again2",
+   title = _"Open the ware statistics window again",
+   number = 1,
+   body = (
+      li_image("images/wui/menus/statistics_wares.png",
+         _[[You closed the ware statistics window before I finished telling you everything about it. If you already know everything, please feel free to leave this tutorial at any time.]]) ..
       -- TRANSLATORS: "it" refers to the ware statistics window.
       li(_[[Otherwise, please reopen it and choose the fourth tab.]])
    )
 }
 
+obj_open_economy_settings = {
+   name = "open_economy_settings",
+   title = _"Open the ‘Configure economy’ window",
+   number = 1,
+   body = objective_text(_"Open the ‘Configure economy’ window",
+      li(_[[Open the ‘Configure economy’ window.]]) ..
+      li_arrow(_[[The window can be accessed by clicking on any flag you own.]])
+   )
+}
 economy_settings1 = {
    position = "topright",
    title = _"Economy options",
    body = (
-      p(_[[I’ve shown you our stock menu window, where you could see which wares are at the warehouses. You remember?]]) ..
-      p(_[[Now I’ll tell you how you can determine how many wares you want to have. The menu window for this purpose can be accessed via any flag and is called ‘Configure economy’.]]) ..
+      li_object("empire_flag",
+         p(_[[I’ve shown you our stock window, where you could see which wares are at the warehouses. You remember?]]) ..
+         p(_[[Now I’ll tell you how you can determine how many wares you want to have. The window for this purpose can be accessed via any flag and is called ‘Configure economy’.]]), plr.color) ..
       -- Yup, that's indeed the correct icon
-      li_image("images/wui/stats/genstats_nrwares.png", _[[This is the icon.]]) ..
-      li(_[[Open this window.]])
+      li_image("images/wui/stats/genstats_nrwares.png", _[[This is the icon.]])
    ),
-   h = 350,
-   obj_name = "open_economy_settings",
-   obj_title = _"Open the ‘Configure economy’ window",
-   obj_body = (
-      li(_[[Open the ‘Configure economy’ window.]]) ..
-      li_arrow(_[[The window can be accessed by clicking on any flag you own.]])
-   )
+   h = 350
 }
 
 economy_settings2 = {
+   position = "topright",
    title = _"Economy options",
    body = (
-      p(_[[This window looks similar to the stock window, but it has additional buttons at the bottom.]]) ..
+      li_image("images/wui/stats/genstats_nrwares.png",
+            _[[This window looks similar to the stock window, but it has additional buttons at the bottom.]]) ..
       p(_[[You first have to select one or more wares (you can also left-click and drag). Then you can set the desired target quantity for the selected wares.]]) ..
       p(_[[Most buildings will only produce something when the stock level in your warehouses falls below the target quantity, so you should indicate the reserve you want to stockpile.]]) ..
-      p(_[[An example: the default value for scythes is 1. If you build a farm, a carrier will take a scythe and become a farmer. Then there will be no scythes left, but the target quantity is 1, therefore your toolsmith will start producing another one.]]) ..
-      p(_[[If you build two farms, only one of them will start working immediately. The second farm will have to wait for its worker, who will lack a scythe. If you had set the target quantity to 2 before, two scythes would have been available and both farms would have been able to start working right away.]])
-   ),
-   h = 450
+      li_image(wl.Game():get_ware_description("scythe").icon_name,
+         _[[An example: the default value for scythes is 1. If you build a farm, a carrier will take a scythe and become a farmer. Then there will be no scythes left, but the target quantity is 1, therefore your toolsmith will start producing another one.]]) ..
+      li_object("empire_farmer",
+         _[[If you build two farms, only one of them will start working immediately. The second farm will have to wait for its worker, who will lack a scythe. If you had set the target quantity to 2 before, two scythes would have been available and both farms would have been able to start working right away.]], plr.color)
+   )
 }
 
+obj_produce_marble_columns = {
+   name = "produce_marble_columns",
+   title = _"Produce 20 marble columns",
+   number = 1,
+   body = objective_text(_"Produce 20 marble columns",
+      li(_[[To be prepared for additional fortifications, you should produce 20 marble columns.]]) ..
+      li_arrow(_[[Your stonemason will not produce marble columns when they are not needed. You have to increase the target quantity.]]) ..
+      li_arrow(_[[To do so, click on any flag and choose ‘Configure economy’. In this window, you can decide how many wares of each type you wish to have in stock.]]) ..
+      li_arrow(_[[Sometimes, you will need many wares at the same time quickly – faster than they can be produced. In this case, it is good to have enough on reserve.]])
+   )
+}
 economy_settings3 = {
+   position = "topright",
    title = _"Economy options",
    body = (
-      p(_[[By changing the target quantity, you can therefore decide which wares/tools your resources (in this case: iron) should be turned into or whether you would like to save your iron and wait until you know what you will need it for.]]) ..
+      li_image(wl.Game():get_ware_description("iron").icon_name,
+         _[[By changing the target quantity, you can therefore decide which wares/tools your resources (in this case: iron) should be turned into or whether you would like to save your iron and wait until you know what you will need it for.]]) ..
       p(_[[Only buildings that consume wares care about this setting. Buildings that produce wares for free (e.g. your farms or wells) will always keep working.]]) ..
-      p(_[[Now let’s try it out: the current target quantity for marble columns is 10. Increase it to be prepared in case you will have to build up your fortifications quickly.]]) ..
-      li(_[[Set the target quantity for marble columns to 20 and wait for your stonemason to produce them.]])
+      li_image(wl.Game():get_ware_description("marble_column").icon_name,
+         _[[Now let’s try it out: the current target quantity for marble columns is 10. Increase it to be prepared in case you will have to build up your fortifications quickly.]])
    ),
-   obj_name = "produce_marble_columns",
-   obj_title = _"Produce 20 marble columns",
-   obj_body = (
-      p(_[[Sometimes, you will need many wares at the same time quickly – faster than they can be produced. In this case, it is good to have enough on reserve.]]) ..
-      li(_[[To be prepared for additional fortifications, you should produce 20 marble columns.]]) ..
-      li_arrow(_[[Your stonemason will not produce marble columns when they are not needed. You have to increase the target quantity.]]) ..
-      li_arrow(_[[To do so, click on any flag and choose ‘Configure economy’. In this menu window, you can decide how many wares of each type you wish to have in stock.]])
+   h = 500,
+}
+
+obj_bring_marble_columns_to_front = {
+   name = "bring_marble_columns_to_front",
+   title = _"Bring 20 marble columns to the front line",
+   number = 1,
+   body = objective_text(_"Bring 20 marble columns to the front line",
+      li(_[[Bring all of the 20 marble columns to the warehouse near the front line.]]) ..
+      li_image("images/wui/buildings/stock_policy_button_prefer.png",
+         _[[To achieve this, you will have to do two things. First, set a preference for marble columns in the desired warehouse. All marble columns produced in the future will be brought there if possible.]]) ..
+      li_image("images/wui/buildings/stock_policy_button_remove.png",
+         _[[Then, to move the marble columns out of your headquarters, you will have to click on the remove button there.]])
    )
 }
-
 warehouse_preference_settings = {
    field = warehouse_field,
    position = "topright",
    title = _"Warehouse Preferences",
    body = (
       h1(_[[Bring the marble columns to the front line]]) ..
-      p(_[[The production of marble columns is working fine now, but it would be great if they were stored where we need them.]]) ..
-      p(_[[Normally, produced wares are brought to the closest warehouse if they are not needed elsewhere. In this case, this means our headquarters. But we would like to have them in the warehouse near our fortresses.]]) ..
-      p(_[[Every warehouse has four buttons to set the preference. If you move your mouse pointer over them, you will see tooltips that explain what the buttons do.]]) ..
-      li(_[[Bring all of the 20 marble columns to the warehouse near the front line.]]) ..
-      li_arrow(_[[To achieve this, you will have to do two things. First, set a preference for marble columns in the desired warehouse. All marble columns produced in the future will be brought there if possible.]]) ..
-      li_arrow(_[[Then, to move the marble columns out of your headquarters, you will have to click on the remove button there.]])
+      li_object("empire_warehouse",
+         p(_[[The production of marble columns is working fine now, but it would be great if they were stored where we need them.]]) ..
+         p(_[[Normally, produced wares are brought to the closest warehouse if they are not needed elsewhere. In this case, this means our headquarters. But we would like to have them in the warehouse near our fortresses.]]) ..
+         p(_[[Every warehouse has four buttons to set the preference. If you move your mouse pointer over them, you will see tooltips that explain what the buttons do.]]), plr.color)
    ),
-   obj_name = "bring_marble_columns_to_front",
-   obj_title = _"Bring 20 marble columns to the front line",
-   obj_body = (
-      p(_[[To decide where your wares get stored, you can use the preference buttons in the warehouses.]]) ..
-      li(_[[Bring all of the 20 marble columns to the warehouse near the front line.]]) ..
-      li_arrow(_[[To achieve this, you will have to do two things. First, set a preference for marble columns in the desired warehouse. All marble columns produced in the future will be brought there if possible.]]) ..
-      li_arrow(_[[Then, to move the marble columns out of your headquarters, you will have to click on the remove button there.]])
-   )
+   h = 500
 }
 
 conclusion = {
    title = _"Borders Secured",
    body =
       h1(_[[We’re safe now]]) ..
-      p(_[[Great. We now have enough marble columns so that in case of an aggressor, we can build up our fortifications. But I do not think that that will be necessary. So far, no enemy has shown up.]]) ..
-      p(_[[I hope I could teach you how you can control the economy in Widelands. There are many options and they can be confusing at first. Even if you’ve only understood a few concepts, you mustn’t give up. Try them out in some games, become familiar with them and experience the possibilities. Then, return to this tutorial and learn the rest!]]) ..
+      li_object("empire_fortress",
+         p(_[[Great. We now have enough marble columns so that in case of an aggressor, we can build up our fortifications. But I do not think that that will be necessary. So far, no enemy has shown up.]]) ..
+         p(_[[I hope I could teach you how you can control the economy in Widelands. There are many options and they can be confusing at first. Even if you’ve only understood a few concepts, you mustn’t give up. Try them out in some games, become familiar with them and experience the possibilities. Then, return to this tutorial and learn the rest!]]), plr.color) ..
       p([[]]) ..
       p(_[[This was the last tutorial I had prepared for you. I’ve now taught you everything I know. There are still secrets hidden in this world even I don’t know about. I will now search for a quiet place to spend my sunset years. If you have still questions, the Widelands community will surely help you. You can find it at:]]) ..
-      h1(p("align=center", u("widelands.org")))
+      h1(p("align=center", u("widelands.org"))),
+   h = 450
 }

=== 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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +0000 differ
=== modified file 'data/scripting/editor/editor_help.lua'
--- data/scripting/editor/editor_help.lua	2018-09-29 09:20:35 +0000
+++ data/scripting/editor/editor_help.lua	2019-06-01 15:41:38 +0000
@@ -79,7 +79,7 @@
          name = "terrains",
          -- TRANSLATORS Tab title: terrain help
          title = _"Terrains",
-         icon = "images/wui/editor/editor_menu_tool_set_terrain.png",
+         icon = "images/wui/editor/tools/terrain.png",
          entries = get_terrains()
       },
       {

=== modified file 'data/scripting/messages.lua'
--- data/scripting/messages.lua	2019-02-09 18:45:42 +0000
+++ data/scripting/messages.lua	2019-06-01 15:41:38 +0000
@@ -6,6 +6,7 @@
 
 include "scripting/coroutine.lua"
 include "scripting/richtext.lua"
+include "scripting/richtext_scenarios.lua"
 include "scripting/table.lua"
 include "scripting/ui.lua"
 
@@ -87,10 +88,57 @@
 --    :arg message: the message to be sent
 --    :arg sleeptime: ms spent sleeping after the message has been dismissed by the player
 --
+--    Besides the normal message arguments (see wl.Game.Player:message_box) the following ones can be used:
+--
+--    :arg position: A string that indicates at which border of the screen the message box shall appear. Can be "top", "bottom", "right", "left" or a combination (e.g. "topright"). Overrides posx and posy. Default: Center. If only one direction is indicated, the other one stays central.
+--    :arg scroll_back: If true, the view scrolls/jumps back to where it came from. If false, the new location stays on the screen when the message box is closed. Default: False.
+--    :arg show_instantly: If true, the message box is shown immediately. If false, this function will wait until the player leaves the roadbuilding mode. Use this with care because it can be very interruptive. Default: false.
+--
 function campaign_message_box(message, sleeptime)
-   if not message.h then message.h = 400 end
-   if not message.w then message.w = 450 end
-   message_box(wl.Game().players[1], message.title, message.body, message)
+   message.show_instantly = message.show_instantly or false
+   message.scroll_back = message.scroll_back or false
+   message.h = message.h or 400
+   message.w = message.w or 450
+
+   if message.position then
+      if string.find(message.position,"top") then
+         -- Set it a bit lover than 0 to prevent overlap with game speed text
+         message.posy = 25
+      elseif string.find(message.position,"bottom") then
+         message.posy = 10000
+      end
+      if string.find(message.position,"left") then
+         message.posx = 0
+      elseif string.find(message.position,"right") then
+         message.posx = 10000
+      end
+   end
+
+   local center_pixel
+
+   if message.field then
+      -- This is necessary. Otherwise, we would scroll and then wait until the road is finished.
+      -- In this time, could user can scroll elsewhere, giving weird results.
+      if not message.show_instantly then
+         wait_for_roadbuilding()
+      end
+      center_pixel = scroll_to_field(message.field);
+   end
+
+   if message.show_instantly then
+      -- message_box takes care of this, but player:message_box does not
+      local user_input = wl.ui.get_user_input_allowed()
+      wl.ui.set_user_input_allowed(true)
+      wl.Game().players[1]:message_box(message.title, rt(message.body), message)
+      wl.ui.set_user_input_allowed(user_input)
+   else
+      message_box(wl.Game().players[1], message.title, message.body, message)
+   end
+
+   if (message.field and message.scroll_back) then
+      scroll_to_map_pixel(center_pixel);
+   end
+
    if sleeptime then sleep(sleeptime) end
 end
 
@@ -112,6 +160,32 @@
    end
 end
 
+
+-- RST
+-- .. function:: campaign_message_box(message, objective [,sleeptime])
+--
+--    Sets message.h and message.w if not set and calls
+--    message_box(player, title, body, parameters) for player 1.
+--
+--    Adds an objective to the scenario afterwards.
+--
+--
+--    :arg message: the message to be sent
+--    :arg objective: The objective to be added. If the variable obj_name exists, obj_name, obj_title and obj_body are used. Otherwise, it needs to have a name, title, and body.
+--    :arg sleeptime: ms spent sleeping after the message has been dismissed by the player
+--
+--    :returns: The new objective.
+--
+-- TODO(wl-zocker): This function should be used by all tutorials, campaigns and scenario maps
+function campaign_message_with_objective(message, objective, sleeptime)
+   -- TODO(GunChleoc): Once everybody is using this function, move new_objectives over from
+   -- richtext_scenarios and add this file to utils/buildcat.py
+   message.body = message.body .. new_objectives(objective)
+   campaign_message_box(message, sleeptime)
+   return add_campaign_objective(objective)
+end
+
+
 -- RST
 -- .. function:: set_objective_done(objective[, sleeptime])
 --
@@ -133,6 +207,7 @@
 -- RST
 -- .. function:: message_box_objective(player, message)
 --
+--    DEPRECATED, use campaign_message_with_objective instead.
 --    Calls message_box(player, message.title, message.body, message). Also adds an objective defined in obj_name, obj_title and obj_body.
 --    This method should gather all options that are used often to avoid reimplementation in every single scenario script.
 --
@@ -146,8 +221,6 @@
 --    :arg show_instantly: If true, the message box is shown immediately. If false, this function calls message_box(), which waits until the player leaves the roadbuilding mode. Use this with care because it can be very interruptive. Default: false.
 --
 --    :returns: the objective if defined, nil otherwise
-
--- TODO(wl-zocker): This function should be used by all tutorials, campaigns and scenario maps
 function message_box_objective(player, message)
    message.show_instantly = message.show_instantly or false
    message.scroll_back = message.scroll_back or false

=== modified file 'data/scripting/richtext.lua'
--- data/scripting/richtext.lua	2018-09-29 09:20:35 +0000
+++ data/scripting/richtext.lua	2019-06-01 15:41:38 +0000
@@ -424,7 +424,7 @@
 end
 
 -- RST
--- .. function:: li_object(name, text)
+-- .. function:: li_object(name, text[, playercolor])
 --
 --    Places a paragraph of text to the right of an image representing the given map object
 --
@@ -434,12 +434,19 @@
 --    :arg text: the text to be placed next to the image
 --    :type text: :class:`string`
 --
+--    :arg playercolor: a playercolor to be applied to the image, in hex notation
+--    :type playercolor: :class:`string`
+--
 --    :returns: the text wrapped in a paragraph and placed next to the image, the outer tag is a div.
 
-function li_object(name, text)
+function li_object(name, text, playercolor)
+   local image = img_object(name)
+   if (playercolor ~= nil) then
+      image = img_object(name, "color=" .. playercolor)
+   end
    return
       div("width=100%",
-         div("float=left padding_r=6", p(img_object(name))) ..
+         div("float=left padding_r=6", p(image)) ..
          p(text)
       )
 end
@@ -607,7 +614,7 @@
 --           h1("6699ff", _[[Colored header]]) ..
 --           p(_[[Normal paragraph, just with a bit more text to show how it looks like.]]) ..
 --           p("align=center", _[[A centered paragraph, just with a bit more text to show how it looks like.]]) ..
---           li_image("images/wui/menus/menu_toggle_menu.png", _[[An image with right aligned text. This is just text to show automatic line breaks and behavior in regard with images]]) ..
+--           li_image("images/wui/menus/statistics.png", _[[An image with right aligned text. This is just text to show automatic line breaks and behavior in regard with images]]) ..
 --           li(_[[A list item]]) ..
 --           li(font("color=6699ff bold=1", _[[Blue and bold]])) ..
 --           li_arrow(_[[A list item with an arrow]]) ..

=== modified file 'data/scripting/richtext_scenarios.lua'
--- data/scripting/richtext_scenarios.lua	2019-05-12 10:35:21 +0000
+++ data/scripting/richtext_scenarios.lua	2019-06-01 15:41:38 +0000
@@ -87,9 +87,17 @@
       text = text .. obj.body
       sum = sum + obj.number
    end
-      local objectives_header = _"New Objective"
+
+   local objectives_header = _"New Objective"
    if (sum > 1) then
       objectives_header = _"New Objectives"
    end
-   return h1(objectives_header) .. text
+
+   return
+      div("width=100%",
+         vspace(18) ..
+         div("float=left padding_r=6", p(img("images/wui/menus/objectives.png"))) ..
+         p_font("", "size=18 bold=1 color=D1D1D1",  vspace(6) .. objectives_header) ..
+         vspace(1) .. text
+      )
 end

=== modified file 'data/tribes/atlanteans.lua'
--- data/tribes/atlanteans.lua	2019-05-25 08:51:42 +0000
+++ data/tribes/atlanteans.lua	2019-06-01 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +0000 differ
=== modified file 'regression_test.py'
--- regression_test.py	2019-03-15 19:37:37 +0000
+++ regression_test.py	2019-06-01 15:41:38 +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 15:41:37 +0000
+++ src/editor/CMakeLists.txt	2019-06-01 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:37 +0000
+++ src/editor/ui_menus/main_menu_new_map.cc	2019-06-01 15:41:38 +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 15:41:37 +0000
+++ src/editor/ui_menus/main_menu_new_map.h	2019-06-01 15:41:38 +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 15:41:37 +0000
+++ src/editor/ui_menus/main_menu_random_map.cc	2019-06-01 15:41:38 +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 15:41:37 +0000
+++ src/editor/ui_menus/main_menu_random_map.h	2019-06-01 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:37 +0000
+++ src/editor/ui_menus/player_menu.cc	2019-06-01 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:37 +0000
+++ src/editor/ui_menus/tool_resize_options_menu.cc	2019-06-01 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:37 +0000
+++ src/wui/economy_options_window.cc	2019-06-01 15:41:38 +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 15:41:37 +0000
+++ src/wui/fieldaction.cc	2019-06-01 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:37 +0000
+++ src/wui/game_client_disconnected.cc	2019-06-01 15:41:38 +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 15:41:37 +0000
+++ src/wui/game_message_menu.cc	2019-06-01 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:37 +0000
+++ src/wui/seafaring_statistics_menu.cc	2019-06-01 15:41:38 +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 15:41:38 +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 15:41:38 +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 15:41:38 +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/',


References