From 2c6e4b4e5bab8ff9f41a41e0c4ef7a4bcfdd4a68 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Tue, 23 Jul 2019 09:40:07 +0200
Subject: [PATCH 01/11] Fixed a missing include in UndoRedo.cpp

---
 src/slic3r/Utils/UndoRedo.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/slic3r/Utils/UndoRedo.cpp b/src/slic3r/Utils/UndoRedo.cpp
index 72e7431bd..eba839ffb 100644
--- a/src/slic3r/Utils/UndoRedo.cpp
+++ b/src/slic3r/Utils/UndoRedo.cpp
@@ -17,6 +17,7 @@
 #define CEREAL_FUTURE_EXPERIMENTAL
 #include <cereal/archives/adapters.hpp>
 
+#include <libslic3r/Config.hpp>
 #include <libslic3r/ObjectID.hpp>
 #include <libslic3r/Utils.hpp>
 

From 3fe355509ce2dd4d9e99cbc6b977bee6ceba4699 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Tue, 23 Jul 2019 12:57:58 +0200
Subject: [PATCH 02/11] Fixed undo/redo snapshot when opening a project using
 the recent files list

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

diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 9e818adfa..b98faaa3c 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -3904,8 +3904,6 @@ void Plater::load_project()
     // Ask user for a project file name.
     wxString input_file;
     wxGetApp().load_project(this, input_file);
-    // Take the Undo / Redo snapshot.
-	Plater::TakeSnapshot snapshot(this, _(L("Load Project")) + ": " + wxString::FromUTF8(into_path(input_file).stem().string().c_str()));
     // And finally load the new project.
     load_project(input_file);
 }
@@ -3915,6 +3913,9 @@ void Plater::load_project(const wxString& filename)
     if (filename.empty())
         return;
 
+    // Take the Undo / Redo snapshot.
+    Plater::TakeSnapshot snapshot(this, _(L("Load Project")) + ": " + wxString::FromUTF8(into_path(filename).stem().string().c_str()));
+
     p->reset();
     p->set_project_filename(filename);
 

From 506be9035b9467127de2dec88579209cb250e403 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Tue, 23 Jul 2019 13:58:07 +0200
Subject: [PATCH 03/11] Wipe tower now supports filaments with diameters
 different from 1.75 mm

---
 src/libslic3r/GCode/WipeTower.cpp |  4 ++--
 src/libslic3r/GCode/WipeTower.hpp | 16 +++++++++++-----
 src/libslic3r/Print.cpp           | 10 +++++++++-
 3 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp
index 354ec6d9e..55a6c4437 100644
--- a/src/libslic3r/GCode/WipeTower.cpp
+++ b/src/libslic3r/GCode/WipeTower.cpp
@@ -157,7 +157,7 @@ public:
             change_analyzer_mm3_per_mm(len, e);
 			// Width of a squished extrusion, corrected for the roundings of the squished extrusions.
 			// This is left zero if it is a travel move.
-			float width = float(double(e) * /*Filament_Area*/2.40528 / (len * m_layer_height));
+			float width = float(double(e) * m_filpar[0].filament_area / (len * m_layer_height));
 			// Correct for the roundings of a squished extrusion.
 			width += m_layer_height * float(1. - M_PI / 4.);
 			if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos)
@@ -822,7 +822,7 @@ void WipeTower::toolchange_Unload(
     while (i < m_filpar[m_current_tool].ramming_speed.size())
     {
         const float x = volume_to_length(m_filpar[m_current_tool].ramming_speed[i] * 0.25f, line_width, m_layer_height);
-        const float e = m_filpar[m_current_tool].ramming_speed[i] * 0.25f / Filament_Area; // transform volume per sec to E move;
+        const float e = m_filpar[m_current_tool].ramming_speed[i] * 0.25f / filament_area(); // transform volume per sec to E move;
         const float dist = std::min(x - e_done, remaining);		  // distance to travel for either the next 0.25s, or to the next turnaround
         const float actual_time = dist/x * 0.25;
         writer.ram(writer.x(), writer.x() + (m_left_to_right ? 1.f : -1.f) * dist, 0, 0, e * (dist / x), dist / (actual_time / 60.));
diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp
index badb3e8b2..6dfad1b8c 100644
--- a/src/libslic3r/GCode/WipeTower.hpp
+++ b/src/libslic3r/GCode/WipeTower.hpp
@@ -111,7 +111,8 @@ public:
 	// Set the extruder properties.
 	void set_extruder(size_t idx, std::string material, int temp, int first_layer_temp, float loading_speed, float loading_speed_start,
                       float unloading_speed, float unloading_speed_start, float delay, int cooling_moves,
-                      float cooling_initial_speed, float cooling_final_speed, std::string ramming_parameters, float max_volumetric_speed, float nozzle_diameter)
+                      float cooling_initial_speed, float cooling_final_speed, std::string ramming_parameters, float max_volumetric_speed,
+                      float nozzle_diameter, float filament_diameter)
 	{
         //while (m_filpar.size() < idx+1)   // makes sure the required element is in the vector
         m_filpar.push_back(FilamentParameters());
@@ -133,10 +134,12 @@ public:
             m_filpar[idx].cooling_final_speed     = cooling_final_speed;
         }
 
-        if (max_volumetric_speed != 0.f)
-            m_filpar[idx].max_e_speed = (max_volumetric_speed / Filament_Area);
+        m_filpar[idx].filament_area = (M_PI/4.f) * pow(filament_diameter, 2); // all extruders are assumed to have the same filament diameter at this point
         m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
 
+        if (max_volumetric_speed != 0.f)
+            m_filpar[idx].max_e_speed = (max_volumetric_speed / filament_area());
+
         m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter
 
         if (m_semm) {
@@ -248,6 +251,7 @@ public:
         float               max_e_speed = std::numeric_limits<float>::max();
         std::vector<float>  ramming_speed;
         float               nozzle_diameter;
+        float               filament_area;
     };
 
 private:
@@ -261,9 +265,11 @@ private:
 
 
     const bool  m_peters_wipe_tower   = false; // sparse wipe tower inspired by Peter's post processor - not finished yet
-    const float Filament_Area         = float(M_PI * 1.75f * 1.75f / 4.f); // filament area in mm^2
     const float Width_To_Nozzle_Ratio = 1.25f; // desired line width (oval) in multiples of nozzle diameter - may not be actually neccessary to adjust
     const float WT_EPSILON            = 1e-3f;
+    const float filament_area() const {
+        return m_filpar[0].filament_area; // all extruders are assumed to have the same filament diameter at this point
+    }
 
 
 	bool   m_semm               = true; // Are we using a single extruder multimaterial printer?
@@ -315,7 +321,7 @@ private:
 	{
 		if ( layer_height < 0 )
 			return m_extrusion_flow;
-		return layer_height * ( m_perimeter_width - layer_height * (1.f-float(M_PI)/4.f)) / Filament_Area;
+		return layer_height * ( m_perimeter_width - layer_height * (1.f-float(M_PI)/4.f)) / filament_area();
 	}
 
 	// Calculates length of extrusion line to extrude given volume
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index a9b8a827f..5702f49e3 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -1092,6 +1092,13 @@ std::string Print::validate() const
     }
 
     if (this->has_wipe_tower() && ! m_objects.empty()) {
+        // make sure all extruders use same diameter filament and have the same nozzle diameter
+        for (const auto& extruder_idx : extruders()) {
+            if (m_config.nozzle_diameter.get_at(extruder_idx) != m_config.nozzle_diameter.get_at(extruders().front())
+             || m_config.filament_diameter.get_at(extruder_idx) != m_config.filament_diameter.get_at(extruders().front()))
+                 return L("The wipe tower is only supported if all extruders have the same nozzle diameter and use filaments of the same diameter.");
+        }
+
         if (m_config.gcode_flavor != gcfRepRap && m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlin)
             return L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter and Repetier G-code flavors.");
         if (! m_config.use_relative_e_distances)
@@ -1701,7 +1708,8 @@ void Print::_make_wipe_tower()
 			(float)m_config.filament_cooling_final_speed.get_at(i),
             m_config.filament_ramming_parameters.get_at(i),
             m_config.filament_max_volumetric_speed.get_at(i),
-            m_config.nozzle_diameter.get_at(i));
+            m_config.nozzle_diameter.get_at(i),
+            m_config.filament_diameter.get_at(i));
 
     m_wipe_tower_data.priming = Slic3r::make_unique<std::vector<WipeTower::ToolChangeResult>>(
         wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false));

