diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 99772efc..50118224 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -243,6 +243,7 @@ set(BASE_SOURCES
     ui/maindialog.cpp
     ui/mainmap.cpp
     ui/mainshort.cpp
+    ui/mainui.cpp
     ui/map.cpp
     ui/scroll.cpp
     ui/shortcut.cpp
diff --git a/src/app/app.cpp b/src/app/app.cpp
index 23813a00..063d2d28 100644
--- a/src/app/app.cpp
+++ b/src/app/app.cpp
@@ -45,8 +45,6 @@
     #include "sound/oalsound/alsound.h"
 #endif
 
-#include "ui/maindialog.h"
-
 #include <boost/filesystem.hpp>
 #include <boost/tokenizer.hpp>
 
@@ -597,7 +595,7 @@ bool CApplication::Create()
         m_controller->StartApp();
     else
     {
-        m_controller->GetMainDialog()->UpdateCustomLevelList(); //TODO: This should be moved out of CMainDialog
+        m_controller->GetRobotMain()->UpdateCustomLevelList(); // To load the userlevels
         m_controller->GetRobotMain()->SetExitAfterMission(true);
         m_controller->StartGame(m_runSceneCategory, m_runSceneRank/100, m_runSceneRank%100);
     }
diff --git a/src/app/controller.cpp b/src/app/controller.cpp
index 5807d39f..e89ec380 100644
--- a/src/app/controller.cpp
+++ b/src/app/controller.cpp
@@ -20,19 +20,16 @@
 #include "app/controller.h"
 
 
-#include "object/robotmain.h"
+#include "common/make_unique.h"
 
-#include "ui/maindialog.h"
+#include "object/robotmain.h"
 
 
 
 CController::CController(CApplication* app, bool configLoaded)
  : m_app(app)
- , m_main(new CRobotMain(this))
- , m_dialog(new Ui::CMainDialog())
 {
-    m_main->Create();
-    m_dialog->Create();
+    m_main = MakeUnique<CRobotMain>();
     if (configLoaded)
         m_main->LoadConfigFile();
     else
@@ -53,11 +50,6 @@ CRobotMain* CController::GetRobotMain()
     return m_main.get();
 }
 
-Ui::CMainDialog* CController::GetMainDialog()
-{
-    return m_dialog.get();
-}
-
 void CController::StartApp()
 {
     m_main->ChangePhase(PHASE_WELCOME1);
@@ -71,7 +63,5 @@ void CController::StartGame(LevelCategory cat, int chap, int lvl)
 
 void CController::ProcessEvent(Event& event)
 {
-    bool passOn = m_dialog->EventProcess(event);
-    if (passOn)
-        m_main->ProcessEvent(event);
+    m_main->ProcessEvent(event);
 }
diff --git a/src/app/controller.h b/src/app/controller.h
index b70eb30c..6f567f91 100644
--- a/src/app/controller.h
+++ b/src/app/controller.h
@@ -32,14 +32,10 @@
 class CApplication;
 class CRobotMain;
 struct Event;
-namespace Ui
-{
-class CMainDialog;
-}
 
 /**
  * \class CController
- * \brief Entry point into CRobotMain and CMainDialog
+ * \brief Entry point into CRobotMain
  */
 class CController
 {
@@ -51,8 +47,6 @@ public:
     CApplication*    GetApplication();
     //! Return CRobotMain instance
     CRobotMain*      GetRobotMain();
-    //! Return CMainDialog instance
-    Ui::CMainDialog* GetMainDialog();
 
     //! Event processing
     void ProcessEvent(Event &event);
@@ -65,5 +59,4 @@ public:
 private:
     CApplication* m_app;
     std::unique_ptr<CRobotMain> m_main;
-    std::unique_ptr<Ui::CMainDialog> m_dialog;
 };
diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp
index 026ce30c..85af6ff9 100644
--- a/src/graphics/engine/engine.cpp
+++ b/src/graphics/engine/engine.cpp
@@ -500,10 +500,10 @@ void CEngine::FrameUpdate()
     }
 }
 
-void CEngine::WriteScreenShot(const std::string& fileName, int width, int height)
+void CEngine::WriteScreenShot(const std::string& fileName)
 {
     auto data = MakeUnique<WriteScreenShotData>();
-    data->img = MakeUnique<CImage>(Math::IntPoint(width, height));
+    data->img = MakeUnique<CImage>(Math::IntPoint(m_size.x, m_size.y));
 
     data->img->SetDataPixels(m_device->GetFrameBufferPixels());
     data->img->FlipVertically();
diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h
index 3e360ea1..675af11e 100644
--- a/src/graphics/engine/engine.h
+++ b/src/graphics/engine/engine.h
@@ -668,7 +668,7 @@ public:
 
 
     //! Writes a screenshot containing the current frame
-    void            WriteScreenShot(const std::string& fileName, int width, int height);
+    void            WriteScreenShot(const std::string& fileName);
 
 
     //! Get pause mode
diff --git a/src/object/robotmain.cpp b/src/object/robotmain.cpp
index 0100ae52..55fe9fd2 100644
--- a/src/object/robotmain.cpp
+++ b/src/object/robotmain.cpp
@@ -22,7 +22,6 @@
 #include "CBot/CBotDll.h"
 
 #include "app/app.h"
-#include "app/controller.h"
 #include "app/input.h"
 
 #include "common/config_file.h"
@@ -97,6 +96,7 @@
 #include "ui/maindialog.h"
 #include "ui/mainmap.h"
 #include "ui/mainshort.h"
+#include "ui/mainui.h"
 #include "ui/map.h"
 #include "ui/shortcut.h"
 #include "ui/slider.h"
@@ -129,38 +129,42 @@ float   g_unit;             // conversion factor
 
 
 //! Constructor of robot application
-CRobotMain::CRobotMain(CController* controller)
+CRobotMain::CRobotMain()
 {
-    m_ctrl       = controller;
-    m_app        = nullptr;
+    m_app        = CApplication::GetInstancePointer();
 
-    m_objMan     = nullptr;
+    m_eventQueue = m_app->GetEventQueue();
+    m_sound      = m_app->GetSound();
 
-    m_eventQueue = nullptr;
-    m_sound      = nullptr;
-
-    m_engine     = nullptr;
-    m_oldModelManager = nullptr;
+    m_engine     = Gfx::CEngine::GetInstancePointer();
+    m_oldModelManager = m_engine->GetModelManager();
     m_modelManager = MakeUnique<Gfx::CModelManager>();
-    m_lightMan   = nullptr;
-    m_particle   = nullptr;
-    m_water      = nullptr;
-    m_cloud      = nullptr;
-    m_lightning  = nullptr;
-    m_planet     = nullptr;
-    m_pause      = nullptr;
-    m_input      = nullptr;
+    m_lightMan   = m_engine->GetLightManager();
+    m_particle   = m_engine->GetParticle();
+    m_water      = m_engine->GetWater();
+    m_cloud      = m_engine->GetCloud();
+    m_lightning  = m_engine->GetLightning();
+    m_planet     = m_engine->GetPlanet();
+    m_pause      = CPauseManager::GetInstancePointer();
+    m_input      = CInput::GetInstancePointer();
+    m_settings   = new CSettings();
 
-    m_interface   = nullptr;
-    m_terrain     = nullptr;
-    m_camera      = nullptr;
-    m_displayText = nullptr;
-    m_movie       = nullptr;
-    m_dialog      = nullptr;
-    m_short       = nullptr;
-    m_map         = nullptr;
+    m_interface   = new Ui::CInterface();
+    m_terrain     = new Gfx::CTerrain();
+    m_camera      = new Gfx::CCamera();
+    m_displayText = new Ui::CDisplayText();
+    m_movie       = new CMainMovie();
+    m_ui          = MakeUnique<Ui::CMainUserInterface>();
+    m_short       = new Ui::CMainShort();
+    m_map         = new Ui::CMainMap();
     m_displayInfo = nullptr;
 
+    m_objMan = new CObjectManager(m_engine,
+                                  m_terrain,
+                                  m_oldModelManager,
+                                  m_modelManager.get(),
+                                  m_particle);
+
     m_time = 0.0f;
     m_gameTime = 0.0f;
     m_gameTimeAbsolute = 0.0f;
@@ -255,42 +259,6 @@ CRobotMain::CRobotMain(CController* controller)
         m_showLimit[i].total = 0;
         m_showLimit[i].link = 0;
     }
-}
-
-void CRobotMain::Create()
-{
-    m_app        = m_ctrl->GetApplication();
-
-    m_eventQueue = m_app->GetEventQueue();
-    m_sound      = m_app->GetSound();
-
-    m_engine     = Gfx::CEngine::GetInstancePointer();
-    m_oldModelManager = m_engine->GetModelManager();
-    m_lightMan   = m_engine->GetLightManager();
-    m_particle   = m_engine->GetParticle();
-    m_water      = m_engine->GetWater();
-    m_cloud      = m_engine->GetCloud();
-    m_lightning  = m_engine->GetLightning();
-    m_planet     = m_engine->GetPlanet();
-    m_pause      = CPauseManager::GetInstancePointer();
-    m_input      = CInput::GetInstancePointer();
-    m_settings   = new CSettings();
-
-    m_interface   = new Ui::CInterface();
-    m_terrain     = new Gfx::CTerrain();
-    m_camera      = new Gfx::CCamera();
-    m_displayText = new Ui::CDisplayText();
-    m_movie       = new CMainMovie();
-    m_dialog      = m_ctrl->GetMainDialog();
-    m_short       = new Ui::CMainShort();
-    m_map         = new Ui::CMainMap();
-    m_displayInfo = nullptr;
-
-    m_objMan = new CObjectManager(m_engine,
-                                  m_terrain,
-                                  m_oldModelManager,
-                                  m_modelManager.get(),
-                                  m_particle);
 
     m_engine->SetTerrain(m_terrain);
 
@@ -341,12 +309,6 @@ CRobotMain::~CRobotMain()
 
     delete m_objMan;
     m_objMan = nullptr;
-
-    m_dialog = nullptr;
-    m_input = nullptr;
-    m_pause = nullptr;
-    m_app = nullptr;
-    m_ctrl = nullptr;
 }
 
 Gfx::CCamera* CRobotMain::GetCamera()
@@ -444,7 +406,7 @@ void CRobotMain::ChangePhase(Phase phase)
         if (phase == PHASE_WIN)  // wins a simulation?
         {
             m_playerProfile->SetLevelPassed(m_levelCategory, m_levelChap, m_levelRank, true);
-            m_dialog->NextMission();  // passes to the next mission
+            m_ui->NextMission();  // passes to the next mission
         }
 
         m_app->SetLowCPU(true); // doesn't use much CPU in interface phases
@@ -524,7 +486,7 @@ void CRobotMain::ChangePhase(Phase phase)
     pb->SetState(Ui::STATE_SIMPLY);
     pb->ClearState(Ui::STATE_VISIBLE);
 
-    m_dialog->ChangePhase(m_phase);
+    m_ui->ChangePhase(m_phase);
     if (!resetWorld) return;
 
     dim.x = 32.0f/640.0f;
