From 5f226c5d7fcb7c019604dde1da1e792986515e96 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Fri, 26 Apr 2019 15:34:26 +0200
Subject: [PATCH 1/8] Allow wipe tower rotation by the rotation gizmo

---
 src/slic3r/GUI/3DScene.cpp                |   5 +-
 src/slic3r/GUI/GLCanvas3D.cpp             |   6 +
 src/slic3r/GUI/GLCanvas3D.hpp             |   1 +
 src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp   |   2 +-
 src/slic3r/GUI/Gizmos/GLGizmosManager.cpp |  17 +-
 src/slic3r/GUI/Plater.cpp                 |  12 ++
 src/slic3r/GUI/Selection.cpp              | 181 ++++++++++++----------
 7 files changed, 135 insertions(+), 89 deletions(-)

diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp
index 037f70962..8bd95e372 100644
--- a/src/slic3r/GUI/3DScene.cpp
+++ b/src/slic3r/GUI/3DScene.cpp
@@ -709,12 +709,15 @@ int GLVolumeCollection::load_wipe_tower_preview(
     brim_mesh.translate(-brim_width, -brim_width, 0.f);
     mesh.merge(brim_mesh);
 
-    mesh.rotate(rotation_angle, &origin_of_rotation); // rotates the box according to the config rotation setting
+    //mesh.rotate(rotation_angle, &origin_of_rotation); // rotates the box according to the config rotation setting
+    
 
     this->volumes.emplace_back(new GLVolume(color));
     GLVolume &v = *this->volumes.back();
     v.indexed_vertex_array.load_mesh(mesh, use_VBOs);
     v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
+    v.set_volume_rotation(Vec3d(0., 0., (M_PI/180.) * rotation_angle));
+
     // finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
     v.bounding_box = v.indexed_vertex_array.bounding_box();
     v.indexed_vertex_array.finalize_geometry(use_VBOs);
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 005b9db9d..cc7514e54 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -1201,6 +1201,7 @@ wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent);
 wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent);
 wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent);
 wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
+wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3dEvent);
 wxDEFINE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>);
 wxDEFINE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>);
 wxDEFINE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent);
@@ -3090,6 +3091,10 @@ void GLCanvas3D::do_rotate()
     for (const GLVolume* v : m_volumes.volumes)
     {
         int object_idx = v->object_idx();
+        if (object_idx == 1000) { // the wipe tower
+            Vec3d offset = v->get_volume_offset();
+            post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3d(offset(0), offset(1), v->get_volume_rotation()(2))));
+        }
         if ((object_idx < 0) || ((int)m_model->objects.size() <= object_idx))
             continue;
 
@@ -4289,6 +4294,7 @@ void GLCanvas3D::_render_selection_sidebar_hints() const
         m_shader.stop_using();
 }
 
+
 void GLCanvas3D::_update_volumes_hover_state() const
 {
     for (GLVolume* v : m_volumes.volumes)
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index 4670b7221..086209872 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -116,6 +116,7 @@ wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent);
 wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent);
 wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent);
 wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent);
+wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_ROTATED, Vec3dEvent);
 wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>);
 wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>);
 wxDECLARE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp
index f5946aa56..c65dee4d8 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp
@@ -102,7 +102,7 @@ protected:
             m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1);
         }
     }
-    virtual bool on_is_activable(const Selection& selection) const { return !selection.is_wipe_tower(); }
+    virtual bool on_is_activable(const Selection& selection) const { return true; }
     virtual void on_enable_grabber(unsigned int id)
     {
         if ((0 <= id) && (id < 3))
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
index a00303634..7cc28ee78 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
@@ -4,6 +4,7 @@
 #include "slic3r/GUI/3DScene.hpp"
 #include "slic3r/GUI/GUI_App.hpp"
 #include "slic3r/GUI/GUI_ObjectManipulation.hpp"
+#include "slic3r/GUI/PresetBundle.hpp"
 
 #include <GL/glew.h>
 #include <wx/glcanvas.h>
@@ -264,8 +265,12 @@ void GLGizmosManager::update_data(GLCanvas3D& canvas)
 
     const Selection& selection = canvas.get_selection();
 
-    bool enable_move_z = !selection.is_wipe_tower();
-    enable_grabber(Move, 2, enable_move_z);
+    bool is_wipe_tower = selection.is_wipe_tower();
+    enable_grabber(Move, 2, !is_wipe_tower);
+    enable_grabber(Move, 2, !is_wipe_tower);
+    enable_grabber(Rotate, 0, !is_wipe_tower);
+    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)
     {
@@ -290,6 +295,14 @@ void GLGizmosManager::update_data(GLCanvas3D& canvas)
         set_flattening_data(nullptr);
         set_sla_support_data(nullptr, selection);
     }
+    else if (is_wipe_tower)
+    {
+        DynamicPrintConfig& config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
+        set_scale(Vec3d::Ones());
+        set_rotation(Vec3d(0., 0., (M_PI/180.) * dynamic_cast<const ConfigOptionFloat*>(config.option("wipe_tower_rotation_angle"))->value));
+        set_flattening_data(nullptr);
+        set_sla_support_data(nullptr, selection);
+    }
     else
     {
         set_scale(Vec3d::Ones());
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 2d44237bd..31b0d9f3a 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -1307,6 +1307,7 @@ struct Plater::priv
     void on_object_select(SimpleEvent&);
     void on_right_click(Vec2dEvent&);
     void on_wipetower_moved(Vec3dEvent&);
+    void on_wipetower_rotated(Vec3dEvent&);
     void on_update_geometry(Vec3dsEvent<2>&);
     void on_3dcanvas_mouse_dragging_finished(SimpleEvent&);
 
@@ -1437,6 +1438,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
         { if (evt.data == 1) this->q->increase_instances(); else if (this->can_decrease_instances()) this->q->decrease_instances(); });
     view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_MOVED, [this](SimpleEvent&) { update(); });
     view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_MOVED, &priv::on_wipetower_moved, this);
+    view3D_canvas->Bind(EVT_GLCANVAS_WIPETOWER_ROTATED, &priv::on_wipetower_rotated, this);
     view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_ROTATED, [this](SimpleEvent&) { update(); });
     view3D_canvas->Bind(EVT_GLCANVAS_INSTANCE_SCALED, [this](SimpleEvent&) { update(); });
     view3D_canvas->Bind(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, [this](Event<bool> &evt) { this->sidebar->enable_buttons(evt.data); });
@@ -1444,6 +1446,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
     view3D_canvas->Bind(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, &priv::on_3dcanvas_mouse_dragging_finished, this);
     view3D_canvas->Bind(EVT_GLCANVAS_TAB, [this](SimpleEvent&) { select_next_view_3D(); });
     view3D_canvas->Bind(EVT_GLCANVAS_RESETGIZMOS, [this](SimpleEvent&) { reset_all_gizmos(); });
+
     // 3DScene/Toolbar:
     view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this);
     view3D_canvas->Bind(EVT_GLTOOLBAR_DELETE, [q](SimpleEvent&) { q->remove_selected(); });
@@ -2851,6 +2854,15 @@ void Plater::priv::on_wipetower_moved(Vec3dEvent &evt)
     wxGetApp().get_tab(Preset::TYPE_PRINT)->load_config(cfg);
 }
 
+void Plater::priv::on_wipetower_rotated(Vec3dEvent& evt)
+{
+    DynamicPrintConfig cfg;
+    cfg.opt<ConfigOptionFloat>("wipe_tower_x", true)->value = evt.data(0);
+    cfg.opt<ConfigOptionFloat>("wipe_tower_y", true)->value = evt.data(1);
+    cfg.opt<ConfigOptionFloat>("wipe_tower_rotation_angle", true)->value = Geometry::rad2deg(evt.data(2));
+    wxGetApp().get_tab(Preset::TYPE_PRINT)->load_config(cfg);
+}
+
 void Plater::priv::on_update_geometry(Vec3dsEvent<2>&)
 {
     // TODO
diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp
index e014851ab..6070a3cd0 100644
--- a/src/slic3r/GUI/Selection.cpp
+++ b/src/slic3r/GUI/Selection.cpp
@@ -492,100 +492,111 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
     // Only relative rotation values are allowed in the world coordinate system.
     assert(!transformation_type.world() || transformation_type.relative());
 
-    int rot_axis_max = 0;
-    if (rotation.isApprox(Vec3d::Zero()))
-    {
-        for (unsigned int i : m_list)
+    if (!is_wipe_tower()) {
+        int rot_axis_max = 0;
+        if (rotation.isApprox(Vec3d::Zero()))
         {
-            GLVolume &volume = *(*m_volumes)[i];
-            if (m_mode == Instance)
-            {
-                volume.set_instance_rotation(m_cache.volumes_data[i].get_instance_rotation());
-                volume.set_instance_offset(m_cache.volumes_data[i].get_instance_position());
-            }
-            else if (m_mode == Volume)
-            {
-                volume.set_volume_rotation(m_cache.volumes_data[i].get_volume_rotation());
-                volume.set_volume_offset(m_cache.volumes_data[i].get_volume_position());
-            }
-        }
-    }
-    else
-    {
-        //FIXME this does not work for absolute rotations (transformation_type.absolute() is true)
-        rotation.cwiseAbs().maxCoeff(&rot_axis_max);
-
-        // For generic rotation, we want to rotate the first volume in selection, and then to synchronize the other volumes with it.
-        std::vector<int> object_instance_first(m_model->objects.size(), -1);
-        auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, transformation_type](GLVolume &volume, int i) {
-            int first_volume_idx = object_instance_first[volume.object_idx()];
-            if (rot_axis_max != 2 && first_volume_idx != -1) {
-                // Generic rotation, but no rotation around the Z axis.
-                // Always do a local rotation (do not consider the selection to be a rigid body).
-                assert(is_approx(rotation.z(), 0.0));
-                const GLVolume &first_volume = *(*m_volumes)[first_volume_idx];
-                const Vec3d    &rotation = first_volume.get_instance_rotation();
-                double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation());
-                volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff));
-            }
-            else {
-                // extracts rotations from the composed transformation
-                Vec3d new_rotation = transformation_type.world() ?
-                    Geometry::extract_euler_angles(Geometry::assemble_transform(Vec3d::Zero(), rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix()) :
-                    transformation_type.absolute() ? rotation : rotation + m_cache.volumes_data[i].get_instance_rotation();
-                if (rot_axis_max == 2 && transformation_type.joint()) {
-                    // Only allow rotation of multiple instances as a single rigid body when rotating around the Z axis.
-                    Vec3d offset = Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.0, new_rotation(2) - m_cache.volumes_data[i].get_instance_rotation()(2))) * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center);
-                    volume.set_instance_offset(m_cache.dragging_center + offset);
-                }
-                volume.set_instance_rotation(new_rotation);
-                object_instance_first[volume.object_idx()] = i;
-            }
-        };
-
-        for (unsigned int i : m_list)
-        {
-            GLVolume &volume = *(*m_volumes)[i];
-            if (is_single_full_instance())
-                rotate_instance(volume, i);
-            else if (is_single_volume() || is_single_modifier())
-            {
-                if (transformation_type.independent())
-                    volume.set_volume_rotation(volume.get_volume_rotation() + rotation);
-                else
-                {
-                    Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
-                    Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
-                    volume.set_volume_rotation(new_rotation);
-                }
-            }
-            else
+            for (unsigned int i : m_list)
             {
+                GLVolume &volume = *(*m_volumes)[i];
                 if (m_mode == Instance)
-                    rotate_instance(volume, i);
+                {
+                    volume.set_instance_rotation(m_cache.volumes_data[i].get_instance_rotation());
+                    volume.set_instance_offset(m_cache.volumes_data[i].get_instance_position());
+                }
                 else if (m_mode == Volume)
                 {
-                    // extracts rotations from the composed transformation
-                    Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
-                    Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
-                    if (transformation_type.joint())
-                    {
-                        Vec3d local_pivot = m_cache.volumes_data[i].get_instance_full_matrix().inverse() * m_cache.dragging_center;
-                        Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() - local_pivot);
-                        volume.set_volume_offset(local_pivot + offset);
-                    }
-                    volume.set_volume_rotation(new_rotation);
+                    volume.set_volume_rotation(m_cache.volumes_data[i].get_volume_rotation());
+                    volume.set_volume_offset(m_cache.volumes_data[i].get_volume_position());
                 }
             }
         }
