diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index 6416a709a..d47cdf99f 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -280,7 +280,7 @@ bool Print::is_step_done(PrintObjectStep step) const
         return false;
 	tbb::mutex::scoped_lock lock(this->state_mutex());
     for (const PrintObject *object : m_objects)
-        if (! object->m_state.is_done_unguarded(step))
+        if (! object->is_step_done_unguarded(step))
             return false;
     return true;
 }
@@ -549,10 +549,14 @@ void Print::model_volume_list_update_supports(ModelObject &model_object_dst, con
             assert(! it->second); // not consumed yet
             it->second = true;
             ModelVolume *model_volume_dst = const_cast<ModelVolume*>(it->first);
-            assert(model_volume_dst->type() == model_volume_src->type());
+			// For support modifiers, the type may have been switched from blocker to enforcer and vice versa.
+			assert((model_volume_dst->is_support_modifier() && model_volume_src->is_support_modifier()) || model_volume_dst->type() == model_volume_src->type());
             model_object_dst.volumes.emplace_back(model_volume_dst);
-			if (model_volume_dst->is_support_modifier())
-                model_volume_dst->set_transformation(model_volume_src->get_transformation());
+			if (model_volume_dst->is_support_modifier()) {
+				// For support modifiers, the type may have been switched from blocker to enforcer and vice versa.
+				model_volume_dst->set_type(model_volume_src->type());
+				model_volume_dst->set_transformation(model_volume_src->get_transformation());
+			}
             assert(model_volume_dst->get_matrix().isApprox(model_volume_src->get_matrix()));
         } else {
             // The volume was not found in the old list. Create a new copy.
diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp
index f67ec4b72..154fa3649 100644
--- a/src/libslic3r/PrintBase.hpp
+++ b/src/libslic3r/PrintBase.hpp
@@ -62,6 +62,10 @@ public:
         return state;
     }
 
+    bool is_started(StepType step, tbb::mutex &mtx) const {
+        return this->state_with_timestamp(step, mtx).state == STARTED;
+    }
+
     bool is_done(StepType step, tbb::mutex &mtx) const {
         return this->state_with_timestamp(step, mtx).state == DONE;
     }
@@ -70,6 +74,10 @@ public:
         return m_state[step];
     }
 
+    bool is_started_unguarded(StepType step) const {
+        return this->state_with_timestamp_unguarded(step).state == STARTED;
+    }
+
     bool is_done_unguarded(StepType step) const {
         return this->state_with_timestamp_unguarded(step).state == DONE;
     }
@@ -235,6 +243,18 @@ public:
     virtual ApplyStatus     apply(const Model &model, const DynamicPrintConfig &config) = 0;
     const Model&            model() const { return m_model; }
 
+    struct TaskParams {
+		TaskParams() : single_model_object(0), single_model_instance_only(false), to_object_step(-1), to_print_step(-1) {}
+        // If non-empty, limit the processing to this ModelObject.
+        ModelID                 single_model_object;
+		// If set, only process single_model_object. Otherwise process everything, but single_model_object first.
+		bool					single_model_instance_only;
+        // If non-negative, stop processing at the successive object step.
+        int                     to_object_step;
+        // If non-negative, stop processing at the successive print step.
+        int                     to_print_step;
+    };
+
     virtual void            process() = 0;
 
     struct SlicingStatus {
@@ -350,6 +370,9 @@ protected:
     bool            invalidate_all_steps() 
         { return m_state.invalidate_all(this->cancel_callback()); }
 
+	bool            is_step_started_unguarded(PrintStepEnum step) const { return m_state.is_started_unguarded(step); }
+	bool            is_step_done_unguarded(PrintStepEnum step) const { return m_state.is_done_unguarded(step); }
+
 private:
     PrintState<PrintStepEnum, COUNT> m_state;
 };
@@ -383,6 +406,9 @@ protected:
     bool            invalidate_all_steps() 
         { return m_state.invalidate_all(PrintObjectBase::cancel_callback(m_print)); }
 
+    bool            is_step_started_unguarded(PrintObjectStepEnum step) const { return m_state.is_started_unguarded(step); }
+    bool            is_step_done_unguarded(PrintObjectStepEnum step) const { return m_state.is_done_unguarded(step); }
+
 protected:
     // If the background processing stop was requested, throw CanceledException.
     // To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly.
diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp
index f25087cbe..0c486e95a 100644
--- a/src/libslic3r/SLAPrint.cpp
+++ b/src/libslic3r/SLAPrint.cpp
@@ -51,7 +51,7 @@ const std::array<std::string, slaposCount> OBJ_STEP_LABELS =
     L("Slicing model"),                 // slaposObjectSlice,
     L("Generating support points"),      // slaposSupportPoints,
     L("Generating support tree"),       // slaposSupportTree,
