← Back to team overview

widelands-dev team mailing list archive

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

 

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

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #1480937 in widelands: "Escape key doesn't work in all dialogues"
  https://bugs.launchpad.net/widelands/+bug/1480937

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

Added missing key bindings to ui_fsmenu. Return and Esc should now work everywhere where it it appropriate.

Used templates for run() and end_modal() in UI::Panel to improve type safety for return codes. All Return codes are now enums in UI::Panel or FullscreenMenuBase.

Uniform naming for clicked_ok()/clicked_back(). Yes/No messgae box is now OK/Cancel.

-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/bug-1480937 into lp:widelands.
=== modified file 'src/editor/editorinteractive.cc'
--- src/editor/editorinteractive.cc	2015-07-26 09:25:51 +0000
+++ src/editor/editorinteractive.cc	2015-08-06 17:33:02 +0000
@@ -250,18 +250,18 @@
 void EditorInteractive::exit() {
 	if (m_need_save) {
 		if (get_key_state(SDL_SCANCODE_LCTRL) || get_key_state(SDL_SCANCODE_RCTRL)) {
-			end_modal(0);
+			end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack);
 		} else {
 			UI::WLMessageBox mmb
 			(this,
 			 _("Unsaved Map"),
 			 _("The map has not been saved, do you really want to quit?"),
-			 UI::WLMessageBox::YESNO);
-			if (mmb.run() == 0)
+			 UI::WLMessageBox::MBoxType::kOkCancel);
+			if (mmb.run<UI::Panel::Returncodes>() == UI::Panel::Returncodes::kBack)
 				return;
 		}
 	}
-	end_modal(0);
+	end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack);
 }
 
 void EditorInteractive::toggle_mainmenu() {
@@ -621,7 +621,7 @@
 			eia.egbase().lua().run_script(script_to_run);
 		}
 	}
-	eia.run();
+	eia.run<UI::Panel::Returncodes>();
 
 	editor.cleanup_objects();
 }

=== modified file 'src/editor/ui_menus/editor_main_menu_save_map.cc'
--- src/editor/ui_menus/editor_main_menu_save_map.cc	2015-07-30 07:16:09 +0000
+++ src/editor/ui_menus/editor_main_menu_save_map.cc	2015-08-06 17:33:02 +0000
@@ -208,7 +208,7 @@
  */
 void MainMenuSaveMap::clicked_make_directory() {
 	MainMenuSaveMapMakeDirectory md(this, _("unnamed"));
-	if (md.run()) {
+	if (md.run<UI::Panel::Returncodes>() == UI::Panel::Returncodes::kOk) {
 		g_fs->ensure_directory_exists(m_basedir);
 		//  create directory
 		std::string fullname = m_curdir;
@@ -380,8 +380,8 @@
 			(boost::format(_("A file with the name ‘%s’ already exists. Overwrite?"))
 				% FileSystem::fs_filename(filename.c_str())).str();
 		UI::WLMessageBox mbox
-			(&eia(), _("Error Saving Map!"), s, UI::WLMessageBox::YESNO);
-		if (!mbox.run())
+			(&eia(), _("Error Saving Map!"), s, UI::WLMessageBox::MBoxType::kOkCancel);
+		if (mbox.run<UI::Panel::Returncodes>() == UI::Panel::Returncodes::kBack)
 			return false;
 
 		g_fs->fs_unlink(complete_filename);
@@ -400,8 +400,8 @@
 			 "given:\n");
 		s += e.what();
 		UI::WLMessageBox  mbox
-			(&eia(), _("Error Saving Map!"), s, UI::WLMessageBox::OK);
-		mbox.run();
+			(&eia(), _("Error Saving Map!"), s, UI::WLMessageBox::MBoxType::kOk);
+		mbox.run<UI::Panel::Returncodes>();
 	}
 	die();
 

=== modified file 'src/editor/ui_menus/editor_main_menu_save_map.h'
--- src/editor/ui_menus/editor_main_menu_save_map.h	2014-09-25 08:58:07 +0000
+++ src/editor/ui_menus/editor_main_menu_save_map.h	2015-08-06 17:33:02 +0000
@@ -40,7 +40,7 @@
 
 private:
 	EditorInteractive & eia();
-	void clicked_ok            ();
+	void clicked_ok();
 	void clicked_make_directory();
 	void        clicked_item(uint32_t);
 	void double_clicked_item(uint32_t);

=== modified file 'src/editor/ui_menus/editor_main_menu_save_map_make_directory.cc'
--- src/editor/ui_menus/editor_main_menu_save_map_make_directory.cc	2015-07-30 07:16:09 +0000
+++ src/editor/ui_menus/editor_main_menu_save_map_make_directory.cc	2015-08-06 17:33:02 +0000
@@ -57,7 +57,9 @@
 		 std::string(),
 		 m_dirname.size());
 	m_ok_button->sigclicked.connect
-		(boost::bind(&MainMenuSaveMapMakeDirectory::end_modal, boost::ref(*this), 1));
+		(boost::bind(&MainMenuSaveMapMakeDirectory::end_modal<UI::Panel::Returncodes>,
+						 boost::ref(*this),
+						 UI::Panel::Returncodes::kOk));
 
 	UI::Button * cancelbtn = new UI::Button
 		(this, "cancel",
@@ -65,7 +67,9 @@
 		 g_gr->images().get("pics/but1.png"),
 		 _("Cancel"));
 	cancelbtn->sigclicked.connect
-		(boost::bind(&MainMenuSaveMapMakeDirectory::end_modal, boost::ref(*this), 0));
+		(boost::bind(&MainMenuSaveMapMakeDirectory::end_modal<UI::Panel::Returncodes>,
+						 boost::ref(*this),
+						 UI::Panel::Returncodes::kBack));
 
 	center_to_parent();
 }

=== modified file 'src/editor/ui_menus/editor_player_menu.cc'
--- src/editor/ui_menus/editor_player_menu.cc	2015-07-29 07:26:48 +0000
+++ src/editor/ui_menus/editor_player_menu.cc	2015-08-06 17:33:02 +0000
@@ -295,7 +295,7 @@
 //                 //                 ("Cannot remove player. It is referenced in some place. Remove all"
 //                 //                  " buildings and bobs that depend on this player and try again."),
 //                 //          UI::WLMessageBox::OK);
-//                 // mmb.run();
+//                 // mmb.run<UI::Panel::Returncodes>();
 //         }
 // }
 
@@ -324,8 +324,8 @@
 			 _
 			 	("Cannot remove player. It is referenced someplace. Remove all"
 			 	 " buildings and animals that depend on this player and try again."),
-			 UI::WLMessageBox::OK);
-		mmb.run();
+			 UI::WLMessageBox::MBoxType::kOk);
+		mmb.run<UI::Panel::Returncodes>();
 	}
 	update();
 }

=== modified file 'src/logic/game.cc'
--- src/logic/game.cc	2015-08-06 07:18:24 +0000
+++ src/logic/game.cc	2015-08-06 17:33:02 +0000
@@ -346,7 +346,7 @@
  * Initialize the savegame based on the given settings.
  * At return the game is at the same state like a map loaded with Game::init()
  * Only difference is, that players are already initialized.
- * run() takes care about this difference.
+ * run<Returncode>() takes care about this difference.
  *
  * \note loaderUI can be nullptr, if this is run as dedicated server.
  */
@@ -564,7 +564,7 @@
 
 		m_state = gs_running;
 
-		get_ibase()->run();
+		get_ibase()->run<UI::Panel::Returncodes>();
 
 		m_state = gs_ending;
 

=== modified file 'src/logic/replay_game_controller.cc'
--- src/logic/replay_game_controller.cc	2015-03-01 09:21:20 +0000
+++ src/logic/replay_game_controller.cc	2015-08-06 17:33:02 +0000
@@ -109,8 +109,8 @@
 		 _("The end of the replay has been reached and the game has "
 			"been paused. You may unpause the game and continue watching "
 			"if you want to."),
-		 UI::WLMessageBox::OK);
-	mmb.run();
+		 UI::WLMessageBox::MBoxType::kOk);
+	mmb.run<UI::Panel::Returncodes>();
 }
 
 uint8_t ReplayGameController::CmdReplayEnd::id() const {

=== modified file 'src/network/netclient.cc'
--- src/network/netclient.cc	2015-07-30 07:16:09 +0000
+++ src/network/netclient.cc	2015-08-06 17:33:02 +0000
@@ -155,19 +155,20 @@
 		FullscreenMenuLaunchMPG lgm(this, this);
 		lgm.set_chat_provider(*this);
 		d->modal = &lgm;
-		int32_t code = lgm.run();
+		FullscreenMenuBase::MenuTarget code = lgm.run<FullscreenMenuBase::MenuTarget>();
 		d->modal = nullptr;
-		if (code == 1) { // Only possible if server is dedicated - client pressed "start game" button
+		 // Only possible if server is dedicated - client pressed "start game" button
+		if (code == FullscreenMenuBase::MenuTarget::kNormalGame) {
 			SendPacket subs;
 			subs.unsigned_8(NETCMD_LAUNCH);
 			subs.send(d->sock);
 
 			// Reopen the menu - perhaps the start is denied or other problems occur
 			d->modal = &lgm;
-			code = lgm.run();
+			code = lgm.run<FullscreenMenuBase::MenuTarget>();
 			d->modal = nullptr;
 		}
-		if (code <= 0) {
+		if (code == FullscreenMenuBase::MenuTarget::kBack) {
 			// if this is an internet game, tell the metaserver that client is back in the lobby.
 			if (m_internet)
 				InternetGaming::ref().set_game_done();
@@ -945,9 +946,10 @@
 	}
 
 	case NETCMD_LAUNCH: {
-		if (!d->modal || d->game)
+		if (!d->modal || d->game) {
 			throw DisconnectException("UNEXPECTED_LAUNCH");
-		d->modal->end_modal(2);
+		}
+		d->modal->end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kOk);
 		break;
 	}
 	case NETCMD_SETSPEED:
@@ -1100,15 +1102,15 @@
 			(d->modal,
 			 _("Disconnected from Host"),
 			 msg,
-			 UI::WLMessageBox::OK);
-		mmb.run();
+			 UI::WLMessageBox::MBoxType::kOk);
+		mmb.run<UI::Panel::Returncodes>();
 	}
 
 	if (trysave)
 		WLApplication::emergency_save(*d->game);
 
 	if (d->modal) {
-		d->modal->end_modal(0);
+		d->modal->end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kBack);
 		d->modal = nullptr;
 	}
 }