From 91a5d70a627aec290860971c338d638e60ce595e Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Tue, 23 Jul 2019 11:22:54 +0200
Subject: [PATCH 04/11] Fixed a few warnings in headers (meaning they were
 reported once for each include) Fixed an identification of CXX compiler in
 cmake so that 'AppleClang' is recognized

---
 CMakeLists.txt                            | 4 ++--
 src/libslic3r/Utils.hpp                   | 2 +-
 src/slic3r/GUI/Gizmos/GLGizmoBase.cpp     | 4 ++--
 src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp   | 6 +++---
 src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +-
 src/slic3r/GUI/wxExtensions.hpp           | 6 +++---
 6 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index f60c8bde6..6f2332ce0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -162,7 +162,7 @@ if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX)
     endif ()
 endif()
 
-if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
     add_compile_options(-Wall)
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder" )
 
@@ -170,7 +170,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STRE
     add_compile_options(-Werror=return-type)
 
     #removes LOTS of extraneous Eigen warnings (GCC only supports it since 6.1)
-    #if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 6.1)
+    #if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 6.1)
         # add_compile_options(-Wno-ignored-attributes) # Tamas: Eigen include dirs are marked as SYSTEM
     #endif()
 
diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp
index 09e24a475..8a4f1424b 100644
--- a/src/libslic3r/Utils.hpp
+++ b/src/libslic3r/Utils.hpp
@@ -172,7 +172,7 @@ extern std::string xml_escape(std::string text);
 #if defined __GNUC__ && __GNUC__ < 5 && !defined __clang__
 // Older GCCs don't have std::is_trivially_copyable
 // cf. https://gcc.gnu.org/onlinedocs/gcc-4.9.4/libstdc++/manual/manual/status.html#status.iso.2011
-#warning "GCC version < 5, faking std::is_trivially_copyable"
+// #warning "GCC version < 5, faking std::is_trivially_copyable"
 template<typename T> struct IsTriviallyCopyable { static constexpr bool value = true; };
 #else
 template<typename T> struct IsTriviallyCopyable : public std::is_trivially_copyable<T> {};
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp
index 4b975e87e..a65074646 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp
@@ -166,7 +166,7 @@ void GLGizmoBase::set_highlight_color(const float* color)
 
 void GLGizmoBase::enable_grabber(unsigned int id)
 {
-    if ((0 <= id) && (id < (unsigned int)m_grabbers.size()))
+    if (id < m_grabbers.size())
         m_grabbers[id].enabled = true;
 
     on_enable_grabber(id);
@@ -174,7 +174,7 @@ void GLGizmoBase::enable_grabber(unsigned int id)
 
 void GLGizmoBase::disable_grabber(unsigned int id)
 {
-    if ((0 <= id) && (id < (unsigned int)m_grabbers.size()))
+    if (id < m_grabbers.size())
         m_grabbers[id].enabled = false;
 
     on_disable_grabber(id);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp
index 7846edb22..8733c9a11 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp
@@ -93,19 +93,19 @@ protected:
     }
     virtual void on_set_hover_id()
     {
-        for (unsigned int i = 0; i < 3; ++i)
+        for (int i = 0; i < 3; ++i)
         {
             m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1);
         }
     }
     virtual void on_enable_grabber(unsigned int id)
     {
-        if ((0 <= id) && (id < 3))
+        if (id < 3)
             m_gizmos[id].enable_grabber(0);
     }
     virtual void on_disable_grabber(unsigned int id)
     {
-        if ((0 <= id) && (id < 3))
+        if (id < 3)
             m_gizmos[id].disable_grabber(0);
     }
     virtual void on_start_dragging();
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
index 2aaf55424..d96b806e5 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
@@ -223,7 +223,7 @@ void GLGizmosManager::update_data()
     enable_grabber(Rotate, 1, !is_wipe_tower);
 
     bool enable_scale_xyz = selection.is_single_full_instance() || selection.is_single_volume() || selection.is_single_modifier();
-    for (int i = 0; i < 6; ++i)
+    for (unsigned int i = 0; i < 6; ++i)
     {
         enable_grabber(Scale, i, enable_scale_xyz);
     }
diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp
index 9a6460dcb..a704f79d7 100644
--- a/src/slic3r/GUI/wxExtensions.hpp
+++ b/src/slic3r/GUI/wxExtensions.hpp
@@ -323,9 +323,9 @@ public:
 	}
 
 	bool SwapChildrens(int frst_id, int scnd_id) {
-		if (GetChildCount() < 2 || 
-			frst_id < 0 || frst_id >= GetChildCount() || 
-			scnd_id < 0 || scnd_id >= GetChildCount())
+		if (GetChildCount() < 2 ||
+			frst_id < 0 || (size_t)frst_id >= GetChildCount() ||
+			scnd_id < 0 || (size_t)scnd_id >= GetChildCount())
 			return false;
 
 		ObjectDataViewModelNode new_scnd = *GetNthChild(frst_id);

From 0a5f8aa2e8e57939451cdb8508141bfb856dd68b Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Tue, 23 Jul 2019 15:13:47 +0200
Subject: [PATCH 05/11] An attempt to silence the Wreorder warning on OSX build
 server Clang apparently cares about order of command line arguments, so -Wall
 should come before -Wno-whatever

---
 CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6f2332ce0..ba291e450 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -163,7 +163,7 @@ if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX)
 endif()
 
 if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
-    add_compile_options(-Wall)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall" )
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder" )
 
     # On GCC and Clang, no return from a non-void function is a warning only. Here, we make it an error.

From 0ae46b06358ef878f98a840b6ffe3266304d2e17 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Mon, 22 Jul 2019 13:25:17 +0200
Subject: [PATCH 06/11] SLA gizmo and undo/redo: 'autogenerated points' state
 is now correctly undone/redone

---
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 40 ++++++++++++++------
 src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp |  2 +
 2 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index 8027906a9..6875a5b88 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -82,7 +82,9 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S
             editing_mode_reload_cache();
         }
 
-        if (m_editing_mode_cache.empty() && m_model_object->sla_points_status != sla::PointsStatus::UserModified)
+        if (m_editing_mode_cache.empty()
+         && m_model_object->sla_points_status != sla::PointsStatus::UserModified
+         && m_model_object->sla_points_status != sla::PointsStatus::None)
             get_data_from_backend();
 
         if (m_state == On) {
@@ -1122,9 +1124,13 @@ void GLGizmoSlaSupports::on_start_dragging()
 
 void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar)
 {
+    if (m_editing_mode)
+        editing_mode_discard_changes();
+
     ar(m_clipping_plane_distance,
        m_clipping_plane_normal,
-       m_current_mesh_object_id
+       m_current_mesh_object_id,
+       m_editing_mode_cache
     );
 }
 
@@ -1134,7 +1140,8 @@ void GLGizmoSlaSupports::on_save(cereal::BinaryOutputArchive& ar) const
 {
     ar(m_clipping_plane_distance,
        m_clipping_plane_normal,
-       m_current_mesh_object_id
+       m_current_mesh_object_id,
+       m_editing_mode_cache
     );
 }
 
@@ -1177,16 +1184,16 @@ void GLGizmoSlaSupports::editing_mode_discard_changes()
     // If the points were autogenerated, they may not be on the ModelObject yet.
     // Because the user probably messed with the cache, we will get the data
     // from the backend again.
-
-    if (m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated)
+    /*if (m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated) {
         get_data_from_backend();
-    else {
-        m_editing_mode_cache.clear();
-        for (const sla::SupportPoint& point : m_model_object->sla_support_points)
-            m_editing_mode_cache.emplace_back(point, false);
-    }
-        m_editing_mode = false;
-        m_unsaved_changes = false;
+        }
+    else
+        editing_mode_reload_cache();*/
+
+    m_editing_mode_cache = m_old_cache;
+
+    m_editing_mode = false;
+    m_unsaved_changes = false;
 }
 
 