@@ -558,7 +520,7 @@ void CRobotMain::ChangePhase(Phase phase)
 
         try
         {
-            CreateScene(m_dialog->GetSceneSoluce(), false, false);  // interactive scene
+            CreateScene(m_ui->GetSceneSoluce(), false, false);  // interactive scene
             if (m_mapImage)
                 m_map->SetFixImage(m_mapFilename);
 
@@ -663,6 +625,8 @@ void CRobotMain::ChangePhase(Phase phase)
 //! Processes an event
 bool CRobotMain::ProcessEvent(Event &event)
 {
+    if (!m_ui->EventProcess(event)) return false;
+
     if (event.type == EVENT_FRAME)
     {
         if (!m_movie->EventProcess(event))  // end of the movie?
@@ -835,7 +799,7 @@ bool CRobotMain::ProcessEvent(Event &event)
                     else if (m_lostDelay > 0.0f)
                         ChangePhase(PHASE_LOST);
                     else if (!m_cmdEdit)
-                        m_dialog->StartAbort();  // do you want to leave?
+                        m_ui->GetDialog()->StartAbort();  // do you want to leave?
                 }
                 if (event.key.slot == INPUT_SLOT_PAUSE)
                 {
@@ -993,7 +957,7 @@ bool CRobotMain::ProcessEvent(Event &event)
                 break;
 
             case EVENT_OBJECT_DELETE:
-                m_dialog->StartDeleteObject();  // do you want to destroy it?
+                m_ui->GetDialog()->StartDeleteObject();  // do you want to destroy it?
                 break;
 
             case EVENT_OBJECT_BHELP:
@@ -1373,14 +1337,14 @@ void CRobotMain::ExecuteCmd(char *cmd)
     if (strcmp(cmd, "showsoluce") == 0)
     {
         m_showSoluce = !m_showSoluce;
-        m_dialog->ShowSoluceUpdate();
+        m_ui->ShowSoluceUpdate();
         return;
     }
 
     if (strcmp(cmd, "allmission") == 0)
     {
         m_showAll = !m_showAll;
-        m_dialog->AllMissionUpdate();
+        m_ui->AllMissionUpdate();
         return;
     }
 
@@ -1472,7 +1436,7 @@ void CRobotMain::StartDisplayInfo(const char *filename, int index)
         m_sound->MuteAll(true);
     }
 
-    bool soluce = m_dialog->GetSceneSoluce();
+    bool soluce = m_ui->GetSceneSoluce();
 
     m_displayInfo = new Ui::CDisplayInfo();
     m_displayInfo->StartDisplayInfo(filename, index, soluce);
@@ -5322,7 +5286,7 @@ void CRobotMain::ResetCreate()
 
     try
     {
-        CreateScene(m_dialog->GetSceneSoluce(), false, true);
+        CreateScene(m_ui->GetSceneSoluce(), false, true);
 
         if (!GetNiceReset()) return;
 
@@ -5665,7 +5629,7 @@ bool CRobotMain::GetShowSoluce()
 bool CRobotMain::GetSceneSoluce()
 {
     if (m_infoFilename[SATCOM_SOLUCE][0] == 0) return false;
-    return m_dialog->GetSceneSoluce();
+    return m_ui->GetSceneSoluce();
 }
 
 bool CRobotMain::GetShowAll()
@@ -5708,13 +5672,13 @@ int CRobotMain::GetGamerGlasses()
 //! Returns the mode with just the head
 bool CRobotMain::GetGamerOnlyHead()
 {
-    return m_dialog->GetGamerOnlyHead();
+    return m_ui->GetGamerOnlyHead();
 }
 
 //! Returns the angle of presentation
 float CRobotMain::GetPersoAngle()
 {
-    return m_dialog->GetPersoAngle();
+    return m_ui->GetPersoAngle();
 }
 
 void CRobotMain::SetLevel(LevelCategory cat, int chap, int rank)
@@ -5743,7 +5707,7 @@ int CRobotMain::GetLevelRank()
 std::string CRobotMain::GetCustomLevelDir()
 {
     assert(m_levelCategory == LevelCategory::CustomLevels);
-    return m_dialog->GetCustomLevelName(m_levelChap);
+    return m_ui->GetCustomLevelName(m_levelChap);
 }
 
 void CRobotMain::SetReadScene(std::string path)
@@ -5753,12 +5717,12 @@ void CRobotMain::SetReadScene(std::string path)
 
 void CRobotMain::UpdateChapterPassed()
 {
-    return m_dialog->UpdateChapterPassed();
+    return m_ui->UpdateChapterPassed();
 }
 
 void CRobotMain::MakeSaveScreenshot(const std::string& name)
 {
-    return m_dialog->MakeSaveScreenshot(name);
+    return m_ui->MakeSaveScreenshot(name);
 }
 
 
@@ -5980,17 +5944,17 @@ void CRobotMain::DisplayError(Error err, Math::Vector goal, float height, float
 
 void CRobotMain::UpdateCustomLevelList()
 {
-    m_dialog->UpdateCustomLevelList();
+    m_ui->UpdateCustomLevelList();
 }
 
 std::string CRobotMain::GetCustomLevelName(int id)
 {
-    return m_dialog->GetCustomLevelName(id);
+    return m_ui->GetCustomLevelName(id);
 }
 
 const std::vector<std::string>& CRobotMain::GetCustomLevelList()
 {
-    return m_dialog->GetCustomLevelList();
+    return m_ui->GetCustomLevelList();
 }
 
 void CRobotMain::StartMissionTimer()
diff --git a/src/object/robotmain.h b/src/object/robotmain.h
index 9e752615..e5ed967e 100644
--- a/src/object/robotmain.h
+++ b/src/object/robotmain.h
@@ -98,7 +98,7 @@ class CModelManager;
 
 namespace Ui
 {
-class CMainDialog;
+class CMainUserInterface;
 class CMainShort;
 class CMainMap;
 class CInterface;
@@ -146,9 +146,8 @@ const int SATCOM_MAX        = 6;
 class CRobotMain : public CSingleton<CRobotMain>
 {
 public:
-    CRobotMain(CController* controller);
+    CRobotMain();
     virtual ~CRobotMain();
-    void        Create();
 
     Gfx::CCamera* GetCamera();
     Gfx::CTerrain* GetTerrain();
@@ -430,7 +429,7 @@ protected:
     Gfx::CLightManager* m_lightMan;
     Gfx::CTerrain*      m_terrain;
     Gfx::CCamera*       m_camera;
-    Ui::CMainDialog*    m_dialog;
+    std::unique_ptr<Ui::CMainUserInterface> m_ui;
     Ui::CMainShort*     m_short;
     Ui::CMainMap*       m_map;
     Ui::CInterface*     m_interface;
diff --git a/src/ui/maindialog.cpp b/src/ui/maindialog.cpp
index 1b5bab78..0c59a9f3 100644
--- a/src/ui/maindialog.cpp
+++ b/src/ui/maindialog.cpp
@@ -23,69 +23,24 @@
 #include "common/config.h"
 
 #include "app/app.h"
-#include "app/input.h"
-#include "app/system.h"
 
-#include "common/config_file.h"
 #include "common/event.h"
-#include "common/global.h"
 #include "common/logger.h"
 #include "common/make_unique.h"
-#include "common/misc.h"
-#include "common/restext.h"
 #include "common/settings.h"
 #include "common/stringutils.h"
 
-#include "common/resources/inputstream.h"
-#include "common/resources/outputstream.h"
-#include "common/resources/resourcemanager.h"
-
 #include "object/player_profile.h"
 #include "object/robotmain.h"
 
-#include "object/level/parser.h"
-
 #include "sound/sound.h"
 
-#include "ui/screen/screen.h"
-#include "ui/screen/screen_apperance.h"
-#include "ui/screen/screen_io_read.h"
-#include "ui/screen/screen_io_write.h"
-#include "ui/screen/screen_level_list.h"
-#include "ui/screen/screen_loading.h"
-#include "ui/screen/screen_main_menu.h"
-#include "ui/screen/screen_player_select.h"
-#include "ui/screen/screen_setup_controls.h"
-#include "ui/screen/screen_setup_display.h"
-#include "ui/screen/screen_setup_game.h"
-#include "ui/screen/screen_setup_graphics.h"
-#include "ui/screen/screen_setup_sound.h"
-#include "ui/screen/screen_quit.h"
-#include "ui/screen/screen_welcome.h"
-
 #include "ui/button.h"
-#include "ui/check.h"
-#include "ui/color.h"
-#include "ui/edit.h"
-#include "ui/editvalue.h"
-#include "ui/group.h"
-#include "ui/image.h"
 #include "ui/interface.h"
-#include "ui/key.h"
-#include "ui/label.h"
-#include "ui/list.h"
-#include "ui/scroll.h"
-#include "ui/slider.h"
+#include "ui/mainui.h"
 #include "ui/window.h"
 
-#include <stdio.h>
-#include <string.h>
-#include <sstream>
-#include <iomanip>
-#include <vector>
-#include <boost/lexical_cast.hpp>
-
-//TODO Get rid of all sprintf's
+#include "ui/screen/screen_setup.h"
 
 namespace Ui
 {
@@ -94,61 +49,16 @@ namespace Ui
 
 CMainDialog::CMainDialog()
 {
-    m_app        = nullptr;
-    m_eventQueue = nullptr;
-    m_sound      = nullptr;
-    m_main       = nullptr;
-    m_interface  = nullptr;
-    m_camera     = nullptr;
-    m_engine     = nullptr;
-    m_particle   = nullptr;
-    m_pause      = nullptr;
-
-    m_currentScreen = nullptr;
-
-    m_phase        = PHASE_PLAYER_SELECT;
-
-    m_shotDelay      = 0;
-
-    m_glintMouse = Math::Point(0.0f, 0.0f);
-    m_glintTime  = 1000.0f;
-
-    for (int i = 0; i < 10; i++)
-    {
-        m_partiPhase[i] = 0;
-        m_partiTime[i]  = 0.0f;
-    }
-
-    m_bDialog = false;
-}
-
-void CMainDialog::Create()
-{
-    m_app        = CApplication::GetInstancePointer();
-    m_eventQueue = m_app->GetEventQueue();
-    m_sound      = m_app->GetSound();
     m_main       = CRobotMain::GetInstancePointer();
-    m_interface  = m_main->GetInterface();
-    m_camera     = m_main->GetCamera();
     m_engine     = Gfx::CEngine::GetInstancePointer();
     m_particle   = m_engine->GetParticle();
-    m_pause      = CPauseManager::GetInstancePointer();
+    m_interface  = m_main->GetInterface();
+    m_sound      = CApplication::GetInstancePointer()->GetSound();
     m_settings   = CSettings::GetInstancePointer();
 
-    m_screenAppearance = MakeUnique<CScreenApperance>();
-    m_screenLevelList = MakeUnique<CScreenLevelList>();
-    m_screenIORead = MakeUnique<CScreenIORead>(m_screenLevelList.get());
-    m_screenIOWrite = MakeUnique<CScreenIOWrite>(m_screenLevelList.get());
-    m_screenLoading = MakeUnique<CScreenLoading>();
-    m_screenSetupControls = MakeUnique<CScreenSetupControls>();
-    m_screenSetupDisplay = MakeUnique<CScreenSetupDisplay>();
-    m_screenSetupGame = MakeUnique<CScreenSetupGame>();
-    m_screenSetupGraphics = MakeUnique<CScreenSetupGraphics>();
-    m_screenSetupSound = MakeUnique<CScreenSetupSound>();
-    m_screenMainMenu = MakeUnique<CScreenMainMenu>();
-    m_screenPlayerSelect = MakeUnique<CScreenPlayerSelect>(this);
-    m_screenQuit = MakeUnique<CScreenQuit>();
-    m_screenWelcome = MakeUnique<CScreenWelcome>();
+    m_phase = PHASE_PLAYER_SELECT;
+
+    m_bDialog = false;
 }
 
 // Destructor of robot application.
@@ -157,190 +67,31 @@ CMainDialog::~CMainDialog()
 {
 }
 
-
-// Changes phase.
-
-CScreenSetup* CMainDialog::GetSetupScreen(Phase phase)
-{
-    if(phase == PHASE_SETUPd) return m_screenSetupDisplay.get();
-    if(phase == PHASE_SETUPg) return m_screenSetupGraphics.get();
-    if(phase == PHASE_SETUPp) return m_screenSetupGame.get();
-    if(phase == PHASE_SETUPc) return m_screenSetupControls.get();
-    if(phase == PHASE_SETUPs) return m_screenSetupSound.get();
-    assert(false);
-    return nullptr;
-}
-
 void CMainDialog::ChangePhase(Phase phase)
 {
-    m_camera->SetType(Gfx::CAM_TYPE_DIALOG);
-    m_engine->SetOverFront(false);
-    m_engine->SetOverColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f), Gfx::ENG_RSTATE_TCOLOR_BLACK); // TODO: color ok?
-
     m_phase = phase;  // copy the info to CRobotMain
-
-    m_currentScreen = nullptr;
-
-    if (m_phase == PHASE_QUIT_SCREEN)
-    {
-        m_currentScreen = m_screenQuit.get();
-    }
-    if (m_phase >= PHASE_WELCOME1 && m_phase <= PHASE_WELCOME3)
-    {
-        m_screenWelcome->SetImageIndex(m_phase - PHASE_WELCOME1);
-        m_currentScreen = m_screenWelcome.get();
-    }
-    if (m_phase == PHASE_PLAYER_SELECT)
-    {
-        m_currentScreen = m_screenPlayerSelect.get();
-    }
-    if (m_phase == PHASE_APPERANCE)
-    {
-        m_currentScreen = m_screenAppearance.get();
-    }
-    if (m_phase == PHASE_MAIN_MENU)
-    {
-        m_currentScreen = m_screenMainMenu.get();
-    }
-    if (m_phase == PHASE_LEVEL_LIST)
-    {
-        m_screenLevelList->SetLevelCategory(m_main->GetLevelCategory());
-        m_currentScreen = m_screenLevelList.get();
-    }
-    if (m_phase == PHASE_LOADING)
-    {
-        m_currentScreen = m_screenLoading.get();
-    }
-    if (m_phase >= PHASE_SETUPd && m_phase <= PHASE_SETUPs)
-    {
-        CScreenSetup* screenSetup = GetSetupScreen(m_phase);
-        screenSetup->SetInSimulation(false);
-        screenSetup->SetActive();
-        m_currentScreen = screenSetup;
-    }
-    if (m_phase >= PHASE_SETUPds && m_phase <= PHASE_SETUPss)
-    {
-        CScreenSetup* screenSetup = GetSetupScreen(static_cast<Phase>(m_phase - PHASE_SETUPds + PHASE_SETUPd));
-        screenSetup->SetInSimulation(true);
-        screenSetup->SetActive();
-        m_currentScreen = screenSetup;
-    }
-    if (m_phase == PHASE_WRITEs)
-    {
-        m_currentScreen = m_screenIOWrite.get();
-    }
-    if (m_phase == PHASE_READ || m_phase == PHASE_READs)
-    {
-        m_currentScreen = m_screenIORead.get();
-        m_screenIORead->SetInSimulation(m_phase == PHASE_READs);
-    }
-
-    if (m_currentScreen != nullptr)
-    {
-        m_currentScreen->CreateInterface();
-    }
-
-    if ( !IsPhaseWithWorld(m_phase) )
-    {
-        if (!m_sound->IsPlayingMusic() && m_sound->IsCachedMusic("Intro1.ogg"))
-        {
-            m_sound->PlayMusic("Intro1.ogg", false);
-        }
-    }
-
-    if ( m_phase == PHASE_MAIN_MENU    ||
-            m_phase == PHASE_PLAYER_SELECT    ||
-            m_phase == PHASE_LEVEL_LIST ||
-            m_phase == PHASE_SETUPd  ||
-            m_phase == PHASE_SETUPg  ||
-            m_phase == PHASE_SETUPp  ||
-            m_phase == PHASE_SETUPc  ||
-            m_phase == PHASE_SETUPs  ||
-            m_phase == PHASE_READ    ||
-            m_phase == PHASE_LOADING )
-    {
-        CWindow* pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
-        if (pw != nullptr)
-        {
-            Math::Point pos, ddim;
-
-            pos.x  = 540.0f/640.0f;
-            pos.y  =   9.0f/480.0f;
-            ddim.x =  90.0f/640.0f;
-            ddim.y =  10.0f/480.0f;
-            CLabel* pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL1, COLOBOT_VERSION_DISPLAY);
-            pl->SetFontType(Gfx::FONT_COURIER);
-            pl->SetFontSize(9.0f);
-        }
-    }
-
-    m_engine->LoadAllTextures();
 }
 
-
 // Processing an event.
 // Returns false if the event has been processed completely.
 
 bool CMainDialog::EventProcess(const Event &event)
 {
-    Event       newEvent;
-
-    if ( !m_interface->EventProcess(event) )
-    {
-        return false;
-    }
-
-    if (m_currentScreen != nullptr && !m_currentScreen->EventProcess(event)) return false;
-
-    if ( event.type == EVENT_FRAME )
-    {
-        if ( !IsPhaseWithWorld(m_phase) )
-        {
-            if (!m_sound->IsPlayingMusic() && m_sound->IsCachedMusic("Intro2.ogg"))
-            {
-                m_sound->PlayMusic("Intro2.ogg", true);
-            }
-        }
-
-        if ( m_shotDelay > 0 && !m_bDialog )  // screenshot done?
-        {
-            m_shotDelay --;
-            if ( m_shotDelay == 0 )
-            {
-                Math::IntPoint windowSize = m_engine->GetWindowSize();
-
-                m_engine->WriteScreenShot(m_shotName, windowSize.x, windowSize.y);
-            }
-        }
-
-        m_glintTime += event.rTime;
-        GlintMove();  // moves reflections
-
-        FrameParticle(event.rTime);
-
-        if ( m_bDialog )  // this dialogue?
-        {
-            FrameDialog(event.rTime);
-        }
-
-        return true;
-    }
-
-    if ( event.type == EVENT_MOUSE_MOVE )
-    {
-        m_glintMouse = event.mousePos;
-        NiceParticle(event.mousePos, event.mouseButtonsState & MOUSE_BUTTON_LEFT);
-    }
-
     if ( m_bDialog )  // this dialogue?
     {
+        if ( event.type == EVENT_FRAME )
+        {
+            FrameDialog(event.rTime);
+            return true;
+        }
+
         if ( event.type == EVENT_DIALOG_OK ||
                 (event.type == EVENT_KEY_DOWN && event.key.key == KEY(RETURN) ) )
         {
             StopDialog();
             if ( m_phase == PHASE_PLAYER_SELECT )
             {
-                m_screenPlayerSelect->NameDelete();
+                CMainUserInterface::GetInstancePointer()->NameDelete(); // TODO: Clean this up
             }
             if ( m_phase == PHASE_SIMUL )
             {
@@ -397,533 +148,6 @@ bool CMainDialog::EventProcess(const Event &event)
     return true;
 }
 
-
-// Moves the reflections.
-
-void CMainDialog::GlintMove()
-{
-    CWindow*    pw;
-    CGroup*     pg;
-    Math::Point     pos, dim, zoom;
-
-    if ( m_phase == PHASE_SIMUL )  return;
-
-    pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
-    if ( pw == 0 )  return;
-
-    if ( m_phase == PHASE_MAIN_MENU )
-    {
-        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTl));
-        if ( pg != 0 )
-        {
-            zoom.x = sinf(m_glintTime*0.23f);
-            zoom.y = sinf(m_glintTime*0.37f);
-            pos.x = 0.35f;
-            pos.y = 0.90f;
-            dim.x = 0.30f-0.10f*(zoom.x+1.0f)/2.0f;
-            dim.y = 0.50f-0.30f*(zoom.y+1.0f)/2.0f;
-            pos.y -= dim.y;
-            pg->SetPos(pos);
-            pg->SetDim(dim);
-        }
-
-        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTr));
-        if ( pg != 0 )
-        {
-            zoom.x = sinf(m_glintTime*0.21f);
-            zoom.y = sinf(m_glintTime*0.26f);
-            pos.x = 0.65f;
-            pos.y = 0.10f;
-            dim.x = 0.30f-0.10f*(zoom.x+1.0f)/2.0f;
-            dim.y = 0.50f-0.30f*(zoom.y+1.0f)/2.0f;
-            pos.x -= dim.x;
-            pg->SetPos(pos);
-            pg->SetDim(dim);
-        }
-    }
-
-    if ( m_phase == PHASE_PLAYER_SELECT       ||
-         m_phase == PHASE_LEVEL_LIST  )
-    {
-        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTl));
-        if ( pg != 0 )
-        {
-            zoom.x = sinf(m_glintTime*0.22f);
-            zoom.y = sinf(m_glintTime*0.37f);
-            pos.x = 0.10f;
-            pos.y = 0.90f;
-            dim.x = 0.60f+0.30f*zoom.x;
-            dim.y = 0.60f+0.30f*zoom.y;
-            pos.y -= dim.y;
-            pg->SetPos(pos);
-            pg->SetDim(dim);
-        }
-
-        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTr));
-        if ( pg != 0 )
-        {
-            zoom.x = sinf(m_glintTime*0.19f);
-            zoom.y = sinf(m_glintTime*0.28f);
-            pos.x = 0.90f;
-            pos.y = 0.10f;
-            dim.x = 0.60f+0.30f*zoom.x;
-            dim.y = 0.60f+0.30f*zoom.y;
-            pos.x -= dim.x;
-            pg->SetPos(pos);
-            pg->SetDim(dim);
-        }
-    }
-
-    if ( m_phase == PHASE_SETUPd  ||
-            m_phase == PHASE_SETUPg  ||
-            m_phase == PHASE_SETUPp  ||
-            m_phase == PHASE_SETUPc  ||
-            m_phase == PHASE_SETUPs  ||
-            m_phase == PHASE_SETUPds ||
-            m_phase == PHASE_SETUPgs ||
-            m_phase == PHASE_SETUPps ||
-            m_phase == PHASE_SETUPcs ||
-            m_phase == PHASE_SETUPss )
-    {
-        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTu));
-        if ( pg != 0 )
-        {
-            zoom.y = sinf(m_glintTime*0.27f);
-            pos.x = 0.10f;
-            pos.y = 0.76f;
-            dim.x = 0.80f;
-            dim.y = 0.32f+0.20f*zoom.y;
-            pos.y -= dim.y;
-            pg->SetPos(pos);
-            pg->SetDim(dim);
-        }
-
-        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTr));
-        if ( pg != 0 )
-        {
-            zoom.x = sinf(m_glintTime*0.29f);
-            zoom.y = sinf(m_glintTime*0.14f);
-            pos.x = 0.90f;
-            pos.y = 0.10f;
-            dim.x = 0.40f+0.20f*zoom.x;
-            dim.y = 0.40f+0.20f*zoom.y;
-            pos.x -= dim.x;
-            pg->SetPos(pos);
-            pg->SetDim(dim);
-        }
-    }
-
-    if ( m_phase == PHASE_WRITEs ||
-         m_phase == PHASE_READ   ||
-         m_phase == PHASE_READs  )
-    {
-        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTl));
-        if ( pg != 0 )
-        {
-            zoom.x = sinf(m_glintTime*0.22f);
-            zoom.y = sinf(m_glintTime*0.37f);
-            pos.x = 0.10f;
-            pos.y = 0.90f;
-            dim.x = 0.60f+0.30f*zoom.x;
-            dim.y = 0.60f+0.30f*zoom.y;
-            pos.y -= dim.y;
-            pg->SetPos(pos);
-            pg->SetDim(dim);
-        }
-
-        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTr));
-        if ( pg != 0 )
-        {
-            zoom.x = sinf(m_glintTime*0.19f);
-            zoom.y = sinf(m_glintTime*0.28f);
-            pos.x = 0.90f;
-            pos.y = 0.10f;
-            dim.x = 0.60f+0.30f*zoom.x;
-            dim.y = 0.60f+0.30f*zoom.y;
-            pos.x -= dim.x;
-            pg->SetPos(pos);
-            pg->SetDim(dim);
-        }
-    }
-}
-
-
-// Returns the position for a sound.
-
-Math::Vector SoundPos(Math::Point pos)
-{
-    Math::Vector    s;
-
-    s.x = (pos.x-0.5f)*2.0f;
-    s.y = (pos.y-0.5f)*2.0f;
-    s.z = 0.0f;
-
-    return s;
-}
-
-// Returns a random position for a sound.
-
-Math::Vector SoundRand()
-{
-    Math::Vector    s;
-
-    s.x = (Math::Rand()-0.5f)*2.0f;
-    s.y = (Math::Rand()-0.5f)*2.0f;
-    s.z = 0.0f;
-
-    return s;
-}
-
-// Makes pretty qq particles evolve.
-
-void CMainDialog::FrameParticle(float rTime)
-{
-    Math::Vector    pos, speed;
-    Math::Point     dim;
-    float       *pParti, *pGlint;
-    int          nParti,  nGlint;
-    int         i, r, ii;
-
-    static float partiPosInit[1+5*12] =
-    { //  x       x      t2    t2   type
-        12.0f,
-        607.0f, 164.0f, 0.2f, 0.8f, 1.0f,  // upper cable
-        604.0f, 205.0f, 0.1f, 0.3f, 1.0f,  // middle cable
-        603.0f, 247.0f, 0.1f, 0.3f, 1.0f,  // lower cable
-        119.0f, 155.0f, 0.2f, 0.4f, 2.0f,  // left pipe
-        366.0f,  23.0f, 0.5f, 1.5f, 4.0f,  // upper pipe
-        560.0f, 414.0f, 0.1f, 0.1f, 1.0f,  // button lower/right
-        20.0f, 413.0f, 0.1f, 0.1f, 2.0f,  // button lower/left
-        39.0f,  78.0f, 0.1f, 0.2f, 1.0f,  // left pot
-        39.0f,  78.0f, 0.5f, 0.9f, 1.0f,  // left pot
-        170.0f, 229.0f, 0.5f, 0.5f, 3.0f,  // left smoke
-        170.0f, 229.0f, 0.5f, 0.5f, 3.0f,  // left smoke
-        474.0f, 229.0f, 0.5f, 0.5f, 3.0f,  // right smoke
-    };
-
-    static float glintPosInit[1+2*14] =
-    {
-        14.0f,
-        15.0f, 407.0f,
-        68.0f, 417.0f,
-        548.0f,  36.0f,
-        611.0f,  37.0f,
-        611.0f, 100.0f,
-        611.0f, 395.0f,
-        36.0f,  35.0f,
-        166.0f,  55.0f,
-        166.0f,  94.0f,
-        477.0f,  56.0f,
-        31.0f, 190.0f,
-        32.0f, 220.0f,
-        65.0f, 221.0f,
-        65.0f, 250.0f,
-    };
-
-    static float partiPosBig[1+5*12] =
-    { //  x       x      t2    t2   type
-        12.0f,
-        607.0f, 164.0f, 0.2f, 0.8f, 1.0f,  // upper cable
-        604.0f, 205.0f, 0.1f, 0.3f, 1.0f,  // middle cable
-        603.0f, 247.0f, 0.1f, 0.3f, 1.0f,  // lower cable
-        64.0f, 444.0f, 0.2f, 0.8f, 1.0f,  // down the left cable
-        113.0f, 449.0f, 0.1f, 0.3f, 1.0f,  // down the left cable
-        340.0f, 463.0f, 0.2f, 0.8f, 1.0f,  // down the middle cable
-        36.0f, 155.0f, 0.2f, 0.4f, 2.0f,  // left pipe
-        366.0f,  23.0f, 0.5f, 1.5f, 4.0f,  // upper pipe
-        612.0f, 414.0f, 0.1f, 0.1f, 1.0f,  // button lower/right
-        20.0f, 413.0f, 0.1f, 0.1f, 2.0f,  // button lower/left
-        39.0f,  78.0f, 0.1f, 0.2f, 1.0f,  // left pot
-        39.0f,  78.0f, 0.5f, 0.9f, 1.0f,  // left pot
-    };
-
-    static float glintPosBig[1+2*12] =
-    {
-        12.0f,
-        15.0f, 407.0f,
-        48.0f, 399.0f,
-        611.0f,  37.0f,
-        611.0f, 100.0f,
-        611.0f, 395.0f,
-        36.0f,  35.0f,
-        31.0f, 190.0f,
-        32.0f, 220.0f,
-        31.0f, 221.0f,
-        31.0f, 189.0f,
-        255.0f,  18.0f,
-        279.0f,  18.0f,
-    };
-
-    if ( m_bDialog || !m_settings->GetInterfaceRain() )  return;
-
-    if ( m_phase == PHASE_MAIN_MENU )
-    {
-        pParti = partiPosInit;
-        pGlint = glintPosInit;
-    }
-    else if ( m_phase == PHASE_PLAYER_SELECT    ||
-            m_phase == PHASE_LEVEL_LIST ||
-            m_phase == PHASE_SETUPd  ||
-            m_phase == PHASE_SETUPg  ||
-            m_phase == PHASE_SETUPp  ||
-            m_phase == PHASE_SETUPc  ||
-            m_phase == PHASE_SETUPs  ||
-            m_phase == PHASE_READ    )
-    {
-        pParti = partiPosBig;
-        pGlint = glintPosBig;
-    }
-    else
-    {
-        return;
-    }
-
-    nParti = static_cast<int>(*pParti++);
-    nGlint = static_cast<int>(*pGlint++);
-
-    for ( i=0 ; i<10 ; i++ )
-    {
-        if ( m_partiPhase[i] == 0 )  // waiting?
-        {
-            m_partiTime[i] -= rTime;
-            if ( m_partiTime[i] <= 0.0f )
-            {
-                r = rand()%3;
-
-                if ( r == 0 )
-                {
-                    ii = rand()%nParti;
-                    m_partiPos[i].x = pParti[ii*5+0]/640.0f;
-                    m_partiPos[i].y = (480.0f-pParti[ii*5+1])/480.0f;
-                    m_partiTime[i] = pParti[ii*5+2]+Math::Rand()*pParti[ii*5+3];
-                    m_partiPhase[i] = static_cast<int>(pParti[ii*5+4]);
-                    if ( m_partiPhase[i] == 3 )
-                    {
-                        m_sound->Play(SOUND_PSHHH, SoundPos(m_partiPos[i]), 0.3f+Math::Rand()*0.3f);
-                    }
-                    else
-                    {
-                        m_sound->Play(SOUND_GGG, SoundPos(m_partiPos[i]), 0.1f+Math::Rand()*0.4f);
-                    }
-                }
-
-                if ( r == 1 )
-                {
-                    ii = rand()%nGlint;
-                    pos.x = pGlint[ii*2+0]/640.0f;
-                    pos.y = (480.0f-pGlint[ii*2+1])/480.0f;
-                    pos.z = 0.0f;
-                    speed.x = 0.0f;
-                    speed.y = 0.0f;
-                    speed.z = 0.0f;
-                    dim.x = 0.04f+Math::Rand()*0.04f;
-                    dim.y = dim.x/0.75f;
-                    m_particle->CreateParticle(pos, speed, dim,
-                            rand()%2?Gfx::PARTIGLINT:Gfx::PARTICONTROL,
-                            Math::Rand()*0.4f+0.4f, 0.0f, 0.0f,
-                            Gfx::SH_INTERFACE);
-                    m_partiTime[i] = 0.5f+Math::Rand()*0.5f;
-                }
-
-                if ( r == 2 )
-                {
-                    ii = rand()%7;
-                    if ( ii == 0 )
-                    {
-                        m_sound->Play(SOUND_ENERGY, SoundRand(), 0.2f+Math::Rand()*0.2f);
-                        m_partiTime[i] = 1.0f+Math::Rand()*1.0f;
-                    }
-                    if ( ii == 1 )
-                    {
-                        m_sound->Play(SOUND_STATION, SoundRand(), 0.2f+Math::Rand()*0.2f);
-                        m_partiTime[i] = 1.0f+Math::Rand()*2.0f;
-                    }
-                    if ( ii == 2 )
-                    {
-                        m_sound->Play(SOUND_ALARM, SoundRand(), 0.1f+Math::Rand()*0.1f);
-                        m_partiTime[i] = 2.0f+Math::Rand()*4.0f;
-                    }
-                    if ( ii == 3 )
-                    {
-                        m_sound->Play(SOUND_INFO, SoundRand(), 0.1f+Math::Rand()*0.1f);
-                        m_partiTime[i] = 2.0f+Math::Rand()*4.0f;
-                    }
-                    if ( ii == 4 )
-                    {
-                        m_sound->Play(SOUND_RADAR, SoundRand(), 0.2f+Math::Rand()*0.2f);
-                        m_partiTime[i] = 0.5f+Math::Rand()*1.0f;
-                    }
-                    if ( ii == 5 )
-                    {
-                        m_sound->Play(SOUND_GFLAT, SoundRand(), 0.3f+Math::Rand()*0.3f);
-                        m_partiTime[i] = 2.0f+Math::Rand()*4.0f;
-                    }
-                    if ( ii == 6 )
-                    {
-                        m_sound->Play(SOUND_ALARMt, SoundRand(), 0.1f+Math::Rand()*0.1f);
-                        m_partiTime[i] = 2.0f+Math::Rand()*4.0f;
-                    }
-                }
-            }
-        }
-
-        if ( m_partiPhase[i] != 0 )  // generates?
-        {
-            m_partiTime[i] -= rTime;
-            if ( m_partiTime[i] > 0.0f )
-            {
-                if ( m_partiPhase[i] == 1 )  // sparks?
-                {
-                    pos.x = m_partiPos[i].x;
-                    pos.y = m_partiPos[i].y;
-                    pos.z = 0.0f;
-                    pos.x += (Math::Rand()-0.5f)*0.01f;
-                    pos.y += (Math::Rand()-0.5f)*0.01f;
-                    speed.x = (Math::Rand()-0.5f)*0.2f;
-                    speed.y = (Math::Rand()-0.5f)*0.2f;
-                    speed.z = 0.0f;
-                    dim.x = 0.005f+Math::Rand()*0.005f;
-                    dim.y = dim.x/0.75f;
-                    m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIBLITZ,
-                            Math::Rand()*0.2f+0.2f, 0.0f, 0.0f,
-                            Gfx::SH_INTERFACE);
-                    pos.x = m_partiPos[i].x;
-                    pos.y = m_partiPos[i].y;
-                    pos.z = 0.0f;
-                    speed.x = (Math::Rand()-0.5f)*0.5f;
-                    speed.y = (0.3f+Math::Rand()*0.3f);
-                    speed.z = 0.0f;
-                    dim.x = 0.01f+Math::Rand()*0.01f;
-                    dim.y = dim.x/0.75f;
-                    m_particle->CreateParticle(pos, speed, dim,
-                            static_cast<Gfx::ParticleType>(Gfx::PARTILENS1+rand()%3),
-                            Math::Rand()*0.5f+0.5f, 2.0f, 0.0f,
-                            Gfx::SH_INTERFACE);
-                }
-                if ( m_partiPhase[i] == 2 )  // sparks?
-                {
-                    pos.x = m_partiPos[i].x;
-                    pos.y = m_partiPos[i].y;
-                    pos.z = 0.0f;
-                    pos.x += (Math::Rand()-0.5f)*0.01f;
-                    pos.y += (Math::Rand()-0.5f)*0.01f;
-                    speed.x = (Math::Rand()-0.5f)*0.2f;
-                    speed.y = (Math::Rand()-0.5f)*0.2f;
-                    speed.z = 0.0f;
-                    dim.x = 0.005f+Math::Rand()*0.005f;
-                    dim.y = dim.x/0.75f;
-                    m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIBLITZ,
-                            Math::Rand()*0.2f+0.2f, 0.0f, 0.0f,
-                            Gfx::SH_INTERFACE);
-                    pos.x = m_partiPos[i].x;
-                    pos.y = m_partiPos[i].y;
-                    pos.z = 0.0f;
-                    speed.x = (Math::Rand()-0.5f)*0.5f;
-                    speed.y = (0.3f+Math::Rand()*0.3f);
-                    speed.z = 0.0f;
-                    dim.x = 0.005f+Math::Rand()*0.005f;
-                    dim.y = dim.x/0.75f;
-                    m_particle->CreateParticle(pos, speed, dim, Gfx::PARTISCRAPS,
-                            Math::Rand()*0.5f+0.5f, 2.0f, 0.0f,
-                            Gfx::SH_INTERFACE);
-                }
-                if ( m_partiPhase[i] == 3 )  // smoke?
-                {
-                    pos.x = m_partiPos[i].x;
-                    pos.y = m_partiPos[i].y;
-                    pos.z = 0.0f;
-                    pos.x += (Math::Rand()-0.5f)*0.03f;
-                    pos.y += (Math::Rand()-0.5f)*0.03f;
-                    speed.x = (Math::Rand()-0.5f)*0.2f;
-                    speed.y = Math::Rand()*0.5f;
-                    speed.z = 0.0f;
-                    dim.x = 0.03f+Math::Rand()*0.07f;
-                    dim.y = dim.x/0.75f;
-                    m_particle->CreateParticle(pos, speed, dim, Gfx::PARTICRASH,
-                            Math::Rand()*0.4f+0.4f, 0.0f, 0.0f,
-                            Gfx::SH_INTERFACE);
-                }
-            }
-            else
-            {
-                m_partiPhase[i] = 0;
-                m_partiTime[i] = 2.0f+Math::Rand()*4.0f;
-            }
-        }
-    }
-    // #endif
-}
-
-// Some nice particles following the mouse.
-
-void CMainDialog::NiceParticle(Math::Point mouse, bool bPress)
-{
-    Math::Vector    pos, speed;
-    Math::Point     dim;
-
-    if ( !m_settings->GetInterfaceRain() )  return;
-    if ( (m_phase == PHASE_SIMUL ||
-                m_phase == PHASE_WIN   ||
-                m_phase == PHASE_LOST  ) &&
-            !m_bDialog             )  return;
-
-    if ( bPress )
-    {
-        pos.x = mouse.x;
-        pos.y = mouse.y;
-        pos.z = 0.0f;
-        speed.x = (Math::Rand()-0.5f)*0.5f;
-        speed.y = (0.3f+Math::Rand()*0.3f);
-        speed.z = 0.0f;
-        dim.x = 0.005f+Math::Rand()*0.005f;
-        dim.y = dim.x/0.75f;
-        m_particle->CreateParticle(pos, speed, dim, Gfx::PARTISCRAPS,
-                Math::Rand()*0.5f+0.5f, 2.0f, 0.0f,
-                Gfx::SH_INTERFACE);
-    }
-    else
-    {
-        pos.x = mouse.x;
-        pos.y = mouse.y;
-        pos.z = 0.0f;
-        speed.x = (Math::Rand()-0.5f)*0.5f;
-        speed.y = (0.3f+Math::Rand()*0.3f);
-        speed.z = 0.0f;
-        dim.x = 0.01f+Math::Rand()*0.01f;
-        dim.y = dim.x/0.75f;
-        m_particle->CreateParticle(pos, speed, dim,
-                static_cast<Gfx::ParticleType>(Gfx::PARTILENS1+rand()%3),
-                Math::Rand()*0.5f+0.5f, 2.0f, 0.0f,
-                Gfx::SH_INTERFACE);
-    }
-}
-
-// Updates the lists according to the cheat code.
-
-void CMainDialog::AllMissionUpdate()
-{
-    if ( m_phase == PHASE_LEVEL_LIST )
-    {
-        m_screenLevelList->AllMissionUpdate();
-    }
-}
-
-void CMainDialog::MakeSaveScreenshot(const std::string& name)
-{
-    m_shotDelay = 3;
-    m_shotName = CResourceManager::GetSaveLocation() + "/" + name; //TODO: Use PHYSFS?
-}
-
-// Updates the button "solution" according to cheat code.
-
-void CMainDialog::ShowSoluceUpdate()
-{
-    if ( m_phase == PHASE_LEVEL_LIST )
-    {
-        m_screenLevelList->ShowSoluceUpdate();
-    }
-}
-
 // Do you want to quit the current mission?
 
 void CMainDialog::StartAbort()