=== modified file 'src/network/nethost.cc'
--- src/network/nethost.cc	2015-03-17 21:29:04 +0000
+++ src/network/nethost.cc	2015-08-06 17:33:02 +0000
@@ -780,8 +780,8 @@
 	} else {
 		FullscreenMenuLaunchMPG lm(&d->hp, this);
 		lm.set_chat_provider(d->chat);
-		const int32_t code = lm.run();
-		if (code <= 0) {
+		const FullscreenMenuBase::MenuTarget code = lm.run<FullscreenMenuBase::MenuTarget>();
+		if (code == FullscreenMenuBase::MenuTarget::kBack) {
 			// if this is an internet game, tell the metaserver that client is back in the lobby.
 			if (m_internet)
 				InternetGaming::ref().set_game_done();

=== modified file 'src/scripting/lua_game.cc'
--- src/scripting/lua_game.cc	2015-04-18 11:29:15 +0000
+++ src/scripting/lua_game.cc	2015-08-06 17:33:02 +0000
@@ -419,7 +419,7 @@
 				(game.get_ipl(), luaL_checkstring(L, 2), luaL_checkstring(L, 3),
 				 button_text, posx, posy, w, h);
 
-	mb->run();
+	mb->run<UI::Panel::Returncodes>();
 	delete mb;
 
 	// Manually force the game to reevaluate it's current state,

=== modified file 'src/scripting/lua_ui.cc'
--- src/scripting/lua_ui.cc	2015-01-31 16:03:59 +0000
+++ src/scripting/lua_ui.cc	2015-08-06 17:33:02 +0000
@@ -703,7 +703,7 @@
 		example used in the widelands Lua test suite.
 */
 int LuaMapView::close(lua_State * /* l */) {
-	get()->end_modal(0);
+	get()->end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack);
 	return 0;
 }
 

=== modified file 'src/ui_basic/helpwindow.cc'
--- src/ui_basic/helpwindow.cc	2015-01-31 16:03:59 +0000
+++ src/ui_basic/helpwindow.cc	2015-08-06 17:33:02 +0000
@@ -84,11 +84,12 @@
 		 in_width / 3, but_height,
 		 g_gr->images().get("pics/but0.png"),
 		 _("OK"), std::string(), true, false);
-	btn->sigclicked.connect(boost::bind(&HelpWindow::pressed_ok, boost::ref(*this)));
+	btn->sigclicked.connect(boost::bind(&HelpWindow::clicked_ok, boost::ref(*this)));
 	btn->set_font(Font::get((UI::g_fh1->fontset()).serif(),
 									(fontsize < 12 ? 12 : fontsize)));
 
 	textarea->set_size(in_width - 10, in_height - 10 - (2 * but_height));
+	focus();
 }
 
 
@@ -157,7 +158,7 @@
 {
 	if (btn == SDL_BUTTON_RIGHT) {
 		play_click();
-		pressed_ok();
+		clicked_ok();
 	}
 	return true;
 }
@@ -167,10 +168,26 @@
 	return true;
 }
 
-void HelpWindow::pressed_ok()
+bool HelpWindow::handle_key(bool down, SDL_Keysym code)
+{
+	if (down) {
+		switch (code.sym) {
+			case SDLK_KP_ENTER:
+			case SDLK_RETURN:
+				clicked_ok();
+				return true;
+			default:
+				return true; // handled
+		}
+	}
+	return true;
+}
+
+
+void HelpWindow::clicked_ok()
 {
 	if (is_modal())
-		end_modal(0);
+		end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack);
 	else {
 		// do not call die() here - could lead to broken pointers.
 		// the window should get deleted with the parent anyways.

=== modified file 'src/ui_basic/helpwindow.h'
--- src/ui_basic/helpwindow.h	2014-09-19 09:07:14 +0000
+++ src/ui_basic/helpwindow.h	2015-08-06 17:33:02 +0000
@@ -61,13 +61,16 @@
 	bool handle_mousepress  (uint8_t btn, int32_t mx, int32_t my) override;
 	bool handle_mouserelease(uint8_t btn, int32_t mx, int32_t my) override;
 
+	/// Handle keypresses
+	bool handle_key(bool down, SDL_Keysym code) override;
+
 	void add_heading   (std::string text);
 	void add_paragraph (std::string text);
 	void add_block     (std::string text);
 	void add_picture_li(std::string text, std::string picpath);
 
 protected:
-	virtual void pressed_ok();
+	void clicked_ok();
 
 private:
 	enum State {

=== modified file 'src/ui_basic/messagebox.cc'
--- src/ui_basic/messagebox.cc	2014-11-22 10:18:20 +0000
+++ src/ui_basic/messagebox.cc	2015-08-06 17:33:02 +0000
@@ -20,6 +20,7 @@
 #include "ui_basic/messagebox.h"
 
 #include "base/i18n.h"
+#include "base/log.h" // NOCOM
 #include "graphic/font_handler.h"
 #include "graphic/graphic.h"
 #include "ui_basic/button.h"
@@ -82,28 +83,29 @@
 
 	d->textarea->set_size(width - 10, height - 50);
 
-	if (type == OK) {
+	if (type == MBoxType::kOk) {
 		UI::Button * okbtn = new Button
 			(this, "ok",
 			 (get_inner_w() - 120) / 2, get_inner_h() - 30, 120, 20,
 			 g_gr->images().get("pics/but0.png"),
 			 _("OK"));
-		okbtn->sigclicked.connect(boost::bind(&WLMessageBox::pressed_ok, boost::ref(*this)));
-	} else if (type == YESNO) {
-		UI::Button * yesbtn = new Button
-			(this, "yes",
+		okbtn->sigclicked.connect(boost::bind(&WLMessageBox::clicked_ok, boost::ref(*this)));
+	} else if (type == MBoxType::kOkCancel) {
+		UI::Button * okbtn = new Button
+			(this, "ok",
 			 (get_inner_w() / 2 - 120) / 2, get_inner_h() - 30, 120, 20,
 			 g_gr->images().get("pics/but0.png"),
-			 _("Yes"));
-		yesbtn->sigclicked.connect(boost::bind(&WLMessageBox::pressed_yes, boost::ref(*this)));
-		UI::Button * nobtn = new Button
+			 _("OK"));
+		okbtn->sigclicked.connect(boost::bind(&WLMessageBox::clicked_ok, boost::ref(*this)));
+		UI::Button * cancelbtn = new Button
 			(this, "no",
 			 (get_inner_w() / 2 - 120) / 2 + get_inner_w() / 2, get_inner_h() - 30,
 			 120, 20,
 			 g_gr->images().get("pics/but1.png"),
-			 _("No"));
-		nobtn->sigclicked.connect(boost::bind(&WLMessageBox::pressed_no, boost::ref(*this)));
+			 _("Cancel"));
+		cancelbtn->sigclicked.connect(boost::bind(&WLMessageBox::clicked_back, boost::ref(*this)));
 	}
+	focus();
 }
 
 WLMessageBox::~WLMessageBox()
@@ -120,10 +122,11 @@
 {
 	if (btn == SDL_BUTTON_RIGHT) {
 		play_click();
-		if (d->type == OK)
-			pressed_ok();
-		else
-			pressed_no();
+		if (d->type == MBoxType::kOk) {
+			clicked_ok();
+		} else {
+			clicked_back();
+		}
 	}
 	return true;
 }
@@ -135,45 +138,35 @@
 
 bool WLMessageBox::handle_key(bool down, SDL_Keysym code)
 {
-	if (!down) {
-		return false;
-	}
-
-	switch (code.sym) {
-		case SDLK_KP_ENTER:
-		case SDLK_RETURN:
-			pressed_yes();
-			pressed_ok();
-			return true;
-		case SDLK_ESCAPE:
-			pressed_no();
-			pressed_ok();
-			return true;
-		default:
-			return false;
-	}
-
+	if (down) {
+		switch (code.sym) {
+			case SDLK_KP_ENTER:
+			case SDLK_RETURN:
+				clicked_ok();
+				return true;
+			case SDLK_ESCAPE:
+				clicked_back();
+				return true;
+			default:
+				break; // not handled
+		}
+	}
+	return UI::Panel::handle_key(down, code);
 }
 
-void WLMessageBox::pressed_ok()
+
+void WLMessageBox::clicked_ok()
 {
 	ok();
 	if (is_modal())
-		end_modal(0);
-}
-
-void WLMessageBox::pressed_yes()
-{
-	yes();
-	if (is_modal())
-		end_modal(1);
-}
-
-void WLMessageBox::pressed_no()
-{
-	no();
-	if (is_modal())
-		end_modal(0);
+		end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kOk);
+}
+
+void WLMessageBox::clicked_back()
+{
+	cancel();
+	if (is_modal())
+		end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack);
 }
 
 

=== modified file 'src/ui_basic/messagebox.h'
--- src/ui_basic/messagebox.h	2014-10-14 06:30:20 +0000
+++ src/ui_basic/messagebox.h	2015-08-06 17:33:02 +0000
@@ -37,23 +37,23 @@
  *
  * Using it as a modal dialog box is very straightforward:
  *     WLMessageBox mb(parent, "Caption", "Text", OK);
