From 126f0e50734ce69b9961e6c0549a98bf2f308dcb Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Mon, 22 Oct 2018 11:45:03 +0200
Subject: [PATCH 1/8] Added mirroring factors to .amf import/export

---
 src/libslic3r/Format/AMF.cpp  | 87 ++++++++++++++++++++++++++++++++---
 src/slic3r/GUI/GLCanvas3D.cpp | 14 ++----
 src/slic3r/GUI/GUI_Utils.cpp  |  1 +
 src/slic3r/GUI/MainFrame.cpp  |  2 +-
 src/slic3r/GUI/Plater.cpp     | 21 +++++++--
 5 files changed, 104 insertions(+), 21 deletions(-)

diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index 00ed0d937..be0261634 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -32,6 +32,9 @@
 // 2 : Added z component of offset
 //     Added x and y components of rotation
 //     Added x, y and z components of scale
+#if ENABLE_MIRROR
+//     Added x, y and z components of mirror
+#endif // ENABLE_MIRROR
 const unsigned int VERSION_AMF = 2;
 const char* SLIC3RPE_AMF_VERSION = "slic3rpe_amf_version";
 
@@ -126,14 +129,27 @@ struct AMFParserContext
         NODE_TYPE_RY,                   // amf/constellation/instance/ry
         NODE_TYPE_RZ,                   // amf/constellation/instance/rz
         NODE_TYPE_SCALE,                // amf/constellation/instance/scale
-        NODE_TYPE_SCALEX,                // amf/constellation/instance/scalex
-        NODE_TYPE_SCALEY,                // amf/constellation/instance/scaley
-        NODE_TYPE_SCALEZ,                // amf/constellation/instance/scalez
+        NODE_TYPE_SCALEX,               // amf/constellation/instance/scalex
+        NODE_TYPE_SCALEY,               // amf/constellation/instance/scaley
+        NODE_TYPE_SCALEZ,               // amf/constellation/instance/scalez
+#if ENABLE_MIRROR
+        NODE_TYPE_MIRRORX,              // amf/constellation/instance/mirrorx
+        NODE_TYPE_MIRRORY,              // amf/constellation/instance/mirrory
+        NODE_TYPE_MIRRORZ,              // amf/constellation/instance/mirrorz
+#endif // ENABLE_MIRROR
         NODE_TYPE_METADATA,             // anywhere under amf/*/metadata
     };
 
     struct Instance {
+#if ENABLE_MIRROR
+        Instance()
+            : deltax_set(false), deltay_set(false), deltaz_set(false)
+            , rx_set(false), ry_set(false), rz_set(false)
+            , scalex_set(false), scaley_set(false), scalez_set(false)
+            , mirrorx_set(false), mirrory_set(false), mirrorz_set(false) {}
+#else
         Instance() : deltax_set(false), deltay_set(false), deltaz_set(false), rx_set(false), ry_set(false), rz_set(false), scalex_set(false), scaley_set(false), scalez_set(false)  {}
+#endif // ENABLE_MIRROR
         // Shift in the X axis.
         float deltax;
         bool  deltax_set;
@@ -159,6 +175,15 @@ struct AMFParserContext
         bool  scaley_set;
         float scalez;
         bool  scalez_set;
+#if ENABLE_MIRROR
+        // Mirroring factors
+        float mirrorx;
+        bool  mirrorx_set;
+        float mirrory;
+        bool  mirrory_set;
+        float mirrorz;
+        bool  mirrorz_set;
+#endif // ENABLE_MIRROR
     };
 
     struct Object {
@@ -289,6 +314,14 @@ void AMFParserContext::startElement(const char *name, const char **atts)
                 node_type_new = NODE_TYPE_SCALEZ;
             else if (strcmp(name, "scale") == 0)
                 node_type_new = NODE_TYPE_SCALE;
+#if ENABLE_MIRROR
+            else if (strcmp(name, "mirrorx") == 0)
+                node_type_new = NODE_TYPE_MIRRORX;
+            else if (strcmp(name, "mirrory") == 0)
+                node_type_new = NODE_TYPE_MIRRORY;
+            else if (strcmp(name, "mirrorz") == 0)
+                node_type_new = NODE_TYPE_MIRRORZ;
+#endif // ENABLE_MIRROR
         }
         break;
     case 4:
@@ -345,16 +378,23 @@ void AMFParserContext::characters(const XML_Char *s, int len)
     {
         switch (m_path.size()) {
         case 4:
-            if (m_path.back() == NODE_TYPE_DELTAX || 
-                m_path.back() == NODE_TYPE_DELTAY || 
-                m_path.back() == NODE_TYPE_DELTAZ || 
+            if (m_path.back() == NODE_TYPE_DELTAX ||
+                m_path.back() == NODE_TYPE_DELTAY ||
+                m_path.back() == NODE_TYPE_DELTAZ ||
                 m_path.back() == NODE_TYPE_RX ||
                 m_path.back() == NODE_TYPE_RY ||
                 m_path.back() == NODE_TYPE_RZ ||
                 m_path.back() == NODE_TYPE_SCALEX ||
                 m_path.back() == NODE_TYPE_SCALEY ||
                 m_path.back() == NODE_TYPE_SCALEZ ||
+#if ENABLE_MIRROR
+                m_path.back() == NODE_TYPE_SCALE ||
+                m_path.back() == NODE_TYPE_MIRRORX ||
+                m_path.back() == NODE_TYPE_MIRRORY ||
+                m_path.back() == NODE_TYPE_MIRRORZ)
+#else
                 m_path.back() == NODE_TYPE_SCALE)
+#endif // ENABLE_MIRROR
                 m_value[0].append(s, len);
             break;
         case 6:
@@ -446,6 +486,26 @@ void AMFParserContext::endElement(const char * /* name */)
         m_instance->scalez_set = true;
         m_value[0].clear();
         break;
+#if ENABLE_MIRROR
+    case NODE_TYPE_MIRRORX:
+        assert(m_instance);
+        m_instance->mirrorx = float(atof(m_value[0].c_str()));
+        m_instance->mirrorx_set = true;
+        m_value[0].clear();
+        break;
+    case NODE_TYPE_MIRRORY:
+        assert(m_instance);
+        m_instance->mirrory = float(atof(m_value[0].c_str()));
+        m_instance->mirrory_set = true;
+        m_value[0].clear();
+        break;
+    case NODE_TYPE_MIRRORZ:
+        assert(m_instance);
+        m_instance->mirrorz = float(atof(m_value[0].c_str()));
+        m_instance->mirrorz_set = true;
+        m_value[0].clear();
+        break;
+#endif // ENABLE_MIRROR
 
     // Object vertices:
     case NODE_TYPE_VERTEX:
@@ -585,6 +645,9 @@ void AMFParserContext::endDocument()
                 mi->set_offset(Vec3d(instance.deltax_set ? (double)instance.deltax : 0.0, instance.deltay_set ? (double)instance.deltay : 0.0, instance.deltaz_set ? (double)instance.deltaz : 0.0));
                 mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0));
                 mi->set_scaling_factor(Vec3d(instance.scalex_set ? (double)instance.scalex : 1.0, instance.scaley_set ? (double)instance.scaley : 1.0, instance.scalez_set ? (double)instance.scalez : 1.0));