@@ -1336,54 +560,4 @@ bool CMainDialog::IsDialog()
     return m_bDialog;
 }
 
-
-// Whether to show the solution.
-
-bool CMainDialog::GetSceneSoluce()
-{
-    return m_screenLevelList->GetSceneSoluce();
-}
-
-bool CMainDialog::GetGamerOnlyHead()
-{
-    if (m_phase == PHASE_APPERANCE)
-        return m_screenAppearance->GetGamerOnlyHead();
-
-    return false;
-}
-
-float CMainDialog::GetPersoAngle()
-{
-    if (m_phase == PHASE_APPERANCE)
-        return m_screenAppearance->GetPersoAngle();
-
-    return 0.0f;
-}
-
-void CMainDialog::UpdateChapterPassed()
-{
-    m_screenLevelList->UpdateChapterPassed();
-}
-
-void CMainDialog::NextMission()
-{
-    m_screenLevelList->NextMission();
-}
-
-void CMainDialog::UpdateCustomLevelList()
-{
-    m_screenLevelList->UpdateCustomLevelList();
-}
-
-std::string CMainDialog::GetCustomLevelName(int id)
-{
-    return m_screenLevelList->GetCustomLevelName(id);
-}
-
-const std::vector<std::string>& CMainDialog::GetCustomLevelList()
-{
-    return m_screenLevelList->GetCustomLevelList();
-}
-
-
 } // namespace Ui