- *     int32_t code = mb.run();
- * The return code is 1 if the "Yes" button has been pressed in a \ref YESNO
- * dialog box. Otherwise, it is 0 (or negative, if the modal messagebox has
+ *     UI::Panel::Returncodes code = mb.run<UI::Panel::Returncodes>();
+ * The return code is ok_code if the "OK" button has been pressed in a \ref YESNO
+ * dialog box. Otherwise, it is dying_code (or negative, if the modal messagebox has
  * been interrupted in an unusual way).
  *
  * Using it as a non-modal dialog box is slightly more complicated. You have
  * to add this dialog box as a child to the current fullscreen panel, and
- * connect the signals \ref yes and \ref no or \ref ok, depending on the
+ * connect the signals \ref ok and \ref no or \ref ok, depending on the
  * messagebox type, to a function that deletes the message box.
  * \note this function is named "WLMessageBox" instead of simply "MessageBox"
  *       because else linking on Windows (even with #undef MessageBox) will
  *       not work.
 */
 struct WLMessageBox : public Window {
-	enum MBoxType {
-		OK,
-		YESNO
+	enum class MBoxType {
+		kOk,
+		kOkCancel
 	};
 	WLMessageBox
 		(Panel * parent,
@@ -64,17 +64,17 @@
 	~WLMessageBox();
 
 	boost::signals2::signal<void ()> ok;
-	boost::signals2::signal<void ()> yes;
-	boost::signals2::signal<void ()> no;
+	boost::signals2::signal<void ()> cancel;
 
 	bool handle_mousepress  (uint8_t btn, int32_t mx, int32_t my) override;
 	bool handle_mouserelease(uint8_t btn, int32_t mx, int32_t my) override;
+
+	/// Handle keypresses
 	bool handle_key(bool down, SDL_Keysym code) override;
 
 protected:
-	virtual void pressed_ok();
-	virtual void pressed_yes();
-	virtual void pressed_no();
+	virtual void clicked_ok();
+	virtual void clicked_back();
 
 private:
 	std::unique_ptr<WLMessageBoxImpl> d;

=== modified file 'src/ui_basic/panel.cc'
--- src/ui_basic/panel.cc	2014-12-06 12:22:35 +0000
+++ src/ui_basic/panel.cc	2015-08-06 17:33:02 +0000
@@ -129,7 +129,7 @@
  * negative when the event loop was quit in an abnormal way (e.g. the user
  * clicked the window's close button or similar).
  */
-int32_t Panel::run()
+int Panel::do_run()
 {
 	// TODO(sirver): the main loop should not be in UI, but in WLApplication.
 	WLApplication * const app = WLApplication::get();
@@ -174,7 +174,7 @@
 
 		app->handle_input(&icb);
 		if (app->should_die())
-			end_modal(dying_code);
+			end_modal<Returncodes>(Returncodes::kBack);
 
 		do_think();
 
@@ -186,7 +186,7 @@
 			rt.blit
 				(app->get_mouse_position() - Point(3, 7),
 				 WLApplication::get()->is_mouse_pressed() ?
-				 	s_default_cursor_click :
+					s_default_cursor_click :
 					s_default_cursor);
 
 			forefather->do_tooltip();
@@ -213,16 +213,6 @@
 }
 
 /**
- * Cause run() to return as soon as possible, with the given return code
- */
-void Panel::end_modal(int32_t const code)
-{
-	_running = false;
-	_retcode = code;
-}
-
-
-/**
  * \return \c true if this is the currently modal panel
  */
 bool Panel::is_modal()
@@ -679,7 +669,7 @@
  * Default is enabled. Note that when mouse handling is disabled, child panels
  * don't receive mouse events either.
  *
- * \param yes rue if the panel should receive mouse events
+ * \param yes true if the panel should receive mouse events
  */
 void Panel::set_handle_mouse(bool const yes)
 {

=== modified file 'src/ui_basic/panel.h'
--- src/ui_basic/panel.h	2014-11-29 20:37:34 +0000
+++ src/ui_basic/panel.h	2015-08-06 17:33:02 +0000
@@ -88,9 +88,26 @@
 	void free_children();
 
 	// Modal
-	static const int32_t dying_code = -1;
-	int32_t run();
-	void end_modal(int32_t code);
+	enum class Returncodes {
+		kBack,
+		kOk
+	};
+
+	template<typename Returncode>
+	Returncode run() {
+		return static_cast<Returncode>(do_run());
+	}
+	int do_run();
+
+	/**
+	 * Cause run() to return as soon as possible, with the given return code
+	 */
+	template<typename Returncode>
+	void end_modal(const Returncode& code) {
+		_running = false;
+		_retcode = static_cast<int>(code);
+	}
+
 	bool is_modal();
 
 	virtual void start();
@@ -310,7 +327,7 @@
 	uint32_t _desired_w, _desired_h;
 
 	bool _running;
-	int32_t _retcode;
+	int _retcode;
 
 	std::string _tooltip;
 	static Panel * _modal;

=== modified file 'src/ui_basic/window.cc'
--- src/ui_basic/window.cc	2014-11-27 19:13:30 +0000
+++ src/ui_basic/window.cc	2015-08-06 17:33:02 +0000
@@ -477,7 +477,7 @@
 void Window::die()
 {
 	if (is_modal()) {
-		end_modal(0);
+		end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack);
 	} else {
 		Panel::die();
 	}

=== modified file 'src/ui_fsmenu/base.cc'
--- src/ui_fsmenu/base.cc	2014-12-11 10:27:30 +0000
+++ src/ui_fsmenu/base.cc	2015-08-06 17:33:02 +0000
@@ -77,3 +77,29 @@
 uint32_t FullscreenMenuBase::fs_big() {
 	return UI_FONT_SIZE_BIG * get_h() / 600;
 }
+
+bool FullscreenMenuBase::handle_key(bool down, SDL_Keysym code)
+{
+	if (down) {
+		switch (code.sym) {
+			case SDLK_KP_ENTER:
+			case SDLK_RETURN:
+				clicked_ok();
+				return true;
+			case SDLK_ESCAPE:
+				clicked_back();
+				return true;
+			default:
+				break; // not handled
+		}
+	}
+	return UI::Panel::handle_key(down, code);
+}
+
+
+void FullscreenMenuBase::clicked_back() {
+	end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kBack);
+}
+void FullscreenMenuBase::clicked_ok() {
+	end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kOk);
+}

=== modified file 'src/ui_fsmenu/base.h'
--- src/ui_fsmenu/base.h	2014-12-06 12:22:35 +0000
+++ src/ui_fsmenu/base.h	2015-08-06 17:33:02 +0000
@@ -40,16 +40,58 @@
  */
 class FullscreenMenuBase : public UI::Panel {
 public:
+	enum class MenuTarget {
+		kBack = UI::Panel::Returncodes::kBack,
+		kOk = UI::Panel::Returncodes::kOk,
+
+		// Options
+		kRestart,
+
+		// Main menu
+		kTutorial,
+		kSinglePlayer,
+		kMultiplayer,
+		kReplay,
+		kEditor,
+		kOptions,
+		kReadme,
+		kLicense,
+		kAuthors,
+		kExit,
+
+		// Single player
+		kNewGame,
+		kCampaign,
+		kLoadGame,
+
+		// Multiplayer
+		kMetaserver,
+		kLan,
+
+		// Launch game
+		kNormalGame,
+		kScenarioGame,
+		kMultiPlayerSavegame,
+		kHostgame,
+		kJoingame
+	};
+
 	FullscreenMenuBase(char const * bgpic);
 	virtual ~FullscreenMenuBase();
 
 	void draw(RenderTarget &) override;
 
-public:
 	///\return the size for texts fitting to current resolution
 	uint32_t fs_small();
 	uint32_t fs_big();
 
+	/// Handle keypresses
+	bool handle_key(bool down, SDL_Keysym code) override;
+
+protected:
+	virtual void clicked_back();
+	virtual void clicked_ok();
+
 private:
 	std::string background_image_;
 };

=== modified file 'src/ui_fsmenu/campaign_select.cc'
--- src/ui_fsmenu/campaign_select.cc	2015-05-02 09:47:26 +0000
+++ src/ui_fsmenu/campaign_select.cc	2015-08-06 17:33:02 +0000
@@ -93,16 +93,10 @@
 	m_ta_difficulty.set_tooltip(_("The difficulty of this campaign"));
 	m_ta_description.set_tooltip(_("Story and hints"));
 
-	m_ok.sigclicked.connect
-		(boost::bind
-			 (&FullscreenMenuCampaignSelect::clicked_ok, boost::ref(*this)));
-	m_back.sigclicked.connect
-		(boost::bind
-			 (&FullscreenMenuCampaignSelect::clicked_back, boost::ref(*this)));
-	m_table.selected.connect
-		(boost::bind(&FullscreenMenuCampaignSelect::entry_selected, this));
-	m_table.double_clicked.connect
-		(boost::bind(&FullscreenMenuCampaignSelect::clicked_ok, boost::ref(*this)));
+	m_ok.sigclicked.connect(boost::bind(&FullscreenMenuCampaignSelect::clicked_ok, boost::ref(*this)));
+	m_back.sigclicked.connect(boost::bind(&FullscreenMenuCampaignSelect::clicked_back, boost::ref(*this)));
+	m_table.selected.connect(boost::bind(&FullscreenMenuCampaignSelect::entry_selected, this));
+	m_table.double_clicked.connect(boost::bind(&FullscreenMenuCampaignSelect::clicked_ok, boost::ref(*this)));
 
 	/** TRANSLATORS: Campaign difficulty table header */
 	m_table.add_column(45, _("Diff."), _("Difficulty"), UI::Align_Left);
@@ -123,7 +117,7 @@
 void FullscreenMenuCampaignSelect::clicked_ok()
 {
 	get_campaign();
-	end_modal(1);
+	end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kOk);
 }
 
 int32_t FullscreenMenuCampaignSelect::get_campaign()

=== modified file 'src/ui_fsmenu/fileview.cc'
--- src/ui_fsmenu/fileview.cc	2015-05-07 09:05:58 +0000
+++ src/ui_fsmenu/fileview.cc	2015-08-06 17:33:02 +0000
@@ -69,7 +69,10 @@
 		 g_gr->images().get("pics/but0.png"),
 		 _("Close"), std::string(), true, false)
 {
-	close_button.sigclicked.connect(boost::bind(&FullscreenMenuTextView::end_modal, boost::ref(*this), 0));
+	close_button.sigclicked.connect(
+				boost::bind(&FullscreenMenuTextView::end_modal<FullscreenMenuBase::MenuTarget>,
+								boost::ref(*this),
+								FullscreenMenuBase::MenuTarget::kBack));
 
 	title.set_font(ui_fn(), fs_big(), UI_FONT_CLR_FG);
 	title.set_pos

=== modified file 'src/ui_fsmenu/internet_lobby.cc'
--- src/ui_fsmenu/internet_lobby.cc	2015-01-21 20:57:11 +0000
+++ src/ui_fsmenu/internet_lobby.cc	2015-08-06 17:33:02 +0000
@@ -110,18 +110,11 @@
 	password(pwd),
 	reg(registered)
 {
-	joingame.sigclicked.connect
-		(boost::bind
-			 (&FullscreenMenuInternetLobby::clicked_joingame,
-			  boost::ref(*this)));
-	hostgame.sigclicked.connect
-		(boost::bind
-			 (&FullscreenMenuInternetLobby::clicked_hostgame,
-			  boost::ref(*this)));
-	back.sigclicked.connect
-		(boost::bind
-			 (&FullscreenMenuInternetLobby::clicked_back,
-			  boost::ref(*this)));
+	joingame.sigclicked.connect(
+				boost::bind(&FullscreenMenuInternetLobby::clicked_joingame, boost::ref(*this)));
+	hostgame.sigclicked.connect(
+				boost::bind(&FullscreenMenuInternetLobby::clicked_hostgame, boost::ref(*this)));
+	back.sigclicked.connect(boost::bind(&FullscreenMenuInternetLobby::clicked_back, boost::ref(*this)));
 
 	// Set the texts and style of UI elements
 	Section & s = g_options.pull_section("global"); //  for playername
@@ -159,9 +152,9 @@
 		(boost::bind(&FullscreenMenuInternetLobby::client_doubleclicked, this, _1));
 	opengames   .set_font(m_fn, m_fs);
 	opengames   .selected.connect
-		(boost::bind(&FullscreenMenuInternetLobby::server_selected, this, _1));
+		(boost::bind(&FullscreenMenuInternetLobby::server_selected, this));
 	opengames   .double_clicked.connect
-		(boost::bind(&FullscreenMenuInternetLobby::server_doubleclicked, this, _1));
+		(boost::bind(&FullscreenMenuInternetLobby::server_doubleclicked, this));
 
 	// try to connect to the metaserver
 	if (!InternetGaming::ref().error() && !InternetGaming::ref().logged_in())
@@ -192,6 +185,16 @@
 		fill_games_list(InternetGaming::ref().games());
 }
 
+void FullscreenMenuInternetLobby::clicked_ok()
+{
+	if (joingame.enabled()) {
+		server_doubleclicked();
+	} else {
+		clicked_hostgame();
+	}
+}
+
+
 
 /// connects Widelands with the metaserver
 void FullscreenMenuInternetLobby::connect_to_metaserver()
@@ -326,7 +329,7 @@
 
 
 /// called when an entry of the server list was selected
-void FullscreenMenuInternetLobby::server_selected (uint32_t)
+void FullscreenMenuInternetLobby::server_selected()
 {
 	if (opengames.has_selection()) {
 		const InternetGame * game = &opengames.get_selected();
@@ -339,7 +342,7 @@
 
 
 /// called when an entry of the server list was doubleclicked
-void FullscreenMenuInternetLobby::server_doubleclicked (uint32_t)
+void FullscreenMenuInternetLobby::server_doubleclicked()
 {
 	// if the game is open try to connect it, if not do nothing.
 	if (opengames.has_selection()) {
@@ -378,14 +381,17 @@
 			 // give some time for the answer + for a relogin, if a problem occurs.
 			if ((INTERNET_GAMING_TIMEOUT * 5 / 3) < time(nullptr) - secs) {
 				// Show a popup warning message
-				std::string warningheader(_("Connection timed out"));
-				std::string warning
+				const std::string warning
 					(_
 						("Widelands was unable to get the IP address of the server in time.\n"
 						 "There seems to be a network problem, either on your side or on the side\n"
 						 "of the server.\n"));
-				UI::WLMessageBox mmb(this, warningheader, warning, UI::WLMessageBox::OK, UI::Align_Left);
-				mmb.run();
+				UI::WLMessageBox mmb(this,
+											_("Connection timed out"),
+											warning,
+											UI::WLMessageBox::MBoxType::kOk,
+											UI::Align_Left);
+				mmb.run<UI::Panel::Returncodes>();
 				return InternetGaming::ref().set_error();
 			}
 		}
@@ -410,8 +416,8 @@
 			// Show a popup warning message
 			std::string warningheader(_("Connection problem"));
 			std::string warning(_("Widelands was unable to connect to the host."));
-			UI::WLMessageBox mmb(this, warningheader, warning, UI::WLMessageBox::OK, UI::Align_Left);
-			mmb.run();
+			UI::WLMessageBox mmb(this, warningheader, warning, UI::WLMessageBox::MBoxType::kOk, UI::Align_Left);
+			mmb.run<UI::Panel::Returncodes>();
 		}
 		SDLNet_ResolveHost (&peer, ip.c_str(), WIDELANDS_PORT);
 
@@ -435,11 +441,3 @@
 	NetHost netgame(InternetGaming::ref().get_local_clientname(), true);
 	netgame.run();
 }
-
-
-/// called when the 'back' button was clicked
-void FullscreenMenuInternetLobby::clicked_back()
-{
-	// Close the lobby UI
-	end_modal(0);
-}

=== modified file 'src/ui_fsmenu/internet_lobby.h'
--- src/ui_fsmenu/internet_lobby.h	2015-01-21 20:57:11 +0000
+++ src/ui_fsmenu/internet_lobby.h	2015-08-06 17:33:02 +0000
@@ -41,6 +41,9 @@
 
 	void think() override;
 
+protected:
+	void clicked_ok() override;
+
 private:
 	uint32_t m_butx;
 	uint32_t m_butw;
@@ -68,13 +71,12 @@
 	void connect_to_metaserver();
 
 	void client_doubleclicked (uint32_t);
-	void server_selected (uint32_t);
-	void server_doubleclicked (uint32_t);
+	void server_selected();
+	void server_doubleclicked();
 
 	void change_servername();
 	void clicked_joingame();
 	void clicked_hostgame();
-	void clicked_back();
 
 	uint8_t convert_clienttype(const std::string &);
 	bool compare_clienttype(unsigned int rowa, unsigned int rowb);

=== modified file 'src/ui_fsmenu/intro.cc'
--- src/ui_fsmenu/intro.cc	2014-11-29 20:37:34 +0000
+++ src/ui_fsmenu/intro.cc	2015-08-06 17:33:02 +0000
@@ -29,14 +29,14 @@
 m_message
 	(this,
 	 get_w() / 2, get_h() * 19 / 20,
-	 _("Press ESC or click to continue ..."), UI::Align_HCenter)
+	 _("Press any key or click to continue ..."), UI::Align_HCenter)
 {
 	m_message.set_font(ui_fn(), fs_small() * 6 / 5, RGBColor(192, 192, 128));
 }
 
 bool FullscreenMenuIntro::handle_mousepress  (uint8_t, int32_t, int32_t)
 {
-	end_modal(0);
+	end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kOk);
 
 	return true;
 }
@@ -45,10 +45,11 @@
 	return true;
 }
 
-bool FullscreenMenuIntro::handle_key(bool const down, SDL_Keysym const code)
+bool FullscreenMenuIntro::handle_key(const bool down, const SDL_Keysym)
 {
-	if (down && code.sym == SDLK_ESCAPE)
-		end_modal(0);
+	if (down) {
+		end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kOk);
+	}
 
 	return false;
 }

=== modified file 'src/ui_fsmenu/launch_mpg.cc'
--- src/ui_fsmenu/launch_mpg.cc	2015-08-06 07:18:24 +0000
+++ src/ui_fsmenu/launch_mpg.cc	2015-08-06 17:33:02 +0000
@@ -67,7 +67,8 @@
 			 _("Map"), _("Select a map"), true, false);
 		btn->sigclicked.connect
 			(boost::bind
-				 (&MapOrSaveSelectionWindow::pressedButton, boost::ref(*this), 1));
+				 (&MapOrSaveSelectionWindow::pressedButton, boost::ref(*this),
+				  FullscreenMenuBase::MenuTarget::kNormalGame));
 
 		btn = new UI::Button
 			(this, "saved_game",
@@ -77,7 +78,8 @@
 			 _("Saved Game"), _("Select a saved game"), true, false);
 		btn->sigclicked.connect
 			(boost::bind
-				 (&MapOrSaveSelectionWindow::pressedButton, boost::ref(*this), 2));
+				 (&MapOrSaveSelectionWindow::pressedButton, boost::ref(*this),
+				  FullscreenMenuBase::MenuTarget::kScenarioGame));
 
 		btn = new UI::Button
 			(this, "cancel",
@@ -86,7 +88,8 @@
 			 _("Cancel"), _("Cancel selection"), true, false);
 		btn->sigclicked.connect
 			(boost::bind
-				 (&MapOrSaveSelectionWindow::pressedButton, boost::ref(*this), 0));
+				 (&MapOrSaveSelectionWindow::pressedButton, boost::ref(*this),
+				  FullscreenMenuBase::MenuTarget::kBack));
 	}
 
 