@@ -1196,7 +1203,13 @@ void GLGizmoSlaSupports::editing_mode_apply_changes()
     // If there are no changes, don't touch the front-end. The data in the cache could have been
     // taken from the backend and copying them to ModelObject would needlessly invalidate them.
     if (m_unsaved_changes) {
+        // In order to make the undo/redo snapshot, we must first temporarily restore
+        // the editing cache to the state before the edits were made.
+        std::vector<CacheEntry> backup = m_editing_mode_cache;
+        m_editing_mode_cache = m_old_cache;
         wxGetApp().plater()->take_snapshot(_(L("Support points edit")));
+        m_editing_mode_cache = std::move(backup);
+
         m_model_object->sla_points_status = sla::PointsStatus::UserModified;
         m_model_object->sla_support_points.clear();
         for (const CacheEntry& cache_entry : m_editing_mode_cache)
@@ -1216,6 +1229,7 @@ void GLGizmoSlaSupports::editing_mode_apply_changes()
 void GLGizmoSlaSupports::editing_mode_reload_cache()
 {
     m_editing_mode_cache.clear();
+
     for (const sla::SupportPoint& point : m_model_object->sla_support_points)
         m_editing_mode_cache.emplace_back(point, false);
 
@@ -1271,6 +1285,8 @@ void GLGizmoSlaSupports::switch_to_editing_mode()
         editing_mode_reload_cache();
     m_unsaved_changes = false;
     m_editing_mode = true;
+    m_old_cache = m_editing_mode_cache;
+    select_point(NoPoints);
 }
 
 
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
index fbc438f1d..5ef1e6aea 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
@@ -98,6 +98,8 @@ private:
     float m_new_point_head_diameter;        // Size of a new point.
     float m_minimal_point_distance = 20.f;
     mutable std::vector<CacheEntry> m_editing_mode_cache; // a support point and whether it is currently selected
+    std::vector<CacheEntry> m_old_cache; // to restore after discarding changes or undo/redo
+
     float m_clipping_plane_distance = 0.f;
     mutable float m_old_clipping_plane_distance = 0.f;
     mutable Vec3d m_old_clipping_plane_normal;

From 7bc893d99a56efdaab2fa8cfed1cc46b136a6e57 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 23 Jul 2019 16:12:29 +0200
Subject: [PATCH 07/11] Update all extriders nozzle diameters according to the
 single_extruder_multi_material flag

---
 src/slic3r/GUI/Tab.cpp | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index b52f9dd46..cb8bb0b6d 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -1892,8 +1892,35 @@ void TabPrinter::build_fff()
 					extruders_count_changed(extruders_count);
                     init_options_list(); // m_options_list should be updated before UI updating
 					update_dirty();
-                    if (opt_key == "single_extruder_multi_material") // the single_extruder_multimaterial was added to force pages
+                    if (opt_key == "single_extruder_multi_material") { // the single_extruder_multimaterial was added to force pages
                         on_value_change(opt_key, value);                      // rebuild - let's make sure the on_value_change is not skipped
+
+                        if (boost::any_cast<bool>(value) && m_extruders_count > 1) {
+                            SuppressBackgroundProcessingUpdate sbpu;
+                            std::vector<double> nozzle_diameters = static_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values;
+                            const double frst_diam = nozzle_diameters[0];
+
+                            for (auto cur_diam : nozzle_diameters) {
+                                // if value is differs from first nozzle diameter value
+                                if (fabs(cur_diam - frst_diam) > EPSILON) {
+                                    const wxString msg_text = _(L("Single Extruder Multi Material is selected, \n"
+                                                                  "and all extruders must have the same diameter.\n"
+                                                                  "Do you want to change the diameter for all extruders to first extruder nozzle diameter value?"));
+                                    auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Nozzle diameter")), wxICON_WARNING | wxYES_NO);
+                                    
+                                    if (dialog->ShowModal() == wxID_YES) {
+                                        DynamicPrintConfig new_conf = *m_config;
+                                        for (size_t i = 1; i < nozzle_diameters.size(); i++)
+                                            nozzle_diameters[i] = frst_diam;
+
+                                        new_conf.set_key_value("nozzle_diameter", new ConfigOptionFloats(nozzle_diameters));
+                                        load_config(new_conf);
+                                    }
+                                    break;
+                                }
+                            } 
+                        }
+                    }
 				}
 				else {
 					update_dirty();
@@ -2318,7 +2345,7 @@ void TabPrinter::build_unregular_pages()
 
             optgroup->m_on_change = [this, extruder_idx](const t_config_option_key& opt_key, boost::any value)
             {
-                if (m_extruders_count > 1 && opt_key.find_first_of("nozzle_diameter") != std::string::npos)
+                if (m_config->opt_bool("single_extruder_multi_material") && m_extruders_count > 1 && opt_key.find_first_of("nozzle_diameter") != std::string::npos)
                 {
                     SuppressBackgroundProcessingUpdate sbpu;
                     const double new_nd = boost::any_cast<double>(value);

From 4245b61afc5ce4edf746efa96e317b1efc6c47eb Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 23 Jul 2019 16:17:37 +0200
Subject: [PATCH 08/11] Added SETTINGS_SELECTED_ON_SIDEBAR flag to undo/redo

---
 src/slic3r/GUI/GUI_ObjectList.cpp | 35 ++++++++++++++++++++++++-------
 src/slic3r/GUI/GUI_ObjectList.hpp |  6 +++++-
 src/slic3r/GUI/Plater.cpp         |  8 +++++++
 src/slic3r/Utils/UndoRedo.hpp     |  1 +
 4 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index a2ddba376..cc7c6c888 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -2638,7 +2638,8 @@ void ObjectList::update_selections()
     const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
     wxDataViewItemArray sels;
 
-    m_selection_mode = smInstance;
+    if (m_selection_mode & smSettings == 0)
+        m_selection_mode = smInstance;
 
     // We doesn't update selection if SettingsItem for the current object/part is selected
 //     if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings )
@@ -2664,6 +2665,12 @@ void ObjectList::update_selections()
     else if (selection.is_single_full_object() || selection.is_multiple_full_object())
     {
         const Selection::ObjectIdxsToInstanceIdxsMap& objects_content = selection.get_content();
+        if (m_selection_mode & smSettings)
+        {
+            wxDataViewItem obj_item = m_objects_model->GetItemById(objects_content.begin()->first);
+            sels.Add(m_objects_model->GetSettingsItem(obj_item));
+        }
+        else {
         for (const auto& object : objects_content) {
             if (object.second.size() == 1)          // object with 1 instance                
                 sels.Add(m_objects_model->GetItemById(object.first));
@@ -2688,10 +2695,23 @@ void ObjectList::update_selections()
                 for (const auto& inst : instances)
                     sels.Add(m_objects_model->GetItemByInstanceId(object.first, inst));
             }
-        }
+        } }
     }
     else if (selection.is_any_volume() || selection.is_any_modifier())
     {
+        if (m_selection_mode & smSettings)
+        {
+            const auto idx = *selection.get_volume_idxs().begin();
+            const auto gl_vol = selection.get_volume(idx);
+            if (gl_vol->volume_idx() >= 0) {
+                // Only add GLVolumes with non-negative volume_ids. GLVolumes with negative volume ids
+                // are not associated with ModelVolumes, but they are temporarily generated by the backend
+                // (for example, SLA supports or SLA pad).
+                wxDataViewItem vol_item = m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx());
+                sels.Add(m_objects_model->GetSettingsItem(vol_item));
+            }
+        }
+        else {
         for (auto idx : selection.get_volume_idxs()) {
             const auto gl_vol = selection.get_volume(idx);
 			if (gl_vol->volume_idx() >= 0)
@@ -2700,7 +2720,7 @@ void ObjectList::update_selections()
                 // (for example, SLA supports or SLA pad).
                 sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx()));
         }
-        m_selection_mode = smVolume;
+        m_selection_mode = smVolume; }
     }
     else if (selection.is_single_full_instance() || selection.is_multiple_full_instance())
     {
@@ -2744,7 +2764,7 @@ void ObjectList::update_selections()
         }
     }
 
-    if (sels.size() == 0)
+    if (sels.size() == 0 || m_selection_mode & smSettings)
         m_selection_mode = smUndef;
     
     select_items(sels);