+#if ENABLE_MIRROR
+                mi->set_mirror(Vec3d(instance.mirrorx_set ? (double)instance.mirrorx : 1.0, instance.mirrory_set ? (double)instance.mirrory : 1.0, instance.mirrorz_set ? (double)instance.mirrorz : 1.0));
+#endif // ENABLE_MIRROR
             }
     }
 }
@@ -891,6 +954,11 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c
                     "      <scalex>%lf</scalex>\n"
                     "      <scaley>%lf</scaley>\n"
                     "      <scalez>%lf</scalez>\n"
+#if ENABLE_MIRROR
+                    "      <mirrorx>%lf</mirrorx>\n"
+                    "      <mirrory>%lf</mirrory>\n"
+                    "      <mirrorz>%lf</mirrorz>\n"
+#endif // ENABLE_MIRROR
                     "    </instance>\n",
                     object_id,
                     instance->get_offset(X),
@@ -901,7 +969,14 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c
                     instance->get_rotation(Z),
                     instance->get_scaling_factor(X),
                     instance->get_scaling_factor(Y),
+#if ENABLE_MIRROR
+                    instance->get_scaling_factor(Z),
+                    instance->get_mirror(X),
+                    instance->get_mirror(Y),
+                    instance->get_mirror(Z));
+#else
                     instance->get_scaling_factor(Z));
+#endif // ENABLE_MIRROR
 
                 //FIXME missing instance->scaling_factor
                 instances.append(buf);
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 4bb0f499f..7d47ff8f6 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -3432,7 +3432,6 @@ int GLCanvas3D::get_in_object_volume_id(int scene_vol_idx) const
 #if ENABLE_EXTENDED_SELECTION
 void GLCanvas3D::mirror_selection(Axis axis)
 {
-    m_regenerate_volumes = false;
     m_selection.mirror(axis);
     _on_mirror();
     wxGetApp().obj_manipul()->update_settings_value(m_selection);
@@ -3457,7 +3456,12 @@ void GLCanvas3D::reload_scene(bool force)
 
 #if ENABLE_EXTENDED_SELECTION
     if (m_regenerate_volumes)
+    {
         reset_volumes();
+
+        // to update the toolbar
+        post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT));
+    }
 #endif // ENABLE_EXTENDED_SELECTION
 
     set_bed_shape(dynamic_cast<const ConfigOptionPoints*>(m_config->option("bed_shape"))->values);
@@ -3477,9 +3481,6 @@ void GLCanvas3D::reload_scene(bool force)
         {
             load_object(*m_model, obj_idx);
         }
-
-        // to update the toolbar
-        post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT));
     }
 
     update_gizmos_data();