@@ -95,8 +98,8 @@
 			m_ctrl->think();
 	}
 
-	void pressedButton(uint8_t i) {
-		end_modal(i);
+	void pressedButton(FullscreenMenuBase::MenuTarget i) {
+		end_modal<FullscreenMenuBase::MenuTarget>(i);
 	}
 	private:
 		GameController * m_ctrl;
@@ -187,10 +190,8 @@
 	m_change_map_or_save.sigclicked.connect
 		(boost::bind
 			 (&FullscreenMenuLaunchMPG::change_map_or_save, boost::ref(*this)));
-	m_ok.sigclicked.connect
-		(boost::bind
-			 (&FullscreenMenuLaunchMPG::start_clicked, boost::ref(*this)));
-	m_back.sigclicked.connect(boost::bind(&FullscreenMenuLaunchMPG::back_clicked, boost::ref(*this)));
+	m_ok.sigclicked.connect(boost::bind(&FullscreenMenuLaunchMPG::clicked_ok, boost::ref(*this)));
+	m_back.sigclicked.connect(boost::bind(&FullscreenMenuLaunchMPG::clicked_back, boost::ref(*this)));
 	m_wincondition.sigclicked.connect
 		(boost::bind
 			 (&FullscreenMenuLaunchMPG::win_condition_clicked,
@@ -272,9 +273,9 @@
 /**
  * back-button has been pressed
  */
-void FullscreenMenuLaunchMPG::back_clicked()
+void FullscreenMenuLaunchMPG::clicked_back()
 {
-	end_modal(0);
+	end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kBack);
 }
 
 /**
@@ -323,11 +324,11 @@
 void FullscreenMenuLaunchMPG::change_map_or_save() {
 	MapOrSaveSelectionWindow selection_window
 		(this, m_ctrl, get_w() / 3, get_h() / 4);
-	switch (selection_window.run()) {
-		case 1:
+	switch (selection_window.run<FullscreenMenuBase::MenuTarget>()) {
+		case FullscreenMenuBase::MenuTarget::kNormalGame:
 			select_map();
 			break;
-		case 2:
+		case FullscreenMenuBase::MenuTarget::kScenarioGame:
 			select_saved_game();
 			break;
 		default:
@@ -343,15 +344,15 @@
 		return;
 
 	FullscreenMenuMapSelect msm(m_settings, m_ctrl);
-	int code = msm.run();
+	FullscreenMenuBase::MenuTarget code = msm.run<FullscreenMenuBase::MenuTarget>();
 
-	if (code <= 0) {
+	if (code == FullscreenMenuBase::MenuTarget::kBack) {
 		// Set scenario = false, else the menu might crash when back is pressed.
 		m_settings->set_scenario(false);
-		return;  // back was pressed
+		return;
 	}
 
-	m_settings->set_scenario(code == 2);
+	m_settings->set_scenario(code == FullscreenMenuBase::MenuTarget::kScenarioGame);
 
 	const MapData & mapdata = *msm.get_map();
 	m_nr_players = mapdata.nrplayers;
@@ -375,10 +376,11 @@
 
 	Widelands::Game game; // The place all data is saved to.
 	FullscreenMenuLoadGame lsgm(game, m_settings, m_ctrl);
-	int code = lsgm.run();
+	FullscreenMenuBase::MenuTarget code = lsgm.run<FullscreenMenuBase::MenuTarget>();
 
-	if (code <= 0)
+	if (code == FullscreenMenuBase::MenuTarget::kBack) {
 		return; // back was pressed
+	}
 
 	// Saved game was selected - therefore not a scenario
 	m_settings->set_scenario(false);
@@ -409,8 +411,8 @@
 					"true or manually unzipped the saved game.\n"
 					"Widelands is not able to transfer directory structures to the clients,"
 					" please select another saved game or zip the directories’ content."),
-				UI::WLMessageBox::OK);
-			warning.run();
+				UI::WLMessageBox::MBoxType::kOk);
+			warning.run<UI::Panel::Returncodes>();
 		}
 	} else {
 		if (!m_settings || m_settings->settings().saved_games.empty())
@@ -428,7 +430,7 @@
 /**
  * start-button has been pressed
  */
-void FullscreenMenuLaunchMPG::start_clicked()
+void FullscreenMenuLaunchMPG::clicked_ok()
 {
 	if (!g_fs->file_exists(m_settings->settings().mapfilename))
 		throw WLWarning
@@ -443,7 +445,7 @@
 			  "finished!?!"),
 			 m_settings->settings().mapfilename.c_str());
 	if (m_settings->can_launch())
-		end_modal(1);
+		end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kNormalGame);
 }
 
 
@@ -509,7 +511,6 @@
 	m_mpsg->refresh();
 }
 
-
 /**
  * if map was selected to be loaded as scenario, set all values like
  * player names and player tribes and take care about visibility

=== modified file 'src/ui_fsmenu/launch_mpg.h'
--- src/ui_fsmenu/launch_mpg.h	2014-11-13 08:39:14 +0000
+++ src/ui_fsmenu/launch_mpg.h	2015-08-06 17:33:02 +0000
@@ -41,12 +41,6 @@
  * Fullscreen menu for setting map and mapsettings for single and multi player
  * games.
  *
- * The return values of run() are:
- *    0  - back was pressed
- *    1  - normal game
- *    2  - scenario game
- *    3  - multi player savegame
- *    4  - multi player scenario savegame <- not yet implemented
  */
 class FullscreenMenuLaunchMPG : public FullscreenMenuBase {
 public:
@@ -59,14 +53,16 @@
 
 	void refresh();
 
+protected:
+	void clicked_ok() override;
+	void clicked_back() override;
+
 private:
 	LuaInterface * m_lua;
 
 	void change_map_or_save();
 	void select_map();
 	void select_saved_game();
-	void back_clicked();
-	void start_clicked();
 	void win_condition_clicked();
 	void win_condition_update();
 	void set_scenario_values();

=== modified file 'src/ui_fsmenu/launch_spg.cc'
--- src/ui_fsmenu/launch_spg.cc	2015-07-29 06:01:48 +0000
+++ src/ui_fsmenu/launch_spg.cc	2015-08-06 17:33:02 +0000
@@ -122,10 +122,10 @@
 		(boost::bind
 			 (&FullscreenMenuLaunchSPG::win_condition_clicked,
 			  boost::ref(*this)));
-	m_back.sigclicked.connect(boost::bind(&FullscreenMenuLaunchSPG::back_clicked, boost::ref(*this)));
+	m_back.sigclicked.connect(boost::bind(&FullscreenMenuLaunchSPG::clicked_back, boost::ref(*this)));
 	m_ok.sigclicked.connect
 		(boost::bind
-			 (&FullscreenMenuLaunchSPG::start_clicked, boost::ref(*this)));
+			 (&FullscreenMenuLaunchSPG::clicked_ok, boost::ref(*this)));
 
 	m_lua = new LuaInterface();
 	m_win_condition_scripts = m_settings->settings().win_condition_scripts;
@@ -178,8 +178,9 @@
 void FullscreenMenuLaunchSPG::start()
 {
 	select_map();
-	if (m_settings->settings().mapname.empty())
-		end_modal(0); // back was pressed
+	if (m_settings->settings().mapname.empty()) {
+		end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kBack);
+	}
 }
 
 