diff --git a/src/ui/maindialog.h b/src/ui/maindialog.h
index f2e5209e..4321341e 100644
--- a/src/ui/maindialog.h
+++ b/src/ui/maindialog.h
@@ -18,17 +18,13 @@
  */
 #pragma once
 
-#include "app/pausemanager.h"
+#include "common/event.h"
 
-#include "graphics/core/color.h"
-
-#include "object/level_category.h"
 #include "object/robotmain.h"
 
 #include <vector>
 
 
-class CEventQueue;
 class CSettings;
 class CSoundInterface;
 
@@ -42,8 +38,6 @@ namespace Ui
 {
 
 class CInterface;
-class CWindow;
-class CControl;
 
 class CScreen;
 class CScreenApperance;
@@ -70,13 +64,9 @@ public:
     CMainDialog();
     ~CMainDialog();
 
-    void    Create();
-
     bool    EventProcess(const Event &event);
     void    ChangePhase(Phase phase);
 
-    bool    GetSceneSoluce();
-
     void    StartAbort();
     void    StartDeleteObject();
     void    StartDeleteGame(char *gamer);
@@ -86,63 +76,15 @@ public:
     void    StopDialog();
     bool    IsDialog();
 
-    void    UpdateChapterPassed();
-    void    NextMission();
-
-    bool    GetGamerOnlyHead();
-    float   GetPersoAngle();
-
-    void    AllMissionUpdate();
-    void    ShowSoluceUpdate();
-
-    void    UpdateCustomLevelList();
-    std::string GetCustomLevelName(int id);
-    const std::vector<std::string>& GetCustomLevelList();
-
-    void    MakeSaveScreenshot(const std::string& name);
-
 protected:
-    void    GlintMove();
-    void    FrameParticle(float rTime);
-    void    NiceParticle(Math::Point mouse, bool bPress);
-
-    CScreenSetup* GetSetupScreen(Phase phase);
-
-protected:
-    CApplication*     m_app;
     CRobotMain*       m_main;
-    CEventQueue*      m_eventQueue;
     Gfx::CEngine*     m_engine;
-    CInterface*       m_interface;
     Gfx::CParticle*   m_particle;
-    Gfx::CCamera*     m_camera;
+    CInterface*       m_interface;
     CSoundInterface*  m_sound;
-    CPauseManager*    m_pause;
     CSettings*        m_settings;
 
-    CScreen* m_currentScreen;
-    std::unique_ptr<CScreenApperance> m_screenAppearance;
-    std::unique_ptr<CScreenIORead> m_screenIORead;
-    std::unique_ptr<CScreenIOWrite> m_screenIOWrite;
-    std::unique_ptr<CScreenLevelList> m_screenLevelList;
-    std::unique_ptr<CScreenLoading> m_screenLoading;
-    std::unique_ptr<CScreenMainMenu> m_screenMainMenu;
-    std::unique_ptr<CScreenPlayerSelect> m_screenPlayerSelect;
-    std::unique_ptr<CScreenQuit> m_screenQuit;
-    std::unique_ptr<CScreenSetupControls> m_screenSetupControls;
-    std::unique_ptr<CScreenSetupDisplay> m_screenSetupDisplay;
-    std::unique_ptr<CScreenSetupGame> m_screenSetupGame;
-    std::unique_ptr<CScreenSetupGraphics> m_screenSetupGraphics;
-    std::unique_ptr<CScreenSetupSound> m_screenSetupSound;
-    std::unique_ptr<CScreenWelcome> m_screenWelcome;
-
-    Phase           m_phase;            // copy of CRobotMain
-
-    int             m_shotDelay;        // number of frames before copy
-    std::string     m_shotName;        // generate a file name
-
-    Math::Point          m_glintMouse;
-    float                m_glintTime;
+    Phase                m_phase;            // copy of CRobotMain
 
     bool                 m_bDialog;          // this dialogue?
     bool                 m_bDialogFire;          // setting on fire?
@@ -151,10 +93,6 @@ protected:
     Math::Point          m_dialogDim;
     float                m_dialogParti;
     float                m_dialogTime;
-
-    int                  m_partiPhase[10];
-    float                m_partiTime[10];
-    Math::Point          m_partiPos[10];
 };
 
 } // namespace Ui