-    }
+        else { // this is not the wipe tower
+            //FIXME this does not work for absolute rotations (transformation_type.absolute() is true)
+            rotation.cwiseAbs().maxCoeff(&rot_axis_max);
 
-#if !DISABLE_INSTANCES_SYNCH
-    if (m_mode == Instance)
-        synchronize_unselected_instances((rot_axis_max == 2) ? SYNC_ROTATION_NONE : SYNC_ROTATION_GENERAL);
-    else if (m_mode == Volume)
-        synchronize_unselected_volumes();
-#endif // !DISABLE_INSTANCES_SYNCH
+            // For generic rotation, we want to rotate the first volume in selection, and then to synchronize the other volumes with it.
+            std::vector<int> object_instance_first(m_model->objects.size(), -1);
+            auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, transformation_type](GLVolume &volume, int i) {
+                int first_volume_idx = object_instance_first[volume.object_idx()];
+                if (rot_axis_max != 2 && first_volume_idx != -1) {
+                    // Generic rotation, but no rotation around the Z axis.
+                    // Always do a local rotation (do not consider the selection to be a rigid body).
+                    assert(is_approx(rotation.z(), 0.0));
+                    const GLVolume &first_volume = *(*m_volumes)[first_volume_idx];
+                    const Vec3d    &rotation = first_volume.get_instance_rotation();
+                    double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation());
+                    volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff));
+                }
+                else {
+                    // extracts rotations from the composed transformation
+                    Vec3d new_rotation = transformation_type.world() ?
+                        Geometry::extract_euler_angles(Geometry::assemble_transform(Vec3d::Zero(), rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix()) :
+                        transformation_type.absolute() ? rotation : rotation + m_cache.volumes_data[i].get_instance_rotation();
+                    if (rot_axis_max == 2 && transformation_type.joint()) {
+                        // Only allow rotation of multiple instances as a single rigid body when rotating around the Z axis.
+                        Vec3d offset = Geometry::assemble_transform(Vec3d::Zero(), Vec3d(0.0, 0.0, new_rotation(2) - m_cache.volumes_data[i].get_instance_rotation()(2))) * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center);
+                        volume.set_instance_offset(m_cache.dragging_center + offset);
+                    }
+                    volume.set_instance_rotation(new_rotation);
+                    object_instance_first[volume.object_idx()] = i;
+                }
+            };
+
+            for (unsigned int i : m_list)
+            {
+                GLVolume &volume = *(*m_volumes)[i];
+                if (is_single_full_instance())
+                    rotate_instance(volume, i);
+                else if (is_single_volume() || is_single_modifier())
+                {
+                    if (transformation_type.independent())
+                        volume.set_volume_rotation(volume.get_volume_rotation() + rotation);
+                    else
+                    {
+                        Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
+                        Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
+                        volume.set_volume_rotation(new_rotation);
+                    }
+                }
+                else
+                {
+                    if (m_mode == Instance)
+                        rotate_instance(volume, i);
+                    else if (m_mode == Volume)
+                    {
+                        // extracts rotations from the composed transformation
+                        Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation);
+                        Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix());
+                        if (transformation_type.joint())
+                        {
+                            Vec3d local_pivot = m_cache.volumes_data[i].get_instance_full_matrix().inverse() * m_cache.dragging_center;
+                            Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() - local_pivot);
+                            volume.set_volume_offset(local_pivot + offset);
+                        }
+                        volume.set_volume_rotation(new_rotation);
+                    }
+                }
+            }
+        }
+
+    #if !DISABLE_INSTANCES_SYNCH
+        if (m_mode == Instance)
+            synchronize_unselected_instances((rot_axis_max == 2) ? SYNC_ROTATION_NONE : SYNC_ROTATION_GENERAL);
+        else if (m_mode == Volume)
+            synchronize_unselected_volumes();
+    #endif // !DISABLE_INSTANCES_SYNCH
+    }
+    else { // it's the wipe tower that's selected and being rotated
+        GLVolume& volume = *((*m_volumes)[*m_list.begin()]); // the wipe tower is always alone in the selection
+
+        // make sure the wipe tower rotates around its center, not origin
+        // we can assume that only Z rotation changes
+        Vec3d center_local = volume.transformed_bounding_box().center() - volume.get_volume_offset();
+        Vec3d center_local_new = Eigen::AngleAxisd(rotation(2)-volume.get_volume_rotation()(2), Vec3d(0, 0, 1)) * center_local;
+        volume.set_volume_rotation(rotation);
+        volume.set_volume_offset(volume.get_volume_offset() + center_local - center_local_new);
+    }
 
     m_bounding_box_dirty = true;
 }

From e9a53e49dba0c10aebad555cedb86d9be405ffd3 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Mon, 29 Apr 2019 14:32:02 +0200
Subject: [PATCH 2/8] Arrange is accounting for the wipe tower now

---
 src/libslic3r/ModelArrange.cpp            | 66 +++++++++++++++++------
 src/libslic3r/ModelArrange.hpp            | 14 ++++-
 src/slic3r/GUI/3DScene.cpp                |  3 --
 src/slic3r/GUI/GLCanvas3D.cpp             | 33 ++++++++++++
 src/slic3r/GUI/GLCanvas3D.hpp             |  4 ++
 src/slic3r/GUI/Gizmos/GLGizmosManager.cpp |  2 +-
 src/slic3r/GUI/Plater.cpp                 | 17 +++++-
 7 files changed, 114 insertions(+), 25 deletions(-)

diff --git a/src/libslic3r/ModelArrange.cpp b/src/libslic3r/ModelArrange.cpp
index 50901da3a..493d820e0 100644
--- a/src/libslic3r/ModelArrange.cpp
+++ b/src/libslic3r/ModelArrange.cpp
@@ -539,7 +539,7 @@ public:
 // 2D shape from top view.
 using ShapeData2D = std::vector<std::pair<Slic3r::ModelInstance*, Item>>;
 
-ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
+ShapeData2D projectModelFromTop(const Slic3r::Model &model, const WipeTowerInfo& wti) {
     ShapeData2D ret;
 
     // Count all the items on the bin (all the object's instances)
@@ -595,6 +595,28 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
         }
     }
 
+    // The wipe tower is a separate case (in case there is one), let's duplicate the code
+    if (wti.is_wipe_tower) {
+        Points pts;
+        pts.emplace_back(coord_t(scale_(0.)), coord_t(scale_(0.)));
+        pts.emplace_back(coord_t(scale_(wti.bb_size(0))), coord_t(scale_(0.)));
+        pts.emplace_back(coord_t(scale_(wti.bb_size(0))), coord_t(scale_(wti.bb_size(1))));
+        pts.emplace_back(coord_t(scale_(-0.)), coord_t(scale_(wti.bb_size(1))));
+        pts.emplace_back(coord_t(scale_(-0.)), coord_t(scale_(0.)));
+        Polygon p(std::move(pts));
+        ClipperLib::Path clpath = Slic3rMultiPoint_to_ClipperPath(p);
+        ClipperLib::Polygon pn;
+        pn.Contour = clpath;
+        // Efficient conversion to item.
+        Item item(std::move(pn));
+        item.rotation(wti.rotation),
+        item.translation({
+        ClipperLib::cInt(wti.pos(0)/SCALING_FACTOR),
+        ClipperLib::cInt(wti.pos(1)/SCALING_FACTOR)
+        });
+        ret.emplace_back(nullptr, item);
+    }
+
     return ret;
 }
 