@@ -195,7 +196,7 @@
 /**
  * back-button has been pressed
  */
-void FullscreenMenuLaunchSPG::back_clicked()
+void FullscreenMenuLaunchSPG::clicked_back()
 {
 	//  The following behaviour might look strange at first view, but for the
 	//  user it seems as if the launchgame-menu is a child of mapselect and
@@ -204,7 +205,7 @@
 	m_settings->set_map(std::string(), std::string(), 0);
 	select_map();
 	if (m_settings->settings().mapname.empty())
-		return end_modal(0);
+		return end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kBack);
 	refresh();
 }
 
@@ -252,7 +253,7 @@
 /**
  * start-button has been pressed
  */
-void FullscreenMenuLaunchSPG::start_clicked()
+void FullscreenMenuLaunchSPG::clicked_ok()
 {
 	if (!g_fs->file_exists(m_filename))
 		throw WLWarning
@@ -267,7 +268,11 @@
 			 	 "finished!?!"),
 			 m_filename.c_str());
 	if (m_settings->can_launch()) {
-		end_modal(1 + m_is_scenario);
+		if (m_is_scenario) {
+			end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kScenarioGame);
+		} else {
+			end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kNormalGame);
+		}
 	}
 }
 
@@ -330,15 +335,15 @@
 		return;
 
 	FullscreenMenuMapSelect msm(m_settings, nullptr);
-	int code = msm.run();
+	FullscreenMenuBase::MenuTarget code = msm.run<FullscreenMenuBase::MenuTarget>();
 
-	if (code <= 0) {
+	if (code == FullscreenMenuBase::MenuTarget::kBack) {
 		// Set scenario = false, else the menu might crash when back is pressed.
 		m_settings->set_scenario(false);
 		return;  // back was pressed
 	}
 
-	m_is_scenario = code == 2;
+	m_is_scenario = code == FullscreenMenuBase::MenuTarget::kScenarioGame;
 	m_settings->set_scenario(m_is_scenario);
 
 	const MapData & mapdata = *msm.get_map();

=== modified file 'src/ui_fsmenu/launch_spg.h'
--- src/ui_fsmenu/launch_spg.h	2014-11-13 08:39:14 +0000
+++ src/ui_fsmenu/launch_spg.h	2015-08-06 17:33:02 +0000
@@ -44,10 +44,6 @@
  *    UI::Button m_select_map  - only shown if the player has the right to
  *                               change the map.
  *
- * The return values of run() are:
- *    0  - back was pressed
- *    1  - normal game (either single or multi player)
- *    2  - scenario game (at the moment only single player)
  */
 class FullscreenMenuLaunchSPG : public FullscreenMenuBase {
 public:
@@ -60,12 +56,14 @@
 
 	void refresh();
 
+protected:
+	void clicked_ok() override;
+	void clicked_back() override;
+
 private:
 	LuaInterface * m_lua;
 
 	void select_map();
-	void back_clicked();
-	void start_clicked();
 	void win_condition_clicked();
 	void win_condition_update();
 	void set_scenario_values();

=== modified file 'src/ui_fsmenu/load_map_or_game.cc'
--- src/ui_fsmenu/load_map_or_game.cc	2014-11-23 11:38:50 +0000
+++ src/ui_fsmenu/load_map_or_game.cc	2015-08-06 17:33:02 +0000
@@ -67,26 +67,6 @@
 		m_table(this, m_tablex, m_tabley, m_tablew, m_tableh, sort_descending)
 	{}
 
-bool FullscreenMenuLoadMapOrGame::handle_key(bool down, SDL_Keysym code) {
-
-	if (!down)
-		return false;
-
-	switch (code.sym)
-	{
-		case SDLK_KP_ENTER:
-		case SDLK_RETURN:
-			clicked_ok();
-			return true;
-		case SDLK_ESCAPE:
-			clicked_back();
-			return true;
-		default:
-			break; // not handled
-	}
-	return FullscreenMenuBase::handle_key(down, code);
-}
-
 int32_t FullscreenMenuLoadMapOrGame::get_y_from_preceding(UI::Panel& preceding_panel) {
 	return preceding_panel.get_y() + preceding_panel.get_h();
 }

=== modified file 'src/ui_fsmenu/load_map_or_game.h'
--- src/ui_fsmenu/load_map_or_game.h	2015-01-30 23:10:35 +0000
+++ src/ui_fsmenu/load_map_or_game.h	2015-08-06 17:33:02 +0000
@@ -76,12 +76,7 @@
 public:
 	FullscreenMenuLoadMapOrGame(bool sortdesc = false);
 
-	bool handle_key(bool down, SDL_Keysym code) override;
-
 protected:
-	virtual void clicked_ok() {end_modal(1);}
-	void clicked_back() {end_modal(0);}
-
 	// Updates the information display on the right-hand side.
 	// Call this function when a different entry in the table gets selected.
 	virtual void entry_selected() {}

=== modified file 'src/ui_fsmenu/loadgame.cc'
--- src/ui_fsmenu/loadgame.cc	2015-07-29 06:01:48 +0000
+++ src/ui_fsmenu/loadgame.cc	2015-08-06 17:33:02 +0000
@@ -244,7 +244,7 @@
 	const SavegameData & gamedata = m_games_data[m_table.get_selected()];
 	if (gamedata.errormessage.empty()) {
 		m_filename = gamedata.filename;
-		end_modal(1);
+		end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kOk);
 	}
 }
 
@@ -282,8 +282,8 @@
 	}
 
 	UI::WLMessageBox confirmationBox
-		(this, _("Confirm deleting file"), message, UI::WLMessageBox::YESNO);
-	if (confirmationBox.run()) {
+		(this, _("Confirm deleting file"), message, UI::WLMessageBox::MBoxType::kOkCancel);
+	if (confirmationBox.run<UI::Panel::Returncodes>() == UI::Panel::Returncodes::kOk) {
 		g_fs->fs_unlink(gamedata.filename);
 		if (m_is_replay) {
 			g_fs->fs_unlink(gamedata.filename + WLGF_SUFFIX);

=== modified file 'src/ui_fsmenu/main.cc'
--- src/ui_fsmenu/main.cc	2015-04-18 11:20:53 +0000
+++ src/ui_fsmenu/main.cc	2015-08-06 17:33:02 +0000
@@ -82,44 +82,44 @@
 {
 	playtutorial.sigclicked.connect
 		(boost::bind
-			 (&FullscreenMenuMain::end_modal, boost::ref(*this),
-			  static_cast<int32_t>(MenuTarget::kTutorial)));
+			 (&FullscreenMenuMain::end_modal<FullscreenMenuBase::MenuTarget>, boost::ref(*this),
+			  FullscreenMenuBase::MenuTarget::kTutorial));
 	singleplayer.sigclicked.connect
 		(boost::bind
-			 (&FullscreenMenuMain::end_modal, boost::ref(*this),
-			  static_cast<int32_t>(MenuTarget::kSinglePlayer)));
+			 (&FullscreenMenuMain::end_modal<FullscreenMenuBase::MenuTarget>, boost::ref(*this),
+			  FullscreenMenuBase::MenuTarget::kSinglePlayer));
 	multiplayer.sigclicked.connect
 		(boost::bind
-			 (&FullscreenMenuMain::end_modal, boost::ref(*this),
-			  static_cast<int32_t>(MenuTarget::kMultiplayer)));
+			 (&FullscreenMenuMain::end_modal<FullscreenMenuBase::MenuTarget>, boost::ref(*this),
+			  FullscreenMenuBase::MenuTarget::kMultiplayer));
 	replay.sigclicked.connect
 		(boost::bind
-			 (&FullscreenMenuMain::end_modal, boost::ref(*this),
-			  static_cast<int32_t>(MenuTarget::kReplay)));
+			 (&FullscreenMenuMain::end_modal<FullscreenMenuBase::MenuTarget>, boost::ref(*this),
+			  FullscreenMenuBase::MenuTarget::kReplay));
 	editor.sigclicked.connect
 		(boost::bind
-			 (&FullscreenMenuMain::end_modal, boost::ref(*this),
-			  static_cast<int32_t>(MenuTarget::kEditor)));
+			 (&FullscreenMenuMain::end_modal<FullscreenMenuBase::MenuTarget>, boost::ref(*this),
+			  FullscreenMenuBase::MenuTarget::kEditor));
 	options.sigclicked.connect
 		(boost::bind
-			 (&FullscreenMenuMain::end_modal, boost::ref(*this),
-			  static_cast<int32_t>(MenuTarget::kOptions)));
+			 (&FullscreenMenuMain::end_modal<FullscreenMenuBase::MenuTarget>, boost::ref(*this),
+			  FullscreenMenuBase::MenuTarget::kOptions));
 	readme.sigclicked.connect
 		(boost::bind
-			 (&FullscreenMenuMain::end_modal, boost::ref(*this),
-			  static_cast<int32_t>(MenuTarget::kReadme)));
+			 (&FullscreenMenuMain::end_modal<FullscreenMenuBase::MenuTarget>, boost::ref(*this),
+			  FullscreenMenuBase::MenuTarget::kReadme));
 	license.sigclicked.connect
 		(boost::bind
-			 (&FullscreenMenuMain::end_modal, boost::ref(*this),
-			  static_cast<int32_t>(MenuTarget::kLicense)));
+			 (&FullscreenMenuMain::end_modal<FullscreenMenuBase::MenuTarget>, boost::ref(*this),
+			  FullscreenMenuBase::MenuTarget::kLicense));
 	authors.sigclicked.connect
 		(boost::bind
-			 (&FullscreenMenuMain::end_modal, boost::ref(*this),
-			  static_cast<int32_t>(MenuTarget::kAuthors)));
+			 (&FullscreenMenuMain::end_modal<FullscreenMenuBase::MenuTarget>, boost::ref(*this),
+			  FullscreenMenuBase::MenuTarget::kAuthors));
 	exit.sigclicked.connect
 		(boost::bind
-			 (&FullscreenMenuMain::end_modal, boost::ref(*this),
-			  static_cast<int32_t>(MenuTarget::kExit)));
+			 (&FullscreenMenuMain::end_modal<FullscreenMenuBase::MenuTarget>, boost::ref(*this),
+			  FullscreenMenuBase::MenuTarget::kExit));
 
 	vbox.add(&playtutorial, UI::Box::AlignCenter);
 
@@ -149,3 +149,8 @@
 
 	vbox.set_size(m_butw, get_h() - vbox.get_y());
 }
+
+void FullscreenMenuMain::clicked_ok() {
+	; // do nothing
+}
+

=== modified file 'src/ui_fsmenu/main.h'
--- src/ui_fsmenu/main.h	2014-11-13 11:29:20 +0000
+++ src/ui_fsmenu/main.h	2015-08-06 17:33:02 +0000
@@ -31,21 +31,11 @@
 */
 class FullscreenMenuMain : public FullscreenMenuMainMenu {
 public:
-	enum class MenuTarget: int32_t {
-		kTutorial,
-		kSinglePlayer,
-		kMultiplayer,
-		kReplay,
-		kEditor,
-		kOptions,
-		kReadme,
-		kLicense,
-		kAuthors,
-		kExit
-	};
-
 	FullscreenMenuMain();
 
+protected:
+	void clicked_ok() override;
+
 private:
 	UI::Box      vbox;
 	UI::Button   playtutorial;

=== modified file 'src/ui_fsmenu/mapselect.cc'
--- src/ui_fsmenu/mapselect.cc	2015-05-02 09:47:26 +0000
+++ src/ui_fsmenu/mapselect.cc	2015-08-06 17:33:02 +0000
@@ -256,7 +256,11 @@
 		m_curdir = mapdata.filename;
 		fill_table();
 	} else {
-		end_modal(1 + is_scenario());
+		if (is_scenario()) {
+			end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kScenarioGame);
+		} else {
+			end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kNormalGame);
+		}
 	}
 }
 