@@ -3858,7 +3859,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
         case Gizmos::Scale:
         {
 #if ENABLE_EXTENDED_SELECTION
-            m_regenerate_volumes = false;
             m_selection.scale(m_gizmos.get_scale());
             _on_scale();
 #else
@@ -3875,7 +3875,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
         case Gizmos::Rotate:
         {
 #if ENABLE_EXTENDED_SELECTION
-            m_regenerate_volumes = false;
             m_selection.rotate(m_gizmos.get_rotation());
             _on_rotate();
 #else
@@ -3958,7 +3957,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
             if (m_gizmos.get_current_type() == Gizmos::Flatten) {
                 // Rotate the object so the normal points downward:
 #if ENABLE_EXTENDED_SELECTION
-                m_regenerate_volumes = false;
                 m_selection.rotate(m_gizmos.get_flattening_rotation());
                 _on_flatten();
                 wxGetApp().obj_manipul()->update_settings_value(m_selection);
@@ -4397,7 +4395,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
             case Gizmos::Scale:
             {
 #if ENABLE_EXTENDED_SELECTION
-                m_regenerate_volumes = false;
                 _on_scale();
 #endif // ENABLE_EXTENDED_SELECTION
                 break;
@@ -4405,7 +4402,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
             case Gizmos::Rotate:
             {
 #if ENABLE_EXTENDED_SELECTION
-                m_regenerate_volumes = false;
                 _on_rotate();
 #else
                 post_event(Vec3dEvent(EVT_GIZMO_ROTATE, m_gizmos.get_rotation()));
diff --git a/src/slic3r/GUI/GUI_Utils.cpp b/src/slic3r/GUI/GUI_Utils.cpp
index fb494ed23..5a7ece586 100644
--- a/src/slic3r/GUI/GUI_Utils.cpp
+++ b/src/slic3r/GUI/GUI_Utils.cpp
@@ -28,6 +28,7 @@ CheckboxFileDialog::ExtraPanel::ExtraPanel(wxWindow *parent)
 
     auto* sizer = new wxBoxSizer(wxHORIZONTAL);
     cbox = new wxCheckBox(this, wxID_ANY, checkbox_label);
+    cbox->SetValue(true);
     sizer->AddSpacer(5);
     sizer->Add(this->cbox, 0, wxEXPAND | wxALL, 5);
     SetSizer(sizer);
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index 6a202ad4c..f1e6595f7 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -300,7 +300,7 @@ void MainFrame::init_menubar()
         append_menu_item(m_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(m_plater_menu, wxID_ANY, _(L("Export plate as AMF...")), _(L("Export current plate as AMF")),
-            [this](wxCommandEvent&){ /*m_plater->export_amf();*/ }, "brick_go.png");
+            [this](wxCommandEvent&){ m_plater->export_amf(); }, "brick_go.png");
         append_menu_item(m_plater_menu, wxID_ANY, _(L("Export plate as 3MF...")), _(L("Export current plate as 3MF")),
             [this](wxCommandEvent&){ m_plater->export_3mf(); }, "brick_go.png");
     }
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index b5cb21625..bef4d5a86 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -850,7 +850,9 @@ private:
     bool layers_height_allowed() const;
     bool can_delete_all() const;
     bool can_arrange() const;
+#if ENABLE_MIRROR
     bool can_mirror() const;
+#endif // ENABLE_MIRROR
 #endif // ENABLE_EXTENDED_SELECTION
 };
 
@@ -1256,14 +1258,17 @@ std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType
     wxString wildcard;
     switch (file_type) {
         case FT_STL:
-        case FT_AMF:
-        case FT_3MF:
             wildcard = file_wildcards[FT_STL];
-        break;
-
+            break;
+        case FT_AMF:
+            wildcard = file_wildcards[FT_AMF];
+            break;
+        case FT_3MF:
+            wildcard = file_wildcards[FT_3MF];
+            break;
         default:
             wildcard = file_wildcards[FT_MODEL];
-        break;
+            break;
     }
 
     fs::path output_file(print.output_filepath(std::string()));
@@ -1899,6 +1904,7 @@ bool Plater::priv::init_object_menu()
 
     object_menu.AppendSeparator();
     
+#if ENABLE_MIRROR
     wxMenu* mirror_menu = new wxMenu();
     if (mirror_menu == nullptr)
         return false;
@@ -1911,6 +1917,7 @@ bool Plater::priv::init_object_menu()
         [this](wxCommandEvent&){ mirror(Z); }, "bullet_blue.png", &object_menu);
 
     wxMenuItem* item_mirror = append_submenu(&object_menu, mirror_menu, wxID_ANY, _(L("Mirror")), _(L("Mirror the selected object")));
+#endif // ENABLE_MIRROR
 
     wxMenuItem* item_split = append_menu_item(&object_menu, wxID_ANY, _(L("Split")), _(L("Split the selected object into individual parts")),
         [this](wxCommandEvent&){ split_object(); }, "shape_ungroup.png");
@@ -1919,7 +1926,9 @@ bool Plater::priv::init_object_menu()
     // ui updates needs to be binded to the parent panel
     if (q != nullptr)
     {
+#if ENABLE_MIRROR
         q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_mirror()); }, item_mirror->GetId());
+#endif // ENABLE_MIRROR
         q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_delete_object()); }, item_delete->GetId());
         q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_increase_instances()); }, item_increase->GetId());
         q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_decrease_instances()); }, item_decrease->GetId());
@@ -1976,10 +1985,12 @@ bool Plater::priv::can_arrange() const
     return !model.objects.empty();
 }
 
+#if ENABLE_MIRROR
 bool Plater::priv::can_mirror() const
 {
     return get_selection().is_from_single_instance();
 }
+#endif // ENABLE_MIRROR
 #endif // ENABLE_EXTENDED_SELECTION
 
 // Plater / Public

From 974e2056fbc85cf19265523adfd2992277081003 Mon Sep 17 00:00:00 2001
From: Vojtech Kral <vojtech@kral.hk>
Date: Mon, 22 Oct 2018 11:52:13 +0200
Subject: [PATCH 2/8] Plater: Fix file patterns

---
 src/slic3r/GUI/Plater.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index bef4d5a86..8fd13cfe2 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -700,7 +700,7 @@ private:
     static const std::regex pattern_drop;
 };
 
-const std::regex PlaterDropTarget::pattern_drop("[.](stl|obj|amf|3mf|prusa)$", std::regex::icase);
+const std::regex PlaterDropTarget::pattern_drop(".*[.](stl|obj|amf|3mf|prusa)", std::regex::icase);
 
 bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &filenames)
 {
@@ -856,9 +856,9 @@ private:
 #endif // ENABLE_EXTENDED_SELECTION
 };
 
-const std::regex Plater::priv::pattern_bundle("[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)$", std::regex::icase);
-const std::regex Plater::priv::pattern_3mf("[.]3mf$", std::regex::icase);
-const std::regex Plater::priv::pattern_zip_amf("[.]zip[.]amf$", std::regex::icase);
+const std::regex Plater::priv::pattern_bundle(".*[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)", std::regex::icase);
+const std::regex Plater::priv::pattern_3mf(".*3mf", std::regex::icase);
+const std::regex Plater::priv::pattern_zip_amf(".*[.]zip[.]amf", std::regex::icase);
 
 Plater::priv::priv(Plater *q, MainFrame *main_frame) :
     q(q),

From 37e165d82d89767dfd18b63592a2bab8c5dea11f Mon Sep 17 00:00:00 2001
From: Vojtech Kral <vojtech@kral.hk>
Date: Mon, 22 Oct 2018 11:50:05 +0200
Subject: [PATCH 3/8] Build: Fix resources symlink

---
 src/CMakeLists.txt | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 330134c3b..332649cf9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -119,28 +119,28 @@ if (MSVC)
         foreach (CONF ${CMAKE_CONFIGURATION_TYPES})
             file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${CONF}" WIN_CONF_OUTPUT_DIR)
             file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${CONF}/resources" WIN_RESOURCES_SYMLINK)
