From ebb6f47f501c83cf7720430f45ff7851e285af39 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Thu, 20 Sep 2018 08:40:22 +0200
Subject: [PATCH] Added GUI_App and MainFrame

---
 src/slic3r.cpp                    |   8 +-
 src/slic3r/CMakeLists.txt         |   4 +
 src/slic3r/GUI/BedShapeDialog.cpp |   6 -
 src/slic3r/GUI/GUI.cpp            |  10 +-
 src/slic3r/GUI/GUI.hpp            |  33 +-
 src/slic3r/GUI/GUI_App.cpp        | 350 ++++++++++++++
 src/slic3r/GUI/GUI_App.hpp        |  77 +++
 src/slic3r/GUI/MainFrame.cpp      | 757 ++++++++++++++++++++++++++++++
 src/slic3r/GUI/MainFrame.hpp      | 101 ++++
 9 files changed, 1314 insertions(+), 32 deletions(-)
 create mode 100644 src/slic3r/GUI/GUI_App.cpp
 create mode 100644 src/slic3r/GUI/GUI_App.hpp
 create mode 100644 src/slic3r/GUI/MainFrame.cpp
 create mode 100644 src/slic3r/GUI/MainFrame.hpp

diff --git a/src/slic3r.cpp b/src/slic3r.cpp
index 8174ba0a2..bd071ee36 100644
--- a/src/slic3r.cpp
+++ b/src/slic3r.cpp
@@ -13,6 +13,7 @@
 #include <boost/nowide/iostream.hpp>
 
 #include "slic3r/GUI/GUI.hpp"
+#include "slic3r/GUI/GUI_App.hpp"
 
 using namespace Slic3r;
 
@@ -252,9 +253,12 @@ main(int argc, char **argv)
 #endif
     
 
-    MyApp *gui = new MyApp();
+//     MyApp *gui = new MyApp();
+    GUI::GUI_App *gui = new GUI::GUI_App();
+
+//     MyApp::SetInstance(gui);
+    GUI::GUI_App::SetInstance(gui);
 
-    MyApp::SetInstance(gui);
     wxEntry(argc, argv);
     return 0;
 }
diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt
index 4a0c31636..a8888701c 100644
--- a/src/slic3r/CMakeLists.txt
+++ b/src/slic3r/CMakeLists.txt
@@ -39,6 +39,10 @@ add_library(libslic3r_gui STATIC
     ${LIBDIR}/slic3r/GUI/GUI_Preview.hpp
     ${LIBDIR}/slic3r/GUI/GUI_PreviewIface.cpp
     ${LIBDIR}/slic3r/GUI/GUI_PreviewIface.hpp
+    ${LIBDIR}/slic3r/GUI/GUI_App.cpp
+    ${LIBDIR}/slic3r/GUI/GUI_App.hpp
+    ${LIBDIR}/slic3r/GUI/MainFrame.cpp
+    ${LIBDIR}/slic3r/GUI/MainFrame.hpp
     ${LIBDIR}/slic3r/GUI/LambdaObjectDialog.cpp
     ${LIBDIR}/slic3r/GUI/LambdaObjectDialog.hpp
     ${LIBDIR}/slic3r/GUI/Tab.cpp
diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp
index e04f2b370..7c019599a 100644
--- a/src/slic3r/GUI/BedShapeDialog.cpp
+++ b/src/slic3r/GUI/BedShapeDialog.cpp
@@ -291,12 +291,6 @@ void BedShapePanel::update_shape()
 // Loads an stl file, projects it to the XY plane and calculates a polygon.
 void BedShapePanel::load_stl()
 {
-	t_file_wild_card vec_FILE_WILDCARDS = get_file_wild_card();
-    std::vector<std::string> file_types = { "known", "stl", "obj", "amf", "3mf", "prusa" };
-    wxString MODEL_WILDCARD;
-	for (auto file_type: file_types)
-		MODEL_WILDCARD += vec_FILE_WILDCARDS.at(file_type) + "|";
-
 	auto dialog = new wxFileDialog(this, _(L("Choose a file to import bed shape from (STL/OBJ/AMF/3MF/PRUSA):")), "", "",
 		MODEL_WILDCARD, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
 	if (dialog->ShowModal() != wxID_OK) {
diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp
index e5ed917b3..4201e33f7 100644
--- a/src/slic3r/GUI/GUI.cpp
+++ b/src/slic3r/GUI/GUI.cpp
@@ -545,14 +545,8 @@ void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_languag
 }
 
 void open_model(wxWindow *parent, wxArrayString& input_files){
-	t_file_wild_card vec_FILE_WILDCARDS = get_file_wild_card();
-	std::vector<std::string> file_types = { "known", "stl", "obj", "amf", "3mf", "prusa" };
-	wxString MODEL_WILDCARD;
-	for (auto file_type : file_types)
-		MODEL_WILDCARD += vec_FILE_WILDCARDS.at(file_type) + "|";
-
-	auto dlg_title = _(L("Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):"));
-	auto dialog = new wxFileDialog(parent /*? parent : GetTopWindow(g_wxMainFrame)*/, dlg_title, 
+	auto dialog = new wxFileDialog(parent ? parent : GetTopWindow(), 
+        _(L("Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):")),
 		g_AppConfig->get_last_dir(), "",
 		MODEL_WILDCARD, wxFD_OPEN | wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST);
 	if (dialog->ShowModal() != wxID_OK) {
diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp
index 9b2fce5b4..878689bf3 100644
--- a/src/slic3r/GUI/GUI.hpp
+++ b/src/slic3r/GUI/GUI.hpp
@@ -71,23 +71,24 @@ namespace GUI {
 class Tab;
 class ConfigOptionsGroup;
 // Map from an file_type name to full file wildcard name.
-typedef std::map<std::string, std::string> t_file_wild_card;
-inline t_file_wild_card& get_file_wild_card() {
-	static t_file_wild_card FILE_WILDCARDS;
-	if (FILE_WILDCARDS.empty()){
-		FILE_WILDCARDS["known"]	= "Known files (*.stl, *.obj, *.amf, *.xml, *.prusa)|*.stl;*.STL;*.obj;*.OBJ;*.amf;*.AMF;*.xml;*.XML;*.prusa;*.PRUSA";
-		FILE_WILDCARDS["stl"]	= "STL files (*.stl)|*.stl;*.STL";
-		FILE_WILDCARDS["obj"]	= "OBJ files (*.obj)|*.obj;*.OBJ";
-        FILE_WILDCARDS["amf"]	= "AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML";
-        FILE_WILDCARDS["3mf"]	= "3MF files (*.3mf)|*.3mf;*.3MF;";
-        FILE_WILDCARDS["prusa"]	= "Prusa Control files (*.prusa)|*.prusa;*.PRUSA";
-		FILE_WILDCARDS["ini"]	= "INI files *.ini|*.ini;*.INI";
-		FILE_WILDCARDS["gcode"] = "G-code files (*.gcode, *.gco, *.g, *.ngc)|*.gcode;*.GCODE;*.gco;*.GCO;*.g;*.G;*.ngc;*.NGC";
-		FILE_WILDCARDS["svg"]	= "SVG files *.svg|*.svg;*.SVG";
-	}
-	return FILE_WILDCARDS;
-}
+const std::map<const std::string, const std::string> FILE_WILDCARDS{
+    std::make_pair("known", "Known files (*.stl, *.obj, *.amf, *.xml, *.prusa)|*.stl;*.STL;*.obj;*.OBJ;*.amf;*.AMF;*.xml;*.XML;*.prusa;*.PRUSA"),
+    std::make_pair("stl",   "STL files (*.stl)|*.stl;*.STL"),
+    std::make_pair("obj",   "OBJ files (*.obj)|*.obj;*.OBJ"),
+    std::make_pair("amf",   "AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML"),
+    std::make_pair("3mf",   "3MF files (*.3mf)|*.3mf;*.3MF;"),
+    std::make_pair("prusa", "Prusa Control files (*.prusa)|*.prusa;*.PRUSA"),
+    std::make_pair("ini",   "INI files *.ini|*.ini;*.INI"),
+    std::make_pair("gcode", "G-code files (*.gcode, *.gco, *.g, *.ngc)|*.gcode;*.GCODE;*.gco;*.GCO;*.g;*.G;*.ngc;*.NGC"),
+    std::make_pair("svg",   "SVG files *.svg|*.svg;*.SVG")
+};
 
+const std::string MODEL_WILDCARD{   FILE_WILDCARDS.at("known") + std::string("|") +
+                                    FILE_WILDCARDS.at("stl") + std::string("|") +
+                                    FILE_WILDCARDS.at("obj") + std::string("|") +
+                                    FILE_WILDCARDS.at("amf") + std::string("|") +
+                                    FILE_WILDCARDS.at("3mf") + std::string("|") +
+                                    FILE_WILDCARDS.at("prusa") };
 struct PresetTab {
     std::string       name;
     Tab*              panel;
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
new file mode 100644
index 000000000..2c1930a11
--- /dev/null
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -0,0 +1,350 @@
+#include "GUI_App.hpp"
+
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include <wx/stdpaths.h>
+#include <wx/imagpng.h>
+#include <wx/display.h>
+#include <wx/menu.h>
+#include <wx/menuitem.h>
+
+#include "Utils.hpp"
+#include "GUI.hpp"
+#include "MainFrame.hpp"
+#include "AppConfig.hpp"
+#include "PresetBundle.hpp"
+#include "3DScene.hpp"
+
+#include "../Utils/PresetUpdater.hpp"
+
+namespace Slic3r {
+namespace GUI {
+
+// IMPLEMENT_APP(GUI_App)
+bool GUI_App::OnInit()
+{
+    SetAppName("Slic3rPE");
+    SetAppDisplayName("Slic3r Prusa Edition");
+
+    //     Slic3r::debugf "wxWidgets version %s, Wx version %s\n", &Wx::wxVERSION_STRING, $Wx::VERSION;
+    // 
+    // Set the Slic3r data directory at the Slic3r XS module.
+    // Unix: ~/ .Slic3r
+    // Windows : "C:\Users\username\AppData\Roaming\Slic3r" or "C:\Documents and Settings\username\Application Data\Slic3r"
+    // Mac : "~/Library/Application Support/Slic3r"
+//     datadir.empty() ?
+//         Slic3r::set_data_dir(wxStandardPaths::Get().GetUserDataDir().ToStdString()) :
+//         Slic3r::set_data_dir(datadir);
+    //     set_wxapp(this); // #ys_FIXME
+
+//     app_config = new AppConfig();
+    //     set_app_config(app_config);// #ys_FIXME
+//     preset_bundle = new PresetBundle();
+    //     set_preset_bundle(preset_bundle);// #ys_FIXME
+
+    // just checking for existence of Slic3r::data_dir is not enough : it may be an empty directory
+    // supplied as argument to --datadir; in that case we should still run the wizard
+    //     eval{ 
+//     preset_bundle->setup_directories();
+    //     };
+    //     if ($@) {
+    //         warn $@ . "\n";
+    //         fatal_error(undef, $@);
+    //     }
+//     app_conf_exists = app_config->exists();
+    // load settings
+//     if (app_conf_exists) app_config->load();
+    //     app_config->set("version", Slic3r::VERSION);
+//     app_config->save();
+
+//     preset_updater = new PresetUpdater(VERSION_ONLINE_EVENT);
+    //     set_preset_updater(preset_updater); // #ys_FIXME
+
+//     Slic3r::GUI::load_language();
+
+    // Suppress the '- default -' presets.
+//     preset_bundle->set_default_suppressed(app_config->get("no_defaults").empty() ? false : true);
+    //     eval{ 
+//     preset_bundle->load_presets(*app_config);
+    //     };
+    //     if ($@) {
+    //         warn $@ . "\n";
+    //         show_error(undef, $@);
+    //     }
+
+    // application frame
+    //     print STDERR "Creating main frame...\n";
+    //     wxImage::FindHandlerType(wxBITMAP_TYPE_PNG) ||
+    wxImage::AddHandler(new wxPNGHandler());
+    mainframe = new Slic3r::GUI::MainFrame(no_plater, false);
+    SetTopWindow(mainframe);
+
+    // This makes CallAfter() work
+    //     /*mainframe->*/Bind(wxEVT_IDLE, 
+//     [this](wxIdleEvent& event)
+//     {
+//         std::function<void()> cur_cb{ nullptr };
+//         // try to get the mutex. If we can't, just skip this idle event and get the next one.
+//         if (!callback_register.try_lock()) return;
+//         // pop callback
+//         if (m_cb.size() != 0){
+//             cur_cb = m_cb.top();
+//             m_cb.pop();
+//         }
+//         // unlock mutex
+//         this->callback_register.unlock();
+// 
+//         try { // call the function if it's not nullptr;
+//             if (cur_cb != nullptr) cur_cb();
+//         }
+//         catch (std::exception& e) {
+//             //             Slic3r::Log::error(LogChannel, LOG_WSTRING("Exception thrown: " << e.what())); // #ys_FIXME
+//         }
+// 
+//         if (app_config->dirty())
+//             app_config->save();
+//     }
+    ;// #ys_FIXME
+    //     );
+
+    // On OS X the UI tends to freeze in weird ways if modal dialogs(config wizard, update notifications, ...)
+    // are shown before or in the same event callback with the main frame creation.
+    // Therefore we schedule them for later using CallAfter.
+//     CallAfter([this](){
+//         //         eval{
+//         if (!preset_updater->config_update())
+//             mainframe->Close();
+//         //         };
+//         //         if ($@) {
+//         //             show_error(undef, $@);
+//         //             mainframe->Close();
+//         //         }
+//     });
+// 
+//     CallAfter([this](){
+//         if (!Slic3r::GUI::config_wizard_startup(app_conf_exists)) {
+//             // Only notify if there was not wizard so as not to bother too much ...
+//             preset_updater->slic3r_update_notify();
+//         }
+//         preset_updater->sync(preset_bundle);
+//     });
+// 
+
+    // #ys_FIXME All of this should to be removed
+    //     # The following event is emited by the C++ menu implementation of application language change.
+    //     EVT_COMMAND($self, -1, $LANGUAGE_CHANGE_EVENT, sub{
+    //         print STDERR "LANGUAGE_CHANGE_EVENT\n";
+    //         $self->recreate_GUI;
+    //     });
+    // 
+    //     # The following event is emited by the C++ menu implementation of preferences change.
+    //     EVT_COMMAND($self, -1, $PREFERENCES_EVENT, sub{
+    //         $self->update_ui_from_settings;
+    //     });
+    // 
+    //     # The following event is emited by PresetUpdater(C++) to inform about
+    //     # the newer Slic3r application version avaiable online.
+    //     EVT_COMMAND($self, -1, $VERSION_ONLINE_EVENT, sub {
+    //         my($self, $event) = @_;
+    //         my $version = $event->GetString;
+    //         $self->{app_config}->set('version_online', $version);
+    //         $self->{app_config}->save;
+    //     });
+
+    mainframe->Show(true);
+
+    return true;
+}
+
+void GUI_App::recreate_GUI()
+{
+//     print STDERR "recreate_GUI\n";
+
+    auto topwindow = GetTopWindow();
+    mainframe = new Slic3r::GUI::MainFrame(no_plater,false);
+
+    if (topwindow) {
+        SetTopWindow(mainframe);
+        topwindow->Destroy();
+    }
+
+    // On OSX the UI was not initialized correctly if the wizard was called
+    // before the UI was up and running.
+    CallAfter([](){
+        // Run the config wizard, don't offer the "reset user profile" checkbox.
+        Slic3r::GUI::config_wizard_startup(true);
+    });
+}
+
+void GUI_App::system_info()
+{
+//     auto slic3r_info = Slic3r::slic3r_info(format = > 'html');
+//     auto copyright_info = Slic3r::copyright_info(format = > 'html');
+//     auto system_info = Slic3r::system_info(format = > 'html');
+    std::string opengl_info = "";
+    std::string opengl_info_txt = "";
+    if (mainframe && mainframe->m_plater /*&& mainframe->m_plater->canvas3D*/) {
+        opengl_info = _3DScene::get_gl_info(true, true);
+        opengl_info_txt = _3DScene::get_gl_info(false, true);
+    }
+//     auto about = new SystemInfo(nullptr, slic3r_info, /*copyright_info,*/system_info, opengl_info,
+//         text_info = > Slic3r::slic3r_info.Slic3r::system_info.$opengl_info_txt,
+//         );
+//     about->ShowModal();
+//     about->Destroy();
+}
+
+// static method accepting a wxWindow object as first parameter
+bool GUI_App::catch_error(std::function<void()> cb,
+    //                       wxMessageDialog* message_dialog,
+    const std::string& err /*= ""*/){
+    if (!err.empty()) {
+        if (cb)
+            cb();
+        //         if (message_dialog)
+        //             message_dialog->(err, "Error", wxOK | wxICON_ERROR);
+        show_error(/*this*/nullptr, err);
+        return true;
+    }
+    return false;
+}
+
+// static method accepting a wxWindow object as first parameter
+void fatal_error(wxWindow* parent){
+    show_error(parent, "");
+    //     exit 1; // #ys_FIXME
+}
+
+// Called after the Preferences dialog is closed and the program settings are saved.
+// Update the UI based on the current preferences.
+void GUI_App::update_ui_from_settings(){
+    mainframe->update_ui_from_settings();
+}
+
+// wxArrayString GUI::open_model(wxWindow* window){
+//     auto dialog = new wxFileDialog(window ? window : GetTopWindow(), 
+//         _(L("Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):")),
+//         app_config->get_last_dir(), "", get_model_wildcard(), 
+//         wxFD_OPEN | wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST);
+//     if (dialog->ShowModal() != wxID_OK) {
+//         dialog->Destroy;
+//         return;
+//     }
+//     wxArrayString input_files;
+//     dialog->GetPaths(input_files);
+//     dialog->Destroy();
+//     return input_files;
+// }
+
+void GUI_App::CallAfter(std::function<void()> cb)
+{
+    // set mutex
+    callback_register.lock();
+    // push function onto stack
+    m_cb.emplace(cb);
+    // unset mutex
+    callback_register.unlock();
+}
+
+wxMenuItem* GUI_App::append_menu_item(wxMenu* menu,
+    int id,
+    const wxString& string,
+    const wxString& description,
+    const std::string& icon,
+    std::function<void(wxCommandEvent& event)> cb,
+    wxItemKind kind/* = wxITEM_NORMAL*/)
+{
+    if (id == wxID_ANY)
+        id = wxNewId();
+    auto item = new wxMenuItem(menu, id, string, description, kind);
+    if (!icon.empty())
+        item->SetBitmap(wxBitmap(Slic3r::var(icon), wxBITMAP_TYPE_PNG));
+    menu->Append(item);
+
+    menu->Bind(wxEVT_MENU, /*[cb](wxCommandEvent& event){cb; }*/cb);
+    return item;
+}
+
+wxMenuItem* GUI_App::append_submenu(wxMenu* menu,
+    wxMenu* sub_menu,
+    int id,
+    const wxString& string,
+    const wxString& description,
+    const std::string& icon)
+{
+    if (id == wxID_ANY)
+        id = wxNewId();
+    auto item = new wxMenuItem(menu, id, string, description);
+    if (!icon.empty())
+        item->SetBitmap(wxBitmap(Slic3r::var(icon), wxBITMAP_TYPE_PNG));
+    item->SetSubMenu(sub_menu);
+    menu->Append(item);
+
+    return item;
+}
+
+void GUI_App::save_window_pos(wxTopLevelWindow* window, const std::string& name){
+    int x, y;
+    window->GetScreenPosition(&x, &y);
+    app_config->set(name + "_pos", wxString::Format("%d,%d", x, y).ToStdString());
+
+    window->GetSize(&x, &y);
+    app_config->set(name + "_size", wxString::Format("%d,%d", x, y).ToStdString());
+
+    app_config->set(name + "_maximized", window->IsMaximized() ? "1" : "0");
+
+    app_config->save();
+}
+
+void GUI_App::restore_window_pos(wxTopLevelWindow* window, const std::string& name){
+    if (!app_config->has(name + "_pos"))
+        return;
+
+    std::string str = app_config->get(name + "_size");
+    std::vector<std::string> values;
+    boost::split(values, str, boost::is_any_of(","));
+    wxSize size = wxSize(atoi(values[0].c_str()), atoi(values[1].c_str()));
+    window->SetSize(size);
+
+    auto display = (new wxDisplay())->GetClientArea();
+    str = app_config->get(name + "_pos");
+    values.resize(0);
+    boost::split(values, str, boost::is_any_of(","));
+    wxPoint pos = wxPoint(atoi(values[0].c_str()), atoi(values[1].c_str()));
+    if (pos.x + 0.5*size.GetWidth() < display.GetRight() &&
+        pos.y + 0.5*size.GetHeight() < display.GetBottom())
+        window->Move(pos);
+
+    if (app_config->get(name + "_maximized") == "1")
+        window->Maximize();
+}
+
+// static method accepting a wxWindow object as first parameter
+// void warning_catcher{
+//     my($self, $message_dialog) = @_;
+//     return sub{
+//         my $message = shift;
+//         return if $message = ~/ GLUquadricObjPtr | Attempt to free unreferenced scalar / ;
+//         my @params = ($message, 'Warning', wxOK | wxICON_WARNING);
+//         $message_dialog
+//             ? $message_dialog->(@params)
+//             : Wx::MessageDialog->new($self, @params)->ShowModal;
+//     };
+// }
+
+// Do we need this function???
+// void GUI_App::notify(message){
+//     auto frame = GetTopWindow();
+//     // try harder to attract user attention on OS X
+//     if (!frame->IsActive())
+//         frame->RequestUserAttention(defined(__WXOSX__/*&Wx::wxMAC */)? wxUSER_ATTENTION_ERROR : wxUSER_ATTENTION_INFO);
+// 
+//     // There used to be notifier using a Growl application for OSX, but Growl is dead.
+//     // The notifier also supported the Linux X D - bus notifications, but that support was broken.
+//     //TODO use wxNotificationMessage ?
+// }
+
+
+} // GUI
+} //Slic3r
\ No newline at end of file
diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp
new file mode 100644
index 000000000..874c63fde
--- /dev/null
+++ b/src/slic3r/GUI/GUI_App.hpp
@@ -0,0 +1,77 @@
+#ifndef slic3r_GUI_App_hpp_
+#define slic3r_GUI_App_hpp_
+
+#include <string>
+// #include <vector>
+// #include "PrintConfig.hpp"
+// #include "../../libslic3r/Utils.hpp"
+// #include "GUI.hpp"
+
+#include <wx/app.h>
+
+#include <mutex>
+#include <stack>
+
+class wxMenuItem;
+class wxTopLevelWindow;
+
+namespace Slic3r {
+class AppConfig;
+class PresetBundle;
+class PresetUpdater;
+
+namespace GUI
+{
+class MainFrame;
+
+class GUI_App : public wxApp
+{
+    // Datadir provided on the command line.
+    std::string     datadir = "";
+    bool            no_plater{ true };
+    bool            app_conf_exists{ false };
+
+    // Lock to guard the callback stack
+    std::mutex      callback_register;
+    // callbacks registered to run during idle event.
+    std::stack<std::function<void()>>    m_cb{};
+
+public:
+    bool            OnInit() override;
+    GUI_App() : wxApp() {}
+
+    void            recreate_GUI();
+    void            system_info();
+    static bool     catch_error(std::function<void()> cb,
+//                                 wxMessageDialog* message_dialog,
+                                const std::string& err);
+//     void            notify(/*message*/);
+    void            update_ui_from_settings();
+    void            CallAfter(std::function<void()> cb);
+    wxMenuItem*     append_menu_item(   wxMenu* menu,
+                                        int id,
+                                        const wxString& string,
+                                        const wxString& description,
+                                        const std::string& icon,
+                                        std::function<void(wxCommandEvent& event)> cb,
+                                        wxItemKind kind = wxITEM_NORMAL);
+    wxMenuItem*     append_submenu( wxMenu* menu,
+                                    wxMenu* sub_menu,
+                                    int id,
+                                    const wxString& string,
+                                    const wxString& description,
+                                    const std::string& icon);
+    void            save_window_pos(wxTopLevelWindow* window, const std::string& name);
+    void            restore_window_pos(wxTopLevelWindow* window, const std::string& name);
+
+    AppConfig*      app_config{ nullptr };
+    PresetBundle*   preset_bundle{ nullptr };
+    PresetUpdater*  preset_updater{ nullptr };
+    MainFrame*      mainframe{ nullptr };
+};
+// DECLARE_APP(GUI_App)
+
+} // GUI
+} //Slic3r
+
+#endif // slic3r_GUI_App_hpp_
\ No newline at end of file
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
new file mode 100644
index 000000000..c3b89b533
--- /dev/null
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -0,0 +1,757 @@
+#include "MainFrame.hpp"
+
+#include <wx/panel.h>
+#include <wx/notebook.h>
+#include <wx/icon.h>
+#include <wx/sizer.h>
+#include <wx/menu.h>
+#include <wx/progdlg.h>
+
+#include "Tab.hpp"
+#include "PresetBundle.hpp"
+#include "..\AppController.hpp"
+#include "ProgressStatusBar.hpp"
+#include "3DScene.hpp"
+#include "Print.hpp"
+#include "Polygon.hpp"
+#include "AppConfig.hpp"
+
+#include <fstream>
+#include <boost/geometry/strategies/spherical/compare_circular.hpp>
+
+namespace Slic3r {
+namespace GUI
+{
+MainFrame::MainFrame(const bool no_plater, const bool loaded) :
+wxFrame(NULL, wxID_ANY, "FORK_NAME-VERSION", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE),
+        m_no_plater(no_plater),
+        m_loaded(loaded)
+{
+//     Slic3r::GUI::set_main_frame(this);
+//     m_appController = new Slic3r::AppController();
+
+// #if _WIN32
+//     // Load the icon either from the exe, or from the ico file.
+// //     auto iconfile = Slic3r::decode_path($FindBin::Bin) . '\slic3r.exe';
+//         auto iconfile = Slic3r::var("Slic3r.ico");// unless - f iconfile;
+//     SetIcon(wxIcon(iconfile, wxBITMAP_TYPE_ICO));
+// #else
+//     SetIcon(wxIcon(Slic3r::var("Slic3r_128px.png"), wxBITMAP_TYPE_PNG));
+    SetIcon(wxIcon("c:\\src\\Slic3r_TMP\\resources\\icons\\Slic3r_128px.png", wxBITMAP_TYPE_PNG));
+// #ifdef // _WIN32
+
+    // initialize tabpanel and menubar
+//     init_tabpanel();
+//     init_menubar();
+
+    // set default tooltip timer in msec
+    // SetAutoPop supposedly accepts long integers but some bug doesn't allow for larger values
+    // (SetAutoPop is not available on GTK.)
+//     wxToolTip::SetAutoPop(32767);
+
+    // initialize status bar
+//     m_statusbar = new Slic3r::GUI::ProgressStatusBar(this);
+//     m_statusbar->embed();
+//     m_statusbar->set_status_text(L("Version ").Slic3r::VERSION.L(" - Remember to check for updates at http://github.com/prusa3d/slic3r/releases"));
+    // Make the global status bar and its progress indicator available in C++
+//     m_appController->set_global_progress_indicator(m_statusbar);
+
+//     m_appController->set_model(m_plater->model);
+//     m_appController->set_print(m_plater->print);
+// 
+//     m_plater->appController = m_appController;
+
+//     m_loaded = true;
+// 
+//     // initialize layout
+//     auto sizer = new wxBoxSizer(wxVERTICAL);
+//     if (m_tabpanel)
+//         sizer->Add(m_tabpanel, 1, wxEXPAND);
+//     sizer->SetSizeHints(this);
+//     SetSizer(sizer);
+//     Fit();
+//     SetMinSize(wxSize(760, 490));
+//     SetSize(GetMinSize());
+// //     wxTheApp->restore_window_pos(this, "main_frame");
+//     Show();
+//     Layout();
+
+    // declare events
+//     Bind(wxEVT_CLOSE_WINDOW,  [](wxEvent& event){
+//         if (event.CanVeto() && !Slic3r::GUI::check_unsaved_changes) {
+//             event.Veto();
+//             return;
+//         }
+//         // save window size
+//         wxTheApp->save_window_pos(this, "main_frame");
+//         // Save the slic3r.ini.Usually the ini file is saved from "on idle" callback,
+//         // but in rare cases it may not have been called yet.
+//         wxTheApp->{app_config}->save();
+//         if (m_plater)
+//             m_plater->print = undef;
+//         _3DScene::remove_all_canvases();
+//         Slic3r::GUI::deregister_on_request_update_callback();
+//         // propagate event
+//         event.Skip();
+//     });
+
+//     update_ui_from_settings();
+// 
+//     Slic3r::GUI::update_mode();
+    wxMenu *menuHelp = new wxMenu;
+    menuHelp->Append(wxID_ABOUT);
+    wxMenuBar *menuBar = new wxMenuBar;
+    menuBar->Append(menuHelp, "&Help");
+    SetMenuBar(menuBar);
+
+    return;
+}
+
+void MainFrame::init_tabpanel()
+{
+    m_tabpanel = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL);
+    Slic3r::GUI::set_tab_panel(m_tabpanel);
+
+//     m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, [m_tabpanel](wxEvent&){
+//         auto panel = m_tabpanel->GetCurrentPage();
+// //             panel->OnActivate(); if panel->can('OnActivate');
+// 
+//         std::vector<std::string> tab_names = { "print", "filament", "printer" };
+//         for (auto& tab_name : tab_names) {
+//             if (tab_name == panel->GetName())
+//                 Slic3r::GUI::get_preset_tab(tab_name.c_str())->OnActivate();
+//         }
+//     });
+
+    if (!m_no_plater) {
+//        m_plater = new Slic3r::GUI::Plater(m_tabpanel,
+//             event_object_selection_changed = > $OBJECT_SELECTION_CHANGED_EVENT,
+//             event_object_settings_changed = > $OBJECT_SETTINGS_CHANGED_EVENT,
+//             event_remove_object = > $OBJECT_REMOVE_EVENT,
+//             event_update_scene = > $UPDATE_SCENE_EVENT,
+//             ), L("Plater")
+//         m_tabpanel->AddPage(plater);
+    }
+
+    // The following event is emited by the C++ Tab implementation on config value change.
+//     EVT_COMMAND($self, -1, $VALUE_CHANGE_EVENT, sub {
+//         my($self, $event) = @_;
+//         auto str = event->GetString;
+//         my($opt_key, $name) = ($str = ~/ (.*) (.*) / );
+//         auto tab = Slic3r::GUI::get_preset_tab(name);
+//         auto config = tab->get_config();
+//         if (m_plater) {
+//             m_plater->on_config_change(config); // propagate config change events to the plater
+//                 if (opt_key == "extruders_count"){
+//                     auto value = event->GetInt();
+//                     m_plater->on_extruders_change(value);
+//                 }
+//             if (opt_key == "printer_technology"){
+//                 auto value = event->GetInt(); // 0 ~"ptFFF"; 1 ~"ptSLA"
+//                     m_plater->show_preset_comboboxes(value);
+//             }
+//         }
+//         // don't save while loading for the first time
+//         if (Slic3r::GUI::autosave && m_loaded)
+//             m_config->save(Slic3r::GUI::autosave) ;
+//     });
+
+    // The following event is emited by the C++ Tab implementation on preset selection,
+    // or when the preset's "modified" status changes.
+//     EVT_COMMAND($self, -1, $PRESETS_CHANGED_EVENT, sub {
+//         my($self, $event) = @_;
+//         auto tab_name = event->GetString;
+// 
+//         Tab* tab = Slic3r::GUI::get_preset_tab(tab_name);
+//         if (m_plater) {
+//             // Update preset combo boxes(Print settings, Filament, Material, Printer) from their respective tabs.
+//             auto presets = tab->get_presets();
+//             if (presets){
+//                 auto reload_dependent_tabs = tab->get_dependent_tabs();
+//                 m_plater->update_presets(tab_name, reload_dependent_tabs, presets);
+//                 m_plater->{"selected_item_$tab_name"} = tab->get_selected_preset_item();
+//                 if (tab_name == "printer") {
+//                     // Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors.
+//                     std::vector<std::string> tab_names_other = { "print", "filament", "sla_materialprinter" };
+//                     for (const auto tab_name_other : tab_names_other) {
+//                         Tab* cur_tab = m_options_tabs[tab_name_other];
+//                         // If the printer tells us that the print or filament preset has been switched or invalidated,
+//                         // refresh the print or filament tab page.Otherwise just refresh the combo box.
+//                         if (reload_dependent_tabs.empty() ||
+//                             find(reload_dependent_tabs.begin(), reload_dependent_tabs.end(), tab_name_other) ==
+//                             reload_dependent_tabs.end() )
+//                             cur_tab->update_tab_ui();
+//                         else
+//                             cur_tab->load_current_preset();
+//                             
+//                     }
+//                 }
+//                 m_plater->on_config_change(tab->get_config());
+//             }
+//         }
+//     });
+
+    // The following event is emited by the C++ Tab implementation on object selection change.
+//     EVT_COMMAND($self, -1, $OBJECT_SELECTION_CHANGED_EVENT, sub {
+//         auto obj_idx = event->GetId();
+//         // my $child = $event->GetInt == 1 ? 1 : undef;
+//         // $self->{plater}->select_object($obj_idx < 0 ? undef : $obj_idx, $child);
+//         // $self->{plater}->item_changed_selection($obj_idx);
+// 
+//         auto vol_idx = event->GetInt();
+//         m_plater->select_object_from_cpp(obj_idx < 0 ? undef : obj_idx, vol_idx < 0 ? -1 : vol_idx);
+//     });
+
+    // The following event is emited by the C++ GUI implementation on object settings change.
+//     EVT_COMMAND($self, -1, $OBJECT_SETTINGS_CHANGED_EVENT, sub {
+//         auto line = event->GetString();
+//         my($obj_idx, $parts_changed, $part_settings_changed) = split('', $line);
+// 
+//         m_plater->changed_object_settings(obj_idx, parts_changed, part_settings_changed);
+//     });
+
+    // The following event is emited by the C++ GUI implementation on object remove.
+//     EVT_COMMAND($self, -1, $OBJECT_REMOVE_EVENT, sub {
+//         m_plater->remove();
+//     });
+// 
+//     // The following event is emited by the C++ GUI implementation on extruder change for object.
+//     EVT_COMMAND($self, -1, $UPDATE_SCENE_EVENT, sub {
+//         m_plater->update();
+//     });
+
+
+//     Slic3r::GUI::create_preset_tabs(true, VALUE_CHANGE_EVENT, PRESETS_CHANGED_EVENT);
+    std::vector<std::string> tab_names = { "print", "filament", "sla_material", "printer" };    
+//     for (auto tab_name : tab_names)
+//         m_options_tabs[tab_name] = Slic3r::GUI::get_preset_tab(tab_name.c_str()); // 
+
+    if (m_plater) {
+//         m_plater->on_select_preset(sub{
+//             my($group, $name) = @_;
+//             $self->{options_tabs}{$group}->select_preset($name);
+//         });
+        // load initial config
+        auto full_config = Slic3r::GUI::get_preset_bundle()->full_config();
+//         m_plater->on_config_change(full_config);
+
+        // Show a correct number of filament fields.
+//         if (defined full_config->nozzle_diameter){
+//             // nozzle_diameter is undefined when SLA printer is selected
+//             m_plater->on_extruders_change(int(@{$full_config->nozzle_diameter}));
+//         }
+
+        // Show correct preset comboboxes according to the printer_technology
+//         m_plater->show_preset_comboboxes(full_config.printer_technology() == "FFF" ? 0 : 1);
+    }
+}
+
+void MainFrame::init_menubar()
+{
+    // File menu
+    auto fileMenu = new wxMenu();
+    {
+//         wxTheApp->append_menu_item(fileMenu, L("Open STL/OBJ/AMF/3MF�\tCtrl+O"), L('Open a model'), [](wxCommandEvent&){
+//             if (m_plater) m_plater->add();
+//         }, undef, undef); //'brick_add.png');
+        append_menu_item(fileMenu, wxID_ANY, _(L("&Load Config�\tCtrl+L")), _(L("Load exported configuration file")), 
+                        [this](wxCommandEvent&){ load_config_file(); }, "plugin_add.png");
+        append_menu_item(fileMenu, wxID_ANY, _(L("&Export Config�\tCtrl+E")), _(L("Export current configuration to file")), 
+                        [this](wxCommandEvent&){ export_config(); }, "plugin_go.png");
+        append_menu_item(fileMenu, wxID_ANY, _(L("&Load Config Bundle�")), _(L("Load presets from a bundle")), 
+                        [this](wxCommandEvent&){ load_configbundle(); }, "lorry_add.png");
+        append_menu_item(fileMenu, wxID_ANY, _(L("&Export Config Bundle�")), _(L("Export all presets to file")), 
+                        [this](wxCommandEvent&){ export_configbundle(); }, "lorry_go.png");
+        fileMenu->AppendSeparator();
+        wxMenuItem* repeat = nullptr;
+        append_menu_item(fileMenu, wxID_ANY, _(L("Q&uick Slice�\tCtrl+U")), _(L("Slice a file into a G-code")), 
+            [this, repeat](wxCommandEvent&){
+                wxTheApp->CallAfter([this, repeat](){
+                    quick_slice();
+                    repeat->Enable(is_last_input_file()/*defined $Slic3r::GUI::MainFrame::last_input_file*/);
+            }); }, "cog_go.png");
+        append_menu_item(fileMenu, wxID_ANY, _(L("Quick Slice and Save &As�\tCtrl+Alt+U")), _(L("Slice a file into a G-code, save as")), 
+            [this, repeat](wxCommandEvent&){
+                wxTheApp->CallAfter([this, repeat](){
+                    quick_slice(/*save_as = > 1*/qsSaveAs);
+                    repeat->Enable(is_last_input_file()/*defined $Slic3r::GUI::MainFrame::last_input_file*/);
+            }); }, "cog_go.png");
+        repeat = append_menu_item(fileMenu, wxID_ANY, _(L("&Repeat Last Quick Slice\tCtrl+Shift+U")), _(L("Repeat last quick slice")), 
+            [this](wxCommandEvent&){
+            wxTheApp->CallAfter([this](){
+                quick_slice(/*reslice = > 1*/qsReslice);
+            }); }, "cog_go.png");
+        repeat->Enable(0);
+        fileMenu->AppendSeparator();
+        append_menu_item(fileMenu, wxID_ANY, _(L("Slice to SV&G�\tCtrl+G")), _(L("Slice file to a multi-layer SVG")),
+            [this](wxCommandEvent&){ quick_slice(/*save_as = > 1, export_svg = > 1*/qsSaveAs | qsExportSVG); }, "shape_handles.png");
+        append_menu_item(fileMenu, wxID_ANY, _(L("Slice to PNG�")), _(L("Slice file to a set of PNG files")),
+            [this](wxCommandEvent&){ slice_to_png(); /*$self->quick_slice(save_as = > 0, export_png = > 1);*/ }, "shape_handles.png");
+        m_menu_item_reslice_now = append_menu_item(fileMenu, wxID_ANY, _(L("(&Re)Slice Now\tCtrl+S")), _(L("Start new slicing process")),
+            [this](wxCommandEvent&){ reslice_now(); }, "shape_handles.png");
+        fileMenu->AppendSeparator();
+        append_menu_item(fileMenu, wxID_ANY, _(L("Repair STL file�")), _(L("Automatically repair an STL file")),
+            [this](wxCommandEvent&){ repair_stl(); }, "wrench.png");
+        fileMenu->AppendSeparator();
+        append_menu_item(fileMenu, wxID_EXIT, _(L("&Quit")), _(L("Quit Slic3r")),
+            [this](wxCommandEvent&){ Close(false); } );
+    }
+
+    // Plater menu
+    if(m_plater) {
+        auto plater_menu = new wxMenu();
+        append_menu_item(plater_menu, wxID_ANY, L("Export G-code..."), L("Export current plate as G-code"), 
+            [this](wxCommandEvent&){ /*m_plater->export_gcode(); */}, "cog_go.png");
+        append_menu_item(plater_menu, wxID_ANY, L("Export plate as STL..."), L("Export current plate as STL"), 
+            [this](wxCommandEvent&){ /*m_plater->export_stl(); */}, "brick_go.png");
+        append_menu_item(plater_menu, wxID_ANY, L("Export plate as AMF..."), L("Export current plate as AMF"), 
+            [this](wxCommandEvent&){ /*m_plater->export_amf();*/ }, "brick_go.png");
+        append_menu_item(plater_menu, wxID_ANY, L("Export plate as 3MF..."), L("Export current plate as 3MF"), 
+            [this](wxCommandEvent&){ /*m_plater->export_3mf(); */}, "brick_go.png");
+
+//         m_object_menu = m_plater->object_menu;
+        on_plater_selection_changed(false);
+    }
+
+    // Window menu
+    auto windowMenu = new wxMenu();
+    {
+        size_t tab_offset = 0;
+        if (m_plater) {
+            append_menu_item(windowMenu, wxID_ANY, L("Select &Plater Tab\tCtrl+1"), L("Show the plater"), 
+                [this](wxCommandEvent&){ select_tab(0); }, "application_view_tile.png");
+            tab_offset += 1;
+        }
+        if (tab_offset > 0) {
+            windowMenu->AppendSeparator();
+        }
+        append_menu_item(windowMenu, wxID_ANY, L("Select P&rint Settings Tab\tCtrl+2"), L("Show the print settings"), 
+            [this, tab_offset](wxCommandEvent&){ select_tab(tab_offset + 0); }, "cog.png");
+        append_menu_item(windowMenu, wxID_ANY, L("Select &Filament Settings Tab\tCtrl+3"), L("Show the filament settings"), 
+            [this, tab_offset](wxCommandEvent&){ select_tab(tab_offset + 1); }, "spool.png");
+        append_menu_item(windowMenu, wxID_ANY, L("Select Print&er Settings Tab\tCtrl+4"), L("Show the printer settings"), 
+            [this, tab_offset](wxCommandEvent&){ select_tab(tab_offset + 2); }, "printer_empty.png");
+    }
+
+    // View menu
+    if (m_plater) {
+        m_viewMenu = new wxMenu();
+// \xA0 is a non-breaing space. It is entered here to spoil the automatic accelerators,
+        // as the simple numeric accelerators spoil all numeric data entry.
+        // The camera control accelerators are captured by 3DScene Perl module instead.
+        auto accel = [](const wxString& st1, const wxString& st2) {
+//             if ($^O eq "MSWin32")
+//                 return st1 + "\t\xA0" + st2;
+//             else
+                return st1; 
+        };
+
+        append_menu_item(m_viewMenu, wxID_ANY, accel(_(L("Iso")), "0"),     L("Iso View"),   [this](wxCommandEvent&){ select_view("iso"); });
+        append_menu_item(m_viewMenu, wxID_ANY, accel(_(L("Top")), "1"),     L("Top View"),   [this](wxCommandEvent&){ select_view("top"); });
+        append_menu_item(m_viewMenu, wxID_ANY, accel(_(L("Bottom")), "2"),  L("Bottom View"),[this](wxCommandEvent&){ select_view("bottom"); });
+        append_menu_item(m_viewMenu, wxID_ANY, accel(_(L("Front")), "3"),   L("Front View"), [this](wxCommandEvent&){ select_view("front"); });
+        append_menu_item(m_viewMenu, wxID_ANY, accel(_(L("Rear")), "4"),    L("Rear View"),  [this](wxCommandEvent&){ select_view("rear"); });
+        append_menu_item(m_viewMenu, wxID_ANY, accel(_(L("Left")), "5"),    L("Left View"),  [this](wxCommandEvent&){ select_view("left"); });
+        append_menu_item(m_viewMenu, wxID_ANY, accel(_(L("Right")), "6"),   L("Right View"), [this](wxCommandEvent&){ select_view("right"); });
+    }
+
+    // Help menu
+    auto helpMenu = new wxMenu();
+    {
+        append_menu_item(helpMenu, wxID_ANY, _(L("Prusa 3D Drivers")), _(L("Open the Prusa3D drivers download page in your browser")), 
+            [this](wxCommandEvent&){ wxLaunchDefaultBrowser("http://www.prusa3d.com/drivers/"); });
+        append_menu_item(helpMenu, wxID_ANY, _(L("Prusa Edition Releases")), _(L("Open the Prusa Edition releases page in your browser")), 
+            [this](wxCommandEvent&){ wxLaunchDefaultBrowser("http://github.com/prusa3d/slic3r/releases"); });
+//#        my $versioncheck = $self->_append_menu_item($helpMenu, "Check for &Updates...", "Check for new Slic3r versions", sub{
+//#            wxTheApp->check_version(1);
+//#        });
+//#        $versioncheck->Enable(wxTheApp->have_version_check);
+        append_menu_item(helpMenu, wxID_ANY, _(L("Slic3r &Website")), _(L("Open the Slic3r website in your browser")), 
+            [this](wxCommandEvent&){ wxLaunchDefaultBrowser("http://slic3r.org/"); });
+        append_menu_item(helpMenu, wxID_ANY, _(L("Slic3r &Manual")), _(L("Open the Slic3r manual in your browser")), 
+            [this](wxCommandEvent&){ wxLaunchDefaultBrowser("http://manual.slic3r.org/"); });
+        helpMenu->AppendSeparator();
+        append_menu_item(helpMenu, wxID_ANY, _(L("System Info")), _(L("Show system information")), 
+            [this](wxCommandEvent&){ /*wxTheApp->system_info();*/ });
+        append_menu_item(helpMenu, wxID_ANY, _(L("Show &Configuration Folder")), _(L("Show user configuration folder (datadir)")), 
+            [this](wxCommandEvent&){ Slic3r::GUI::desktop_open_datadir_folder(); });
+        append_menu_item(helpMenu, wxID_ANY, _(L("Report an Issue")), _(L("Report an issue on the Slic3r Prusa Edition")), 
+            [this](wxCommandEvent&){ wxLaunchDefaultBrowser("http://github.com/prusa3d/slic3r/issues/new"); });
+        append_menu_item(helpMenu, wxID_ANY, _(L("&About Slic3r")), _(L("Show about dialog")), 
+            [this](wxCommandEvent&){ Slic3r::GUI::about(); });
+    }
+
+    // menubar
+    // assign menubar to frame after appending items, otherwise special items
+    // will not be handled correctly
+    {
+        auto menubar = new wxMenuBar();
+        menubar->Append(fileMenu, L("&File"));
+        if (m_plater_menu) menubar->Append(m_plater_menu, L("&Plater")) ;
+        if (m_object_menu) menubar->Append(m_object_menu, L("&Object")) ;
+        menubar->Append(windowMenu, L("&Window"));
+        if (m_viewMenu) menubar->Append(m_viewMenu, L("&View"));
+        // Add additional menus from C++
+//         Slic3r::GUI::add_menus(menubar, preferences_event, lang_ch_event);
+        menubar->Append(helpMenu, L("&Help"));
+        SetMenuBar(menubar);
+    }
+}
+
+// Selection of a 3D object changed on the platter.
+void MainFrame::on_plater_selection_changed(const bool have_selection)
+{
+    if (!m_object_menu) return;
+    
+    for (auto item : m_object_menu->GetMenuItems())
+        m_object_menu->Enable(item->GetId(), have_selection);
+}
+
+void MainFrame::slice_to_png(){
+//     m_plater->stop_background_process();
+//     m_plater->async_apply_config();
+    m_appController->print_ctl()->slice_to_png();
+}
+
+// To perform the "Quck Slice", "Quick Slice and Save As", "Repeat last Quick Slice" and "Slice to SVG".
+void MainFrame::quick_slice(const /*QuickSlice*/int qs/* = qsUndef const bool reslice,
+                            const bool export_svg,
+                            const bool export_png,
+                            const bool save_as*/){
+//     my $progress_dialog;
+    wxString input_file;
+//  eval
+//     {
+    // validate configuration
+    auto config = get_preset_bundle()->full_config();
+    config.validate();
+
+    // select input file
+    if (/*!reslice*/(qs & qsReslice) == 0) {
+        auto dlg = new wxFileDialog(this, _(L("Choose a file to slice (STL/OBJ/AMF/3MF/PRUSA):")),
+            get_app_config()->get_last_dir(), "",
+            MODEL_WILDCARD, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
+        if (dlg->ShowModal() != wxID_OK) {
+            dlg->Destroy();
+            return;
+        }
+        input_file = dlg->GetPath();
+        dlg->Destroy();
+        if (/*!export_svg*/(qs & qsExportSVG) == 0)
+            m_qs_last_input_file = input_file;
+    }
+    else {
+        if (m_qs_last_input_file.IsEmpty()) {
+            auto dlg = new wxMessageDialog(this, _(L("No previously sliced file.")),
+                _(L("Error")), wxICON_ERROR | wxOK);
+            dlg->ShowModal();
+            return;
+        }
+        if (std::ifstream(m_qs_last_input_file.char_str())) {
+            auto dlg = new wxMessageDialog(this, _(L("Previously sliced file ("))+m_qs_last_input_file+_(L(") not found.")),
+                _(L("File Not Found")), wxICON_ERROR | wxOK);
+            dlg->ShowModal();
+            return;
+        }
+        input_file = m_qs_last_input_file;
+    }
+    auto input_file_basename = get_base_name(input_file);
+    get_app_config()->update_skein_dir(get_dir_name(input_file));
+
+    auto bed_shape = Slic3r::Polygon::new_scale(config.option<ConfigOptionPoints>("bed_shape")->values);
+//     auto print_center = Slic3r::Pointf->new_unscale(bed_shape.bounding_box().center());
+// 
+//     auto sprint = new Slic3r::Print::Simple(
+//         print_center = > print_center,
+//         status_cb = > [](int percent, const wxString& msg){
+//         m_progress_dialog->Update(percent, msg+"�");
+//     });
+
+    // keep model around
+    auto model = Slic3r::Model::read_from_file(input_file.ToStdString());
+
+//     sprint->apply_config(config);
+//     sprint->set_model(model);
+
+    // Copy the names of active presets into the placeholder parser.
+//     get_preset_bundle()->export_selections(sprint->placeholder_parser);
+
+    // select output file
+    wxString output_file;
+    if (/*reslice*/(qs & qsReslice)/* != 0*/) {
+        if (!m_qs_last_output_file.IsEmpty())
+            output_file = m_qs_last_output_file;
+    } 
+    else if (/*save_as*/(qs & qsSaveAs)/* != 0*/) {
+        // The following line may die if the output_filename_format template substitution fails.
+//         output_file = sprint->output_filepath;
+//         if (export_svg)
+//         output_file = ~s / \.[gG][cC][oO][dD][eE]$ / .svg /;
+        auto dlg = new wxFileDialog(this, _(L("Save ")) + (qs & qsExportSVG/*export_svg*/ ? _(L("SVG")) : _(L("G-code"))) + _(L(" file as:")),
+            get_app_config()->get_last_output_dir(get_dir_name(output_file)), get_base_name(input_file), 
+            qs & qsExportSVG/*export_svg*/ ? FILE_WILDCARDS.at("svg") : FILE_WILDCARDS.at("gcode"),
+            wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+        if (dlg->ShowModal() != wxID_OK) {
+            dlg->Destroy();
+            return;
+        }
+        output_file = dlg->GetPath();
+        dlg->Destroy();
+        if (/*!export_svg*/!(qs & qsExportSVG))
+            m_qs_last_output_file = output_file;
+        get_app_config()->update_last_output_dir(get_dir_name(output_file));
+    } 
+    else if (/*export_png*/qs & qsExportPNG) {
+//         output_file = sprint->output_filepath;
+//         output_file = ~s / \.[gG][cC][oO][dD][eE]$ / .zip / ;
+        auto dlg = new wxFileDialog(this, _(L("Save zip file as:")),
+            get_app_config()->get_last_output_dir(get_dir_name(output_file)),
+            get_base_name(output_file), "*.zip", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+        if (dlg->ShowModal() != wxID_OK) {
+            dlg->Destroy();
+            return;
+        }
+        output_file = dlg->GetPath();
+        dlg->Destroy();
+    }
+
+    // show processbar dialog
+    m_progress_dialog = new wxProgressDialog(_(L("Slicing�")), _(L("Processing ")) + input_file_basename + "�",
+        100, this, 4);
+    m_progress_dialog->Pulse();
+    {
+//         my @warnings = ();
+//         local $SIG{ __WARN__ } = sub{ push @warnings, $_[0] };
+
+//         sprint->output_file(output_file);
+//         if (export_svg) {
+//             sprint->export_svg();
+//         }
+//         else if(export_png) {
+//             sprint->export_png();
+//         }
+//         else {
+//             sprint->export_gcode();
+//         }
+//         sprint->status_cb(undef);
+//         Slic3r::GUI::warning_catcher($self)->($_) for @warnings;
+    }
+    m_progress_dialog->Destroy();
+    m_progress_dialog = nullptr;
+
+    auto message = input_file_basename + _(L(" was successfully sliced."));
+//     wxTheApp->notify(message);
+    wxMessageDialog(this, message, _(L("Slicing Done!")), wxOK | wxICON_INFORMATION).ShowModal();
+//     };
+//     Slic3r::GUI::catch_error(this, [](){ if (m_progress_dialog) m_progress_dialog->Destroy(); });
+}
+
+void MainFrame::reslice_now(){
+//     if (m_plater)
+//         m_plater->reslice();
+}
+
+void MainFrame::repair_stl()
+{
+    wxString input_file;
+    {
+        auto dlg = new wxFileDialog(this, _(L("Select the STL file to repair:")),
+            get_app_config()->get_last_dir(), "",
+            FILE_WILDCARDS.at("stl"), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
+        if (dlg->ShowModal() != wxID_OK) {
+            dlg->Destroy();
+            return;
+        }
+        input_file = dlg->GetPath();
+        dlg->Destroy();
+    }
+
+    auto output_file = input_file;
+    {
+//         output_file = ~s / \.[sS][tT][lL]$ / _fixed.obj / ;
+        auto dlg = new wxFileDialog( this, L("Save OBJ file (less prone to coordinate errors than STL) as:"), 
+                                        get_dir_name(output_file), get_base_name(output_file), 
+                                        FILE_WILDCARDS.at("obj"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+        if (dlg->ShowModal() != wxID_OK) {
+            dlg->Destroy();
+            return /*undef*/;
+        }
+        output_file = dlg->GetPath();
+        dlg->Destroy();
+    }
+
+    auto tmesh = new Slic3r::TriangleMesh();
+    tmesh->ReadSTLFile(input_file.char_str());
+    tmesh->repair();
+    tmesh->WriteOBJFile(output_file.char_str());
+    Slic3r::GUI::show_info(this, L("Your file was repaired."), L("Repair"));
+}
+
+void MainFrame::export_config()
+{
+    // Generate a cummulative configuration for the selected print, filaments and printer.
+    auto config = get_preset_bundle()->full_config();
+    // Validate the cummulative configuration.
+    auto valid = config.validate();
+    if (!valid.empty()) {
+//         Slic3r::GUI::catch_error(this);
+        return;
+    }
+    // Ask user for the file name for the config file.
+    auto dlg = new wxFileDialog(this, _(L("Save configuration as:")),
+        !m_last_config.IsEmpty() ? get_dir_name(m_last_config) : get_app_config()->get_last_dir(),
+        !m_last_config.IsEmpty() ? get_base_name(m_last_config) : "config.ini",
+        FILE_WILDCARDS.at("ini"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+    wxString file = dlg->ShowModal() == wxID_OK ? dlg->GetPath() : wxEmptyString;
+    dlg->Destroy();
+    if (!file.IsEmpty()) {
+        get_app_config()->update_config_dir(get_dir_name(file));
+        m_last_config = file;
+        config.save(file.ToStdString());
+    }
+}
+
+// Load a config file containing a Print, Filament & Printer preset.
+void MainFrame::load_config_file(wxString file/* = wxEmptyString*/)
+{
+    if (file.IsEmpty()) {
+        if (!Slic3r::GUI::check_unsaved_changes())
+            return;
+        auto dlg = new wxFileDialog(this, _(L("Select configuration to load:")),
+            !m_last_config.IsEmpty() ? get_dir_name(m_last_config) : get_app_config()->get_last_dir(),
+            "config.ini", "INI files (*.ini, *.gcode)|*.ini;*.INI;*.gcode;*.g", wxFD_OPEN | wxFD_FILE_MUST_EXIST);
+        if (dlg->ShowModal() != wxID_OK)
+            return;
+        file = dlg->GetPath();
+        dlg->Destroy();
+    }
+//     eval{ 
+        get_preset_bundle()->load_config_file(file.ToStdString()); 
+//     };
+    // Dont proceed further if the config file cannot be loaded.
+//     if (Slic3r::GUI::catch_error(this))
+//         return;
+    for (auto tab : m_options_tabs )
+        tab.second->load_current_preset();
+    get_app_config()->update_config_dir(get_dir_name(file));
+    m_last_config = file;
+}
+
+void MainFrame::export_configbundle()
+{
+    if (!Slic3r::GUI::check_unsaved_changes())
+        return;
+    // validate current configuration in case it's dirty
+    auto valid = get_preset_bundle()->full_config().validate();
+    if (!valid.empty()) {
+//         Slic3r::GUI::catch_error(this);
+        return;
+    }
+    // Ask user for a file name.
+    auto dlg = new wxFileDialog(this, _(L("Save presets bundle as:")),
+        !m_last_config.IsEmpty() ? get_dir_name(m_last_config) : get_app_config()->get_last_dir(),
+        "Slic3r_config_bundle.ini",
+        FILE_WILDCARDS.at("ini"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
+    wxString file = dlg->ShowModal() == wxID_OK ? dlg->GetPath() : wxEmptyString;
+    dlg->Destroy();
+    if (!file.IsEmpty()) {
+        // Export the config bundle.
+       get_app_config()->update_config_dir(get_dir_name(file));
+//         eval{ 
+            get_preset_bundle()->export_configbundle(file.ToStdString()); 
+//         };
+//         Slic3r::GUI::catch_error(this);
+    }
+}
+
+// Loading a config bundle with an external file name used to be used
+// to auto - install a config bundle on a fresh user account,
+// but that behavior was not documented and likely buggy.
+void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool reset_user_profile*/){
+    if (!Slic3r::GUI::check_unsaved_changes())
+        return;
+    if (file.IsEmpty()) {
+        auto dlg = new wxFileDialog(this, _(L("Select configuration to load:")),
+            !m_last_config.IsEmpty() ? get_dir_name(m_last_config) : get_app_config()->get_last_dir(),
+            "config.ini", FILE_WILDCARDS.at("ini"), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
+        if (dlg->ShowModal() != wxID_OK)
+            return;
+        file = dlg->GetPath();
+        dlg->Destroy();
+    }
+
+    get_app_config()->update_config_dir(get_dir_name(file));
+
+    auto presets_imported = 0;
+//     eval{ 
+        presets_imported = get_preset_bundle()->load_configbundle(file.ToStdString()); 
+//     };
+//     Slic3r::GUI::catch_error(this) and return;
+
+    // Load the currently selected preset into the GUI, update the preset selection box.
+    for (auto tab : m_options_tabs)
+        tab.second->load_current_preset();
+
+    const auto message = wxString::Format(_(L("%d presets successfully imported.")), presets_imported);
+    Slic3r::GUI::show_info(this, message, "Info");
+}
+
+// Load a provied DynamicConfig into the Print / Filament / Printer tabs, thus modifying the active preset.
+// Also update the platter with the new presets.
+void MainFrame::load_config(const DynamicPrintConfig& config){
+    for (auto tab : m_options_tabs)
+        tab.second->load_config(config);
+//     if (m_plater) m_plater->on_config_change(config);
+}
+
+void MainFrame::select_tab(size_t tab) const{
+    m_tabpanel->SetSelection(tab);
+}
+
+// Set a camera direction, zoom to all objects.
+void MainFrame::select_view(const std::string& direction){
+//     if (m_plater)
+//         m_plater->select_view(direction);
+}
+
+wxMenuItem* MainFrame::append_menu_item(wxMenu* menu, 
+                                        int id, 
+                                        const wxString& string,
+                                        const wxString& description,
+                                        std::function<void(wxCommandEvent& event)> cb, 
+                                        const std::string& icon /*= ""*/)
+{
+    if (id == wxID_ANY)
+        id = wxNewId();
+    auto item = menu->Append(id, string, description);
+    if (!icon.empty())
+        item->SetBitmap(wxBitmap(Slic3r::var(icon), wxBITMAP_TYPE_PNG));
+    menu->Bind(wxEVT_MENU, /*[cb](wxCommandEvent& event){cb; }*/cb);
+    return item;
+}
+
+// Called after the Preferences dialog is closed and the program settings are saved.
+// Update the UI based on the current preferences.
+void MainFrame::update_ui_from_settings()
+{
+//     m_menu_item_reslice_now->Enable(get_app_config()->get("background_processing"));
+//     if (m_plater) m_plater->update_ui_from_settings();
+    std::vector<std::string> tab_names = { "print", "filament", "printer" };
+    for (auto tab_name: tab_names)
+        m_options_tabs[tab_name]->update_ui_from_settings();
+}
+
+
+std::string MainFrame::get_base_name(const wxString full_name) const 
+{
+    return boost::filesystem::path(full_name).filename().string();
+}
+
+std::string MainFrame::get_dir_name(const wxString full_name) const 
+{
+    return boost::filesystem::path(full_name).parent_path().string();
+}
+
+
+} // GUI
+} //Slic3r
diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp
new file mode 100644
index 000000000..2156db691
--- /dev/null
+++ b/src/slic3r/GUI/MainFrame.hpp
@@ -0,0 +1,101 @@
+#ifndef slic3r_MainFrame_hpp_
+#define slic3r_MainFrame_hpp_
+
+#include "PrintConfig.hpp"
+
+#include <wx/frame.h>
+
+#include <string>
+#include <map>
+
+class wxMenuBar;
+class wxNotebook;
+class wxPanel;
+class wxMenu;
+class wxProgressDialog;
+
+namespace Slic3r {
+
+class ProgressStatusBar;
+class AppController;
+
+// #define _(s)    Slic3r::GUI::I18N::translate((s))
+
+namespace GUI
+{
+class Tab;
+
+enum QuickSlice
+{
+    qsUndef,
+    qsReslice,
+    qsSaveAs,
+    qsExportSVG,
+    qsExportPNG
+};
+
+class MainFrame : public wxFrame
+{
+    bool        m_no_plater;
+    bool        m_loaded;
+    int         m_lang_ch_event;
+    int         m_preferences_event;
+
+    wxString    m_qs_last_input_file = wxEmptyString;
+    wxString    m_qs_last_output_file = wxEmptyString;
+    wxString    m_last_config = wxEmptyString;
+
+    ProgressStatusBar*              m_statusbar;
+    AppController*                  m_appController = nullptr;
+    std::map<std::string, Tab*>     m_options_tabs;
+
+    wxMenuItem* append_menu_item(wxMenu* menu,
+                                 int id,
+                                 const wxString& string,
+                                 const wxString& description,
+                                 std::function<void(wxCommandEvent& event)> cb,
+                                 const std::string& icon = "");
+
+    wxMenuItem* m_menu_item_reslice_now = nullptr;
+    wxMenu*     m_plater_menu = nullptr;
+    wxMenu*     m_object_menu = nullptr;
+    wxMenu*     m_viewMenu = nullptr;
+
+    std::string     get_base_name(const wxString full_name) const ;
+    std::string     get_dir_name(const wxString full_name) const ;
+public:
+    MainFrame() {}
+    MainFrame(const bool no_plater, const bool loaded);
+    ~MainFrame() {}
+
+
+    void        init_tabpanel();
+    void        init_menubar();
+
+    void        update_ui_from_settings();
+    bool        is_loaded() const { return m_loaded; }
+    bool        is_last_input_file() const  { return !m_qs_last_input_file.IsEmpty(); }
+
+    void        on_plater_selection_changed(const bool have_selection);
+    void        slice_to_png();
+    void        quick_slice(const int qs = qsUndef);
+    void        reslice_now();
+    void        repair_stl();
+    void        export_config();
+    void        load_config_file(wxString file = wxEmptyString);
+    void        export_configbundle();
+    void        load_configbundle(wxString file = wxEmptyString);
+    void        load_config(const DynamicPrintConfig& config);
+    void        select_tab(size_t tab) const;
+    void        select_view(const std::string& direction);
+
+
+    wxPanel*            m_plater = nullptr;
+    wxNotebook*         m_tabpanel = nullptr;
+    wxProgressDialog*   m_progress_dialog = nullptr;
+};
+
+} // GUI
+} //Slic3r
+
+#endif // slic3r_MainFrame_hpp_
\ No newline at end of file