=== modified file 'src/ui_fsmenu/multiplayer.cc'
--- src/ui_fsmenu/multiplayer.cc	2015-04-18 11:20:53 +0000
+++ src/ui_fsmenu/multiplayer.cc	2015-08-06 17:33:02 +0000
@@ -50,13 +50,13 @@
 
 	lan.sigclicked.connect
 		(boost::bind
-			 (&FullscreenMenuMultiPlayer::end_modal, boost::ref(*this),
-			  static_cast<int32_t>(MenuTarget::kLan)));
+			 (&FullscreenMenuMultiPlayer::end_modal<FullscreenMenuBase::MenuTarget>, boost::ref(*this),
+			  FullscreenMenuBase::MenuTarget::kLan));
 
 	back.sigclicked.connect
 		(boost::bind
-			 (&FullscreenMenuMultiPlayer::end_modal, boost::ref(*this),
-			  static_cast<int32_t>(MenuTarget::kBack)));
+			 (&FullscreenMenuMultiPlayer::end_modal<FullscreenMenuBase::MenuTarget>, boost::ref(*this),
+			  FullscreenMenuBase::MenuTarget::kBack));
 
 	title.set_font(ui_fn(), fs_big(), UI_FONT_CLR_FG);
 
@@ -114,12 +114,12 @@
 		m_nickname = s.get_string("nickname", _("nobody"));
 		m_password = s.get_string("password", "nobody");
 		m_register = s.get_bool("registered", false);
-		end_modal(static_cast<int32_t>(MenuTarget::kMetaserver));
+		end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kMetaserver);
 		return;
 	}
 
 	LoginBox lb(*this);
-	if (lb.run()) {
+	if (lb.run<UI::Panel::Returncodes>() == UI::Panel::Returncodes::kOk) {
 		m_nickname = lb.get_nickname();
 		m_password = lb.get_password();
 		m_register = lb.registered();
@@ -127,6 +127,10 @@
 		s.set_bool("registered", lb.registered());
 		s.set_bool("auto_log", lb.set_automaticlog());
 
-		end_modal(static_cast<int32_t>(MenuTarget::kMetaserver));
+		end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kMetaserver);
 	}
 }
+
+void FullscreenMenuMultiPlayer::clicked_ok() {
+	internet_login();
+}

=== modified file 'src/ui_fsmenu/multiplayer.h'
--- src/ui_fsmenu/multiplayer.h	2014-11-13 11:29:20 +0000
+++ src/ui_fsmenu/multiplayer.h	2015-08-06 17:33:02 +0000
@@ -34,18 +34,15 @@
 public:
 	FullscreenMenuMultiPlayer();
 
-	enum class MenuTarget: int32_t {
-		kBack = UI::Panel::dying_code,
-		kMetaserver,
-		kLan
-	};
-
 	void show_internet_login();
 	void internet_login();
 	std::string get_nickname() {return m_nickname;}
 	std::string get_password() {return m_password;}
 	bool registered()          {return m_register;}
 
+protected:
+	void clicked_ok() override;
+
 private:
 	UI::Textarea title;
 	UI::Box      vbox;

=== modified file 'src/ui_fsmenu/netsetup_lan.cc'
--- src/ui_fsmenu/netsetup_lan.cc	2014-12-06 12:22:35 +0000
+++ src/ui_fsmenu/netsetup_lan.cc	2015-08-06 17:33:02 +0000
@@ -98,8 +98,7 @@
 			 (&FullscreenMenuNetSetupLAN::clicked_hostgame, boost::ref(*this)));
 	back.sigclicked.connect
 		(boost::bind
-			 (&FullscreenMenuNetSetupLAN::end_modal, boost::ref(*this),
-			  static_cast<int32_t>(CANCEL)));
+			 (&FullscreenMenuNetSetupLAN::clicked_back, boost::ref(*this)));
 	loadlasthost.sigclicked.connect
 		(boost::bind
 			 (&FullscreenMenuNetSetupLAN::clicked_lasthost, boost::ref(*this)));
@@ -164,6 +163,13 @@
 	return playername.text();
 }
 
+void FullscreenMenuNetSetupLAN::clicked_ok() {
+	if (hostname.text().empty()) {
+		clicked_hostgame();
+	} else {
+		clicked_joingame();
+	}
+}
 
 void FullscreenMenuNetSetupLAN::game_selected (uint32_t) {
 	if (opengames.has_selection()) {
@@ -243,11 +249,11 @@
 	// Save selected host so users can reload it for reconnection.
 	g_options.pull_section("global").set_string("lasthost", hostname.text());
 
-	end_modal(JOINGAME);
+	end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kJoingame);
 }
 
 void FullscreenMenuNetSetupLAN::clicked_hostgame() {
-	end_modal(HOSTGAME);
+	end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kHostgame);
 }
 
 void FullscreenMenuNetSetupLAN::clicked_lasthost() {

=== modified file 'src/ui_fsmenu/netsetup_lan.h'
--- src/ui_fsmenu/netsetup_lan.h	2014-11-13 08:39:14 +0000
+++ src/ui_fsmenu/netsetup_lan.h	2015-08-06 17:33:02 +0000
@@ -36,12 +36,6 @@
 
 class FullscreenMenuNetSetupLAN : public FullscreenMenuBase {
 public:
-	enum {
-		CANCEL = 0,
-		HOSTGAME,
-		JOINGAME,
-	};
-
 	FullscreenMenuNetSetupLAN ();
 
 	void think() override;
@@ -59,6 +53,9 @@
 	 */
 	const std::string & get_playername();
 
+protected:
+	void clicked_ok() override;
+
 private:
 	uint32_t m_butx;
 	uint32_t m_butw;

=== modified file 'src/ui_fsmenu/options.cc'
--- src/ui_fsmenu/options.cc	2015-08-02 10:12:49 +0000
+++ src/ui_fsmenu/options.cc	2015-08-06 17:33:02 +0000
@@ -305,10 +305,8 @@
 {
 	m_advanced_options.sigclicked.connect
 		(boost::bind(&FullscreenMenuOptions::advanced_options, boost::ref(*this)));
-	m_cancel.sigclicked.connect
-		(boost::bind(&FullscreenMenuOptions::end_modal, this, static_cast<int32_t>(om_cancel)));
-	m_apply.sigclicked.connect
-		(boost::bind(&FullscreenMenuOptions::end_modal, this, static_cast<int32_t>(om_ok)));
+	m_cancel.sigclicked.connect(boost::bind(&FullscreenMenuOptions::clicked_back, this));
+	m_apply.sigclicked.connect(boost::bind(&FullscreenMenuOptions::clicked_ok, this));
 
 	/** TRANSLATORS Options: Save game automatically every: */
 	m_sb_autosave     .add_replacement(0, _("Off"));
@@ -396,9 +394,9 @@
 
 void FullscreenMenuOptions::advanced_options() {
 	FullscreenMenuAdvancedOptions aom(os);
-	if (aom.run() == FullscreenMenuAdvancedOptions::om_ok) {
+	if (aom.run<FullscreenMenuBase::MenuTarget>() == FullscreenMenuBase::MenuTarget::kOk) {
 		os = aom.get_values();
-		end_modal(om_restart);
+		end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kRestart);
 	}
 }
 
@@ -464,25 +462,6 @@
 }
 
 
-bool FullscreenMenuOptions::handle_key(bool down, SDL_Keysym code)
-{
-	if (down) {
-		switch (code.sym) {
-			case SDLK_KP_ENTER:
-			case SDLK_RETURN:
-				end_modal(static_cast<int32_t>(om_ok));
-				return true;
-			case SDLK_ESCAPE:
-				end_modal(static_cast<int32_t>(om_cancel));
-				return true;
-			default:
-				break; // not handled
-		}
-	}
-
-	return FullscreenMenuBase::handle_key(down, code);
-}
-
 OptionsCtrl::OptionsStruct FullscreenMenuOptions::get_values() {
 	const uint32_t res_index = m_reslist.selection_index();
 
@@ -622,16 +601,8 @@
 					 boost::ref(*this)));
 	}
 
-	m_cancel.sigclicked.connect
-		(boost::bind
-			(&FullscreenMenuAdvancedOptions::end_modal,
-			 boost::ref(*this),
-			 static_cast<int32_t>(om_cancel)));
-	m_apply.sigclicked.connect
-		(boost::bind
-			(&FullscreenMenuAdvancedOptions::end_modal,
-			 boost::ref(*this),
-			 static_cast<int32_t>(om_ok)));
+	m_cancel.sigclicked.connect(boost::bind(&FullscreenMenuAdvancedOptions::clicked_back, boost::ref(*this)));
+	m_apply.sigclicked.connect(boost::bind(&FullscreenMenuAdvancedOptions::clicked_ok, boost::ref(*this)));
 
 	m_title                .set_textstyle(UI::TextStyle::ui_big());
 	m_message_sound        .set_state(opt.message_sound);
@@ -640,25 +611,6 @@
 	m_transparent_chat     .set_state(opt.transparent_chat);
 }
 
-bool FullscreenMenuAdvancedOptions::handle_key(bool down, SDL_Keysym code)
-{
-	if (down) {
-		switch (code.sym) {
-			case SDLK_KP_ENTER:
-			case SDLK_RETURN:
-				end_modal(static_cast<int32_t>(om_ok));
-				return true;
-			case SDLK_ESCAPE:
-				end_modal(static_cast<int32_t>(om_cancel));
-				return true;
-			default:
-				break; // not handled
-		}
-	}
-
-	return FullscreenMenuBase::handle_key(down, code);
-}
-
 void FullscreenMenuAdvancedOptions::update_sb_dis_panel_unit() {
 	m_sb_dis_panel.set_unit(ngettext("pixel", "pixels", m_sb_dis_panel.get_value()));
 }