@@ -603,7 +625,8 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
 void applyResult(
         IndexedPackGroup::value_type& group,
         Coord batch_offset,
-        ShapeData2D& shapemap)
+        ShapeData2D& shapemap,
+        WipeTowerInfo& wti)
 {
     for(auto& r : group) {
         auto idx = r.first;     // get the original item index
@@ -612,18 +635,25 @@ void applyResult(
         // Get the model instance from the shapemap using the index
         ModelInstance *inst_ptr = shapemap[idx].first;
 
-        // Get the transformation data from the item object and scale it
-        // appropriately
-        auto off = item.translation();
-        Radians rot = item.rotation();
+            // Get the transformation data from the item object and scale it
+            // appropriately
+            auto off = item.translation();
+            Radians rot = item.rotation();
 
-        Vec3d foff(off.X*SCALING_FACTOR + batch_offset,
-                   off.Y*SCALING_FACTOR,
-                   inst_ptr->get_offset()(Z));
+            Vec3d foff(off.X*SCALING_FACTOR + batch_offset,
+                       off.Y*SCALING_FACTOR,
+                       inst_ptr ? inst_ptr->get_offset()(Z) : 0.);
 
-        // write the transformation data into the model instance
-        inst_ptr->set_rotation(Z, rot);
-        inst_ptr->set_offset(foff);
+        if (inst_ptr) {
+            // write the transformation data into the model instance
+            inst_ptr->set_rotation(Z, rot);
+            inst_ptr->set_offset(foff);
+        }
+        else { // this is the wipe tower - we will modify the struct with the info
+               // and leave it up to the called to actually move the wipe tower
+            wti.pos = Vec2d(foff(0), foff(1));
+            wti.rotation = rot;
+        }
     }
 }
 
@@ -709,6 +739,7 @@ BedShapeHint bedShape(const Polyline &bed) {
 // The final client function to arrange the Model. A progress indicator and
 // a stop predicate can be also be passed to control the process.
 bool arrange(Model &model,              // The model with the geometries
+             WipeTowerInfo& wti,        // Wipe tower info
              coord_t min_obj_distance,  // Has to be in scaled (clipper) measure
              const Polyline &bed,       // The bed geometry.
              BedShapeHint bedhint,      // Hint about the bed geometry type.
@@ -721,7 +752,7 @@ bool arrange(Model &model,              // The model with the geometries
     bool ret = true;
 
     // Get the 2D projected shapes with their 3D model instance pointers
-    auto shapemap = arr::projectModelFromTop(model);
+    auto shapemap = arr::projectModelFromTop(model, wti);
 
     // Copy the references for the shapes only as the arranger expects a
     // sequence of objects convertible to Item or ClipperPolygon
@@ -791,7 +822,7 @@ bool arrange(Model &model,              // The model with the geometries
     if(result.empty() || stopcondition()) return false;
 
     if(first_bin_only) {
-        applyResult(result.front(), 0, shapemap);
+        applyResult(result.front(), 0, shapemap, wti);
     } else {
 
         const auto STRIDE_PADDING = 1.2;
@@ -801,7 +832,7 @@ bool arrange(Model &model,              // The model with the geometries
         Coord batch_offset = 0;
 
         for(auto& group : result) {
-            applyResult(group, batch_offset, shapemap);
+            applyResult(group, batch_offset, shapemap, wti);
 
             // Only the first pack group can be placed onto the print bed. The
             // other objects which could not fit will be placed next to the
@@ -818,10 +849,11 @@ bool arrange(Model &model,              // The model with the geometries
 void find_new_position(const Model &model,
                        ModelInstancePtrs toadd,
                        coord_t min_obj_distance,
-                       const Polyline &bed)
+                       const Polyline &bed,
+                       WipeTowerInfo& wti)
 {
     // Get the 2D projected shapes with their 3D model instance pointers
-    auto shapemap = arr::projectModelFromTop(model);
+    auto shapemap = arr::projectModelFromTop(model, wti);
 
     // Copy the references for the shapes only as the arranger expects a
     // sequence of objects convertible to Item or ClipperPolygon
diff --git a/src/libslic3r/ModelArrange.hpp b/src/libslic3r/ModelArrange.hpp
index d76769081..b61443da0 100644
--- a/src/libslic3r/ModelArrange.hpp
+++ b/src/libslic3r/ModelArrange.hpp
@@ -40,6 +40,13 @@ struct BedShapeHint {
 
 BedShapeHint bedShape(const Polyline& bed);
 
+struct WipeTowerInfo {
+    bool is_wipe_tower = false;
+    Vec2d pos;
+    Vec2d bb_size;
+    double rotation;
+};
+
 /**
  * \brief Arranges the model objects on the screen.
  *
@@ -66,7 +73,9 @@ BedShapeHint bedShape(const Polyline& bed);
  * packed. The unsigned argument is the number of items remaining to pack.
  * \param stopcondition A predicate returning true if abort is needed.
  */
-bool arrange(Model &model, coord_t min_obj_distance,
+bool arrange(Model &model,
+             WipeTowerInfo& wipe_tower_info,
+             coord_t min_obj_distance,
              const Slic3r::Polyline& bed,
              BedShapeHint bedhint,
              bool first_bin_only,
@@ -78,7 +87,8 @@ bool arrange(Model &model, coord_t min_obj_distance,
 void find_new_position(const Model& model,
                        ModelInstancePtrs instances_to_add,
                        coord_t min_obj_distance,
-                       const Slic3r::Polyline& bed);
+                       const Slic3r::Polyline& bed,
+                       WipeTowerInfo& wti);
 
 }   // arr
 }   // Slic3r
diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp
index 8bd95e372..c3d5c1395 100644
--- a/src/slic3r/GUI/3DScene.cpp
+++ b/src/slic3r/GUI/3DScene.cpp
@@ -709,9 +709,6 @@ int GLVolumeCollection::load_wipe_tower_preview(
     brim_mesh.translate(-brim_width, -brim_width, 0.f);
     mesh.merge(brim_mesh);
 
-    //mesh.rotate(rotation_angle, &origin_of_rotation); // rotates the box according to the config rotation setting
-    
-
     this->volumes.emplace_back(new GLVolume(color));
     GLVolume &v = *this->volumes.back();
     v.indexed_vertex_array.load_mesh(mesh, use_VBOs);
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index cc7514e54..eca621051 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -16,6 +16,7 @@
 #include "slic3r/GUI/GLShader.hpp"
 #include "slic3r/GUI/GUI.hpp"
 #include "slic3r/GUI/PresetBundle.hpp"
+#include "slic3r/GUI/Tab.hpp"
 #include "GUI_App.hpp"
 #include "GUI_ObjectList.hpp"
 #include "GUI_ObjectManipulation.hpp"
@@ -3291,6 +3292,38 @@ void GLCanvas3D::update_ui_from_settings()
 #endif
 }
 
+
+
+arr::WipeTowerInfo GLCanvas3D::get_wipe_tower_info() const
+{
+    arr::WipeTowerInfo wti;
+    for (const GLVolume* vol : m_volumes.volumes) {
+        if (vol->is_wipe_tower) {
+            wti.is_wipe_tower = true;
+            wti.pos = Vec2d(m_config->opt_float("wipe_tower_x"),
+                            m_config->opt_float("wipe_tower_y"));
+            wti.rotation = (M_PI/180.) * m_config->opt_float("wipe_tower_rotation_angle");
+            const BoundingBoxf3& bb = vol->bounding_box;
+            wti.bb_size = Vec2d(bb.size()(0), bb.size()(1));
+            break;
+        }
+    }
+    return wti;
+}
+
+
+void GLCanvas3D::arrange_wipe_tower(const arr::WipeTowerInfo& wti) const
+{
+    if (wti.is_wipe_tower) {
+        DynamicPrintConfig cfg;
+        cfg.opt<ConfigOptionFloat>("wipe_tower_x", true)->value = wti.pos(0);
+        cfg.opt<ConfigOptionFloat>("wipe_tower_y", true)->value = wti.pos(1);
+        cfg.opt<ConfigOptionFloat>("wipe_tower_rotation_angle", true)->value = (180./M_PI) * wti.rotation;
+        wxGetApp().get_tab(Preset::TYPE_PRINT)->load_config(cfg);
+    }
+}
+
+
 Linef3 GLCanvas3D::mouse_ray(const Point& mouse_pos)
 {
     float z0 = 0.0f;
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index 086209872..ce4c7df74 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -4,6 +4,7 @@
 #include <stddef.h>
 #include <memory>
 
+#include "libslic3r/ModelArrange.hpp"
 #include "3DScene.hpp"
 #include "GLToolbar.hpp"
 #include "Event.hpp"
@@ -608,6 +609,9 @@ public:
     int get_move_volume_id() const { return m_mouse.drag.move_volume_idx; }
     int get_first_hover_volume_idx() const { return m_hover_volume_idxs.empty() ? -1 : m_hover_volume_idxs.front(); }
 
+    arr::WipeTowerInfo get_wipe_tower_info() const;
+    void arrange_wipe_tower(const arr::WipeTowerInfo& wti) const;
+
     // Returns the view ray line, in world coordinate, at the given mouse position.
     Linef3 mouse_ray(const Point& mouse_pos);
 
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
index 7cc28ee78..7af1f5400 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
@@ -270,7 +270,7 @@ void GLGizmosManager::update_data(GLCanvas3D& canvas)
     enable_grabber(Move, 2, !is_wipe_tower);
     enable_grabber(Rotate, 0, !is_wipe_tower);
     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)
     {
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 31b0d9f3a..b770a7660 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -1869,7 +1869,13 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
     Polyline bed; bed.points.reserve(bedpoints.size());
     for(auto& v : bedpoints) bed.append(Point::new_scale(v(0), v(1)));
 
-    arr::find_new_position(model, new_instances, min_obj_distance, bed);
+    arr::WipeTowerInfo wti = view3D->get_canvas3d()->get_wipe_tower_info();
+
+    arr::find_new_position(model, new_instances, min_obj_distance, bed, wti);
+
+    // it remains to move the wipe tower:
+    view3D->get_canvas3d()->arrange_wipe_tower(wti);
+
 #endif /* AUTOPLACEMENT_ON_LOAD */
 
     if (scaled_down) {
@@ -2126,6 +2132,8 @@ void Plater::priv::arrange()
 
     statusfn(0, arrangestr);
 
+    arr::WipeTowerInfo wti = view3D->get_canvas3d()->get_wipe_tower_info();
+
     try {
         arr::BedShapeHint hint;
 
@@ -2133,6 +2141,7 @@ void Plater::priv::arrange()
         hint.type = arr::BedShapeType::WHO_KNOWS;
 
         arr::arrange(model,
+                     wti,
                      min_obj_distance,
                      bed,
                      hint,
@@ -2144,6 +2153,9 @@ void Plater::priv::arrange()
                                    "Some geometries may be invalid."));
     }
 
+    // it remains to move the wipe tower:
+    view3D->get_canvas3d()->arrange_wipe_tower(wti);
+
     statusfn(0, L("Arranging done."));
     statusbar()->set_range(prev_range);
     statusbar()->set_cancel_callback(); // remove cancel button
@@ -2246,7 +2258,8 @@ void Plater::priv::sla_optimize_rotation() {
         oi->set_rotation(rt);
     }
 
-    arr::find_new_position(model, o->instances, coord_t(mindist/SCALING_FACTOR), bed);
+    arr::WipeTowerInfo wti; // useless in SLA context
+    arr::find_new_position(model, o->instances, coord_t(mindist/SCALING_FACTOR), bed, wti);
 
     // Correct the z offset of the object which was corrupted be the rotation
     o->ensure_on_bed();

From 39be95f0f6d66a2a8a2b09c372890de3d76e1757 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 10 May 2019 11:05:54 +0200
Subject: [PATCH 3/8] Fixed SPE-913 (Slicer do not display all extruders when
 it is started with SLA profile)

+ Updated POT-file
---
 resources/localization/Slic3rPE.pot | 14 ++++++++++++--
 src/slic3r/GUI/Tab.cpp              | 15 ++++++++++++++-
 2 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/resources/localization/Slic3rPE.pot b/resources/localization/Slic3rPE.pot
index e2f4a6ec2..7e31401c4 100644
--- a/resources/localization/Slic3rPE.pot
+++ b/resources/localization/Slic3rPE.pot
@@ -2161,8 +2161,13 @@ msgid "Iso View"
 msgstr ""
 
 #. TRN To be shown in the main menu View->Top
+#: src/slic3r/GUI/MainFrame.cpp:527
+msgctxt "Layers"
+msgid "Top"
+msgstr ""
+
 #. TRN To be shown in Print Settings "Top solid layers"
-#: src/slic3r/GUI/MainFrame.cpp:527 src/libslic3r/PrintConfig.cpp:2068
+#: src/libslic3r/PrintConfig.cpp:2068
 msgid "Top"
 msgstr ""
 
@@ -2171,8 +2176,13 @@ msgid "Top View"
 msgstr ""
 
 #. TRN To be shown in the main menu View->Bottom
+#: src/slic3r/GUI/MainFrame.cpp:529
+msgid "Bottom"
+msgstr ""
+
 #. TRN To be shown in Print Settings "Bottom solid layers"
-#: src/slic3r/GUI/MainFrame.cpp:529 src/libslic3r/PrintConfig.cpp:150
+#: src/libslic3r/PrintConfig.cpp:150
+msgctxt "Layers"
 msgid "Bottom"
 msgstr ""
 
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index 3a1b5d37d..4e2403914 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -2333,7 +2333,20 @@ void TabPrinter::update_pages()
     // set m_pages_(technology after changing) to m_pages
     // m_printer_technology will be set by Tab::load_current_preset()
     if (new_printer_technology == ptFFF)
-        m_pages_fff.empty() ? build_fff() : m_pages.swap(m_pages_fff);
+    {
+        if (m_pages_fff.empty())
+        {
+            build_fff();
+            if (m_extruders_count > 1)
+            {
+                m_preset_bundle->update_multi_material_filament_presets();
+                on_value_change("extruders_count", m_extruders_count);
+                wxGetApp().sidebar().update_objects_list_extruder_column(m_extruders_count);
+            }
+        }
+        else
+            m_pages.swap(m_pages_fff);
+    }
     else 
         m_pages_sla.empty() ? build_sla() : m_pages.swap(m_pages_sla);
 

From 5dbcec5126931b38a8ed4c595e1fc9438b5124b5 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Fri, 10 May 2019 11:29:21 +0200
Subject: [PATCH 4/8] Turn off the SLA gizmo when switching to FFF printer
 profile

---
 src/slic3r/GUI/GLCanvas3D.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index deb55c986..07a189275 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -2073,6 +2073,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
 	}
 
     m_gizmos.update_data(*this);
+    m_gizmos.refresh_on_off_state(m_selection);
 
     // Update the toolbar
 	if (update_object_list)

From c9f79655992d447181013b16722fdc2c998d89f1 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Fri, 10 May 2019 11:44:21 +0200
Subject: [PATCH 5/8] Reverted a change in number text formatting. Fixed some
 message wording.

---
 src/slic3r/GUI/Field.cpp      | 26 +++++++++++++++++++++++++-
 src/slic3r/GUI/GLCanvas3D.cpp |  8 ++++----
 2 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp
index edc65aca0..9443f3658 100644
--- a/src/slic3r/GUI/Field.cpp
+++ b/src/slic3r/GUI/Field.cpp
@@ -15,7 +15,31 @@ namespace Slic3r { namespace GUI {
 
 wxString double_to_string(double const value, const int max_precision /*= 4*/)
 {
-	return wxNumberFormatter::ToString(value, max_precision, wxNumberFormatter::Style_NoTrailingZeroes);
+// Style_NoTrailingZeroes does not work on OSX. It also does not work correctly with some locales on Windows.
+//	return wxNumberFormatter::ToString(value, max_precision, wxNumberFormatter::Style_NoTrailingZeroes);
+
+	wxString s = wxNumberFormatter::ToString(value, max_precision, wxNumberFormatter::Style_None);
+
+	// The following code comes from wxNumberFormatter::RemoveTrailingZeroes(wxString& s)
+	// with the exception that here one sets the decimal separator explicitely to dot.
+    // If number is in scientific format, trailing zeroes belong to the exponent and cannot be removed.
+    if (s.find_first_of("eE") == wxString::npos) {
+	    const size_t posDecSep = s.find(".");
+	    // No decimal point => removing trailing zeroes irrelevant for integer number.
+	    if (posDecSep != wxString::npos) {
+		    // Find the last character to keep.
+		    size_t posLastNonZero = s.find_last_not_of("0");
+		    // If it's the decimal separator itself, don't keep it neither.
+		    if (posLastNonZero == posDecSep)
+		        -- posLastNonZero;
+		    s.erase(posLastNonZero + 1);
+		    // Remove sign from orphaned zero.
+		    if (s.compare("-0") == 0)
+		        s = "0";
+		}
+	}
+
+    return s;
 }
 
 void Field::PostInitialize()
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 80815c8be..084762a80 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -716,12 +716,12 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool
     std::string text;
     bool red_colored = false;
     switch (m_warnings.back()) {
-        case ObjectOutside      : text = L("Detected object outside print volume"); break;
-        case ToolpathOutside    : text = L("Detected toolpath outside print volume"); break;
+        case ObjectOutside      : text = L("An object outside the print area was detected"); break;
+        case ToolpathOutside    : text = L("A toolpath outside the print area was detected"); break;
         case SomethingNotShown  : text = L("Some objects are not visible when editing supports"); break;
         case ObjectClashed: {
-            text = L("Detected object outside print volume\n"
-                     "Resolve a clash to continue slicing/export process correctly"); 
+            text = L("An object outside the print area was detected\n"
+                     "Resolve the current problem to continue slicing");
             red_colored = true;
             break;
         }

From baa8bace8dd6ed84ed2c1e5e8b958a4f0db88096 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Fri, 10 May 2019 11:44:47 +0200
Subject: [PATCH 6/8] Removed duplicated line

---
 src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
index 143233bf5..7c1a7037c 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
@@ -267,7 +267,6 @@ void GLGizmosManager::update_data(GLCanvas3D& canvas)
 
     bool is_wipe_tower = selection.is_wipe_tower();
     enable_grabber(Move, 2, !is_wipe_tower);
-    enable_grabber(Move, 2, !is_wipe_tower);
     enable_grabber(Rotate, 0, !is_wipe_tower);
     enable_grabber(Rotate, 1, !is_wipe_tower);
 

From 580447317134f665a267f7291ef5b7378f676b11 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 10 May 2019 11:49:47 +0200
Subject: [PATCH 7/8] Localization improvements New list.txt and POT

---
 resources/localization/Slic3rPE.pot | 236 +++++++++++++++++-----------
 resources/localization/list.txt     |   2 +
 src/slic3r/GUI/GUI_App.cpp          |   2 +-
 src/slic3r/GUI/Tab.hpp              |  10 +-
 4 files changed, 153 insertions(+), 97 deletions(-)

diff --git a/resources/localization/Slic3rPE.pot b/resources/localization/Slic3rPE.pot
index 7e31401c4..9ab29d6c8 100644
--- a/resources/localization/Slic3rPE.pot
+++ b/resources/localization/Slic3rPE.pot
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-05-09 19:23+0200\n"
+"POT-Creation-Date: 2019-05-10 11:46+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -46,6 +46,33 @@ msgid ""
 "numerous others."
 msgstr ""
 
+#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:84
+#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:400
+msgid "Copying of the temporary G-code to the output G-code failed"
+msgstr ""
+
+#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:85
+#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:398
+msgid "Running post-processing scripts"
+msgstr ""
+
+#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:87
+msgid "G-code file exported to %1%"
+msgstr ""
+
+#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:91
+#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:109
+msgid "Slicing complete"
+msgstr ""
+
+#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:105
+msgid "Masked SLA file exported to %1%"
+msgstr ""
+
+#: src/slic3r/GUI/BackgroundSlicingProcess.cpp:409
+msgid "Scheduling upload to `%1%`. See Window -> Print Host Upload Queue"
+msgstr ""
+
 #: src/slic3r/GUI/BedShapeDialog.cpp:60
 msgid "Shape"
 msgstr ""
@@ -225,6 +252,7 @@ msgid "slic3r version"
 msgstr ""
 
 #: src/slic3r/GUI/ConfigSnapshotDialog.cpp:46 src/slic3r/GUI/Preset.cpp:1274
+#: src/slic3r/GUI/Tab.hpp:315
 msgid "print"
 msgstr ""
 
@@ -233,6 +261,7 @@ msgid "filaments"
 msgstr ""
 
 #: src/slic3r/GUI/ConfigSnapshotDialog.cpp:48 src/slic3r/GUI/Preset.cpp:1278
+#: src/slic3r/GUI/Tab.hpp:366
 msgid "printer"
 msgstr ""
 
@@ -285,7 +314,7 @@ msgstr ""
 msgid "All standard"
 msgstr ""
 
-#: src/slic3r/GUI/ConfigWizard.cpp:189 src/slic3r/GUI/Tab.cpp:2987
+#: src/slic3r/GUI/ConfigWizard.cpp:189 src/slic3r/GUI/Tab.cpp:3000
 msgid "All"
 msgstr ""
 
@@ -703,58 +732,62 @@ msgid "Detected toolpath outside print volume"
 msgstr ""
 
 #: src/slic3r/GUI/GLCanvas3D.cpp:721
+msgid "Detected support outside print volume"
+msgstr ""
+
+#: src/slic3r/GUI/GLCanvas3D.cpp:722
 msgid "Some objects are not visible when editing supports"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:723
+#: src/slic3r/GUI/GLCanvas3D.cpp:724
 msgid ""
 "Detected object outside print volume\n"
 "Resolve a clash to continue slicing/export process correctly"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3392
+#: src/slic3r/GUI/GLCanvas3D.cpp:3395
 msgid "Add..."
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3402 src/slic3r/GUI/GUI_ObjectList.cpp:1269
+#: src/slic3r/GUI/GLCanvas3D.cpp:3405 src/slic3r/GUI/GUI_ObjectList.cpp:1269
 #: src/slic3r/GUI/Plater.cpp:2908 src/slic3r/GUI/Plater.cpp:2926
-#: src/slic3r/GUI/Tab.cpp:2938
+#: src/slic3r/GUI/Tab.cpp:2951
 msgid "Delete"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3413 src/slic3r/GUI/Plater.cpp:3316
+#: src/slic3r/GUI/GLCanvas3D.cpp:3416 src/slic3r/GUI/Plater.cpp:3316
 msgid "Delete all"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3424 src/slic3r/GUI/KBShortcutsDialog.cpp:135
+#: src/slic3r/GUI/GLCanvas3D.cpp:3427 src/slic3r/GUI/KBShortcutsDialog.cpp:135
 msgid "Arrange"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3438 src/slic3r/GUI/Tab.cpp:2879
+#: src/slic3r/GUI/GLCanvas3D.cpp:3441 src/slic3r/GUI/Tab.cpp:2892
 msgid "Copy"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3449
+#: src/slic3r/GUI/GLCanvas3D.cpp:3452
 msgid "Paste"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3463
+#: src/slic3r/GUI/GLCanvas3D.cpp:3466
 msgid "Add instance"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3475
+#: src/slic3r/GUI/GLCanvas3D.cpp:3478
 msgid "Remove instance"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3490
+#: src/slic3r/GUI/GLCanvas3D.cpp:3493
 msgid "Split to objects"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3502 src/slic3r/GUI/GUI_ObjectList.cpp:1122
+#: src/slic3r/GUI/GLCanvas3D.cpp:3505 src/slic3r/GUI/GUI_ObjectList.cpp:1122
 msgid "Split to parts"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3517
+#: src/slic3r/GUI/GLCanvas3D.cpp:3520
 msgid "Layers editing"
 msgstr ""
 
@@ -974,7 +1007,7 @@ msgstr ""
 msgid "Switch to editing mode"
 msgstr ""
 
-#: src/slic3r/GUI/GUI.cpp:142 src/slic3r/GUI/Tab.cpp:2797
+#: src/slic3r/GUI/GUI.cpp:142 src/slic3r/GUI/Tab.cpp:2810
 msgid "It's impossible to print multi-part object(s) with SLA technology."
 msgstr ""
 
@@ -982,7 +1015,7 @@ msgstr ""
 msgid "Please check and fix your object list."
 msgstr ""
 
-#: src/slic3r/GUI/GUI.cpp:144 src/slic3r/GUI/Tab.cpp:2799
+#: src/slic3r/GUI/GUI.cpp:144 src/slic3r/GUI/Tab.cpp:2812
 msgid "Attention!"
 msgstr ""
 
@@ -1067,7 +1100,7 @@ msgstr ""
 #: src/slic3r/GUI/GUI_ObjectList.cpp:539 src/slic3r/GUI/Tab.cpp:1027
 #: src/slic3r/GUI/Tab.cpp:1042 src/slic3r/GUI/Tab.cpp:1140
 #: src/slic3r/GUI/Tab.cpp:1143 src/slic3r/GUI/Tab.cpp:1516
-#: src/slic3r/GUI/Tab.cpp:1941 src/slic3r/GUI/Tab.cpp:3440
+#: src/slic3r/GUI/Tab.cpp:1941 src/slic3r/GUI/Tab.cpp:3453
 #: src/slic3r/GUI/wxExtensions.cpp:2510 src/libslic3r/PrintConfig.cpp:73
 #: src/libslic3r/PrintConfig.cpp:188 src/libslic3r/PrintConfig.cpp:351
 #: src/libslic3r/PrintConfig.cpp:989 src/libslic3r/PrintConfig.cpp:2200
@@ -1134,10 +1167,10 @@ msgid "&Configuration"
 msgstr ""
 
 #: src/slic3r/GUI/GUI_App.cpp:801
-msgid "The following presets were modified: "
+msgid "The following presets were modified"
 msgstr ""
 
-#: src/slic3r/GUI/GUI_App.cpp:801 src/slic3r/GUI/Tab.cpp:2785
+#: src/slic3r/GUI/GUI_App.cpp:801 src/slic3r/GUI/Tab.cpp:2798
 msgid "Discard changes and continue anyway?"
 msgstr ""
 
@@ -1235,8 +1268,8 @@ msgid "Extrusion Width"
 msgstr ""
 
 #: src/slic3r/GUI/GUI_ObjectList.cpp:87 src/slic3r/GUI/GUI_ObjectList.cpp:541
-#: src/slic3r/GUI/Plater.cpp:429 src/slic3r/GUI/Tab.cpp:3402
-#: src/slic3r/GUI/Tab.cpp:3403 src/libslic3r/PrintConfig.cpp:2388
+#: src/slic3r/GUI/Plater.cpp:429 src/slic3r/GUI/Tab.cpp:3415
+#: src/slic3r/GUI/Tab.cpp:3416 src/libslic3r/PrintConfig.cpp:2388
 #: src/libslic3r/PrintConfig.cpp:2395 src/libslic3r/PrintConfig.cpp:2404
 #: src/libslic3r/PrintConfig.cpp:2413 src/libslic3r/PrintConfig.cpp:2423
 #: src/libslic3r/PrintConfig.cpp:2449 src/libslic3r/PrintConfig.cpp:2456
@@ -1248,7 +1281,7 @@ msgid "Supports"
 msgstr ""
 
 #: src/slic3r/GUI/GUI_ObjectList.cpp:88 src/slic3r/GUI/GUI_ObjectList.cpp:542
-#: src/slic3r/GUI/Tab.cpp:3430 src/slic3r/GUI/Tab.cpp:3431
+#: src/slic3r/GUI/Tab.cpp:3443 src/slic3r/GUI/Tab.cpp:3444
 #: src/libslic3r/PrintConfig.cpp:2541 src/libslic3r/PrintConfig.cpp:2548
 #: src/libslic3r/PrintConfig.cpp:2562 src/libslic3r/PrintConfig.cpp:2572
 #: src/libslic3r/PrintConfig.cpp:2585 src/libslic3r/PrintConfig.cpp:2594
@@ -1460,13 +1493,13 @@ msgid "Renaming"
 msgstr ""
 
 #: src/slic3r/GUI/GUI_ObjectList.cpp:2730
-#: src/slic3r/GUI/GUI_ObjectList.cpp:2824 src/slic3r/GUI/Tab.cpp:3283
-#: src/slic3r/GUI/Tab.cpp:3287
+#: src/slic3r/GUI/GUI_ObjectList.cpp:2824 src/slic3r/GUI/Tab.cpp:3296
+#: src/slic3r/GUI/Tab.cpp:3300
 msgid "The supplied name is not valid;"
 msgstr ""
 
 #: src/slic3r/GUI/GUI_ObjectList.cpp:2731
-#: src/slic3r/GUI/GUI_ObjectList.cpp:2825 src/slic3r/GUI/Tab.cpp:3284
+#: src/slic3r/GUI/GUI_ObjectList.cpp:2825 src/slic3r/GUI/Tab.cpp:3297
 msgid "the following characters are not allowed:"
 msgstr ""
 
@@ -2348,7 +2381,7 @@ msgstr ""
 msgid "File Not Found"
 msgstr ""
 
-#: src/slic3r/GUI/MainFrame.cpp:686 src/slic3r/GUI/Tab.cpp:3244
+#: src/slic3r/GUI/MainFrame.cpp:686 src/slic3r/GUI/Tab.cpp:3257
 msgid "Save "
 msgstr ""
 
@@ -2370,7 +2403,7 @@ msgstr ""
 
 #: src/slic3r/GUI/MainFrame.cpp:713 src/slic3r/GUI/Plater.cpp:2423
 #: src/slic3r/GUI/Plater.cpp:3633 src/slic3r/GUI/Tab.cpp:1160
-#: src/slic3r/GUI/Tab.cpp:3441
+#: src/slic3r/GUI/Tab.cpp:3454
 msgid "Slicing"
 msgstr ""
 
@@ -2992,7 +3025,7 @@ msgstr ""
 msgid "Add a new printer"
 msgstr ""
 
-#: src/slic3r/GUI/Preset.cpp:1275
+#: src/slic3r/GUI/Preset.cpp:1275 src/slic3r/GUI/Tab.hpp:333
 msgid "filament"
 msgstr ""
 
@@ -3294,7 +3327,7 @@ msgstr ""
 msgid "default SLA print profile"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:998 src/slic3r/GUI/Tab.cpp:3396
+#: src/slic3r/GUI/Tab.cpp:998 src/slic3r/GUI/Tab.cpp:3409
 msgid "Layers and perimeters"
 msgstr ""
 
@@ -3378,7 +3411,7 @@ msgstr ""
 msgid "Other"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:1169 src/slic3r/GUI/Tab.cpp:3444
+#: src/slic3r/GUI/Tab.cpp:1169 src/slic3r/GUI/Tab.cpp:3457
 msgid "Output options"
 msgstr ""
 
@@ -3390,7 +3423,7 @@ msgstr ""
 msgid "Extruder clearance (mm)"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:1181 src/slic3r/GUI/Tab.cpp:3445
+#: src/slic3r/GUI/Tab.cpp:1181 src/slic3r/GUI/Tab.cpp:3458
 msgid "Output file"
 msgstr ""
 
@@ -3402,19 +3435,19 @@ msgstr ""
 #: src/slic3r/GUI/Tab.cpp:1577 src/slic3r/GUI/Tab.cpp:1578
 #: src/slic3r/GUI/Tab.cpp:1986 src/slic3r/GUI/Tab.cpp:1987
 #: src/slic3r/GUI/Tab.cpp:2080 src/slic3r/GUI/Tab.cpp:2081
-#: src/slic3r/GUI/Tab.cpp:3333 src/slic3r/GUI/Tab.cpp:3334
+#: src/slic3r/GUI/Tab.cpp:3346 src/slic3r/GUI/Tab.cpp:3347
 msgid "Notes"
 msgstr ""
 
 #: src/slic3r/GUI/Tab.cpp:1201 src/slic3r/GUI/Tab.cpp:1585
 #: src/slic3r/GUI/Tab.cpp:1993 src/slic3r/GUI/Tab.cpp:2087
-#: src/slic3r/GUI/Tab.cpp:3341 src/slic3r/GUI/Tab.cpp:3450
+#: src/slic3r/GUI/Tab.cpp:3354 src/slic3r/GUI/Tab.cpp:3463
 msgid "Dependencies"
 msgstr ""
 
 #: src/slic3r/GUI/Tab.cpp:1202 src/slic3r/GUI/Tab.cpp:1586
 #: src/slic3r/GUI/Tab.cpp:1994 src/slic3r/GUI/Tab.cpp:2088
-#: src/slic3r/GUI/Tab.cpp:3342 src/slic3r/GUI/Tab.cpp:3451
+#: src/slic3r/GUI/Tab.cpp:3355 src/slic3r/GUI/Tab.cpp:3464
 msgid "Profile dependencies"
 msgstr ""
 
@@ -3586,7 +3619,7 @@ msgid "Size and coordinates"
 msgstr ""
 
 #: src/slic3r/GUI/Tab.cpp:1819 src/slic3r/GUI/Tab.cpp:2020
-#: src/slic3r/GUI/Tab.cpp:2989
+#: src/slic3r/GUI/Tab.cpp:3002
 msgid " Set "
 msgstr ""
 
@@ -3650,7 +3683,7 @@ msgstr ""
 msgid "Tilt time"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2060 src/slic3r/GUI/Tab.cpp:3315
+#: src/slic3r/GUI/Tab.cpp:2060 src/slic3r/GUI/Tab.cpp:3328
 msgid "Corrections"
 msgstr ""
 
@@ -3729,104 +3762,104 @@ msgid ""
 "setups)"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2430
+#: src/slic3r/GUI/Tab.cpp:2443
 msgid ""
 "The Wipe option is not available when using the Firmware Retraction mode.\n"
 "\n"
 "Shall I disable it in order to enable Firmware Retraction?"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2432
+#: src/slic3r/GUI/Tab.cpp:2445
 msgid "Firmware Retraction"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2758
+#: src/slic3r/GUI/Tab.cpp:2771
 #, possible-c-format
 msgid "Default preset (%s)"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2759
+#: src/slic3r/GUI/Tab.cpp:2772
 #, possible-c-format
 msgid "Preset (%s)"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2776
+#: src/slic3r/GUI/Tab.cpp:2789
 msgid "has the following unsaved changes:"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2779
+#: src/slic3r/GUI/Tab.cpp:2792
 msgid "is not compatible with printer"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2780
+#: src/slic3r/GUI/Tab.cpp:2793
 msgid "is not compatible with print profile"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2782
+#: src/slic3r/GUI/Tab.cpp:2795
 msgid "and it has the following unsaved changes:"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2786
+#: src/slic3r/GUI/Tab.cpp:2799
 msgid "Unsaved Changes"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2798
+#: src/slic3r/GUI/Tab.cpp:2811
 msgid "Please check your object list before preset changing."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2901
+#: src/slic3r/GUI/Tab.cpp:2914
 msgid "The supplied name is empty. It can't be saved."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2906
+#: src/slic3r/GUI/Tab.cpp:2919
 msgid "Cannot overwrite a system profile."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2910
+#: src/slic3r/GUI/Tab.cpp:2923
 msgid "Cannot overwrite an external profile."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2936
+#: src/slic3r/GUI/Tab.cpp:2949
 msgid "remove"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2936
+#: src/slic3r/GUI/Tab.cpp:2949
 msgid "delete"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2937
+#: src/slic3r/GUI/Tab.cpp:2950
 msgid "Are you sure you want to "
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2937
+#: src/slic3r/GUI/Tab.cpp:2950
 msgid " the selected preset?"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2938
+#: src/slic3r/GUI/Tab.cpp:2951
 msgid "Remove"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:2939
+#: src/slic3r/GUI/Tab.cpp:2952
 msgid " Preset"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3065
+#: src/slic3r/GUI/Tab.cpp:3078
 msgid "LOCKED LOCK"
 msgstr ""
 
 #. TRN Description for "LOCKED LOCK"
-#: src/slic3r/GUI/Tab.cpp:3067
+#: src/slic3r/GUI/Tab.cpp:3080
 msgid ""
 "indicates that the settings are the same as the system values for the "
 "current option group"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3069
+#: src/slic3r/GUI/Tab.cpp:3082
 msgid "UNLOCKED LOCK"
 msgstr ""
 
 #. TRN Description for "UNLOCKED LOCK"
-#: src/slic3r/GUI/Tab.cpp:3071
+#: src/slic3r/GUI/Tab.cpp:3084
 msgid ""
 "indicates that some settings were changed and are not equal to the system "
 "values for the current option group.\n"
@@ -3834,23 +3867,23 @@ msgid ""
 "to the system values."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3076
+#: src/slic3r/GUI/Tab.cpp:3089
 msgid "WHITE BULLET"
 msgstr ""
 
 #. TRN Description for "WHITE BULLET"
-#: src/slic3r/GUI/Tab.cpp:3078
+#: src/slic3r/GUI/Tab.cpp:3091
 msgid ""
 "for the left button: \tindicates a non-system preset,\n"
 "for the right button: \tindicates that the settings hasn't been modified."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3081
+#: src/slic3r/GUI/Tab.cpp:3094
 msgid "BACK ARROW"
 msgstr ""
 
 #. TRN Description for "BACK ARROW"
-#: src/slic3r/GUI/Tab.cpp:3083
+#: src/slic3r/GUI/Tab.cpp:3096
 msgid ""
 "indicates that the settings were changed and are not equal to the last saved "
 "preset for the current option group.\n"
@@ -3858,30 +3891,30 @@ msgid ""
 "to the last saved preset."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3108
+#: src/slic3r/GUI/Tab.cpp:3121
 msgid ""
 "LOCKED LOCK icon indicates that the settings are the same as the system "
 "values for the current option group"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3110
+#: src/slic3r/GUI/Tab.cpp:3123
 msgid ""
 "UNLOCKED LOCK icon indicates that some settings were changed and are not "
 "equal to the system values for the current option group.\n"
 "Click to reset all settings for current option group to the system values."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3113
+#: src/slic3r/GUI/Tab.cpp:3126
 msgid "WHITE BULLET icon indicates a non system preset."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3116
+#: src/slic3r/GUI/Tab.cpp:3129
 msgid ""
 "WHITE BULLET icon indicates that the settings are the same as in the last "
 "saved preset for the current option group."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3118
+#: src/slic3r/GUI/Tab.cpp:3131
 msgid ""
 "BACK ARROW icon indicates that the settings were changed and are not equal "
 "to the last saved preset for the current option group.\n"
@@ -3889,84 +3922,84 @@ msgid ""
 "preset."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3124
+#: src/slic3r/GUI/Tab.cpp:3137
 msgid ""
 "LOCKED LOCK icon indicates that the value is the same as the system value."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3125
+#: src/slic3r/GUI/Tab.cpp:3138
 msgid ""
 "UNLOCKED LOCK icon indicates that the value was changed and is not equal to "
 "the system value.\n"
 "Click to reset current value to the system value."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3131
+#: src/slic3r/GUI/Tab.cpp:3144
 msgid ""
 "WHITE BULLET icon indicates that the value is the same as in the last saved "
 "preset."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3132
+#: src/slic3r/GUI/Tab.cpp:3145
 msgid ""
 "BACK ARROW icon indicates that the value was changed and is not equal to the "
 "last saved preset.\n"
 "Click to reset current value to the last saved preset."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3244
+#: src/slic3r/GUI/Tab.cpp:3257
 msgid " as:"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3288
+#: src/slic3r/GUI/Tab.cpp:3301
 msgid "the following postfix are not allowed:"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3292
+#: src/slic3r/GUI/Tab.cpp:3305
 msgid "The supplied name is not available."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3305
+#: src/slic3r/GUI/Tab.cpp:3318
 msgid "Material"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3307 src/slic3r/GUI/Tab.cpp:3398
+#: src/slic3r/GUI/Tab.cpp:3320 src/slic3r/GUI/Tab.cpp:3411
 msgid "Layers"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3311
+#: src/slic3r/GUI/Tab.cpp:3324
 msgid "Exposure"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3406
+#: src/slic3r/GUI/Tab.cpp:3419
 msgid "Support head"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3411
+#: src/slic3r/GUI/Tab.cpp:3424
 msgid "Support pillar"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3421
+#: src/slic3r/GUI/Tab.cpp:3434
 msgid "Connection of the support sticks and junctions"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3426
+#: src/slic3r/GUI/Tab.cpp:3439
 msgid "Automatic generation"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3488
+#: src/slic3r/GUI/Tab.cpp:3501
 msgid "Head penetration should not be greater than the head width."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3489
+#: src/slic3r/GUI/Tab.cpp:3502
 msgid "Invalid Head penetration"
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3501
+#: src/slic3r/GUI/Tab.cpp:3514
 msgid "Pinhead diameter should be smaller than the pillar diameter."
 msgstr ""
 
-#: src/slic3r/GUI/Tab.cpp:3502
+#: src/slic3r/GUI/Tab.cpp:3515
 msgid "Invalid pinhead diameter"
 msgstr ""
 
@@ -3986,6 +4019,14 @@ msgstr ""
 msgid "Material Settings"
 msgstr ""
 
+#: src/slic3r/GUI/Tab.hpp:389
+msgid "sla_material"
+msgstr ""
+
+#: src/slic3r/GUI/Tab.hpp:403
+msgid "sla_print"
+msgstr ""
+
 #: src/slic3r/GUI/Tab.hpp:415
 msgid "Save preset"
 msgstr ""
@@ -4813,6 +4854,7 @@ msgstr ""
 #: src/libslic3r/PrintConfig.cpp:1595 src/libslic3r/PrintConfig.cpp:1605
 #: src/libslic3r/PrintConfig.cpp:1833 src/libslic3r/PrintConfig.cpp:1987
 #: src/libslic3r/PrintConfig.cpp:2171 src/libslic3r/PrintConfig.cpp:2488
+#: src/libslic3r/PrintConfig.cpp:2597
 msgid "°"
 msgstr ""
 
@@ -7298,10 +7340,6 @@ msgid ""
 "straight walls."
 msgstr ""
 
-#: src/libslic3r/PrintConfig.cpp:2597
-msgid "degrees"
-msgstr ""
-
 #: src/libslic3r/PrintConfig.cpp:2957
 msgid "Export OBJ"
 msgstr ""
@@ -7555,6 +7593,22 @@ msgid ""
 "loaded instead of the default OpenGL driver."
 msgstr ""
 
+#: src/libslic3r/PrintObject.cpp:110
+msgid "Processing triangulated mesh"
+msgstr ""
+
+#: src/libslic3r/PrintObject.cpp:141
+msgid "Generating perimeters"
+msgstr ""
+
+#: src/libslic3r/PrintObject.cpp:251
+msgid "Preparing infill"
+msgstr ""
+
+#: src/libslic3r/PrintObject.cpp:391
+msgid "Generating support material"
+msgstr ""
+
 #: src/libslic3r/GCode/PreviewData.cpp:176
 msgid "Mixed"
 msgstr ""
diff --git a/resources/localization/list.txt b/resources/localization/list.txt
index cf6ca4c84..fdffaf9d9 100644
--- a/resources/localization/list.txt
+++ b/resources/localization/list.txt
@@ -1,4 +1,5 @@
 src/slic3r/GUI/AboutDialog.cpp
+src/slic3r/GUI/BackgroundSlicingProcess.cpp
 src/slic3r/GUI/BedShapeDialog.cpp
 src/slic3r/GUI/BedShapeDialog.hpp
 src/slic3r/GUI/BonjourDialog.cpp
@@ -47,4 +48,5 @@ src/libslic3r/Print.cpp
 src/libslic3r/SLAPrint.cpp
 src/libslic3r/PrintBase.cpp
 src/libslic3r/PrintConfig.cpp
+src/libslic3r/PrintObject.cpp
 src/libslic3r/GCode/PreviewData.cpp
diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index 79b24fe1a..04ea99505 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -798,7 +798,7 @@ bool GUI_App::check_unsaved_changes()
         return true;
     // Ask the user.
     wxMessageDialog dialog(mainframe,
-        _(L("The following presets were modified: ")) + dirty + "\n" + _(L("Discard changes and continue anyway?")),
+        _(L("The following presets were modified")) + ": " + dirty + "\n" + _(L("Discard changes and continue anyway?")),
         wxString(SLIC3R_APP_NAME) + " - " + _(L("Unsaved Presets")),
         wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT);
     return dialog.ShowModal() == wxID_YES;
diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp
index 58bd3cfb5..5f01988f5 100644
--- a/src/slic3r/GUI/Tab.hpp
+++ b/src/slic3r/GUI/Tab.hpp
@@ -312,7 +312,7 @@ class TabPrint : public Tab
     bool is_msg_dlg_already_exist {false};
 public:
 	TabPrint(wxNotebook* parent) : 
-		Tab(parent, _(L("Print Settings")), "print") {}
+		Tab(parent, _(L("Print Settings")), L("print")) {}
 	~TabPrint() {}
 
 	ogStaticText*	m_recommended_thin_wall_thickness_description_line;
@@ -330,7 +330,7 @@ class TabFilament : public Tab
 	ogStaticText*	m_cooling_description_line;
 public:
 	TabFilament(wxNotebook* parent) : 
-		Tab(parent, _(L("Filament Settings")), "filament") {}
+		Tab(parent, _(L("Filament Settings")), L("filament")) {}
 	~TabFilament() {}
 
 	void		build() override;
@@ -363,7 +363,7 @@ public:
 
     PrinterTechnology               m_printer_technology = ptFFF;
 
-	TabPrinter(wxNotebook* parent) : Tab(parent, _(L("Printer Settings")), "printer") {}
+	TabPrinter(wxNotebook* parent) : Tab(parent, _(L("Printer Settings")), L("printer")) {}
 	~TabPrinter() {}
 
 	void		build() override;
@@ -386,7 +386,7 @@ class TabSLAMaterial : public Tab
 {
 public:
     TabSLAMaterial(wxNotebook* parent) :
-		Tab(parent, _(L("Material Settings")), "sla_material") {}
+		Tab(parent, _(L("Material Settings")), L("sla_material")) {}
     ~TabSLAMaterial() {}
 
 	void		build() override;
@@ -400,7 +400,7 @@ class TabSLAPrint : public Tab
 {
 public:
     TabSLAPrint(wxNotebook* parent) :
-        Tab(parent, _(L("Print Settings")), "sla_print") {}
+        Tab(parent, _(L("Print Settings")), L("sla_print")) {}
     ~TabSLAPrint() {}
     void		build() override;
 	void		reload_config() override;

From 62590d291c18ffa4c500eabbd16c47ca0f319453 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 10 May 2019 12:28:56 +0200
Subject: [PATCH 8/8] use _() instead of _utf8() for ButtonsDescription

---
 resources/localization/Slic3rPE.pot   | 210 +++++++++++++-------------
 src/slic3r/GUI/ButtonsDescription.cpp |   4 +-
 2 files changed, 107 insertions(+), 107 deletions(-)

diff --git a/resources/localization/Slic3rPE.pot b/resources/localization/Slic3rPE.pot
index 9ab29d6c8..b0852567f 100644
--- a/resources/localization/Slic3rPE.pot
+++ b/resources/localization/Slic3rPE.pot
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-05-10 11:46+0200\n"
+"POT-Creation-Date: 2019-05-10 11:50+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -567,28 +567,28 @@ msgstr ""
 msgid "Configuration &Wizard"
 msgstr ""
 
-#: src/slic3r/GUI/Field.cpp:93
+#: src/slic3r/GUI/Field.cpp:117
 msgid "default value"
 msgstr ""
 
-#: src/slic3r/GUI/Field.cpp:96
+#: src/slic3r/GUI/Field.cpp:120
 msgid "parameter name"
 msgstr ""
 
-#: src/slic3r/GUI/Field.cpp:124
+#: src/slic3r/GUI/Field.cpp:148
 #, possible-c-format
 msgid "%s doesn't support percentage"
 msgstr ""
 
-#: src/slic3r/GUI/Field.cpp:138 src/slic3r/GUI/Field.cpp:161
+#: src/slic3r/GUI/Field.cpp:162 src/slic3r/GUI/Field.cpp:185
 msgid "Invalid numeric input."
 msgstr ""
 
-#: src/slic3r/GUI/Field.cpp:143
+#: src/slic3r/GUI/Field.cpp:167
 msgid "Input value is out of range"
 msgstr ""
 
-#: src/slic3r/GUI/Field.cpp:169
+#: src/slic3r/GUI/Field.cpp:193
 #, possible-c-format
 msgid ""
 "Do you mean %d%% instead of %d %s?\n"
@@ -596,7 +596,7 @@ msgid ""
 "or NO if you are sure that %d %s is a correct value."
 msgstr ""
 
-#: src/slic3r/GUI/Field.cpp:172
+#: src/slic3r/GUI/Field.cpp:196
 msgid "Parameter validation"
 msgstr ""
 
@@ -723,71 +723,71 @@ msgstr ""
 msgid "Cancelling..."
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:719
-msgid "Detected object outside print volume"
-msgstr ""
-
 #: src/slic3r/GUI/GLCanvas3D.cpp:720
-msgid "Detected toolpath outside print volume"
+msgid "An object outside the print area was detected"
 msgstr ""
 
 #: src/slic3r/GUI/GLCanvas3D.cpp:721
-msgid "Detected support outside print volume"
+msgid "A toolpath outside the print area was detected"
 msgstr ""
 
 #: src/slic3r/GUI/GLCanvas3D.cpp:722
+msgid "SLA supports outside the print area were detected"
+msgstr ""
+
+#: src/slic3r/GUI/GLCanvas3D.cpp:723
 msgid "Some objects are not visible when editing supports"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:724
+#: src/slic3r/GUI/GLCanvas3D.cpp:725
 msgid ""
-"Detected object outside print volume\n"
-"Resolve a clash to continue slicing/export process correctly"
+"An object outside the print area was detected\n"
+"Resolve the current problem to continue slicing"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3395
+#: src/slic3r/GUI/GLCanvas3D.cpp:3434
 msgid "Add..."
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3405 src/slic3r/GUI/GUI_ObjectList.cpp:1269
-#: src/slic3r/GUI/Plater.cpp:2908 src/slic3r/GUI/Plater.cpp:2926
+#: src/slic3r/GUI/GLCanvas3D.cpp:3444 src/slic3r/GUI/GUI_ObjectList.cpp:1269
+#: src/slic3r/GUI/Plater.cpp:2933 src/slic3r/GUI/Plater.cpp:2951
 #: src/slic3r/GUI/Tab.cpp:2951
 msgid "Delete"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3416 src/slic3r/GUI/Plater.cpp:3316
+#: src/slic3r/GUI/GLCanvas3D.cpp:3455 src/slic3r/GUI/Plater.cpp:3341
 msgid "Delete all"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3427 src/slic3r/GUI/KBShortcutsDialog.cpp:135
+#: src/slic3r/GUI/GLCanvas3D.cpp:3466 src/slic3r/GUI/KBShortcutsDialog.cpp:135
 msgid "Arrange"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3441 src/slic3r/GUI/Tab.cpp:2892
+#: src/slic3r/GUI/GLCanvas3D.cpp:3480 src/slic3r/GUI/Tab.cpp:2892
 msgid "Copy"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3452
+#: src/slic3r/GUI/GLCanvas3D.cpp:3491
 msgid "Paste"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3466
+#: src/slic3r/GUI/GLCanvas3D.cpp:3505
 msgid "Add instance"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3478
+#: src/slic3r/GUI/GLCanvas3D.cpp:3517
 msgid "Remove instance"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3493
+#: src/slic3r/GUI/GLCanvas3D.cpp:3532
 msgid "Split to objects"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3505 src/slic3r/GUI/GUI_ObjectList.cpp:1122
+#: src/slic3r/GUI/GLCanvas3D.cpp:3544 src/slic3r/GUI/GUI_ObjectList.cpp:1122
 msgid "Split to parts"
 msgstr ""
 
-#: src/slic3r/GUI/GLCanvas3D.cpp:3520
+#: src/slic3r/GUI/GLCanvas3D.cpp:3559
 msgid "Layers editing"
 msgstr ""
 
@@ -1388,7 +1388,7 @@ msgstr ""
 msgid "Fix through the Netfabb"
 msgstr ""
 
-#: src/slic3r/GUI/GUI_ObjectList.cpp:1231 src/slic3r/GUI/Plater.cpp:2944
+#: src/slic3r/GUI/GUI_ObjectList.cpp:1231 src/slic3r/GUI/Plater.cpp:2969
 msgid "Export as STL"
 msgstr ""
 
@@ -1416,7 +1416,7 @@ msgstr ""
 msgid "You can't delete the last intance from object."
 msgstr ""
 
-#: src/slic3r/GUI/GUI_ObjectList.cpp:1742 src/slic3r/GUI/Plater.cpp:2290
+#: src/slic3r/GUI/GUI_ObjectList.cpp:1742 src/slic3r/GUI/Plater.cpp:2306
 msgid ""
 "The selected object couldn't be split because it contains only one part."
 msgstr ""
@@ -1701,7 +1701,7 @@ msgid "Load Config from .ini/amf/3mf/gcode"
 msgstr ""
 
 #: src/slic3r/GUI/KBShortcutsDialog.cpp:108 src/slic3r/GUI/Plater.cpp:740
-#: src/slic3r/GUI/Plater.cpp:3839 src/libslic3r/PrintConfig.cpp:2990
+#: src/slic3r/GUI/Plater.cpp:3864 src/libslic3r/PrintConfig.cpp:2990
 msgid "Export G-code"
 msgstr ""
 
@@ -2349,7 +2349,7 @@ msgstr ""
 msgid "&Help"
 msgstr ""
 
-#: src/slic3r/GUI/MainFrame.cpp:607 src/slic3r/GUI/Plater.cpp:3839
+#: src/slic3r/GUI/MainFrame.cpp:607 src/slic3r/GUI/Plater.cpp:3864
 msgid "Export"
 msgstr ""
 
@@ -2401,8 +2401,8 @@ msgstr ""
 msgid "Save zip file as:"
 msgstr ""
 
-#: src/slic3r/GUI/MainFrame.cpp:713 src/slic3r/GUI/Plater.cpp:2423
-#: src/slic3r/GUI/Plater.cpp:3633 src/slic3r/GUI/Tab.cpp:1160
+#: src/slic3r/GUI/MainFrame.cpp:713 src/slic3r/GUI/Plater.cpp:2439
+#: src/slic3r/GUI/Plater.cpp:3658 src/slic3r/GUI/Tab.cpp:1160
 #: src/slic3r/GUI/Tab.cpp:3454
 msgid "Slicing"
 msgstr ""
@@ -2568,12 +2568,12 @@ msgstr ""
 msgid "Printer"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:738 src/slic3r/GUI/Plater.cpp:3840
+#: src/slic3r/GUI/Plater.cpp:738 src/slic3r/GUI/Plater.cpp:3865
 msgid "Send to printer"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:741 src/slic3r/GUI/Plater.cpp:2423
-#: src/slic3r/GUI/Plater.cpp:3636
+#: src/slic3r/GUI/Plater.cpp:741 src/slic3r/GUI/Plater.cpp:2439
+#: src/slic3r/GUI/Plater.cpp:3661
 msgid "Slice now"
 msgstr ""
 
@@ -2630,286 +2630,286 @@ msgstr ""
 msgid "stealth mode"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:1601
+#: src/slic3r/GUI/Plater.cpp:1604
 msgid "Loading"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:1611
+#: src/slic3r/GUI/Plater.cpp:1614
 #, possible-c-format
 msgid "Processing input file %s\n"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:1669
+#: src/slic3r/GUI/Plater.cpp:1672
 msgid ""
 "This file contains several objects positioned at multiple heights. Instead "
 "of considering them as multiple objects, should I consider\n"
 "this file as a single object having multiple parts?\n"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:1672 src/slic3r/GUI/Plater.cpp:1780
+#: src/slic3r/GUI/Plater.cpp:1675 src/slic3r/GUI/Plater.cpp:1783
 msgid "Multi-part object detected"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:1723
+#: src/slic3r/GUI/Plater.cpp:1726
 msgid ""
 "This file cannot be loaded in a simple mode. Do you want to switch to an "
 "advanced mode?\n"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:1724
+#: src/slic3r/GUI/Plater.cpp:1727
 msgid "Detected advanced data"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:1757
+#: src/slic3r/GUI/Plater.cpp:1760
 #, possible-c-format
 msgid ""
 "You can't to add the object(s) from %s because of one or some of them "
 "is(are) multi-part"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:1777
+#: src/slic3r/GUI/Plater.cpp:1780
 msgid ""
 "Multiple objects were loaded for a multi-material printer.\n"
 "Instead of considering them as multiple objects, should I consider\n"
 "these files to represent a single object having multiple parts?\n"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:1793
+#: src/slic3r/GUI/Plater.cpp:1796
 msgid "Loaded"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:1885
+#: src/slic3r/GUI/Plater.cpp:1894
 msgid ""
 "Your object appears to be too large, so it was automatically scaled down to "
 "fit your print bed."
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:1886
+#: src/slic3r/GUI/Plater.cpp:1895
 msgid "Object too large?"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:1936
+#: src/slic3r/GUI/Plater.cpp:1945
 msgid "Export STL file:"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:1943
+#: src/slic3r/GUI/Plater.cpp:1952
 msgid "Export AMF file:"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:1949
+#: src/slic3r/GUI/Plater.cpp:1958
 msgid "Save file as:"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2114
+#: src/slic3r/GUI/Plater.cpp:2123
 msgid "Arranging canceled"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2117
+#: src/slic3r/GUI/Plater.cpp:2126
 msgid "Arranging"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2151
+#: src/slic3r/GUI/Plater.cpp:2163
 msgid "Could not arrange model objects! Some geometries may be invalid."
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2155
+#: src/slic3r/GUI/Plater.cpp:2170
 msgid "Arranging done."
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2196
+#: src/slic3r/GUI/Plater.cpp:2211
 msgid "Orientation search canceled"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2201
+#: src/slic3r/GUI/Plater.cpp:2216
 msgid "Searching for optimal orientation"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2262
+#: src/slic3r/GUI/Plater.cpp:2278
 msgid "Orientation found."
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2282
+#: src/slic3r/GUI/Plater.cpp:2298
 msgid ""
 "The selected object can't be split because it contains more than one volume/"
 "material."
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2408
+#: src/slic3r/GUI/Plater.cpp:2424
 msgid "Invalid data"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2417
+#: src/slic3r/GUI/Plater.cpp:2433
 msgid "Ready to slice"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2455 src/slic3r/GUI/PrintHostDialogs.cpp:231
+#: src/slic3r/GUI/Plater.cpp:2471 src/slic3r/GUI/PrintHostDialogs.cpp:231
 msgid "Cancelling"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2472
+#: src/slic3r/GUI/Plater.cpp:2488
 msgid "Another export job is currently running."
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2733
+#: src/slic3r/GUI/Plater.cpp:2749
 msgid "Export failed"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2738 src/slic3r/GUI/PrintHostDialogs.cpp:232
+#: src/slic3r/GUI/Plater.cpp:2754 src/slic3r/GUI/PrintHostDialogs.cpp:232
 msgid "Cancelled"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2824 src/slic3r/GUI/Plater.cpp:2836
-#: src/slic3r/GUI/Plater.cpp:2914
+#: src/slic3r/GUI/Plater.cpp:2840 src/slic3r/GUI/Plater.cpp:2852
+#: src/slic3r/GUI/Plater.cpp:2939
 msgid "Increase copies"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2908 src/slic3r/GUI/Plater.cpp:2926
+#: src/slic3r/GUI/Plater.cpp:2933 src/slic3r/GUI/Plater.cpp:2951
 msgid "Remove the selected object"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2914
+#: src/slic3r/GUI/Plater.cpp:2939
 msgid "Place one more copy of the selected object"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2916
+#: src/slic3r/GUI/Plater.cpp:2941
 msgid "Decrease copies"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2916
+#: src/slic3r/GUI/Plater.cpp:2941
 msgid "Remove one copy of the selected object"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2918
+#: src/slic3r/GUI/Plater.cpp:2943
 msgid "Set number of copies"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2918
+#: src/slic3r/GUI/Plater.cpp:2943
 msgid "Change the number of copies of the selected object"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2941
+#: src/slic3r/GUI/Plater.cpp:2966
 msgid "Reload from Disk"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2941
+#: src/slic3r/GUI/Plater.cpp:2966
 msgid "Reload the selected file from Disk"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2944
+#: src/slic3r/GUI/Plater.cpp:2969
 msgid "Export the selected object as STL file"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2956
+#: src/slic3r/GUI/Plater.cpp:2981
 msgid "Along X axis"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2956
+#: src/slic3r/GUI/Plater.cpp:2981
 msgid "Mirror the selected object along the X axis"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2958
+#: src/slic3r/GUI/Plater.cpp:2983
 msgid "Along Y axis"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2958
+#: src/slic3r/GUI/Plater.cpp:2983
 msgid "Mirror the selected object along the Y axis"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2960
+#: src/slic3r/GUI/Plater.cpp:2985
 msgid "Along Z axis"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2960
+#: src/slic3r/GUI/Plater.cpp:2985
 msgid "Mirror the selected object along the Z axis"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2963
+#: src/slic3r/GUI/Plater.cpp:2988
 msgid "Mirror"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2963
+#: src/slic3r/GUI/Plater.cpp:2988
 msgid "Mirror the selected object"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2983
+#: src/slic3r/GUI/Plater.cpp:3008
 msgid "To objects"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2983 src/slic3r/GUI/Plater.cpp:3005
+#: src/slic3r/GUI/Plater.cpp:3008 src/slic3r/GUI/Plater.cpp:3030
 msgid "Split the selected object into individual objects"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2985
+#: src/slic3r/GUI/Plater.cpp:3010
 msgid "To parts"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2985 src/slic3r/GUI/Plater.cpp:3025
+#: src/slic3r/GUI/Plater.cpp:3010 src/slic3r/GUI/Plater.cpp:3050
 msgid "Split the selected object into individual sub-parts"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2988 src/slic3r/GUI/Plater.cpp:3005
-#: src/slic3r/GUI/Plater.cpp:3025 src/libslic3r/PrintConfig.cpp:3108
+#: src/slic3r/GUI/Plater.cpp:3013 src/slic3r/GUI/Plater.cpp:3030
+#: src/slic3r/GUI/Plater.cpp:3050 src/libslic3r/PrintConfig.cpp:3108
 msgid "Split"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:2988
+#: src/slic3r/GUI/Plater.cpp:3013
 msgid "Split the selected object"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:3011
+#: src/slic3r/GUI/Plater.cpp:3036
 msgid "Optimize orientation"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:3011
+#: src/slic3r/GUI/Plater.cpp:3036
 msgid "Optimize the rotation of the object for better print results."
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:3074
+#: src/slic3r/GUI/Plater.cpp:3099
 msgid "3D editor view"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:3085 src/slic3r/GUI/Tab.cpp:2289
+#: src/slic3r/GUI/Plater.cpp:3110 src/slic3r/GUI/Tab.cpp:2289
 msgid "Preview"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:3316
+#: src/slic3r/GUI/Plater.cpp:3341
 msgid "All objects will be removed, continue ?"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:3451
+#: src/slic3r/GUI/Plater.cpp:3476
 msgid "Save G-code file as:"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:3451
+#: src/slic3r/GUI/Plater.cpp:3476
 msgid "Save SL1 file as:"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:3563
+#: src/slic3r/GUI/Plater.cpp:3588
 #, possible-c-format
 msgid "STL file exported to %s"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:3579
+#: src/slic3r/GUI/Plater.cpp:3604
 #, possible-c-format
 msgid "AMF file exported to %s"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:3582
+#: src/slic3r/GUI/Plater.cpp:3607
 #, possible-c-format
 msgid "Error exporting AMF file %s"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:3608
+#: src/slic3r/GUI/Plater.cpp:3633
 #, possible-c-format
 msgid "3MF file exported to %s"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:3611
+#: src/slic3r/GUI/Plater.cpp:3636
 #, possible-c-format
 msgid "Error exporting 3MF file %s"
 msgstr ""
 
-#: src/slic3r/GUI/Plater.cpp:3840
+#: src/slic3r/GUI/Plater.cpp:3865
 msgid "Send G-code"
 msgstr ""
 
diff --git a/src/slic3r/GUI/ButtonsDescription.cpp b/src/slic3r/GUI/ButtonsDescription.cpp
index f9ab9b89c..0610199f5 100644
--- a/src/slic3r/GUI/ButtonsDescription.cpp
+++ b/src/slic3r/GUI/ButtonsDescription.cpp
@@ -26,9 +26,9 @@ ButtonsDescription::ButtonsDescription(wxWindow* parent, const std::vector<Entry
 	{
 		auto icon = new wxStaticBitmap(this, wxID_ANY, entry.bitmap->bmp());
 		grid_sizer->Add(icon, -1, wxALIGN_CENTRE_VERTICAL);
-		auto description = new wxStaticText(this, wxID_ANY, _utf8(entry.symbol));
+		auto description = new wxStaticText(this, wxID_ANY, _(entry.symbol));
 		grid_sizer->Add(description, -1, wxALIGN_CENTRE_VERTICAL);
-		description = new wxStaticText(this, wxID_ANY, _utf8(entry.explanation));
+		description = new wxStaticText(this, wxID_ANY, _(entry.explanation));
 		grid_sizer->Add(description, -1, wxALIGN_CENTRE_VERTICAL | wxEXPAND);
 	}