diff --git a/src/ui/mainui.cpp b/src/ui/mainui.cpp
new file mode 100644
index 00000000..18511328
--- /dev/null
+++ b/src/ui/mainui.cpp
@@ -0,0 +1,866 @@
+/*
+ * This file is part of the Colobot: Gold Edition source code
+ * Copyright (C) 2001-2015, Daniel Roux, EPSITEC SA & TerranovaTeam
+ * http://epsiteс.ch; http://colobot.info; http://github.com/colobot
+ *
+ * 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 3 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, see http://gnu.org/licenses
+ */
+
+
+#include "ui/mainui.h"
+
+#include "common/config.h"
+
+#include "app/app.h"
+
+#include "common/event.h"
+#include "common/logger.h"
+#include "common/make_unique.h"
+#include "common/settings.h"
+
+#include "common/resources/resourcemanager.h"
+
+#include "object/robotmain.h"
+
+#include "sound/sound.h"
+
+#include "ui/screen/screen.h"
+#include "ui/screen/screen_apperance.h"
+#include "ui/screen/screen_io_read.h"
+#include "ui/screen/screen_io_write.h"
+#include "ui/screen/screen_level_list.h"
+#include "ui/screen/screen_loading.h"
+#include "ui/screen/screen_main_menu.h"
+#include "ui/screen/screen_player_select.h"
+#include "ui/screen/screen_setup_controls.h"
+#include "ui/screen/screen_setup_display.h"
+#include "ui/screen/screen_setup_game.h"
+#include "ui/screen/screen_setup_graphics.h"
+#include "ui/screen/screen_setup_sound.h"
+#include "ui/screen/screen_quit.h"
+#include "ui/screen/screen_welcome.h"
+
+#include "ui/interface.h"
+#include "ui/label.h"
+#include "ui/maindialog.h"
+#include "ui/window.h"
+
+namespace Ui
+{
+
+template<> CMainUserInterface* CSingleton<CMainUserInterface>::m_instance = nullptr;
+
+// Constructor of robot application.
+
+CMainUserInterface::CMainUserInterface()
+{
+    m_main       = CRobotMain::GetInstancePointer();
+    m_engine     = Gfx::CEngine::GetInstancePointer();
+    m_particle   = m_engine->GetParticle();
+    m_interface  = m_main->GetInterface();
+    m_sound      = CApplication::GetInstancePointer()->GetSound();
+    m_settings   = CSettings::GetInstancePointer();
+
+    m_dialog     = MakeUnique<CMainDialog>();
+
+    m_screenAppearance = MakeUnique<CScreenApperance>();
+    m_screenLevelList = MakeUnique<CScreenLevelList>();
+    m_screenIORead = MakeUnique<CScreenIORead>(m_screenLevelList.get());
+    m_screenIOWrite = MakeUnique<CScreenIOWrite>(m_screenLevelList.get());
+    m_screenLoading = MakeUnique<CScreenLoading>();
+    m_screenSetupControls = MakeUnique<CScreenSetupControls>();
+    m_screenSetupDisplay = MakeUnique<CScreenSetupDisplay>();
+    m_screenSetupGame = MakeUnique<CScreenSetupGame>();
+    m_screenSetupGraphics = MakeUnique<CScreenSetupGraphics>();
+    m_screenSetupSound = MakeUnique<CScreenSetupSound>();
+    m_screenMainMenu = MakeUnique<CScreenMainMenu>();
+    m_screenPlayerSelect = MakeUnique<CScreenPlayerSelect>(m_dialog.get());
+    m_screenQuit = MakeUnique<CScreenQuit>();
+    m_screenWelcome = MakeUnique<CScreenWelcome>();
+
+    m_currentScreen = nullptr;
+
+    m_phase         = PHASE_PLAYER_SELECT;
+
+    m_shotDelay  = 0;
+
+    m_glintMouse = Math::Point(0.0f, 0.0f);
+    m_glintTime  = 1000.0f;
+
+    for (int i = 0; i < 10; i++)
+    {
+        m_partiPhase[i] = 0;
+        m_partiTime[i]  = 0.0f;
+    }
+}
+
+// Destructor of robot application.
+
+CMainUserInterface::~CMainUserInterface()
+{
+}
+
+CMainDialog* CMainUserInterface::GetDialog()
+{
+    return m_dialog.get();
+}
+
+
+// Changes phase.
+
+CScreenSetup* CMainUserInterface::GetSetupScreen(Phase phase)
+{
+    if(phase == PHASE_SETUPd) return m_screenSetupDisplay.get();
+    if(phase == PHASE_SETUPg) return m_screenSetupGraphics.get();
+    if(phase == PHASE_SETUPp) return m_screenSetupGame.get();
+    if(phase == PHASE_SETUPc) return m_screenSetupControls.get();
+    if(phase == PHASE_SETUPs) return m_screenSetupSound.get();
+    assert(false);
+    return nullptr;
+}
+
+void CMainUserInterface::ChangePhase(Phase phase)
+{
+    m_main->GetCamera()->SetType(Gfx::CAM_TYPE_DIALOG);
+    m_engine->SetOverFront(false);
+    m_engine->SetOverColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f), Gfx::ENG_RSTATE_TCOLOR_BLACK); // TODO: color ok?
+
+    m_phase = phase;  // copy the info from CRobotMain
+    m_dialog->ChangePhase(m_phase);
+
+    m_currentScreen = nullptr;
+
+    if (m_phase == PHASE_QUIT_SCREEN)
+    {
+        m_currentScreen = m_screenQuit.get();
+    }
+    if (m_phase >= PHASE_WELCOME1 && m_phase <= PHASE_WELCOME3)
+    {
+        m_screenWelcome->SetImageIndex(m_phase - PHASE_WELCOME1);
+        m_currentScreen = m_screenWelcome.get();
+    }
+    if (m_phase == PHASE_PLAYER_SELECT)
+    {
+        m_currentScreen = m_screenPlayerSelect.get();
+    }
+    if (m_phase == PHASE_APPERANCE)
+    {
+        m_currentScreen = m_screenAppearance.get();
+    }
+    if (m_phase == PHASE_MAIN_MENU)
+    {
+        m_currentScreen = m_screenMainMenu.get();
+    }
+    if (m_phase == PHASE_LEVEL_LIST)
+    {
+        m_screenLevelList->SetLevelCategory(m_main->GetLevelCategory());
+        m_currentScreen = m_screenLevelList.get();
+    }
+    if (m_phase == PHASE_LOADING)
+    {
+        m_currentScreen = m_screenLoading.get();
+    }
+    if (m_phase >= PHASE_SETUPd && m_phase <= PHASE_SETUPs)
+    {
+        CScreenSetup* screenSetup = GetSetupScreen(m_phase);
+        screenSetup->SetInSimulation(false);
+        screenSetup->SetActive();
+        m_currentScreen = screenSetup;
+    }
+    if (m_phase >= PHASE_SETUPds && m_phase <= PHASE_SETUPss)
+    {
+        CScreenSetup* screenSetup = GetSetupScreen(static_cast<Phase>(m_phase - PHASE_SETUPds + PHASE_SETUPd));
+        screenSetup->SetInSimulation(true);
+        screenSetup->SetActive();
+        m_currentScreen = screenSetup;
+    }
+    if (m_phase == PHASE_WRITEs)
+    {
+        m_currentScreen = m_screenIOWrite.get();
+    }
+    if (m_phase == PHASE_READ || m_phase == PHASE_READs)
+    {
+        m_currentScreen = m_screenIORead.get();
+        m_screenIORead->SetInSimulation(m_phase == PHASE_READs);
+    }
+
+    if (m_currentScreen != nullptr)
+    {
+        m_currentScreen->CreateInterface();
+    }
+
+    if ( !IsPhaseWithWorld(m_phase) )
+    {
+        if (!m_sound->IsPlayingMusic() && m_sound->IsCachedMusic("Intro1.ogg"))
+        {
+            m_sound->PlayMusic("Intro1.ogg", false);
+        }
+    }
+
+    if ( !IsPhaseWithWorld(m_phase) )
+    {
+        CWindow* pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
+        if (pw != nullptr)
+        {
+            Math::Point pos, ddim;
+
+            pos.x  = 540.0f/640.0f;
+            pos.y  =   9.0f/480.0f;
+            ddim.x =  90.0f/640.0f;
+            ddim.y =  10.0f/480.0f;
+            CLabel* pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL1, COLOBOT_VERSION_DISPLAY);
+            pl->SetFontType(Gfx::FONT_COURIER);
+            pl->SetFontSize(9.0f);
+        }
+    }
+
+    m_engine->LoadAllTextures();
+}
+
+
+// Processing an event.
+// Returns false if the event has been processed completely.
+
+bool CMainUserInterface::EventProcess(const Event &event)
+{
+    if ( !m_interface->EventProcess(event) )
+    {
+        return false;
+    }
+
+    if (m_currentScreen != nullptr && !m_currentScreen->EventProcess(event)) return false;
+
+    if ( event.type == EVENT_FRAME )
+    {
+        if ( !IsPhaseWithWorld(m_phase) )
+        {
+            if (!m_sound->IsPlayingMusic() && m_sound->IsCachedMusic("Intro2.ogg"))
+            {
+                m_sound->PlayMusic("Intro2.ogg", true);
+            }
+        }
+
+        if ( m_shotDelay > 0 && !m_dialog->IsDialog() )
+        {
+            m_shotDelay --;
+            if ( m_shotDelay == 0 )
+            {
+                m_engine->WriteScreenShot(m_shotName);
+            }
+        }
+
+        m_glintTime += event.rTime;
+        GlintMove();  // moves reflections
+
+        FrameParticle(event.rTime);
+
+        return true;
+    }
+
+    if ( event.type == EVENT_MOUSE_MOVE )
+    {
+        m_glintMouse = event.mousePos;
+        NiceParticle(event.mousePos, event.mouseButtonsState & MOUSE_BUTTON_LEFT);
+    }
+
+    if (!m_dialog->EventProcess(event)) return false;
+
+    return true;
+}
+
+
+// Moves the reflections.
+
+void CMainUserInterface::GlintMove()
+{
+    CWindow*    pw;
+    CGroup*     pg;
+    Math::Point     pos, dim, zoom;
+
+    if ( m_phase == PHASE_SIMUL )  return;
+
+    pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
+    if ( pw == 0 )  return;
+
+    if ( m_phase == PHASE_MAIN_MENU )
+    {
+        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTl));
+        if ( pg != 0 )
+        {
+            zoom.x = sinf(m_glintTime*0.23f);
+            zoom.y = sinf(m_glintTime*0.37f);
+            pos.x = 0.35f;
+            pos.y = 0.90f;
+            dim.x = 0.30f-0.10f*(zoom.x+1.0f)/2.0f;
+            dim.y = 0.50f-0.30f*(zoom.y+1.0f)/2.0f;
+            pos.y -= dim.y;
+            pg->SetPos(pos);
+            pg->SetDim(dim);
+        }
+
+        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTr));
+        if ( pg != 0 )
+        {
+            zoom.x = sinf(m_glintTime*0.21f);
+            zoom.y = sinf(m_glintTime*0.26f);
+            pos.x = 0.65f;
+            pos.y = 0.10f;
+            dim.x = 0.30f-0.10f*(zoom.x+1.0f)/2.0f;
+            dim.y = 0.50f-0.30f*(zoom.y+1.0f)/2.0f;
+            pos.x -= dim.x;
+            pg->SetPos(pos);
+            pg->SetDim(dim);
+        }
+    }
+
+    if ( m_phase == PHASE_PLAYER_SELECT       ||
+         m_phase == PHASE_LEVEL_LIST  )
+    {
+        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTl));
+        if ( pg != 0 )
+        {
+            zoom.x = sinf(m_glintTime*0.22f);
+            zoom.y = sinf(m_glintTime*0.37f);
+            pos.x = 0.10f;
+            pos.y = 0.90f;
+            dim.x = 0.60f+0.30f*zoom.x;
+            dim.y = 0.60f+0.30f*zoom.y;
+            pos.y -= dim.y;
+            pg->SetPos(pos);
+            pg->SetDim(dim);
+        }
+
+        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTr));
+        if ( pg != 0 )
+        {
+            zoom.x = sinf(m_glintTime*0.19f);
+            zoom.y = sinf(m_glintTime*0.28f);
+            pos.x = 0.90f;
+            pos.y = 0.10f;
+            dim.x = 0.60f+0.30f*zoom.x;
+            dim.y = 0.60f+0.30f*zoom.y;
+            pos.x -= dim.x;
+            pg->SetPos(pos);
+            pg->SetDim(dim);
+        }
+    }
+
+    if ( m_phase == PHASE_SETUPd  ||
+            m_phase == PHASE_SETUPg  ||
+            m_phase == PHASE_SETUPp  ||
+            m_phase == PHASE_SETUPc  ||
+            m_phase == PHASE_SETUPs  ||
+            m_phase == PHASE_SETUPds ||
+            m_phase == PHASE_SETUPgs ||
+            m_phase == PHASE_SETUPps ||
+            m_phase == PHASE_SETUPcs ||
+            m_phase == PHASE_SETUPss )
+    {
+        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTu));
+        if ( pg != 0 )
+        {
+            zoom.y = sinf(m_glintTime*0.27f);
+            pos.x = 0.10f;
+            pos.y = 0.76f;
+            dim.x = 0.80f;
+            dim.y = 0.32f+0.20f*zoom.y;
+            pos.y -= dim.y;
+            pg->SetPos(pos);
+            pg->SetDim(dim);
+        }
+
+        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTr));
+        if ( pg != 0 )
+        {
+            zoom.x = sinf(m_glintTime*0.29f);
+            zoom.y = sinf(m_glintTime*0.14f);
+            pos.x = 0.90f;
+            pos.y = 0.10f;
+            dim.x = 0.40f+0.20f*zoom.x;
+            dim.y = 0.40f+0.20f*zoom.y;
+            pos.x -= dim.x;
+            pg->SetPos(pos);
+            pg->SetDim(dim);
+        }
+    }
+
+    if ( m_phase == PHASE_WRITEs ||
+         m_phase == PHASE_READ   ||
+         m_phase == PHASE_READs  )
+    {
+        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTl));
+        if ( pg != 0 )
+        {
+            zoom.x = sinf(m_glintTime*0.22f);
+            zoom.y = sinf(m_glintTime*0.37f);
+            pos.x = 0.10f;
+            pos.y = 0.90f;
+            dim.x = 0.60f+0.30f*zoom.x;
+            dim.y = 0.60f+0.30f*zoom.y;
+            pos.y -= dim.y;
+            pg->SetPos(pos);
+            pg->SetDim(dim);
+        }
+
+        pg = static_cast<CGroup*>(pw->SearchControl(EVENT_INTERFACE_GLINTr));
+        if ( pg != 0 )
+        {
+            zoom.x = sinf(m_glintTime*0.19f);
+            zoom.y = sinf(m_glintTime*0.28f);
+            pos.x = 0.90f;
+            pos.y = 0.10f;
+            dim.x = 0.60f+0.30f*zoom.x;
+            dim.y = 0.60f+0.30f*zoom.y;
+            pos.x -= dim.x;
+            pg->SetPos(pos);
+            pg->SetDim(dim);
+        }
+    }
+}
+
+
+// Returns the position for a sound.
+
+Math::Vector SoundPos(Math::Point pos)
+{
+    Math::Vector    s;
+
+    s.x = (pos.x-0.5f)*2.0f;
+    s.y = (pos.y-0.5f)*2.0f;
+    s.z = 0.0f;
+
+    return s;
+}
+
+// Returns a random position for a sound.
+
+Math::Vector SoundRand()
+{
+    Math::Vector    s;
+
+    s.x = (Math::Rand()-0.5f)*2.0f;
+    s.y = (Math::Rand()-0.5f)*2.0f;
+    s.z = 0.0f;
+
+    return s;
+}
+
+// Makes pretty qq particles evolve.
+
+void CMainUserInterface::FrameParticle(float rTime)
+{
+    Math::Vector    pos, speed;
+    Math::Point     dim;
+    float       *pParti, *pGlint;
+    int          nParti,  nGlint;
+    int         i, r, ii;
+
+    static float partiPosInit[1+5*12] =
+    { //  x       x      t2    t2   type
+        12.0f,
+        607.0f, 164.0f, 0.2f, 0.8f, 1.0f,  // upper cable
+        604.0f, 205.0f, 0.1f, 0.3f, 1.0f,  // middle cable
+        603.0f, 247.0f, 0.1f, 0.3f, 1.0f,  // lower cable
+        119.0f, 155.0f, 0.2f, 0.4f, 2.0f,  // left pipe
+        366.0f,  23.0f, 0.5f, 1.5f, 4.0f,  // upper pipe
+        560.0f, 414.0f, 0.1f, 0.1f, 1.0f,  // button lower/right
+        20.0f, 413.0f, 0.1f, 0.1f, 2.0f,  // button lower/left
+        39.0f,  78.0f, 0.1f, 0.2f, 1.0f,  // left pot
+        39.0f,  78.0f, 0.5f, 0.9f, 1.0f,  // left pot
+        170.0f, 229.0f, 0.5f, 0.5f, 3.0f,  // left smoke
+        170.0f, 229.0f, 0.5f, 0.5f, 3.0f,  // left smoke
+        474.0f, 229.0f, 0.5f, 0.5f, 3.0f,  // right smoke
+    };
+
+    static float glintPosInit[1+2*14] =
+    {
+        14.0f,
+        15.0f, 407.0f,
+        68.0f, 417.0f,
+        548.0f,  36.0f,
+        611.0f,  37.0f,
+        611.0f, 100.0f,
+        611.0f, 395.0f,
+        36.0f,  35.0f,
+        166.0f,  55.0f,
+        166.0f,  94.0f,
+        477.0f,  56.0f,
+        31.0f, 190.0f,
+        32.0f, 220.0f,
+        65.0f, 221.0f,
+        65.0f, 250.0f,
+    };
+
+    static float partiPosBig[1+5*12] =
+    { //  x       x      t2    t2   type
+        12.0f,
+        607.0f, 164.0f, 0.2f, 0.8f, 1.0f,  // upper cable
+        604.0f, 205.0f, 0.1f, 0.3f, 1.0f,  // middle cable
+        603.0f, 247.0f, 0.1f, 0.3f, 1.0f,  // lower cable
+        64.0f, 444.0f, 0.2f, 0.8f, 1.0f,  // down the left cable
+        113.0f, 449.0f, 0.1f, 0.3f, 1.0f,  // down the left cable
+        340.0f, 463.0f, 0.2f, 0.8f, 1.0f,  // down the middle cable
+        36.0f, 155.0f, 0.2f, 0.4f, 2.0f,  // left pipe
+        366.0f,  23.0f, 0.5f, 1.5f, 4.0f,  // upper pipe
+        612.0f, 414.0f, 0.1f, 0.1f, 1.0f,  // button lower/right
+        20.0f, 413.0f, 0.1f, 0.1f, 2.0f,  // button lower/left
+        39.0f,  78.0f, 0.1f, 0.2f, 1.0f,  // left pot
+        39.0f,  78.0f, 0.5f, 0.9f, 1.0f,  // left pot
+    };
+
+    static float glintPosBig[1+2*12] =
+    {
+        12.0f,
+        15.0f, 407.0f,
+        48.0f, 399.0f,
+        611.0f,  37.0f,
+        611.0f, 100.0f,
+        611.0f, 395.0f,
+        36.0f,  35.0f,
+        31.0f, 190.0f,
+        32.0f, 220.0f,
+        31.0f, 221.0f,
+        31.0f, 189.0f,
+        255.0f,  18.0f,
+        279.0f,  18.0f,
+    };
+
+    if ( m_dialog->IsDialog() || !m_settings->GetInterfaceRain() )  return;
+
+    if ( m_phase == PHASE_MAIN_MENU )
+    {
+        pParti = partiPosInit;
+        pGlint = glintPosInit;
+    }
+    else if ( m_phase == PHASE_PLAYER_SELECT    ||
+            m_phase == PHASE_LEVEL_LIST ||
+            m_phase == PHASE_SETUPd  ||
+            m_phase == PHASE_SETUPg  ||
+            m_phase == PHASE_SETUPp  ||
+            m_phase == PHASE_SETUPc  ||
+            m_phase == PHASE_SETUPs  ||
+            m_phase == PHASE_READ    )
+    {
+        pParti = partiPosBig;
+        pGlint = glintPosBig;
+    }
+    else
+    {
+        return;
+    }
+
+    nParti = static_cast<int>(*pParti++);
+    nGlint = static_cast<int>(*pGlint++);
+
+    for ( i=0 ; i<10 ; i++ )
+    {
+        if ( m_partiPhase[i] == 0 )  // waiting?
+        {
+            m_partiTime[i] -= rTime;
+            if ( m_partiTime[i] <= 0.0f )
+            {
+                r = rand()%3;
+
+                if ( r == 0 )
+                {
+                    ii = rand()%nParti;
+                    m_partiPos[i].x = pParti[ii*5+0]/640.0f;
+                    m_partiPos[i].y = (480.0f-pParti[ii*5+1])/480.0f;
+                    m_partiTime[i] = pParti[ii*5+2]+Math::Rand()*pParti[ii*5+3];
+                    m_partiPhase[i] = static_cast<int>(pParti[ii*5+4]);
+                    if ( m_partiPhase[i] == 3 )
+                    {
+                        m_sound->Play(SOUND_PSHHH, SoundPos(m_partiPos[i]), 0.3f+Math::Rand()*0.3f);
+                    }
+                    else
+                    {
+                        m_sound->Play(SOUND_GGG, SoundPos(m_partiPos[i]), 0.1f+Math::Rand()*0.4f);
+                    }
+                }
+
+                if ( r == 1 )
+                {
+                    ii = rand()%nGlint;
+                    pos.x = pGlint[ii*2+0]/640.0f;
+                    pos.y = (480.0f-pGlint[ii*2+1])/480.0f;
+                    pos.z = 0.0f;
+                    speed.x = 0.0f;
+                    speed.y = 0.0f;
+                    speed.z = 0.0f;
+                    dim.x = 0.04f+Math::Rand()*0.04f;
+                    dim.y = dim.x/0.75f;
+                    m_particle->CreateParticle(pos, speed, dim,
+                            rand()%2?Gfx::PARTIGLINT:Gfx::PARTICONTROL,
+                            Math::Rand()*0.4f+0.4f, 0.0f, 0.0f,
+                            Gfx::SH_INTERFACE);
+                    m_partiTime[i] = 0.5f+Math::Rand()*0.5f;
+                }
+
+                if ( r == 2 )
+                {
+                    ii = rand()%7;
+                    if ( ii == 0 )
+                    {
+                        m_sound->Play(SOUND_ENERGY, SoundRand(), 0.2f+Math::Rand()*0.2f);
+                        m_partiTime[i] = 1.0f+Math::Rand()*1.0f;
+                    }
+                    if ( ii == 1 )
+                    {
+                        m_sound->Play(SOUND_STATION, SoundRand(), 0.2f+Math::Rand()*0.2f);
+                        m_partiTime[i] = 1.0f+Math::Rand()*2.0f;
+                    }
+                    if ( ii == 2 )
+                    {
+                        m_sound->Play(SOUND_ALARM, SoundRand(), 0.1f+Math::Rand()*0.1f);
+                        m_partiTime[i] = 2.0f+Math::Rand()*4.0f;
+                    }
+                    if ( ii == 3 )
+                    {
+                        m_sound->Play(SOUND_INFO, SoundRand(), 0.1f+Math::Rand()*0.1f);
+                        m_partiTime[i] = 2.0f+Math::Rand()*4.0f;
+                    }
+                    if ( ii == 4 )
+                    {
+                        m_sound->Play(SOUND_RADAR, SoundRand(), 0.2f+Math::Rand()*0.2f);
+                        m_partiTime[i] = 0.5f+Math::Rand()*1.0f;
+                    }
+                    if ( ii == 5 )
+                    {
+                        m_sound->Play(SOUND_GFLAT, SoundRand(), 0.3f+Math::Rand()*0.3f);
+                        m_partiTime[i] = 2.0f+Math::Rand()*4.0f;
+                    }
+                    if ( ii == 6 )
+                    {
+                        m_sound->Play(SOUND_ALARMt, SoundRand(), 0.1f+Math::Rand()*0.1f);
+                        m_partiTime[i] = 2.0f+Math::Rand()*4.0f;
+                    }
+                }
+            }
+        }
+
+        if ( m_partiPhase[i] != 0 )  // generates?
+        {
+            m_partiTime[i] -= rTime;
+            if ( m_partiTime[i] > 0.0f )
+            {
+                if ( m_partiPhase[i] == 1 )  // sparks?
+                {
+                    pos.x = m_partiPos[i].x;
+                    pos.y = m_partiPos[i].y;
+                    pos.z = 0.0f;
+                    pos.x += (Math::Rand()-0.5f)*0.01f;
+                    pos.y += (Math::Rand()-0.5f)*0.01f;
+                    speed.x = (Math::Rand()-0.5f)*0.2f;
+                    speed.y = (Math::Rand()-0.5f)*0.2f;
+                    speed.z = 0.0f;
+                    dim.x = 0.005f+Math::Rand()*0.005f;
+                    dim.y = dim.x/0.75f;
+                    m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIBLITZ,
+                            Math::Rand()*0.2f+0.2f, 0.0f, 0.0f,
+                            Gfx::SH_INTERFACE);
+                    pos.x = m_partiPos[i].x;
+                    pos.y = m_partiPos[i].y;
+                    pos.z = 0.0f;
+                    speed.x = (Math::Rand()-0.5f)*0.5f;
+                    speed.y = (0.3f+Math::Rand()*0.3f);
+                    speed.z = 0.0f;
+                    dim.x = 0.01f+Math::Rand()*0.01f;
+                    dim.y = dim.x/0.75f;
+                    m_particle->CreateParticle(pos, speed, dim,
+                            static_cast<Gfx::ParticleType>(Gfx::PARTILENS1+rand()%3),
+                            Math::Rand()*0.5f+0.5f, 2.0f, 0.0f,
+                            Gfx::SH_INTERFACE);
+                }
+                if ( m_partiPhase[i] == 2 )  // sparks?
+                {
+                    pos.x = m_partiPos[i].x;
+                    pos.y = m_partiPos[i].y;
+                    pos.z = 0.0f;
+                    pos.x += (Math::Rand()-0.5f)*0.01f;
+                    pos.y += (Math::Rand()-0.5f)*0.01f;
+                    speed.x = (Math::Rand()-0.5f)*0.2f;
+                    speed.y = (Math::Rand()-0.5f)*0.2f;
+                    speed.z = 0.0f;
+                    dim.x = 0.005f+Math::Rand()*0.005f;
+                    dim.y = dim.x/0.75f;
+                    m_particle->CreateParticle(pos, speed, dim, Gfx::PARTIBLITZ,
+                            Math::Rand()*0.2f+0.2f, 0.0f, 0.0f,
+                            Gfx::SH_INTERFACE);
+                    pos.x = m_partiPos[i].x;
+                    pos.y = m_partiPos[i].y;
+                    pos.z = 0.0f;
+                    speed.x = (Math::Rand()-0.5f)*0.5f;
+                    speed.y = (0.3f+Math::Rand()*0.3f);
+                    speed.z = 0.0f;
+                    dim.x = 0.005f+Math::Rand()*0.005f;
+                    dim.y = dim.x/0.75f;
+                    m_particle->CreateParticle(pos, speed, dim, Gfx::PARTISCRAPS,
+                            Math::Rand()*0.5f+0.5f, 2.0f, 0.0f,
+                            Gfx::SH_INTERFACE);
+                }
+                if ( m_partiPhase[i] == 3 )  // smoke?
+                {
+                    pos.x = m_partiPos[i].x;
+                    pos.y = m_partiPos[i].y;
+                    pos.z = 0.0f;
+                    pos.x += (Math::Rand()-0.5f)*0.03f;
+                    pos.y += (Math::Rand()-0.5f)*0.03f;
+                    speed.x = (Math::Rand()-0.5f)*0.2f;
+                    speed.y = Math::Rand()*0.5f;
+                    speed.z = 0.0f;
+                    dim.x = 0.03f+Math::Rand()*0.07f;
+                    dim.y = dim.x/0.75f;
+                    m_particle->CreateParticle(pos, speed, dim, Gfx::PARTICRASH,
+                            Math::Rand()*0.4f+0.4f, 0.0f, 0.0f,
+                            Gfx::SH_INTERFACE);
+                }
+            }
+            else
+            {
+                m_partiPhase[i] = 0;
+                m_partiTime[i] = 2.0f+Math::Rand()*4.0f;
+            }
+        }
+    }
+}
+
+// Some nice particles following the mouse.
+
+void CMainUserInterface::NiceParticle(Math::Point mouse, bool bPress)
+{
+    Math::Vector    pos, speed;
+    Math::Point     dim;
+
+    if ( !m_settings->GetInterfaceRain() )  return;
+    if ( (m_phase == PHASE_SIMUL ||
+          m_phase == PHASE_WIN   ||
+          m_phase == PHASE_LOST  ) &&
+         m_dialog->IsDialog()       )  return;
+
+    if ( bPress )
+    {
+        pos.x = mouse.x;
+        pos.y = mouse.y;
+        pos.z = 0.0f;
+        speed.x = (Math::Rand()-0.5f)*0.5f;
+        speed.y = (0.3f+Math::Rand()*0.3f);
+        speed.z = 0.0f;
+        dim.x = 0.005f+Math::Rand()*0.005f;
+        dim.y = dim.x/0.75f;
+        m_particle->CreateParticle(pos, speed, dim, Gfx::PARTISCRAPS,
+                Math::Rand()*0.5f+0.5f, 2.0f, 0.0f,
+                Gfx::SH_INTERFACE);
+    }
+    else
+    {
+        pos.x = mouse.x;
+        pos.y = mouse.y;
+        pos.z = 0.0f;
+        speed.x = (Math::Rand()-0.5f)*0.5f;
+        speed.y = (0.3f+Math::Rand()*0.3f);
+        speed.z = 0.0f;
+        dim.x = 0.01f+Math::Rand()*0.01f;
+        dim.y = dim.x/0.75f;
+        m_particle->CreateParticle(pos, speed, dim,
+                static_cast<Gfx::ParticleType>(Gfx::PARTILENS1+rand()%3),
+                Math::Rand()*0.5f+0.5f, 2.0f, 0.0f,
+                Gfx::SH_INTERFACE);
+    }
+}
+
+// Updates the lists according to the cheat code.
+
+void CMainUserInterface::AllMissionUpdate()
+{
+    if ( m_phase == PHASE_LEVEL_LIST )
+    {
+        m_screenLevelList->AllMissionUpdate();
+    }
+}
+
+void CMainUserInterface::MakeSaveScreenshot(const std::string& name)
+{
+    m_shotDelay = 3;
+    m_shotName = CResourceManager::GetSaveLocation() + "/" + name; //TODO: Use PHYSFS?
+}
+
+// Updates the button "solution" according to cheat code.
+
+void CMainUserInterface::ShowSoluceUpdate()
+{
+    if ( m_phase == PHASE_LEVEL_LIST )
+    {
+        m_screenLevelList->ShowSoluceUpdate();
+    }
+}
+
+// TODO: Clean this up
+void CMainUserInterface::NameDelete()
+{
+    if ( m_phase == PHASE_PLAYER_SELECT )
+    {
+        m_screenPlayerSelect->NameDelete();
+    }
+}
+
+// Whether to show the solution.
+
+bool CMainUserInterface::GetSceneSoluce()
+{
+    return m_screenLevelList->GetSceneSoluce();
+}
+
+bool CMainUserInterface::GetGamerOnlyHead()
+{
+    if (m_phase == PHASE_APPERANCE)
+        return m_screenAppearance->GetGamerOnlyHead();
+
+    return false;
+}
+
+float CMainUserInterface::GetPersoAngle()
+{
+    if (m_phase == PHASE_APPERANCE)
+        return m_screenAppearance->GetPersoAngle();
+
+    return 0.0f;
+}
+
+void CMainUserInterface::UpdateChapterPassed()
+{
+    m_screenLevelList->UpdateChapterPassed();
+}
+
+void CMainUserInterface::NextMission()
+{
+    m_screenLevelList->NextMission();
+}
+
+void CMainUserInterface::UpdateCustomLevelList()
+{
+    m_screenLevelList->UpdateCustomLevelList();
+}
+
+std::string CMainUserInterface::GetCustomLevelName(int id)
+{
+    return m_screenLevelList->GetCustomLevelName(id);
+}
+
+const std::vector<std::string>& CMainUserInterface::GetCustomLevelList()
+{
+    return m_screenLevelList->GetCustomLevelList();
+}
+
+
+} // namespace Ui
diff --git a/src/ui/mainui.h b/src/ui/mainui.h
new file mode 100644
index 00000000..28e589c8
--- /dev/null
+++ b/src/ui/mainui.h
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the Colobot: Gold Edition source code
+ * Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam
+ * http://epsiteс.ch; http://colobot.info; http://github.com/colobot
+ *
+ * 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 3 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, see http://gnu.org/licenses
+ */
+#pragma once
+
+#include "common/singleton.h"
+
+#include "object/robotmain.h"
+
+#include <vector>
+
+
+class CSettings;
+class CSoundInterface;
+
+namespace Gfx
+{
+class CEngine;
+class CParticle;
+}
+
+namespace Ui
+{
+class CInterface;
+class CMainDialog;
+
+class CScreen;
+class CScreenApperance;
+class CScreenIORead;
+class CScreenIOWrite;
+class CScreenLevelList;
+class CScreenLoading;
+class CScreenMainMenu;
+class CScreenPlayerSelect;
+class CScreenQuit;
+class CScreenSetup;
+class CScreenSetupControls;
+class CScreenSetupDisplay;
+class CScreenSetupGame;
+class CScreenSetupGraphics;
+class CScreenSetupSound;
+class CScreenWelcome;
+
+
+
+class CMainUserInterface : public CSingleton<CMainUserInterface>
+{
+public:
+    CMainUserInterface();
+    ~CMainUserInterface();
+    void    Create();
+
+    CMainDialog* GetDialog();
+
+
+    bool    EventProcess(const Event &event);
+    void    ChangePhase(Phase phase);
+
+    bool    GetSceneSoluce();
+
+    void    UpdateChapterPassed();
+    void    NextMission();
+
+    bool    GetGamerOnlyHead();
+    float   GetPersoAngle();
+
+    void    AllMissionUpdate();
+    void    ShowSoluceUpdate();
+
+    void    NameDelete();
+
+    void    UpdateCustomLevelList();
+    std::string GetCustomLevelName(int id);
+    const std::vector<std::string>& GetCustomLevelList();
+
+    void    MakeSaveScreenshot(const std::string& name);
+
+protected:
+    void    GlintMove();
+    void    FrameParticle(float rTime);
+    void    NiceParticle(Math::Point mouse, bool bPress);
+
+    CScreenSetup* GetSetupScreen(Phase phase);
+
+protected:
+    CRobotMain*       m_main;
+    Gfx::CEngine*     m_engine;
+    Gfx::CParticle*   m_particle;
+    CInterface*       m_interface;
+    CSoundInterface*  m_sound;
+    CSettings*        m_settings;
+
+    std::unique_ptr<CMainDialog> m_dialog;
+
+    CScreen* m_currentScreen;
+    std::unique_ptr<CScreenApperance> m_screenAppearance;
+    std::unique_ptr<CScreenIORead> m_screenIORead;
+    std::unique_ptr<CScreenIOWrite> m_screenIOWrite;
+    std::unique_ptr<CScreenLevelList> m_screenLevelList;
+    std::unique_ptr<CScreenLoading> m_screenLoading;
+    std::unique_ptr<CScreenMainMenu> m_screenMainMenu;
+    std::unique_ptr<CScreenPlayerSelect> m_screenPlayerSelect;
+    std::unique_ptr<CScreenQuit> m_screenQuit;
+    std::unique_ptr<CScreenSetupControls> m_screenSetupControls;
+    std::unique_ptr<CScreenSetupDisplay> m_screenSetupDisplay;
+    std::unique_ptr<CScreenSetupGame> m_screenSetupGame;
+    std::unique_ptr<CScreenSetupGraphics> m_screenSetupGraphics;
+    std::unique_ptr<CScreenSetupSound> m_screenSetupSound;
+    std::unique_ptr<CScreenWelcome> m_screenWelcome;
+
+    Phase                m_phase;            // copy of CRobotMain
+
+    int                  m_shotDelay;        // number of frames before copy
+    std::string          m_shotName;        // generate a file name
+
+    Math::Point          m_glintMouse;
+    float                m_glintTime;
+
+    int                  m_partiPhase[10];
+    float                m_partiTime[10];
+    Math::Point          m_partiPos[10];
+};
+
+} // namespace Ui