@@ -694,10 +646,10 @@
 
 void OptionsCtrl::handle_menu()
 {
-	int32_t i = m_opt_dialog->run();
-	if (i != FullscreenMenuOptions::om_cancel)
+	FullscreenMenuBase::MenuTarget i = m_opt_dialog->run<FullscreenMenuBase::MenuTarget>();
+	if (i != FullscreenMenuBase::MenuTarget::kBack)
 		save_options();
-	if (i == FullscreenMenuOptions::om_restart) {
+	if (i == FullscreenMenuBase::MenuTarget::kRestart) {
 		delete m_opt_dialog;
 		m_opt_dialog = new FullscreenMenuOptions(options_struct());
 		handle_menu(); // Restart general options menu

=== modified file 'src/ui_fsmenu/options.h'
--- src/ui_fsmenu/options.h	2015-01-12 09:19:59 +0000
+++ src/ui_fsmenu/options.h	2015-08-06 17:33:02 +0000
@@ -84,14 +84,6 @@
 public:
 	FullscreenMenuOptions(OptionsCtrl::OptionsStruct opt);
 	OptionsCtrl::OptionsStruct get_values();
-	enum {
-		om_cancel  = 0,
-		om_ok      = 1,
-		om_restart = 2
-	};
-
-	/// Handle keypresses
-	bool handle_key(bool down, SDL_Keysym code) override;
 
 private:
 	uint32_t const              m_vbutw;
@@ -166,13 +158,6 @@
 public:
 	FullscreenMenuAdvancedOptions(OptionsCtrl::OptionsStruct opt);
 	OptionsCtrl::OptionsStruct get_values();
-	enum {
-		om_cancel =   0,
-		om_ok     =   1
-	};
-
-	/// Handle keypresses
-	bool handle_key(bool down, SDL_Keysym code) override;
 
 private:
 	void update_sb_dis_panel_unit();

=== modified file 'src/ui_fsmenu/singleplayer.cc'
--- src/ui_fsmenu/singleplayer.cc	2015-04-18 11:20:53 +0000
+++ src/ui_fsmenu/singleplayer.cc	2015-08-06 17:33:02 +0000
@@ -50,24 +50,24 @@
 {
 	new_game.sigclicked.connect
 		(boost::bind
-			(&FullscreenMenuSinglePlayer::end_modal,
+			(&FullscreenMenuSinglePlayer::end_modal<FullscreenMenuBase::MenuTarget>,
 			 boost::ref(*this),
-			 static_cast<int32_t>(MenuTarget::kNewGame)));
+			 FullscreenMenuBase::MenuTarget::kNewGame));
 	campaign.sigclicked.connect
 		(boost::bind
-			(&FullscreenMenuSinglePlayer::end_modal,
+			(&FullscreenMenuSinglePlayer::end_modal<FullscreenMenuBase::MenuTarget>,
 			 boost::ref(*this),
-			 static_cast<int32_t>(MenuTarget::kCampaign)));
+			 FullscreenMenuBase::MenuTarget::kCampaign));
 	load_game.sigclicked.connect
 		(boost::bind
-			(&FullscreenMenuSinglePlayer::end_modal,
+			(&FullscreenMenuSinglePlayer::end_modal<FullscreenMenuBase::MenuTarget>,
 			 boost::ref(*this),
-			 static_cast<int32_t>(MenuTarget::kLoadGame)));
+			 FullscreenMenuBase::MenuTarget::kLoadGame));
 	back.sigclicked.connect
 		(boost::bind
-			(&FullscreenMenuSinglePlayer::end_modal,
+			(&FullscreenMenuSinglePlayer::end_modal<FullscreenMenuBase::MenuTarget>,
 			 boost::ref(*this),
-			 static_cast<int32_t>(MenuTarget::kBack)));
+			 FullscreenMenuBase::MenuTarget::kBack));
 
 	title.set_font(ui_fn(), fs_big(), UI_FONT_CLR_FG);
 
@@ -84,3 +84,7 @@
 
 	vbox.set_size(m_butw, get_h() - vbox.get_y());
 }
+
+void FullscreenMenuSinglePlayer::clicked_ok() {
+	end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kNewGame);
+}

=== modified file 'src/ui_fsmenu/singleplayer.h'
--- src/ui_fsmenu/singleplayer.h	2014-11-13 11:29:20 +0000
+++ src/ui_fsmenu/singleplayer.h	2015-08-06 17:33:02 +0000
@@ -33,12 +33,8 @@
 public:
 	FullscreenMenuSinglePlayer();
 
-	enum class MenuTarget: int32_t {
-		kBack = UI::Panel::dying_code,
-		kNewGame,
-		kCampaign,
-		kLoadGame
-	};
+protected:
+	void clicked_ok() override;
 
 private:
 	UI::Textarea title;

=== modified file 'src/wlapplication.cc'
--- src/wlapplication.cc	2015-06-09 09:22:36 +0000
+++ src/wlapplication.cc	2015-08-06 17:33:02 +0000
@@ -449,7 +449,7 @@
 
 		{
 			FullscreenMenuIntro intro;
-			intro.run();
+			intro.run<FullscreenMenuBase::MenuTarget>();
 		}
 
 		g_sound_handler.change_music("menu", 1000);
@@ -1049,53 +1049,53 @@
 				(&mm,
 				 messagetitle,
 				 message,
-				 UI::WLMessageBox::OK,
+				 UI::WLMessageBox::MBoxType::kOk,
 				 UI::Align_Left);