@@ -3522,15 +3542,16 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const
 
 void ObjectList::update_after_undo_redo()
 {
-    m_prevent_list_events = true;
     m_prevent_canvas_selection_update = true;
 
     Plater::SuppressSnapshots suppress(wxGetApp().plater());
 
     // Unselect all objects before deleting them, so that no change of selection is emitted during deletion.
-    this->UnselectAll();
+    unselect_objects();//this->UnselectAll();
     m_objects_model->DeleteAll();
 
+//    m_prevent_list_events = true;
+
     size_t obj_idx = 0;
     while (obj_idx < m_objects->size()) {
         add_object_to_list(obj_idx, false);
@@ -3544,7 +3565,7 @@ void ObjectList::update_after_undo_redo()
     update_selections();
 
     m_prevent_canvas_selection_update = false;
-    m_prevent_list_events = false;
+//    m_prevent_list_events = false;
 }
 
 ModelObject* ObjectList::object(const int obj_idx) const
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 5f5d5d625..c3fb5ba80 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -66,14 +66,17 @@ struct ItemForDelete
 
 class ObjectList : public wxDataViewCtrl
 {
+public:
     enum SELECTION_MODE
     {
         smUndef     = 0,
         smVolume    = 1,
         smInstance  = 2,
-        smLayer     = 4
+        smLayer     = 4,
+        smSettings  = 8, // used for undo/redo
     } m_selection_mode {smUndef};
 
+private:
     struct dragged_item_data
     {
         void init(const int obj_idx, const int subobj_idx, const ItemType type) {
@@ -302,6 +305,7 @@ public:
     void init_objects();
     bool multiple_selection() const ;
     bool is_selected(const ItemType type) const;
+    void set_selection_mode(SELECTION_MODE mode) { m_selection_mode = mode; }
     void update_selections();
     void update_selections_on_canvas();
     void select_item(const wxDataViewItem& item);
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 9e818adfa..f615e4958 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -3729,6 +3729,8 @@ void Plater::priv::take_snapshot(const std::string& snapshot_name)
     snapshot_data.printer_technology = this->printer_technology;
     if (this->view3D->is_layers_editing_enabled())
     	snapshot_data.flags |= UndoRedo::SnapshotData::VARIABLE_LAYER_EDITING_ACTIVE;
+    if (this->sidebar->obj_list()->is_selected(itSettings))
+        snapshot_data.flags |= UndoRedo::SnapshotData::SETTINGS_SELECTED_ON_SIDEBAR;
     //FIXME updating the Wipe tower config values at the ModelWipeTower from the Print config.
     // This is a workaround until we refactor the Wipe Tower position / orientation to live solely inside the Model, not in the Print config.
     if (this->printer_technology == ptFFF) {
@@ -3795,7 +3797,10 @@ void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator
     top_snapshot_data.printer_technology = this->printer_technology;
     if (this->view3D->is_layers_editing_enabled())
     	top_snapshot_data.flags |= UndoRedo::SnapshotData::VARIABLE_LAYER_EDITING_ACTIVE;
+    if (this->sidebar->obj_list()->is_selected(itSettings))
+    	top_snapshot_data.flags |= UndoRedo::SnapshotData::SETTINGS_SELECTED_ON_SIDEBAR;
 	bool   		 new_variable_layer_editing_active = (new_flags & UndoRedo::SnapshotData::VARIABLE_LAYER_EDITING_ACTIVE) != 0;
+    bool         new_settings_selected_on_sidebar  = (new_flags & UndoRedo::SnapshotData::SETTINGS_SELECTED_ON_SIDEBAR) != 0;
 	// Disable layer editing before the Undo / Redo jump.
     if (!new_variable_layer_editing_active && view3D->is_layers_editing_enabled())
         view3D->get_canvas3d()->force_main_toolbar_left_action(view3D->get_canvas3d()->get_main_toolbar_item_id("layersediting"));
@@ -3828,6 +3833,9 @@ void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator
                 tab_print->update_dirty();
             }
         }
+        // set settings mode for ObjectList on sidebar
+        if (new_settings_selected_on_sidebar)
+            this->sidebar->obj_list()->set_selection_mode(ObjectList::SELECTION_MODE::smSettings);
         this->update_after_undo_redo(temp_snapshot_was_taken);
 		// Enable layer editing after the Undo / Redo jump.
 		if (! view3D->is_layers_editing_enabled() && this->layers_height_allowed() && new_variable_layer_editing_active)
diff --git a/src/slic3r/Utils/UndoRedo.hpp b/src/slic3r/Utils/UndoRedo.hpp
index c17802560..a3a130efd 100644
--- a/src/slic3r/Utils/UndoRedo.hpp
+++ b/src/slic3r/Utils/UndoRedo.hpp
@@ -38,6 +38,7 @@ struct SnapshotData
 	// Bitmask of various binary flags to be stored with the snapshot.
 	enum Flags {
 		VARIABLE_LAYER_EDITING_ACTIVE = 1,
+		SETTINGS_SELECTED_ON_SIDEBAR  = 2,
 	};
 };
 

From 804e1b19397b5a1d05e4aa99171911277b649c8f Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 23 Jul 2019 17:09:19 +0200
Subject: [PATCH 09/11] Fixed ObjectList::last_volume_is_deleted() to avoid
 clearing volume[0].config after undo/redo

---
 src/slic3r/GUI/GUI_ObjectList.cpp | 4 ++--
 src/slic3r/GUI/wxExtensions.cpp   | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index cc7c6c888..047b7e8ed 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1741,7 +1741,7 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
     ItemType type;
 
     m_objects_model->GetItemInfo(item, type, obj_idx, idx);
-    if (type & itUndef)
+    if (type == itUndef)
         return;
 
     if (type & itSettings)
@@ -3101,7 +3101,7 @@ void ObjectList::change_part_type()
 void ObjectList::last_volume_is_deleted(const int obj_idx)
 {
 
-    if (obj_idx < 0 || obj_idx >= m_objects->size() || (*m_objects)[obj_idx]->volumes.empty())
+    if (obj_idx < 0 || obj_idx >= m_objects->size() || (*m_objects)[obj_idx]->volumes.size() != 1)
         return;
 
     auto volume = (*m_objects)[obj_idx]->volumes.front();
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index 6300ada31..3fc404864 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -1508,7 +1508,7 @@ ItemType ObjectDataViewModel::GetItemType(const wxDataViewItem &item) const
     if (!item.IsOk())
         return itUndef;
     ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
-    return node->m_type;
+    return node->m_type < 0 ? itUndef : node->m_type;
 }
 
 wxDataViewItem ObjectDataViewModel::GetItemByType(const wxDataViewItem &parent_item, ItemType type) const 

From 0592ae65eeff51038aac647c68b009b1314c765c Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 23 Jul 2019 18:17:57 +0200
Subject: [PATCH 10/11] Completed setting of the item focus in ObjectList after
 undo/redo

---
 src/slic3r/GUI/GUI_ObjectList.cpp | 40 ++++++++++++++++++++++++------
 src/slic3r/GUI/GUI_ObjectList.hpp | 10 ++++++--
 src/slic3r/GUI/Plater.cpp         | 41 +++++++++++++++++++++++++------
 src/slic3r/Utils/UndoRedo.cpp     |  2 +-
 src/slic3r/Utils/UndoRedo.hpp     |  9 ++++++-
 5 files changed, 82 insertions(+), 20 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 047b7e8ed..14c6db654 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -2633,12 +2633,28 @@ bool ObjectList::is_selected(const ItemType type) const
     return false;
 }
 
+t_layer_height_range ObjectList::get_selected_layers_range() const
+{
+    t_layer_height_range layer_range = { 0.0, 0.0 };
+    const wxDataViewItem& item = GetSelection();
+    if (!item) 
+        return layer_range;
+
+    const ItemType type = m_objects_model->GetItemType(item);
+    if (type & itSettings && m_objects_model->GetItemType(m_objects_model->GetParent(item)) != itLayer)
+        return layer_range;
+
+    return  type & itLayer ? m_objects_model->GetLayerRangeByItem(item) :
+            type & itSettings ? m_objects_model->GetLayerRangeByItem(m_objects_model->GetParent(item)) :
+            layer_range;
+}
+
 void ObjectList::update_selections()
 {
     const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
     wxDataViewItemArray sels;
 
-    if (m_selection_mode & smSettings == 0)
+    if ( ( m_selection_mode & (smSettings|smLayer|smLayerRoot) ) == 0)
         m_selection_mode = smInstance;
 
     // We doesn't update selection if SettingsItem for the current object/part is selected
@@ -2665,10 +2681,21 @@ void ObjectList::update_selections()
     else if (selection.is_single_full_object() || selection.is_multiple_full_object())
     {
         const Selection::ObjectIdxsToInstanceIdxsMap& objects_content = selection.get_content();
-        if (m_selection_mode & smSettings)
+        if (m_selection_mode & (smSettings | smLayer | smLayerRoot))
         {
-            wxDataViewItem obj_item = m_objects_model->GetItemById(objects_content.begin()->first);
-            sels.Add(m_objects_model->GetSettingsItem(obj_item));
+            auto obj_idx = objects_content.begin()->first;
+            wxDataViewItem obj_item = m_objects_model->GetItemById(obj_idx);
+            if (m_selection_mode & smSettings)
+            {
+                if (m_selected_layers_range.first <= EPSILON && m_selected_layers_range.second <= EPSILON)
+                    sels.Add(m_objects_model->GetSettingsItem(obj_item));
+                else
+                    sels.Add(m_objects_model->GetSettingsItem(m_objects_model->GetItemByLayerRange(obj_idx, m_selected_layers_range)));
+            }
+            else if (m_selection_mode & smLayerRoot)
+                sels.Add(m_objects_model->GetLayerRootItem(obj_item));
+            else if (m_selection_mode & smLayer)
+                sels.Add(m_objects_model->GetItemByLayerRange(obj_idx, m_selected_layers_range));
         }
         else {
         for (const auto& object : objects_content) {
@@ -3550,8 +3577,6 @@ void ObjectList::update_after_undo_redo()
     unselect_objects();//this->UnselectAll();
     m_objects_model->DeleteAll();
 
-//    m_prevent_list_events = true;
-
     size_t obj_idx = 0;
     while (obj_idx < m_objects->size()) {
         add_object_to_list(obj_idx, false);
@@ -3559,13 +3584,12 @@ void ObjectList::update_after_undo_redo()
     }
 
 #ifndef __WXOSX__ 
-    selection_changed();
+//    selection_changed();
 #endif /* __WXOSX__ */
 
     update_selections();
 
     m_prevent_canvas_selection_update = false;
-//    m_prevent_list_events = false;
 }
 
 ModelObject* ObjectList::object(const int obj_idx) const
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index c3fb5ba80..1c30a4d97 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -73,10 +73,14 @@ public:
         smVolume    = 1,
         smInstance  = 2,
         smLayer     = 4,
-        smSettings  = 8, // used for undo/redo
-    } m_selection_mode {smUndef};
+        smSettings  = 8,  // used for undo/redo
+        smLayerRoot = 16, // used for undo/redo
+    };
 
 private:
+    SELECTION_MODE m_selection_mode {smUndef};
+    t_layer_height_range m_selected_layers_range;
+
     struct dragged_item_data
     {
         void init(const int obj_idx, const int subobj_idx, const ItemType type) {
@@ -305,6 +309,8 @@ public:
     void init_objects();
     bool multiple_selection() const ;
     bool is_selected(const ItemType type) const;
+    t_layer_height_range get_selected_layers_range() const;
+    void set_selected_layers_range(const t_layer_height_range range) { m_selected_layers_range = range; }
     void set_selection_mode(SELECTION_MODE mode) { m_selection_mode = mode; }
     void update_selections();
     void update_selections_on_canvas();
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 7653a5833..3d1e7b97c 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -3729,8 +3729,16 @@ void Plater::priv::take_snapshot(const std::string& snapshot_name)
     snapshot_data.printer_technology = this->printer_technology;
     if (this->view3D->is_layers_editing_enabled())
     	snapshot_data.flags |= UndoRedo::SnapshotData::VARIABLE_LAYER_EDITING_ACTIVE;
-    if (this->sidebar->obj_list()->is_selected(itSettings))
-        snapshot_data.flags |= UndoRedo::SnapshotData::SETTINGS_SELECTED_ON_SIDEBAR;
+    if (this->sidebar->obj_list()->is_selected(itSettings)) {
+        snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_SETTINGS_ON_SIDEBAR;
+        snapshot_data.layer_range = this->sidebar->obj_list()->get_selected_layers_range();
+    }
+    else if (this->sidebar->obj_list()->is_selected(itLayer)) {
+        snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_LAYER_ON_SIDEBAR;
+        snapshot_data.layer_range = this->sidebar->obj_list()->get_selected_layers_range();
+    }
+    else if (this->sidebar->obj_list()->is_selected(itLayerRoot))
+        snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_LAYERROOT_ON_SIDEBAR;
     //FIXME updating the Wipe tower config values at the ModelWipeTower from the Print config.
     // This is a workaround until we refactor the Wipe Tower position / orientation to live solely inside the Model, not in the Print config.
     if (this->printer_technology == ptFFF) {
@@ -3797,10 +3805,22 @@ void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator
     top_snapshot_data.printer_technology = this->printer_technology;
     if (this->view3D->is_layers_editing_enabled())
     	top_snapshot_data.flags |= UndoRedo::SnapshotData::VARIABLE_LAYER_EDITING_ACTIVE;
-    if (this->sidebar->obj_list()->is_selected(itSettings))
-    	top_snapshot_data.flags |= UndoRedo::SnapshotData::SETTINGS_SELECTED_ON_SIDEBAR;
+    if (this->sidebar->obj_list()->is_selected(itSettings)) {
+    	top_snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_SETTINGS_ON_SIDEBAR;
+        top_snapshot_data.layer_range = this->sidebar->obj_list()->get_selected_layers_range();
+    }
+    else if (this->sidebar->obj_list()->is_selected(itLayer)) {
+        top_snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_LAYER_ON_SIDEBAR;
+        top_snapshot_data.layer_range = this->sidebar->obj_list()->get_selected_layers_range();
+    }
+    else if (this->sidebar->obj_list()->is_selected(itLayerRoot))
+        top_snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_LAYERROOT_ON_SIDEBAR;
 	bool   		 new_variable_layer_editing_active = (new_flags & UndoRedo::SnapshotData::VARIABLE_LAYER_EDITING_ACTIVE) != 0;
-    bool         new_settings_selected_on_sidebar  = (new_flags & UndoRedo::SnapshotData::SETTINGS_SELECTED_ON_SIDEBAR) != 0;
+    bool         new_selected_settings_on_sidebar  = (new_flags & UndoRedo::SnapshotData::SELECTED_SETTINGS_ON_SIDEBAR) != 0;
+    bool         new_selected_layer_on_sidebar     = (new_flags & UndoRedo::SnapshotData::SELECTED_LAYER_ON_SIDEBAR) != 0;
+    bool         new_selected_layerroot_on_sidebar = (new_flags & UndoRedo::SnapshotData::SELECTED_LAYERROOT_ON_SIDEBAR) != 0;
+
+    t_layer_height_range layer_range = it_snapshot->snapshot_data.layer_range;
 	// Disable layer editing before the Undo / Redo jump.
     if (!new_variable_layer_editing_active && view3D->is_layers_editing_enabled())
         view3D->get_canvas3d()->force_main_toolbar_left_action(view3D->get_canvas3d()->get_main_toolbar_item_id("layersediting"));
@@ -3833,9 +3853,14 @@ void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator
                 tab_print->update_dirty();
             }
         }
-        // set settings mode for ObjectList on sidebar
-        if (new_settings_selected_on_sidebar)
-            this->sidebar->obj_list()->set_selection_mode(ObjectList::SELECTION_MODE::smSettings);
+        // set selection mode for ObjectList on sidebar
+        this->sidebar->obj_list()->set_selection_mode(new_selected_settings_on_sidebar  ? ObjectList::SELECTION_MODE::smSettings :
+                                                      new_selected_layer_on_sidebar     ? ObjectList::SELECTION_MODE::smLayer :
+                                                      new_selected_layerroot_on_sidebar ? ObjectList::SELECTION_MODE::smLayerRoot : 
+                                                                                          ObjectList::SELECTION_MODE::smUndef);
+        if (new_selected_settings_on_sidebar || new_selected_layer_on_sidebar)
+            this->sidebar->obj_list()->set_selected_layers_range(/*top_snapshot_data.*/layer_range);
+
         this->update_after_undo_redo(temp_snapshot_was_taken);
 		// Enable layer editing after the Undo / Redo jump.
 		if (! view3D->is_layers_editing_enabled() && this->layers_height_allowed() && new_variable_layer_editing_active)
diff --git a/src/slic3r/Utils/UndoRedo.cpp b/src/slic3r/Utils/UndoRedo.cpp
index eba839ffb..9b12be00e 100644
--- a/src/slic3r/Utils/UndoRedo.cpp
+++ b/src/slic3r/Utils/UndoRedo.cpp
@@ -36,7 +36,7 @@
 namespace Slic3r {
 namespace UndoRedo {
 
-SnapshotData::SnapshotData() : printer_technology(ptUnknown), flags(0)
+SnapshotData::SnapshotData() : printer_technology(ptUnknown), flags(0), layer_range({0.0, 0.0})
 {
 }
 
diff --git a/src/slic3r/Utils/UndoRedo.hpp b/src/slic3r/Utils/UndoRedo.hpp
index a3a130efd..85ad11b82 100644
--- a/src/slic3r/Utils/UndoRedo.hpp
+++ b/src/slic3r/Utils/UndoRedo.hpp
@@ -9,6 +9,9 @@
 
 #include <libslic3r/ObjectID.hpp>
 
+typedef double                          coordf_t;
+typedef std::pair<coordf_t, coordf_t>   t_layer_height_range;
+
 namespace Slic3r {
 
 class Model;
@@ -38,8 +41,12 @@ struct SnapshotData
 	// Bitmask of various binary flags to be stored with the snapshot.
 	enum Flags {
 		VARIABLE_LAYER_EDITING_ACTIVE = 1,
-		SETTINGS_SELECTED_ON_SIDEBAR  = 2,
+		SELECTED_SETTINGS_ON_SIDEBAR  = 2,
+		SELECTED_LAYERROOT_ON_SIDEBAR = 4,
+		SELECTED_LAYER_ON_SIDEBAR     = 8,
 	};
+
+    t_layer_height_range layer_range;
 };
 
 struct Snapshot

From 1a3fc0994b64c2a8939bf91ff54c1160da6e6358 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Wed, 24 Jul 2019 12:32:38 +0200
Subject: [PATCH 11/11] Fix for
 https://github.com/prusa3d/PrusaSlicer/commit/0592ae65eeff51038aac647c68b009b1314c765c

---
 src/slic3r/GUI/GUI_ObjectList.cpp | 17 +++++++----------
 src/slic3r/GUI/GUI_ObjectList.hpp |  8 ++++----
 src/slic3r/GUI/Plater.cpp         | 11 +++++------
 src/slic3r/Utils/UndoRedo.cpp     |  2 +-
 src/slic3r/Utils/UndoRedo.hpp     |  3 +--
 5 files changed, 18 insertions(+), 23 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 14c6db654..8d5c3fda9 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -2633,20 +2633,17 @@ bool ObjectList::is_selected(const ItemType type) const
     return false;
 }
 
-t_layer_height_range ObjectList::get_selected_layers_range() const
+int ObjectList::get_selected_layers_range_idx() const
 {
-    t_layer_height_range layer_range = { 0.0, 0.0 };
     const wxDataViewItem& item = GetSelection();
     if (!item) 
-        return layer_range;
+        return -1;
 
     const ItemType type = m_objects_model->GetItemType(item);
     if (type & itSettings && m_objects_model->GetItemType(m_objects_model->GetParent(item)) != itLayer)
-        return layer_range;
+        return -1;
 
-    return  type & itLayer ? m_objects_model->GetLayerRangeByItem(item) :
-            type & itSettings ? m_objects_model->GetLayerRangeByItem(m_objects_model->GetParent(item)) :
-            layer_range;
+    return m_objects_model->GetLayerIdByItem(type & itLayer ? item : m_objects_model->GetParent(item));
 }
 
 void ObjectList::update_selections()
@@ -2687,15 +2684,15 @@ void ObjectList::update_selections()
             wxDataViewItem obj_item = m_objects_model->GetItemById(obj_idx);
             if (m_selection_mode & smSettings)
             {
-                if (m_selected_layers_range.first <= EPSILON && m_selected_layers_range.second <= EPSILON)
+                if (m_selected_layers_range_idx < 0)
                     sels.Add(m_objects_model->GetSettingsItem(obj_item));
                 else
-                    sels.Add(m_objects_model->GetSettingsItem(m_objects_model->GetItemByLayerRange(obj_idx, m_selected_layers_range)));
+                    sels.Add(m_objects_model->GetSettingsItem(m_objects_model->GetItemByLayerId(obj_idx, m_selected_layers_range_idx)));
             }
             else if (m_selection_mode & smLayerRoot)
                 sels.Add(m_objects_model->GetLayerRootItem(obj_item));
             else if (m_selection_mode & smLayer)
-                sels.Add(m_objects_model->GetItemByLayerRange(obj_idx, m_selected_layers_range));
+                sels.Add(m_objects_model->GetItemByLayerId(obj_idx, m_selected_layers_range_idx));
         }
         else {
         for (const auto& object : objects_content) {
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 1c30a4d97..5c971c40f 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -78,8 +78,8 @@ public:
     };
 
 private:
-    SELECTION_MODE m_selection_mode {smUndef};
-    t_layer_height_range m_selected_layers_range;
+    SELECTION_MODE  m_selection_mode {smUndef};
+    int             m_selected_layers_range_idx;
 
     struct dragged_item_data
     {
@@ -309,8 +309,8 @@ public:
     void init_objects();
     bool multiple_selection() const ;
     bool is_selected(const ItemType type) const;
-    t_layer_height_range get_selected_layers_range() const;
-    void set_selected_layers_range(const t_layer_height_range range) { m_selected_layers_range = range; }
+    int  get_selected_layers_range_idx() const;
+    void set_selected_layers_range_idx(const int range_idx) { m_selected_layers_range_idx = range_idx; }
     void set_selection_mode(SELECTION_MODE mode) { m_selection_mode = mode; }
     void update_selections();
     void update_selections_on_canvas();
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 3d1e7b97c..067d13b8a 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -3731,11 +3731,11 @@ void Plater::priv::take_snapshot(const std::string& snapshot_name)
     	snapshot_data.flags |= UndoRedo::SnapshotData::VARIABLE_LAYER_EDITING_ACTIVE;
     if (this->sidebar->obj_list()->is_selected(itSettings)) {
         snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_SETTINGS_ON_SIDEBAR;
-        snapshot_data.layer_range = this->sidebar->obj_list()->get_selected_layers_range();
+        snapshot_data.layer_range_idx = this->sidebar->obj_list()->get_selected_layers_range_idx();
     }
     else if (this->sidebar->obj_list()->is_selected(itLayer)) {
         snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_LAYER_ON_SIDEBAR;
-        snapshot_data.layer_range = this->sidebar->obj_list()->get_selected_layers_range();
+        snapshot_data.layer_range_idx = this->sidebar->obj_list()->get_selected_layers_range_idx();
     }
     else if (this->sidebar->obj_list()->is_selected(itLayerRoot))
         snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_LAYERROOT_ON_SIDEBAR;
@@ -3807,11 +3807,11 @@ void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator
     	top_snapshot_data.flags |= UndoRedo::SnapshotData::VARIABLE_LAYER_EDITING_ACTIVE;
     if (this->sidebar->obj_list()->is_selected(itSettings)) {
     	top_snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_SETTINGS_ON_SIDEBAR;
-        top_snapshot_data.layer_range = this->sidebar->obj_list()->get_selected_layers_range();
+        top_snapshot_data.layer_range_idx = this->sidebar->obj_list()->get_selected_layers_range_idx();
     }
     else if (this->sidebar->obj_list()->is_selected(itLayer)) {
         top_snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_LAYER_ON_SIDEBAR;
-        top_snapshot_data.layer_range = this->sidebar->obj_list()->get_selected_layers_range();
+        top_snapshot_data.layer_range_idx = this->sidebar->obj_list()->get_selected_layers_range_idx();
     }
     else if (this->sidebar->obj_list()->is_selected(itLayerRoot))
         top_snapshot_data.flags |= UndoRedo::SnapshotData::SELECTED_LAYERROOT_ON_SIDEBAR;
@@ -3820,7 +3820,6 @@ void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator
     bool         new_selected_layer_on_sidebar     = (new_flags & UndoRedo::SnapshotData::SELECTED_LAYER_ON_SIDEBAR) != 0;
     bool         new_selected_layerroot_on_sidebar = (new_flags & UndoRedo::SnapshotData::SELECTED_LAYERROOT_ON_SIDEBAR) != 0;
 
-    t_layer_height_range layer_range = it_snapshot->snapshot_data.layer_range;
 	// Disable layer editing before the Undo / Redo jump.
     if (!new_variable_layer_editing_active && view3D->is_layers_editing_enabled())
         view3D->get_canvas3d()->force_main_toolbar_left_action(view3D->get_canvas3d()->get_main_toolbar_item_id("layersediting"));
@@ -3859,7 +3858,7 @@ void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator
                                                       new_selected_layerroot_on_sidebar ? ObjectList::SELECTION_MODE::smLayerRoot : 
                                                                                           ObjectList::SELECTION_MODE::smUndef);
         if (new_selected_settings_on_sidebar || new_selected_layer_on_sidebar)
-            this->sidebar->obj_list()->set_selected_layers_range(/*top_snapshot_data.*/layer_range);
+            this->sidebar->obj_list()->set_selected_layers_range_idx(it_snapshot->snapshot_data.layer_range_idx);
 
         this->update_after_undo_redo(temp_snapshot_was_taken);
 		// Enable layer editing after the Undo / Redo jump.
diff --git a/src/slic3r/Utils/UndoRedo.cpp b/src/slic3r/Utils/UndoRedo.cpp
index 9b12be00e..daf6752b7 100644
--- a/src/slic3r/Utils/UndoRedo.cpp
+++ b/src/slic3r/Utils/UndoRedo.cpp
@@ -36,7 +36,7 @@
 namespace Slic3r {
 namespace UndoRedo {
 
-SnapshotData::SnapshotData() : printer_technology(ptUnknown), flags(0), layer_range({0.0, 0.0})
+SnapshotData::SnapshotData() : printer_technology(ptUnknown), flags(0), layer_range_idx(-1)
 {
 }
 
diff --git a/src/slic3r/Utils/UndoRedo.hpp b/src/slic3r/Utils/UndoRedo.hpp
index 85ad11b82..37cc5a049 100644
--- a/src/slic3r/Utils/UndoRedo.hpp
+++ b/src/slic3r/Utils/UndoRedo.hpp
@@ -37,6 +37,7 @@ struct SnapshotData
 	PrinterTechnology 	printer_technology;
 	// Bitmap of Flags (see the Flags enum).
 	unsigned int        flags;
+    int                 layer_range_idx;
 
 	// Bitmask of various binary flags to be stored with the snapshot.
 	enum Flags {
@@ -45,8 +46,6 @@ struct SnapshotData
 		SELECTED_LAYERROOT_ON_SIDEBAR = 4,
 		SELECTED_LAYER_ON_SIDEBAR     = 8,
 	};
-
-    t_layer_height_range layer_range;
 };
 
 struct Snapshot