-            add_custom_target("resources_symlink_${CONF}" ALL
-                DEPENDS slic3r
+            add_custom_command(TARGET slic3r POST_BUILD
                 COMMAND if exist "${WIN_CONF_OUTPUT_DIR}" "("
                         if not exist "${WIN_RESOURCES_SYMLINK}" "("
                             mklink /J "${WIN_RESOURCES_SYMLINK}" "${SLIC3R_RESOURCES_DIR_WIN}"
                         ")"
                     ")"
+                COMMENT "Symlinking the resources directory into the build tree"
                 VERBATIM
             )
         endforeach ()
     else ()
         file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/resources" WIN_RESOURCES_SYMLINK)
-        add_custom_target(resources_symlink ALL
-            DEPENDS slic3r
+        add_custom_command(TARGET slic3r POST_BUILD
             COMMAND if not exist "${WIN_RESOURCES_SYMLINK}" "(" mklink /J "${WIN_RESOURCES_SYMLINK}" "${SLIC3R_RESOURCES_DIR_WIN}" ")"
+            COMMENT "Symlinking the resources directory into the build tree"
             VERBATIM
         )
     endif ()
 else ()
-    add_custom_target(resources_symlink ALL
-        DEPENDS slic3r
+    add_custom_command(TARGET slic3r POST_BUILD
         COMMAND ln -sf "${SLIC3R_RESOURCES_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/../resources"
+        COMMENT "Symlinking the resources directory into the build tree"
         VERBATIM
     )
 endif()

From f6e6d9dc4ada0d8481884d8ad73c9bee2291f4c7 Mon Sep 17 00:00:00 2001
From: Vojtech Kral <vojtech@kral.hk>
Date: Fri, 19 Oct 2018 16:52:41 +0200
Subject: [PATCH 4/8] Fix Plater::priv::get_export_file()

---
 src/slic3r/GUI/MainFrame.cpp |  4 ++--
 src/slic3r/GUI/Plater.cpp    | 12 +++++-------
 2 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index f1e6595f7..5df19df80 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -296,9 +296,9 @@ void MainFrame::init_menubar()
     if (m_plater) {
         m_plater_menu = new wxMenu();
         append_menu_item(m_plater_menu, wxID_ANY, _(L("Export G-code...")), _(L("Export current plate as G-code")),
-            [this](wxCommandEvent&){ /*m_plater->export_gcode(); */}, "cog_go.png");
+            [this](wxCommandEvent&){ m_plater->export_gcode(); }, "cog_go.png");
         append_menu_item(m_plater_menu, wxID_ANY, _(L("Export plate as STL...")), _(L("Export current plate as STL")),
-            [this](wxCommandEvent&){ /*m_plater->export_stl(); */}, "brick_go.png");
+            [this](wxCommandEvent&){ m_plater->export_stl(); }, "brick_go.png");
         append_menu_item(m_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(m_plater_menu, wxID_ANY, _(L("Export plate as 3MF...")), _(L("Export current plate as 3MF")),
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 8fd13cfe2..8bdc43a37 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -1258,17 +1258,15 @@ std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType
     wxString wildcard;
     switch (file_type) {
         case FT_STL:
-            wildcard = file_wildcards[FT_STL];
-            break;
         case FT_AMF:
-            wildcard = file_wildcards[FT_AMF];
-            break;
         case FT_3MF:
-            wildcard = file_wildcards[FT_3MF];
-            break;
+        case FT_GCODE:
+            wildcard = file_wildcards[file_type];
+        break;
+
         default:
             wildcard = file_wildcards[FT_MODEL];
-            break;
+        break;
     }
 
     fs::path output_file(print.output_filepath(std::string()));

From 84de664fb54fe87939c7072cc2f0932d82afb4a7 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 22 Oct 2018 12:07:40 +0200
Subject: [PATCH 5/8] Fixed TreeCtrl updating after mode change

+ Added another images for mode visualization
---
 resources/icons/mode_expert_.png | Bin 0 -> 1379 bytes
 resources/icons/mode_middle_.png | Bin 0 -> 1466 bytes
 resources/icons/mode_simple_.png | Bin 0 -> 1164 bytes
 src/slic3r/GUI/OptionsGroup.cpp  |   2 ++
 src/slic3r/GUI/Tab.cpp           |  13 +++++++++----
 5 files changed, 11 insertions(+), 4 deletions(-)
 create mode 100644 resources/icons/mode_expert_.png
 create mode 100644 resources/icons/mode_middle_.png
 create mode 100644 resources/icons/mode_simple_.png

diff --git a/resources/icons/mode_expert_.png b/resources/icons/mode_expert_.png
new file mode 100644
index 0000000000000000000000000000000000000000..4d78bcccf511511455f4de48fca473bb2d0aa677
GIT binary patch
literal 1379
zcmV-p1)TbcP)<h;3K|Lk000e1NJLTq000O8000yS1^@s6up4}9000EEdQ@0+Qek%>
zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3vrlIti8h5u_6vjhYPiRJLDnjOsY=is;#C!O&f
zciL3^P%udPbTBmj`Fqk|IJ~G)#3|*J9FCY{_60ZQZpZD)E^g<eZ9PBPiR1o<hbiD1
zZjWi~{R`~!ctQ96T%YZvZ6C+>fxc$m2MlXwkDI-p?E?jWvwt~4d4I3OgX{Y*_sx07
zd#Bgus7OW^j2Arl5jZ%U)0!o~gJ7X78_qs>@Amr`63$`udzU-9rTKgE?sqS_b7i-O
z=TwmU8YsQwXt%Sx&)t@xCu)zGpZ=Kj4*FZ}=Il1-xJ6fDLZ%Y!L4Ad?-JxSeD#P|#
zLR0(%_qw%=W(cu?SO?9D)`&BEWOH)l&V?tB?b^7(#ps7uT)l5TY&Hw(vu_)exEfEd
zA%{+2<U<3s0JFdQ!rQ!go3F89=FaHp8H4en`P%56@h9y*(44DunVsG8gtCBNe$_PG
zSmf3jy#R#go>STKyEQu0jXQu1AShd!4FMKcZ$nh!M{R|Tb3i|Fk#0rrSo=NzQiQn$
z&Ts$$mpBL~cIv${Baa3?1)lp5eFXs)@ttXc4eB0n%&)oej`G&mi@%w%v;c%aA__D)
z6u^p6P(K<CHB=->BoRrXVv?n#kYbXQlBTsr6%86yG^wg-)?&e;i6v7r%T}__0ZW+V
zl$EmOoJ+x^1w$9SUC^VH>T9U6N=;R()m%$M`Lx)irKZhVZl(JkI^^F|SL)VtFM|h4
zX~ZET4IMV}C=<0d!;DjAnmTRfS?<($m+ccZej#^GjdyB`Sls&QgBr}LUqkR(PGm6y
zF&`PkbrC>8`^C%|$LJTi#mr?7QHTdMmIbHtA_jtSu$Reqb`Nr=+(_ajZvMZ>(L(nd
z<Y=MW$$jVchFUM%7bR?fmI_x+U6@$dW++9QOtsm4&T(2DKwt3XMCxFSC2LETOBD}s
zJCMk83@fdc9<8n(O0yy)?^Ju_tU9r>wbj`a6EwIUYTce^(%HhyJtYXSH{oujE6-7#
zc29+ojS*%~4o*N)C29(7mOk+@E#3;e%q9^ZDOYS1tfWpP##YK`fE|T_59`s$6Vk^}
zu_Ot@&)Rfku~t*SqKisE2|Pkr5mY~JQGUf}#?&VYSUL(<YnX#)8#VYE$5;W4(DS;w
zIaH9pSe4<iuhMju#+cnwN!2DzF*qfzr;MOy7!`?aD<UhXCl>F9t-{FIKVa!WeV2;w
z1|mWQve~?mqE}QYEK)H&fqIAOg%T~tH&D-*{sie8Bl;nvZ;a>)q(><N)149u9h~R|
z)Q;(okk+72l<3EpUMSIfOz-t{CMUY0r!zUxN2m^@=!%}s<V08WbS5YI0MrvFx}v8u
zInfUxePcvFg!GLOUD4B-oal<4&g4Wt#`Gd5x}v8uInhU`4y5QKR0mRYMNemPqAPkj
zlN0?2)Eha`6+NBFiGFDh5$KaW#8FOkMNemPqAPkjlM`Lh)0v#;lkMJ7PV^C~11b7s
zyLXfmeX`v<%85SN?j1SNC)>TFoamG7-jNag(jFqvC)>RvC;DW&cceuB3lrw)**W?b
z+PYSP@1brk00006VoOIv0RI600RN!9r;`8x010qNS#tmY5_A9n5_AFHW*>L}000Mc
zNliru;tCcBE-rCcRgeGx05C~JK~yNuW8BWh_Fw1MF9t3d6^0K_?l7EXfB+^228K^O
lJPb?>1i+|*Q3cdh002W22;H2eLIwZ;002ovPDHLkV1id3f^Pr-