-			mmb.run();
+			mmb.run<UI::Panel::Returncodes>();
 
 			message.clear();
 			messagetitle.clear();
 		}
 
 		try {
-			switch (static_cast<FullscreenMenuMain::MenuTarget>(mm.run())) {
-			case FullscreenMenuMain::MenuTarget::kTutorial:
+			switch (mm.run<FullscreenMenuBase::MenuTarget>()) {
+			case FullscreenMenuBase::MenuTarget::kTutorial:
 				mainmenu_tutorial();
 				break;
-			case FullscreenMenuMain::MenuTarget::kSinglePlayer:
+			case FullscreenMenuBase::MenuTarget::kSinglePlayer:
 				mainmenu_singleplayer();
 				break;
-			case FullscreenMenuMain::MenuTarget::kMultiplayer:
+			case FullscreenMenuBase::MenuTarget::kMultiplayer:
 				mainmenu_multiplayer();
 				break;
-			case FullscreenMenuMain::MenuTarget::kReplay:
+			case FullscreenMenuBase::MenuTarget::kReplay:
 				replay();
 				break;
-			case FullscreenMenuMain::MenuTarget::kOptions: {
+			case FullscreenMenuBase::MenuTarget::kOptions: {
 				Section & s = g_options.pull_section("global");
 				OptionsCtrl om(s);
 				break;
 			}
-			case FullscreenMenuMain::MenuTarget::kReadme: {
+			case FullscreenMenuBase::MenuTarget::kReadme: {
 				FullscreenMenuFileView ff("txts/README.lua");
-				ff.run();
+				ff.run<FullscreenMenuBase::MenuTarget>();
 				break;
 			}
-			case FullscreenMenuMain::MenuTarget::kLicense: {
+			case FullscreenMenuBase::MenuTarget::kLicense: {
 				FullscreenMenuFileView ff("txts/LICENSE.lua");
-				ff.run();
+				ff.run<FullscreenMenuBase::MenuTarget>();
 				break;
 			}
-			case FullscreenMenuMain::MenuTarget::kAuthors: {
+			case FullscreenMenuBase::MenuTarget::kAuthors: {
 				FullscreenMenuFileView ff("txts/AUTHORS.lua");
-				ff.run();
+				ff.run<FullscreenMenuBase::MenuTarget>();
 				break;
 			}
-			case FullscreenMenuMain::MenuTarget::kEditor:
+			case FullscreenMenuBase::MenuTarget::kEditor:
 				EditorInteractive::run_editor(m_filename, m_script_to_run);
 				break;
 			default:
-			case FullscreenMenuMain::MenuTarget::kExit:
+			case FullscreenMenuBase::MenuTarget::kExit:
 				return;
 			}
 		} catch (const WLWarning & e) {
@@ -1140,7 +1140,7 @@
 		//  Start UI for the tutorials.
 		FullscreenMenuCampaignMapSelect select_campaignmap(true);
 		select_campaignmap.set_campaign(0);
-		if (select_campaignmap.run() > 0) {
+		if (select_campaignmap.run<FullscreenMenuBase::MenuTarget>() == FullscreenMenuBase::MenuTarget::kOk) {
 			filename = select_campaignmap.get_map();
 		}
 	try {
@@ -1161,26 +1161,27 @@
  */
 void WLApplication::mainmenu_singleplayer()
 {
-	//  This is the code returned by UI::Panel::run() when the panel is dying.
+	//  This is the code returned by UI::Panel::run<Returncode>() when the panel is dying.
 	//  Make sure that the program exits when the window manager says so.
 	static_assert
-		(static_cast<int32_t>(FullscreenMenuSinglePlayer::MenuTarget::kBack) == UI::Panel::dying_code,
+		(static_cast<int>(FullscreenMenuBase::MenuTarget::kBack)
+		 == static_cast<int>(UI::Panel::Returncodes::kBack),
 		 "Panel should be dying.");
 
 	for (;;) {
 		FullscreenMenuSinglePlayer single_player_menu;
-		switch (static_cast<FullscreenMenuSinglePlayer::MenuTarget>(single_player_menu.run())) {
-		case FullscreenMenuSinglePlayer::MenuTarget::kBack:
+		switch (single_player_menu.run<FullscreenMenuBase::MenuTarget>()) {
+		case FullscreenMenuBase::MenuTarget::kBack:
 			return;
-		case FullscreenMenuSinglePlayer::MenuTarget::kNewGame:
+		case FullscreenMenuBase::MenuTarget::kNewGame:
 			if (new_game())
 				return;
 			break;
-		case FullscreenMenuSinglePlayer::MenuTarget::kLoadGame:
+		case FullscreenMenuBase::MenuTarget::kLoadGame:
 			if (load_game())
 				return;
 			break;
-		case FullscreenMenuSinglePlayer::MenuTarget::kCampaign:
+		case FullscreenMenuBase::MenuTarget::kCampaign:
 			if (campaign_game())
 				return;
 			break;
@@ -1197,17 +1198,17 @@
  */
 void WLApplication::mainmenu_multiplayer()
 {
-	int32_t menu_result = FullscreenMenuNetSetupLAN::JOINGAME; // dummy init;
+	FullscreenMenuBase::MenuTarget menu_result = FullscreenMenuBase::MenuTarget::kJoingame; // dummy init;
 	for (;;) { // stay in menu until player clicks "back" button
 		bool internet = false;
 		FullscreenMenuMultiPlayer mp;
-		switch (static_cast<FullscreenMenuMultiPlayer::MenuTarget>(mp.run())) {
-			case FullscreenMenuMultiPlayer::MenuTarget::kBack:
+		switch (mp.run<FullscreenMenuBase::MenuTarget>()) {
+			case FullscreenMenuBase::MenuTarget::kBack:
 				return;
-			case FullscreenMenuMultiPlayer::MenuTarget::kMetaserver:
+			case FullscreenMenuBase::MenuTarget::kMetaserver:
 				internet = true;
 				break;
-			case FullscreenMenuMultiPlayer::MenuTarget::kLan:
+			case FullscreenMenuBase::MenuTarget::kLan:
 				break;
 			default:
 				assert(false);
@@ -1227,7 +1228,7 @@
 
 			// reinitalise in every run, else graphics look strange
 			FullscreenMenuInternetLobby ns(playername.c_str(), password.c_str(), registered);
-			ns.run();
+			ns.run<FullscreenMenuBase::MenuTarget>();
 
 			if (InternetGaming::ref().logged_in())
 				// logout of the metaserver
@@ -1238,19 +1239,19 @@
 		} else {
 			// reinitalise in every run, else graphics look strange
 			FullscreenMenuNetSetupLAN ns;
-			menu_result = ns.run();
+			menu_result = ns.run<FullscreenMenuBase::MenuTarget>();
 			std::string playername = ns.get_playername();
 			uint32_t addr;
 			uint16_t port;
 			bool const host_address = ns.get_host_address(addr, port);
 
 			switch (menu_result) {
-				case FullscreenMenuNetSetupLAN::HOSTGAME: {
+				case FullscreenMenuBase::MenuTarget::kHostgame: {
 					NetHost netgame(playername);
 					netgame.run();
 					break;
 				}
-				case FullscreenMenuNetSetupLAN::JOINGAME: {
+				case FullscreenMenuBase::MenuTarget::kJoingame: {
 					IPaddress peer;
 
 					if (!host_address)
@@ -1283,12 +1284,13 @@
 {
 	SinglePlayerGameSettingsProvider sp;
 	FullscreenMenuLaunchSPG lgm(&sp);
-	const int32_t code = lgm.run();
+	const FullscreenMenuBase::MenuTarget code = lgm.run<FullscreenMenuBase::MenuTarget>();
 	Widelands::Game game;
 
-	if (code <= 0)
+	if (code == FullscreenMenuBase::MenuTarget::kBack) {
 		return false;
-	if (code == 2) { // scenario
+	}
+	if (code == FullscreenMenuBase::MenuTarget::kScenarioGame) { // scenario
 		try {
 			game.run_splayer_scenario_direct(sp.get_map().c_str(), "");
 		} catch (const std::exception & e) {
@@ -1346,7 +1348,7 @@
 	SinglePlayerGameSettingsProvider sp;
 	FullscreenMenuLoadGame ssg(game, &sp, nullptr);
 
-	if (ssg.run() > 0)
+	if (ssg.run<FullscreenMenuBase::MenuTarget>() == FullscreenMenuBase::MenuTarget::kOk)
 		filename = ssg.filename();
 	else
 		return false;
@@ -1378,7 +1380,7 @@
 		int32_t campaign;
 		{ //  First start UI for selecting the campaign.
 			FullscreenMenuCampaignSelect select_campaign;
-			if (select_campaign.run() > 0)
+			if (select_campaign.run<FullscreenMenuBase::MenuTarget>() == FullscreenMenuBase::MenuTarget::kOk)
 				campaign = select_campaign.get_campaign();
 			else { //  back was pressed
 				filename = "";
@@ -1388,7 +1390,7 @@
 		//  Then start UI for the selected campaign.
 		FullscreenMenuCampaignMapSelect select_campaignmap;
 		select_campaignmap.set_campaign(campaign);
-		if (select_campaignmap.run() > 0) {
+		if (select_campaignmap.run<FullscreenMenuBase::MenuTarget>() == FullscreenMenuBase::MenuTarget::kOk) {
 			filename = select_campaignmap.get_map();
 			break;
 		}
@@ -1414,7 +1416,7 @@
 	if (m_filename.empty()) {
 		SinglePlayerGameSettingsProvider sp;
 		FullscreenMenuLoadGame rm(game, &sp, nullptr, true);
-		if (rm.run() <= 0)
+		if (rm.run<FullscreenMenuBase::MenuTarget>() == FullscreenMenuBase::MenuTarget::kBack)
 			return;
 
 		m_filename = rm.filename();

=== modified file 'src/wui/game_main_menu_save_game.cc'
--- src/wui/game_main_menu_save_game.cc	2015-07-29 06:01:48 +0000
+++ src/wui/game_main_menu_save_game.cc	2015-08-06 17:33:02 +0000
@@ -245,8 +245,8 @@
 			 "Reason given:\n");
 		s += error;
 		UI::WLMessageBox mbox
-			(&igbase, _("Save Game Error!"), s, UI::WLMessageBox::OK);
-		mbox.run();
+			(&igbase, _("Save Game Error!"), s, UI::WLMessageBox::MBoxType::kOk);
+		mbox.run<UI::Panel::Returncodes>();
 	}
 	game.save_handler().set_current_filename(complete_filename);
 }
@@ -260,7 +260,7 @@
 			 _("Save Game Error!"),
 			(boost::format(_("A file with the name ‘%s’ already exists. Overwrite?"))
 				% FileSystem::fs_filename(filename.c_str())).str(),
-			 YESNO),
+			 MBoxType::kOkCancel),
 		m_filename(filename)
 	{}
 
@@ -269,14 +269,14 @@
 	}
 
 
-	void pressed_yes() override
+	void clicked_ok() override
 	{
 		g_fs->fs_unlink(m_filename);
 		dosave(menu_save_game().igbase(), m_filename);
 		menu_save_game().die();
 	}
 
-	void pressed_no() override
+	void clicked_back() override
 	{
 		die();
 	}
@@ -324,18 +324,18 @@
 			 str
 				 (boost::format(_("Do you really want to delete the file %s?")) %
 				  FileSystem::fs_filename(filename.c_str())),
-			 YESNO),
+			 MBoxType::kOkCancel),
 		m_filename(filename)
 	{}
 
-	void pressed_yes() override
+	void clicked_ok() override
 	{
 		g_fs->fs_unlink(m_filename);
 		dynamic_cast<GameMainMenuSaveGame&>(*get_parent()).fill_list();
 		die();
 	}
 
-	void pressed_no() override
+	void clicked_back() override
 	{
 		die();
 	}

=== modified file 'src/wui/game_options_menu.cc'
--- src/wui/game_options_menu.cc	2015-05-07 09:05:58 +0000
+++ src/wui/game_options_menu.cc	2015-08-06 17:33:02 +0000
@@ -39,15 +39,15 @@
 								 /** TRANSLATORS: Window label when "Exit game" has been pressed */
 								 _("Exit Game Confirmation"),
 								 _("Are you sure you wish to exit this game?"),
-								 YESNO),
+								 MBoxType::kOkCancel),
 		  m_gb(gb) {
 	}
 
-	void pressed_yes() override {
-		m_gb.end_modal(0);
+	void clicked_ok() override {
+		m_gb.end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack);
 	}
 
-	void pressed_no() override {
+	void clicked_back() override {
 		die();
 	}
 
@@ -183,7 +183,7 @@
 
 void GameOptionsMenu::clicked_exit_game() {
 	if (get_key_state(SDL_SCANCODE_LCTRL) || get_key_state(SDL_SCANCODE_RCTRL)) {
-		m_gb.end_modal(0);
+		m_gb.end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack);
 	}
 	else {
 		new GameOptionsMenuExitConfirmBox(*get_parent(), m_gb);

=== modified file 'src/wui/game_summary.cc'
--- src/wui/game_summary.cc	2015-08-04 07:49:23 +0000
+++ src/wui/game_summary.cc	2015-08-06 17:33:02 +0000
@@ -220,7 +220,7 @@
 
 void GameSummaryScreen::stop_clicked()
 {
-	m_game.get_ibase()->end_modal(0);
+	m_game.get_ibase()->end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack);
 }
 
 void GameSummaryScreen::player_selected(uint32_t entry_index)

=== modified file 'src/wui/interactive_spectator.cc'
--- src/wui/interactive_spectator.cc	2015-02-16 12:42:35 +0000
+++ src/wui/interactive_spectator.cc	2015-08-06 17:33:02 +0000
@@ -171,7 +171,7 @@
 	if (is_multiplayer()) {
 		return;
 	}
-	end_modal(0);
+	end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack);
 }
 
 

=== modified file 'src/wui/login_box.cc'
--- src/wui/login_box.cc	2014-09-29 19:25:24 +0000
+++ src/wui/login_box.cc	2015-08-06 17:33:02 +0000
@@ -65,13 +65,13 @@
 		 200, 20,
 		 g_gr->images().get("pics/but0.png"),
 		 _("Login"));
-	loginbtn->sigclicked.connect(boost::bind(&LoginBox::pressed_login, boost::ref(*this)));
+	loginbtn->sigclicked.connect(boost::bind(&LoginBox::clicked_ok, boost::ref(*this)));
 	UI::Button * cancelbtn = new UI::Button
 		(this, "cancel",
 		 (get_inner_w() / 2 - 200) / 2 + get_inner_w() / 2, loginbtn->get_y(), 200, 20,
 		 g_gr->images().get("pics/but1.png"),
 		 _("Cancel"));
-	cancelbtn->sigclicked.connect(boost::bind(&LoginBox::pressed_cancel, boost::ref(*this)));
+	cancelbtn->sigclicked.connect(boost::bind(&LoginBox::clicked_back, boost::ref(*this)));
 
 	Section & s = g_options.pull_section("global");
 	eb_nickname->set_text(s.get_string("nickname", _("nobody")));
@@ -81,37 +81,54 @@
 
 
 /// called, if "login" is pressed
-void LoginBox::pressed_login()
+void LoginBox::clicked_ok()
 {
 	// Check if all needed input fields are valid
 	if (eb_nickname->text().empty()) {
 		UI::WLMessageBox mb
 			(this, _("Empty Nickname"), _("Please enter a nickname!"),
-			 UI::WLMessageBox::OK);
-		mb.run();
+			 UI::WLMessageBox::MBoxType::kOk);
+		mb.run<UI::Panel::Returncodes>();
 		return;
 	}
 	if (eb_nickname->text().find(' ') <= eb_nickname->text().size()) {
 		UI::WLMessageBox mb
 			(this, _("Space in Nickname"),
 			 _("Sorry, but spaces are not allowed in nicknames!"),
-			 UI::WLMessageBox::OK);
-		mb.run();
+			 UI::WLMessageBox::MBoxType::kOk);
+		mb.run<UI::Panel::Returncodes>();
 		return;
 	}
 	if (eb_password->text().empty() && cb_register->get_state()) {
 		UI::WLMessageBox mb
 			(this, _("Empty Password"), _("Please enter your password!"),
-			 UI::WLMessageBox::OK);
-		mb.run();
+			 UI::WLMessageBox::MBoxType::kOk);
+		mb.run<UI::Panel::Returncodes>();
 		return;
 	}
-	end_modal(1);
+	end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kOk);
 }
 
 
 /// Called if "cancel" was pressed
-void LoginBox::pressed_cancel()
+void LoginBox::clicked_back() {
+	end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack);
+}
+
+bool LoginBox::handle_key(bool down, SDL_Keysym code)
 {
-	end_modal(0);
+	if (down) {
+		switch (code.sym) {
+			case SDLK_KP_ENTER:
+			case SDLK_RETURN:
+				clicked_ok();
+				return true;
+			case SDLK_ESCAPE:
+				clicked_back();
+				return true;
+			default:
+				break; // not handled
+		}
+	}
+	return UI::Panel::handle_key(down, code);
 }

=== modified file 'src/wui/login_box.h'
--- src/wui/login_box.h	2014-09-29 19:25:24 +0000
+++ src/wui/login_box.h	2015-08-06 17:33:02 +0000
@@ -34,11 +34,13 @@
 	bool registered()          {return cb_register->get_state();}
 	bool set_automaticlog()    {return cb_auto_log->get_state();}
 
-private:
-	void pressed_login();
-	void pressed_cancel();
-
-private:
+	/// Handle keypresses
+	bool handle_key(bool down, SDL_Keysym code) override;
+
+private:
+	void clicked_back();
+	void clicked_ok();
+
 	UI::EditBox  * eb_nickname;
 	UI::EditBox  * eb_password;
 	UI::Checkbox * cb_register;

=== modified file 'src/wui/story_message_box.cc'
--- src/wui/story_message_box.cc	2014-09-10 14:48:40 +0000
+++ src/wui/story_message_box.cc	2015-08-06 17:33:02 +0000
@@ -82,8 +82,7 @@
  * Clicked
  */
 void StoryMessageBox::clicked_ok() {
-	end_modal(0);
-	return;
+	end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kOk);
 }
 
 /*
@@ -97,3 +96,18 @@
 
 	return UI::Window::handle_mousepress(btn, mx, my);
 }
+
+bool StoryMessageBox::handle_key(bool down, SDL_Keysym code)
+{
+	if (down) {
+		switch (code.sym) {
+			case SDLK_KP_ENTER:
+			case SDLK_RETURN:
+				clicked_ok();
+				return true;
+			default:
+				break; // not handled
+		}
+	}
+	return UI::Panel::handle_key(down, code);
+}

=== modified file 'src/wui/story_message_box.h'
--- src/wui/story_message_box.h	2014-09-10 13:03:40 +0000
+++ src/wui/story_message_box.h	2015-08-06 17:33:02 +0000
@@ -32,6 +32,9 @@
 
 	bool handle_mousepress(uint8_t btn, int32_t mx, int32_t my) override;
 
+	/// Handle keypresses
+	bool handle_key(bool down, SDL_Keysym code) override;
+
 private:
 	void clicked_ok();
 };


Follow ups