-    L("Generating base pool"),          // slaposBasePool,
+    L("Generating pad"),                // slaposBasePool,
     L("Slicing supports"),              // slaposSliceSupports,
     L("Slicing supports")               // slaposIndexSlices,
 };
@@ -402,6 +402,61 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
     return static_cast<ApplyStatus>(apply_status);
 }
 
+void SLAPrint::set_task(const TaskParams &params)
+{
+	// Grab the lock for the Print / PrintObject milestones.
+	tbb::mutex::scoped_lock lock(this->state_mutex());
+
+	int n_object_steps = params.to_object_step + 1;
+	if (n_object_steps = 0)
+		n_object_steps = (int)slaposCount;
+
+	if (params.single_model_object.valid()) {
+		SLAPrintObject *print_object = nullptr;
+		size_t          idx_print_object = 0;
+		for (; idx_print_object < m_objects.size(); ++idx_print_object)
+			if (m_objects[idx_print_object]->model_object()->id() == params.single_model_object) {
+				print_object = m_objects[idx_print_object];
+				break;
+			}
+		assert(print_object != nullptr);
+		bool shall_cancel = false;
+		for (int istep = 0; istep < n_object_steps; ++istep)
+			if (! print_object->m_stepmask[istep]) {
+				shall_cancel = true;
+				break;
+			}
+		bool running = false;
+		if (!shall_cancel) {
+			for (int istep = 0; istep < n_object_steps; ++ istep)
+				if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) {
+					running = true;
+					break;
+				}
+		}
+		if (!running)
+			this->cancel_callback();
+
+		// Now the background process is either stopped, or it is inside one of the print object steps to be calculated anyway.
+		if (params.single_model_instance_only) {
+			// Suppress all the steps of other instances.
+			for (SLAPrintObject *po : m_objects)
+				for (int istep = 0; istep < (int)slaposCount; ++istep)
+					print_object->m_stepmask[istep] = false;
+		}
+		else if (!running) {
+			// Swap the print objects, so that the selected print_object is first in the row.
+			// At this point the background processing must be stopped, so it is safe to shuffle print objects.
+			if (idx_print_object != 0)
+				std::swap(m_objects.front(), m_objects[idx_print_object]);
+		}
+		for (int istep = 0; istep < n_object_steps; ++ istep)
+			print_object->m_stepmask[istep] = true;
+		for (int istep = 0; istep < (int)slaposCount; ++ istep)
+			print_object->m_stepmask[istep] = false;
+	}
+}
+
 namespace {
 // Compile the argument for support creation from the static print config.
 sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) {
@@ -1035,7 +1090,7 @@ bool SLAPrint::is_step_done(SLAPrintObjectStep step) const
         return false;
     tbb::mutex::scoped_lock lock(this->state_mutex());
     for (const SLAPrintObject *object : m_objects)
-        if (! object->m_state.is_done_unguarded(step))
+        if (! object->is_step_done_unguarded(step))
             return false;
     return true;
 }
diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp
index 9aaba6a47..be862095c 100644
--- a/src/libslic3r/SLAPrint.hpp
+++ b/src/libslic3r/SLAPrint.hpp
@@ -139,6 +139,10 @@ protected:
     // Invalidate steps based on a set of parameters changed.
     bool                    invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
 
+    // Which steps have to be performed. Implicitly: all
+    // to be accessible from SLAPrint
+    std::vector<bool>                       m_stepmask;
+
 private:
     // Object specific configuration, pulled from the configuration layer.
     SLAPrintObjectConfig                    m_config;
@@ -146,9 +150,6 @@ private:
     Transform3d                             m_trafo = Transform3d::Identity();
     std::vector<Instance> 					m_instances;
 
-    // Which steps have to be performed. Implicitly: all
-    std::vector<bool>                       m_stepmask;
-
     // Individual 2d slice polygons from lower z to higher z levels
     std::vector<ExPolygons>                 m_model_slices;
 
@@ -194,6 +195,7 @@ public:
     void                clear() override;
     bool                empty() const override { return m_objects.empty(); }
     ApplyStatus         apply(const Model &model, const DynamicPrintConfig &config) override;
+    void                set_task(const TaskParams &params);
     void                process() override;
     // Returns true if an object step is done on all objects and there's at least one object.    
     bool                is_step_done(SLAPrintObjectStep step) const;