literal 0
HcmV?d00001

diff --git a/resources/icons/mode_middle_.png b/resources/icons/mode_middle_.png
new file mode 100644
index 0000000000000000000000000000000000000000..d98d8f7091d0fcebd33a354a11feb8cd0a08f5bf
GIT binary patch
literal 1466
zcmV;r1x5OaP)<h;3K|Lk000e1NJLTq000O8000yS1^@s6up4}9000FMdQ@0+Qek%>
zaB^>EX>4U6ba`-PAZ2)IW&i+q+O1Yww&N%a{MRaG2}VK)mc#R$-oY$?3hX>@uG@Wk
zLSl>p0;-C#ssH<H&_DRFq>a2<3@L;SAD?{UjGMUapS^aQU)Sf@Y`?_G`Qr~pNKnh(
z4E^Yz5!c56JNmow8Yinqo_Hj>&3q)3IWyzt=ogPf!h8I-5K70m?4Oo?{8C$s-`vsZ
zz3mNPG(|pP;x0}$T*I72umXvaXAD;s=IyxmVz`Q=&)Crp^H=chcW>Bj`H0Ia6tvwE
zg*S|jxYN(rErecJd(8auhm1SXU$7ga#WDK6yX*sy3UqAhwv}~<js;N48WvCtKgGSR
zl29VHSix8Wn+2tkOOAo&aNaeS-Ee)?)m1Ffb7w=%Tv=8uigDt)Nb$3{!6r!>fg_d*
z)&ya`uf?r-)0(fkh?$#1Pj*P=CY$etJ_UbL?uo{j(sgc&J5G=V*2PoPSjJ>-UeODL
zxN%^r3*S}fNjKXQu>uBl!5p!{yp=sgQTNc6ES?4Zbn~=}esk821b_&0D;DDf3~a%P
zy5KfrHs^q21V0%oXYpLXfK%n>Xn-4$0CFPFxiQAv>dVS|7}f$JR00l31Vb5Qd9Toq
z`3MbV74@X5K~1A3%|U_>8bYuzJt~`+H??49(URpT(MOFTT8uHpoHz+AOjAfkDW;Ti
z#-tgkGe&3h$hmNl;)|A0ti+N^u8>dlRcokLV@)+TZqji4TWCftw$yTW9a8GPYY*Le
z?5XDgtqmD|=m^6`9BJe`YwkF<FRZyY=FVAj2WyitzxvsOHH6J>DcrOZot%L&_705O
zWB`KZ$=Md2_dJ=KoNbA5D3rmP(@9QqlQA&pyJH>h&fSB#Q{G7ZAMwWDF-McS|ART2
z)E&%y<?RD&Ew3kvEQ01KoS4D}VQj;@oO-j-LK--Z7V`EKuuuj|25eb+3O2UFt!efH
ziyR*7){vxA=h3*dT&4HgC1G*MpxD>|2|92MxiqfcDo$R*o=rzD-bN`nu72!II@%VS
z7Ce(Ic<DH+Uhxe9|E$~XQTu@<V&u3b+M6^tgGg2$u{n_e_Cg1S)~b#SN^|jPn6sX=
zx8Sf>a}{V~e6CF`7Y8>3M!AS8cF)pzi=nD7d8XGaqct#|Z3gbmQbTUTfl$U-0iGN)
z7dT{`H!;u0|50P4?y2maYNE9_8z-v)iWv|?u?2O9vK#08L;|+FVfPX{#JQ(iXluNa
z;ETi429JoqSwU`YZh*Ch(<JTIUd=8V#?)5Y0NIYSrgTs+-$0HU1F`Ac<dJBhvLXO9
zc@XG*9o+>jPhe|!uz=l0Yb{k1S9s9avCh@sS<o0qjEuvr+zVtGr!1FBZ_Put5NQEk
zwbzIjtsC049t_~=ey^Vu{v!C9s`w>%o^q#;djGB5ZxlQPPv0p1j|EQ;#V>`w9f9kD
zr*9PhS?+IQe^P&;k9z-J?r&nhtH04lz5h<`AH+@{)czx})2rI=>h{m_zan<}p!RXI
zmfy+!Zp#SJ;{ZJA{j%I24o?q@f71I8<WAS^{aoyH-QLgLovz#axx3SKdp~z~x^D01
za;NL|elB>rZtv&rPS@@I+}-KAy`RgSuG{;$-08Z#p9`LT@;>v)-RZC2XAZg3b$dUT
zJ6*T;bGg%Xdp{RD{q$Yt-Q8*Y&AZH#yVG@hKX-Tfq<0y3!%vX?fA%);>rHq<8UO$Q
z24YJ`L;(K){{a7>y{D4^000SaNLh0L01|Wn01|Wo-ew<o00007bV*G`2jU7A2rnps
zAi?AS001gUL_t(2&tv?5jOjmvupI*fr#=J2_lpb+Zx1mb111InU{t}V0_rLN0BO1g
U?neBJ+yDRo07*qoM6N<$f@EOK;{X5v

literal 0
HcmV?d00001

diff --git a/resources/icons/mode_simple_.png b/resources/icons/mode_simple_.png
new file mode 100644
index 0000000000000000000000000000000000000000..aac2b61b042094981b9e8f37da32662fb48b8c5c
GIT binary patch
literal 1164
zcmV;71atd|P)<h;3K|Lk000e1NJLTq000O8000yS1^@s6up4}9000BydQ@0+Qek%>
zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3vrlEfwqg#YUlIRX+0!EwMqRc?^ur?Hv0vx#Rj
z)Y^=UCAq&gv(*3kbI>37h~q#(EyWz8!zbjBrC^fW@j1@y!hU>?&F?R9;;=3tt@Akh
z<7@0|eL-9wH`rRw^)*hmtvqQZx>a5Y{j4mQtaWK6@^Zv)jZj|qmGIR1`pa!^-tk)W
z{yiAPXo`GZNV;e5aE!BxM+ZLnGGjQ37jbJIyzTLLt{ojRe~NdXy=mvliu+e7$lVgf
zH;q=D^<2AMp%-e8$}bnTbT9Ft-54#6(T}GqAwsE0>!EIsvd^%vLQ22i7BLKein;A0
zV<bG{24W2~E5=5gS)k_Nz>NzJ?)!P;4J`)gVmOOz;`dncCRw%}N|=L(n9sfu7>VCN
z%_A)LUU;vY_j(&ARBnuw!brxG=KG+t;5Xx*XpCuHW|t0~U<>pm)6-~UlAA}Y0uUZc
zQ{DC52R-@5J%RNgsJqMw4_I71QdH%KxBSl8W1YG{hv^+#TL~Z$YAc#y4+1W-SB~sV
z#F(LD0-u7;#RsV%z^c-i2H1EX0Vm0<jeCsuwW4x_v9$n%`iPe#flvXg5ETBgkl>-B
zUIVFWRMVtcOY|{BjWJrBdsH!R!PKIeCCgTlPa$cF$x=!=l`Pp~3)394QBFDMQc$!Y
zb-~>QD@v(SeGOG>tX5OawQR7@7B=1DW?S0wR+=>5@cOsdj9O~BmChYj>Y;0o-FoV|
zmjSO0Kf=%vhmADyD0gbSUfUOH{6_9)YP_gTVqsrr4{8XT-BR$}PINK@F$oOfHVMGc
zGMTx=A;=^*nYk=@DO5m>b;4;piGg6~EIRnk?m_NHZlvK7H~A-WG|~MZ<Y=N><UYBb
zP-|uXMe#eJ`4&!1ogdiP<}I5R8>RWtds8cwV;;SRF>2M3%U0w3fzW{81y@op*u0!Z
zpoyd634F=KwfBr`$w_W);Jq%5@A=GTKAZWpS4$mRT9E`5us+S1TW546KlbCLC0DbG
z>uHLZ@mtH9;DOZv_Uzde;ToE-m(s}m)?4cyJLOS(uHR=*=gM>|4%e<6kM07r`4?&K
z%FvSLJ7J!5p-*A<-u|mJcV*~9nk&LQL7`vB@?seJl`v1b&~?Y08-}hs=G-v!wKQ*r
zp<fB})EoU$n!91>x?|1_L)RU1ZW#Jnm^Z`Fcd~pMhORs2+%R<AG3SP%>y9}$3|)83
zxnbzKW6ljj*Bx_i7`pD5bHmVe$DA96t~=)3Fm&B9=Z2x{jyX3BU3bijVLblP$@DkZ
z+afZyIfuyr000JJOGiWi{{a60|De66lK=n!32;bRa{vGmbN~PnbOGLGA9w%&00(qQ
zO+^Rd3Kj@25=Sf;RsaA1DoI2^R4C75oO43_zpx}T0~;$d!>`|e8Qwns%YY1+7zlt-
e1)~b6s{jD4<_My71_K=c0000<MNUMnLSTY7el2zY

literal 0
HcmV?d00001

diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp
index 8ee78cee6..b2f9cd272 100644
--- a/src/slic3r/GUI/OptionsGroup.cpp
+++ b/src/slic3r/GUI/OptionsGroup.cpp
@@ -388,6 +388,8 @@ void ConfigOptionsGroup::reload_config(){
 }
 
 bool ConfigOptionsGroup::update_visibility(ConfigOptionMode mode) {
+    if (m_options_mode.empty())
+        return true;
     if (m_grid_sizer->GetEffectiveRowsCount() != m_options_mode.size() &&
         m_options_mode.size() == 1)
         return m_options_mode[0] <= mode;
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index bb7aa3e9b..698c46d23 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -483,7 +483,7 @@ void Tab::update_changed_tree_ui()
 		auto title = m_treectrl->GetItemText(cur_item);
 		for (auto page : m_pages)
 		{
-			if (page->title() != title)
+			if (page->title() != title) 
 				continue;
 			bool sys_page = true;
 			bool modified_page = false;
@@ -644,6 +644,11 @@ void Tab::update_visibility(ConfigOptionMode mode)
     Refresh();
 
 	Thaw();
+
+    // to update tree items color
+    wxTheApp->CallAfter([this]() {
+        update_changed_tree_ui();
+    });
 }
 
 Field* Tab::get_field(const t_config_option_key& opt_key, int opt_index/* = -1*/) const
@@ -1782,7 +1787,7 @@ void TabPrinter::build_sla()
     auto page = add_options_page(_(L("General")), "printer_empty.png");
     auto optgroup = page->new_optgroup(_(L("Size and coordinates")));
 
-    Line line{ _(L("Bed shape")), "" };
+    Line line = optgroup->create_single_option_line("bed_shape");//{ _(L("Bed shape")), "" };
     line.widget = [this](wxWindow* parent){
         auto btn = new wxButton(parent, wxID_ANY, _(L(" Set ")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT);
         //			btn->SetFont(Slic3r::GUI::small_font);
@@ -2762,8 +2767,8 @@ ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_la
             bmp_name = "error.png";
         else {
             auto mode = line.get_options()[0].opt.mode;  //we assume that we have one option per line
-            bmp_name = mode == comExpert ? "mode_expert.png" :
-                       mode == comMiddle ? "mode_middle.png" : "mode_simple.png";
+            bmp_name = mode == comExpert ? "mode_expert_.png" :
+                       mode == comMiddle ? "mode_middle_.png" : "mode_simple_.png";
         }                               
         auto bmp = new wxStaticBitmap(parent, wxID_ANY, wxBitmap(from_u8(var(bmp_name)), wxBITMAP_TYPE_PNG));
         return bmp;

From 2a2d1d85f8e1dcc46f2d97d3e2970e49824997c5 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Mon, 22 Oct 2018 13:27:53 +0200
Subject: [PATCH 6/8] Added mirror factors to .3mf import and enabled import
 factors

---
 src/libslic3r/Format/3mf.cpp   | 22 ++++++++++++++++++----
 src/libslic3r/Model.cpp        |  4 ++++
 src/libslic3r/Technologies.hpp |  2 +-
 3 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index bf94db6b1..085f55b9b 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -1249,14 +1249,25 @@ namespace Slic3r {
 
     void _3MF_Importer::_apply_transform(ModelInstance& instance, const Transform3d& transform)
     {
-        // slic3r ModelInstance cannot be transformed using a matrix
-        // we extract from the given matrix only the values currently used
-
         // translation
         Vec3d offset = transform.matrix().block(0, 3, 3, 1);
 
-        // scale
         Eigen::Matrix<double, 3, 3, Eigen::DontAlign> m3x3 = transform.matrix().block(0, 0, 3, 3);
+#if ENABLE_MIRROR
+        // mirror
+        // it is impossible to reconstruct the original mirroring factors from a matrix,
+        // we can only detect if the matrix contains a left handed reference system
+        // in which case we reorient it back to right handed by mirroring the x axis
+        Vec3d mirror = Vec3d::Ones();
+        if (m3x3.col(0).dot(m3x3.col(1).cross(m3x3.col(2))) < 0.0)
+        {
+            mirror(0) = -1.0;
+            // remove mirror
+            m3x3.col(0) *= -1.0;
+        }
+
+        // scale
+#endif // ENABLE_MIRROR
         Vec3d scale(m3x3.col(0).norm(), m3x3.col(1).norm(), m3x3.col(2).norm());
 
         // invalid scale value, return
@@ -1273,6 +1284,9 @@ namespace Slic3r {
         instance.set_offset(offset);
         instance.set_scaling_factor(scale);
         instance.set_rotation(rotation);
+#if ENABLE_MIRROR
+        instance.set_mirror(mirror);
+#endif // ENABLE_MIRROR
     }
 
     bool _3MF_Importer::_handle_start_config(const char** attributes, unsigned int num_attributes)
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index d001acedb..331d11833 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -711,9 +711,13 @@ void ModelObject::center_around_origin()
 
     if (!this->instances.empty()) {
         for (ModelInstance *i : this->instances) {
+#if ENABLE_MIRROR
+            i->set_offset(i->get_offset() - shift);
+#else
             // apply rotation and scaling to vector as well before translating instance,
             // in order to leave final position unaltered
             i->set_offset(i->get_offset() + i->transform_vector(-shift, true));
+#endif // ENABLE_MIRROR
         }
         this->invalidate_bounding_box();
     }
diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp
index 3f8fd80f0..d80d6df0d 100644
--- a/src/libslic3r/Technologies.hpp
+++ b/src/libslic3r/Technologies.hpp
@@ -11,7 +11,7 @@
 // New selections
 #define ENABLE_EXTENDED_SELECTION (1 && ENABLE_1_42_0)
 // Add mirror components along the three axes in ModelInstance and GLVolume
-#define ENABLE_MIRROR (0 && ENABLE_1_42_0)
+#define ENABLE_MIRROR (1 && ENABLE_1_42_0)
 
 #endif // _technologies_h_
 

From 3ecb65d62c5f1509af8889de74fbe84452c26674 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 22 Oct 2018 15:18:05 +0200
Subject: [PATCH 7/8] Fixed mode updating under GTK

---
 src/slic3r/GUI/GUI_ObjectList.hpp | 1 +
 src/slic3r/GUI/OptionsGroup.cpp   | 8 +++++++-
 src/slic3r/GUI/Tab.cpp            | 2 +-
 src/slic3r/GUI/wxExtensions.hpp   | 1 +
 4 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index c56e69670..56d01b7f5 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -4,6 +4,7 @@
 #include <wx/bitmap.h>
 #include <wx/dataview.h>
 #include <map>
+#include <vector>
 
 class wxBoxSizer;
 class PrusaObjectDataViewModel;
diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp
index b2f9cd272..371747bc1 100644
--- a/src/slic3r/GUI/OptionsGroup.cpp
+++ b/src/slic3r/GUI/OptionsGroup.cpp
@@ -395,19 +395,25 @@ bool ConfigOptionsGroup::update_visibility(ConfigOptionMode mode) {
         return m_options_mode[0] <= mode;
 
     sizer->ShowItems(true);
+#ifdef __WXGTK__
+    m_panel->Show(true);
+    m_grid_sizer->Show(true);
+#endif /* __WXGTK__ */
 
     int coef = 0;
+    int hidden_row_cnt = 0;
     const int cols = m_grid_sizer->GetCols();
     for (auto opt_mode : m_options_mode) {
 		const bool show = opt_mode <= mode;
         if (!show) {
+            hidden_row_cnt++;
             for (int i = 0; i < cols; ++i)
                 m_grid_sizer->Show(coef + i, show);
         }
         coef+= cols;
 	}
 
-    if (!sizer->IsShown(m_grid_sizer)) {
+    if (hidden_row_cnt == m_options_mode.size()) {
         sizer->ShowItems(false);
         return false;
     }
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index 698c46d23..d4249ea23 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -476,7 +476,7 @@ void Tab::get_sys_and_mod_flags(const std::string& opt_key, bool& sys_page, bool
 void Tab::update_changed_tree_ui()
 {
 	auto cur_item = m_treectrl->GetFirstVisibleItem();
-    if (!m_treectrl->IsVisible(cur_item))
+    if (!cur_item || !m_treectrl->IsVisible(cur_item))
         return;
 	auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection());
 	while (cur_item){
diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp
index 4ff73027c..80a564fd0 100644
--- a/src/slic3r/GUI/wxExtensions.hpp
+++ b/src/slic3r/GUI/wxExtensions.hpp
@@ -12,6 +12,7 @@
 
 #include <vector>
 #include <set>
+#include <functional>
 
 wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
     std::function<void(wxCommandEvent& event)> cb, const std::string& icon = "", wxEvtHandler* event_handler = nullptr);

From 2f11df47ce28de70a4ae2c8919339356906ec608 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Mon, 22 Oct 2018 15:18:56 +0200
Subject: [PATCH 8/8] Layers editing

---
 src/slic3r/GUI/Plater.cpp | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 8bdc43a37..ecf36595e 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -1365,7 +1365,7 @@ void Plater::priv::selection_changed()
     _3DScene::enable_toolbar_item(canvas3D, "split", have_sel);
     _3DScene::enable_toolbar_item(canvas3D, "cut", have_sel);
     _3DScene::enable_toolbar_item(canvas3D, "settings", have_sel);
-    _3DScene::enable_toolbar_item(canvas3D, "layersediting", layers_height_allowed);
+    _3DScene::enable_toolbar_item(canvas3D, "layersediting", have_sel && config->opt_bool("variable_layer_height") && _3DScene::is_layers_editing_allowed(canvas3D));
 #endif // ENABLE_EXTENDED_SELECTION
 
 #if ENABLE_EXTENDED_SELECTION
@@ -1477,6 +1477,9 @@ void Plater::priv::remove(size_t obj_idx)
     // Prevent toolpaths preview from rendering while we modify the Print object
     preview->set_enabled(false);
 
+    if (_3DScene::is_layers_editing_enabled(canvas3D))
+        _3DScene::enable_layers_editing(canvas3D, false);
+
 #if !ENABLE_EXTENDED_SELECTION
     objects.erase(objects.begin() + obj_idx);
 #endif // !ENABLE_EXTENDED_SELECTION
@@ -1500,6 +1503,9 @@ void Plater::priv::reset()
     // Prevent toolpaths preview from rendering while we modify the Print object
     preview->set_enabled(false);
 
+    if (_3DScene::is_layers_editing_enabled(canvas3D))
+        _3DScene::enable_layers_editing(canvas3D, false);
+
 #if !ENABLE_EXTENDED_SELECTION
     objects.clear();
 #endif // !ENABLE_EXTENDED_SELECTION
@@ -1777,7 +1783,10 @@ void Plater::priv::on_action_settings(SimpleEvent&)
 
 void Plater::priv::on_action_layersediting(SimpleEvent&)
 {
-    // TODO
+    bool enable = !_3DScene::is_layers_editing_enabled(canvas3D);
+    _3DScene::enable_layers_editing(canvas3D, enable);
+    if (enable && !_3DScene::is_layers_editing_enabled(canvas3D))
+        _3DScene::enable_toolbar_item(canvas3D, "layersediting", false);
 }
 
 #if !ENABLE_EXTENDED_SELECTION
@@ -1970,7 +1979,8 @@ bool Plater::priv::can_cut_object() const
 
 bool Plater::priv::layers_height_allowed() const
 {
-    return config->opt_bool("variable_layer_height") && _3DScene::is_layers_editing_allowed(canvas3D);
+    int obj_idx = get_selected_object_idx();
+    return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && config->opt_bool("variable_layer_height") && _3DScene::is_layers_editing_allowed(canvas3D);
 }
 
 bool Plater::priv::can_delete_all() const