From 48a94ebae14cf99726bb83369eb7886db0d70340 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 14 Dec 2018 09:52:54 +0100
Subject: [PATCH 01/10] Fixed scroll the Object List to selected item on OSX &
 GTK

+ fixed #1395 (maximum PresetComboBox's width limit on Ubuntu)
---
 src/slic3r/GUI/GUI_ObjectList.cpp | 8 +++-----
 src/slic3r/GUI/GUI_ObjectList.hpp | 2 --
 src/slic3r/GUI/Plater.cpp         | 2 +-
 3 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 575444c4b..a90dff621 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1459,13 +1459,11 @@ void ObjectList::update_selections()
     
     select_items(sels);
 
-#ifdef __WXMSW__
     if (GetSelection()) {
-        const int sel_item_row = GetRowByItem(GetSelection());
-        ScrollLines(sel_item_row - m_selected_row);
-        m_selected_row = sel_item_row;
+        const wxRect& top_rc = GetItemRect(GetTopItem());
+        const wxRect& sel_rc = GetItemRect(GetSelection());
+        ScrollLines(int((sel_rc.y - top_rc.y) / top_rc.GetHeight()) - 0.5*GetCountPerPage());
     }
-#endif //__WXMSW__
 }
 
 void ObjectList::update_selections_on_canvas()
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 7631782df..3664e6fda 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -108,8 +108,6 @@ class ObjectList : public wxDataViewCtrl
     bool        m_parts_changed = false;
     bool        m_part_settings_changed = false;
 
-    int         m_selected_row = 0;
-
 public:
     ObjectList(wxWindow* parent);
     ~ObjectList();
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index b1526fdb4..381a9e864 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -213,7 +213,7 @@ void SlicedInfo::SetTextAndShow(SlisedInfoIdx idx, const wxString& text, const w
 }
 
 PresetComboBox::PresetComboBox(wxWindow *parent, Preset::Type preset_type) :
-    wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_READONLY),
+    wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200,-1), 0, nullptr, wxCB_READONLY),
     preset_type(preset_type),
     last_selected(wxNOT_FOUND)
 {

From 2be23c8b149e4c4713707861f0528da06b9def59 Mon Sep 17 00:00:00 2001
From: tamasmeszaros <meszaros.q@gmail.com>
Date: Fri, 14 Dec 2018 13:45:58 +0100
Subject: [PATCH 02/10] Eliminate build warning with TBB_USE_CAPTURED_EXCEPTION

also make small adjustment on wxWidgets detection on Unix.
---
 src/CMakeLists.txt           | 13 ++++++++++++-
 src/libnest2d/CMakeLists.txt |  2 +-
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d714eb91a..31c801379 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -46,7 +46,18 @@ endif()
 add_subdirectory(libslic3r)
 
 if (SLIC3R_GUI)
-    message(STATUS "WXWIN environment set to: $ENV{WXWIN}")
+    if(WIN32)
+        message(STATUS "WXWIN environment set to: $ENV{WXWIN}")
+    elseif(UNIX)
+        message(STATUS "wx-config path: ${wxWidgets_CONFIG_EXECUTABLE}")
+        set(wxWidgets_USE_UNICODE ON)
+        if(SLIC3R_STATIC)
+            set(wxWidgets_USE_STATIC ON)
+        else()
+            set(wxWidgets_USE_STATIC OFF)
+        endif()
+    endif()
+
     find_package(wxWidgets REQUIRED COMPONENTS base core adv html gl)
     include(${wxWidgets_USE_FILE})
 endif()
diff --git a/src/libnest2d/CMakeLists.txt b/src/libnest2d/CMakeLists.txt
index 163143bcb..1faf542dd 100644
--- a/src/libnest2d/CMakeLists.txt
+++ b/src/libnest2d/CMakeLists.txt
@@ -68,7 +68,7 @@ if(TBB_FOUND)
        target_compile_definitions(libnest2d INTERFACE -D__TBB_NO_IMPLICIT_LINKAGE)
     endif()
     # The Intel TBB library will use the std::exception_ptr feature of C++11.
-    target_compile_definitions(libnest2d INTERFACE -DTBB_USE_CAPTURED_EXCEPTION=1)
+    target_compile_definitions(libnest2d INTERFACE -DTBB_USE_CAPTURED_EXCEPTION=0)
 
     target_link_libraries(libnest2d INTERFACE tbb)
 else()

From dae01af2aca8a872a0393c9461c98691e3de9332 Mon Sep 17 00:00:00 2001
From: tamasmeszaros <meszaros.q@gmail.com>
Date: Fri, 14 Dec 2018 16:58:55 +0100
Subject: [PATCH 03/10] Logging during sla processing.

---
 src/libslic3r/SLAPrint.cpp | 38 +++++++++++++++++++++++++++-----------
 1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp
index 0c61b591b..96b304ac2 100644
--- a/src/libslic3r/SLAPrint.cpp
+++ b/src/libslic3r/SLAPrint.cpp
@@ -420,6 +420,12 @@ void swapXY(ExPolygon& expoly) {
 
 }
 
+template<class...Args>
+void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args) {
+    BOOST_LOG_TRIVIAL(info) << st << "% " << msg;
+    p.set_status(st, msg, std::forward<Args>(args)...);
+}
+
 void SLAPrint::process()
 {
     using namespace sla;
@@ -524,9 +530,11 @@ void SLAPrint::process()
             // scaling for the sub operations
             double d = *stthis / (objcount * 100.0);
 
-            ctl.statuscb = [this, init, d](unsigned st, const std::string& msg){
-                set_status(int(init + st*d), msg);
+            ctl.statuscb = [this, init, d](unsigned st, const std::string& msg)
+            {
+                report_status(*this, int(init + st*d), msg);
             };
+
             ctl.stopcondition = [this](){ return canceled(); };
             ctl.cancelfn = [this]() { throw_if_canceled(); };
 
@@ -536,9 +544,9 @@ void SLAPrint::process()
 
             // Create the unified mesh
             auto rc = SlicingStatus::RELOAD_SCENE;
-            set_status(-1, L("Visualizing supports"));
+            report_status(*this, -1, L("Visualizing supports"));
             po.m_supportdata->support_tree_ptr->merged_mesh();
-            set_status(-1, L("Visualizing supports"), rc);
+            report_status(*this, -1, L("Visualizing supports"), rc);
         } catch(sla::SLASupportsStoppedException&) {
             // no need to rethrow
             // throw_if_canceled();
@@ -581,7 +589,7 @@ void SLAPrint::process()
 
         po.throw_if_canceled();
         auto rc = SlicingStatus::RELOAD_SCENE;
-        set_status(-1, L("Visualizing supports"), rc);
+        report_status(*this, -1, L("Visualizing supports"), rc);
     };
 
     // Slicing the support geometries similarly to the model slicing procedure.
@@ -740,8 +748,12 @@ void SLAPrint::process()
         auto lvlcnt = unsigned(m_printer_input.size());
         printer.layers(lvlcnt);
 
+        // slot is the portion of 100% that is realted to rasterization
         unsigned slot = PRINT_STEP_LEVELS[slapsRasterize];
+        // ist: initial state; pst: previous state
         unsigned ist = max_objstatus, pst = ist;
+        // coefficient to map the rasterization state (0-99) to the allocated
+        // portion (slot) of the process state
         double sd = (100 - ist) / 100.0;
         SpinMutex slck;
 
@@ -778,11 +790,11 @@ void SLAPrint::process()
             // Finish the layer for later saving it.
             printer.finish_layer(level_id);
 
-            // Status indication
+            // Status indication guarded with the spinlock
             auto st = ist + unsigned(sd*level_id*slot/m_printer_input.size());
             { std::lock_guard<SpinMutex> lck(slck);
             if( st > pst) {
-                set_status(int(st), PRINT_STEP_LABELS[slapsRasterize]);
+                report_status(*this, int(st), PRINT_STEP_LABELS[slapsRasterize]);
                 pst = st;
             }
             }
@@ -832,9 +844,14 @@ void SLAPrint::process()
     unsigned st = min_objstatus;
     unsigned incr = 0;
 
+    BOOST_LOG_TRIVIAL(info) << "Start slicing process.";
+
     // TODO: this loop could run in parallel but should not exhaust all the CPU
     // power available
     for(SLAPrintObject * po : m_objects) {
+
+        BOOST_LOG_TRIVIAL(info) << "Slicing object " << po->model_object()->name;
+
         for(size_t s = 0; s < objectsteps.size(); ++s) {
             auto currentstep = objectsteps[s];
 
@@ -846,8 +863,7 @@ void SLAPrint::process()
             st += unsigned(incr * ostepd);
 
             if(po->m_stepmask[currentstep] && po->set_started(currentstep)) {
-
-                set_status(int(st), OBJ_STEP_LABELS[currentstep]);
+                report_status(*this, int(st), OBJ_STEP_LABELS[currentstep]);
                 pobj_program[currentstep](*po);
                 po->set_done(currentstep);
             }
@@ -872,7 +888,7 @@ void SLAPrint::process()
 
         if(m_stepmask[currentstep] && set_started(currentstep))
         {
-            set_status(int(st), PRINT_STEP_LABELS[currentstep]);
+            report_status(*this, int(st), PRINT_STEP_LABELS[currentstep]);
             print_program[currentstep]();
             set_done(currentstep);
         }
@@ -881,7 +897,7 @@ void SLAPrint::process()
     }
 
     // If everything vent well
-    set_status(100, L("Slicing done"));
+    report_status(*this, 100, L("Slicing done"));
 }
 
 bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys)

From 907e51053553e393e95768b1a7bc2f9e7c5135c7 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 14 Dec 2018 16:07:28 +0100
Subject: [PATCH 04/10] Changed PrusaBitmapTextRenderer's inheritance to
 wxDataViewRenderer instead of wxDataViewCustomRenderer : to fix name editing
 under OSX

---
 src/slic3r/GUI/GUI_ObjectList.cpp |  4 +++-
 src/slic3r/GUI/wxExtensions.cpp   | 34 +++++++++++++++++++++++++++----
 src/slic3r/GUI/wxExtensions.hpp   | 14 +++++++------
 3 files changed, 41 insertions(+), 11 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index a90dff621..78310443d 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1654,7 +1654,9 @@ void ObjectList::change_part_type()
 void ObjectList::last_volume_is_deleted(const int obj_idx)
 {
 
-    if (obj_idx < 0 || (*m_objects).empty() || (*m_objects)[obj_idx]->volumes.empty())
+    if (obj_idx < 0 || m_objects->empty() ||
+        obj_idx <= m_objects->size() ||
+        (*m_objects)[obj_idx]->volumes.empty())
         return;
     auto volume = (*m_objects)[obj_idx]->volumes[0];
 
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index 2e5a37040..710710913 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -1228,6 +1228,14 @@ void PrusaObjectDataViewModel::SetVolumeType(const wxDataViewItem &item, const i
     ItemChanged(item);
 }
 
+PrusaBitmapTextRenderer::PrusaBitmapTextRenderer(wxDataViewCellMode mode /*= wxDATAVIEW_CELL_EDITABLE*/, 
+                                                 int align /*= wxDVR_DEFAULT_ALIGNMENT*/): 
+wxDataViewRenderer(wxT("PrusaDataViewBitmapText"), mode, align)
+{
+    SetMode(mode);
+    SetAlignment(align);
+}
+
 //-----------------------------------------------------------------------------
 // PrusaDataViewBitmapText
 //-----------------------------------------------------------------------------
@@ -1251,6 +1259,13 @@ bool PrusaBitmapTextRenderer::GetValue(wxVariant& WXUNUSED(value)) const
     return false;
 }
 
+#if wxUSE_ACCESSIBILITY
+wxString PrusaBitmapTextRenderer::GetAccessibleDescription() const
+{
+    return m_value.GetText();
+}
+#endif // wxUSE_ACCESSIBILITY
+
 bool PrusaBitmapTextRenderer::Render(wxRect rect, wxDC *dc, int state)
 {
     int xoffset = 0;
@@ -1291,12 +1306,12 @@ wxWindow* PrusaBitmapTextRenderer::CreateEditorCtrl(wxWindow* parent, wxRect lab
 
     PrusaDataViewBitmapText data;
     data << value;
-    m_bmp_from_editing_item = data.GetBitmap();
+
     m_was_unusable_symbol = false;
 
     wxPoint position = labelRect.GetPosition();
-    if (m_bmp_from_editing_item.IsOk()) {
-        const int bmp_width = m_bmp_from_editing_item.GetWidth();
+    if (data.GetBitmap().IsOk()) {
+        const int bmp_width = data.GetBitmap().GetWidth();
         position.x += bmp_width;
         labelRect.SetWidth(labelRect.GetWidth() - bmp_width);
     }
@@ -1304,6 +1319,7 @@ wxWindow* PrusaBitmapTextRenderer::CreateEditorCtrl(wxWindow* parent, wxRect lab
     wxTextCtrl* text_editor = new wxTextCtrl(parent, wxID_ANY, data.GetText(),
                                              position, labelRect.GetSize(), wxTE_PROCESS_ENTER);
     text_editor->SetInsertionPointEnd();
+    text_editor->SelectAll();
 
     return text_editor;
 }
@@ -1323,7 +1339,17 @@ bool PrusaBitmapTextRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant&
         }
     }
 
-    value << PrusaDataViewBitmapText(text_editor->GetValue(), m_bmp_from_editing_item);
+    // The icon can't be edited so get its old value and reuse it.
+    wxVariant valueOld;
+    GetView()->GetModel()->GetValue(valueOld, m_item, 0); 
+    
+    PrusaDataViewBitmapText bmpText;
+    bmpText << valueOld;
+
+    // But replace the text with the value entered by user.
+    bmpText.SetText(text_editor->GetValue());
+
+    value << bmpText;
     return true;
 }
 
diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp
index 3fbf9a083..e3fd1cbf6 100644
--- a/src/slic3r/GUI/wxExtensions.hpp
+++ b/src/slic3r/GUI/wxExtensions.hpp
@@ -519,15 +519,18 @@ public:
 // PrusaBitmapTextRenderer
 // ----------------------------------------------------------------------------
 
-class PrusaBitmapTextRenderer : public wxDataViewCustomRenderer
+class PrusaBitmapTextRenderer : public wxDataViewRenderer//CustomRenderer
 {
 public:
-    PrusaBitmapTextRenderer(  wxDataViewCellMode mode = wxDATAVIEW_CELL_EDITABLE,
-                            int align = wxDVR_DEFAULT_ALIGNMENT): 
-                            wxDataViewCustomRenderer(wxT("PrusaDataViewBitmapText"), mode, align) {}
+    PrusaBitmapTextRenderer(wxDataViewCellMode mode = wxDATAVIEW_CELL_EDITABLE,
+                            int align = wxDVR_DEFAULT_ALIGNMENT);//: 
+//                             wxDataViewRenderer/*CustomRenderer*/(wxT("PrusaDataViewBitmapText"), mode, align) {}
 
     bool SetValue(const wxVariant &value);
     bool GetValue(wxVariant &value) const;
+#if wxUSE_ACCESSIBILITY
+    virtual wxString GetAccessibleDescription() const override;
+#endif // wxUSE_ACCESSIBILITY
 
     virtual bool Render(wxRect cell, wxDC *dc, int state);
     virtual wxSize GetSize() const;
@@ -542,8 +545,7 @@ public:
 
 private:
     PrusaDataViewBitmapText m_value;
-    wxBitmap                m_bmp_from_editing_item;
-    bool                    m_was_unusable_symbol;
+    bool                    m_was_unusable_symbol {false};
 };
 
 

From 880c1ef2b4ea05cef2d5db28531efe80db06fc57 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 14 Dec 2018 17:09:44 +0100
Subject: [PATCH 05/10] Next try to fix scroll the Object List to selected item
 (OSX & GTK)

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

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 78310443d..a7f1ca608 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1460,9 +1460,12 @@ void ObjectList::update_selections()
     select_items(sels);
 
     if (GetSelection()) {
-        const wxRect& top_rc = GetItemRect(GetTopItem());
         const wxRect& sel_rc = GetItemRect(GetSelection());
-        ScrollLines(int((sel_rc.y - top_rc.y) / top_rc.GetHeight()) - 0.5*GetCountPerPage());
+        if (!sel_rc.IsEmpty()) {
+            const int rc_h = sel_rc.height;
+            const int displ = GetMainWindow()->GetClientRect().GetHeight()/(2*rc_h)+1;
+            ScrollLines(int(sel_rc.y / rc_h - displ));
+        }
     }
 }
 

From 506cbcb4a7027834bd07038c8e186cda197915bd Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Fri, 14 Dec 2018 17:17:51 +0100
Subject: [PATCH 06/10] Fix of G-code invalidation on "wipe_into_object"
 "wipe_into_infill" changes.

WIP: Fix of "levitating objects cannot be sliced".
---
 src/libslic3r/Layer.cpp       | 10 ++++++++++
 src/libslic3r/Layer.hpp       |  3 ++-
 src/libslic3r/PrintObject.cpp | 24 +++++++++++++++---------
 3 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp
index 7878bffab..fa5d29692 100644
--- a/src/libslic3r/Layer.cpp
+++ b/src/libslic3r/Layer.cpp
@@ -17,6 +17,16 @@ Layer::~Layer()
     m_regions.clear();
 }
 
+// Test whether whether there are any slices assigned to this layer.
+bool Layer::empty() const
+{
+	for (const LayerRegion *layerm : m_regions)
+        if (layerm != nullptr && ! layerm->slices.empty())
+            // Non empty layer.
+            return false;
+    return true;
+}
+
 LayerRegion* Layer::add_region(PrintRegion* print_region)
 {
     m_regions.emplace_back(new LayerRegion(this, print_region));
diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp
index 8dbe850cc..78897a2db 100644
--- a/src/libslic3r/Layer.hpp
+++ b/src/libslic3r/Layer.hpp
@@ -114,7 +114,8 @@ public:
     LayerRegion*            get_region(int idx) { return m_regions[idx]; }
     LayerRegion*            add_region(PrintRegion* print_region);
     const LayerRegionPtrs&  regions() const { return m_regions; }
-    
+    // Test whether whether there are any slices assigned to this layer.
+    bool                    empty() const;    
     void                    make_slices();
     void                    merge_slices();
     template <class T> bool any_internal_region_slice_contains(const T &item) const {
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index 4b7a8906f..772d930aa 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -384,6 +384,12 @@ void PrintObject::generate_support_material()
             m_print->set_status(85, "Generating support material");    
             this->_generate_support_material();
             m_print->throw_if_canceled();
+        } else {
+            // Printing without supports. Empty layer means some objects or object parts are levitating,
+            // therefore they cannot be printed without supports.
+            for (const Layer *layer : m_layers)
+                if (layer->empty())
+                    throw std::runtime_error("Levitating objects cannot be printed without supports.");
         }
         this->set_done(posSupportMaterial);
     }
@@ -522,11 +528,13 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
             || opt_key == "perimeter_speed"
             || opt_key == "small_perimeter_speed"
             || opt_key == "solid_infill_speed"
-            || opt_key == "top_solid_infill_speed"
-            || opt_key == "wipe_into_infill"    // when these these two are changed, we only need to invalidate the wipe tower,
-            || opt_key == "wipe_into_objects"   // which we already did at the very beginning - nothing more to be done
-            ) {
-            // these options only affect G-code export, so nothing to invalidate
+            || opt_key == "top_solid_infill_speed") {
+            invalidated |= m_print->invalidate_step(psGCodeExport);
+        } else if (
+               opt_key == "wipe_into_infill"
+            || opt_key == "wipe_into_objects") {
+            invalidated |= m_print->invalidate_step(psWipeTower);
+            invalidated |= m_print->invalidate_step(psGCodeExport);
         } else {
             // for legacy, if we can't handle this option let's invalidate all steps
             this->invalidate_all_steps();
@@ -1463,10 +1471,8 @@ void PrintObject::_slice()
     BOOST_LOG_TRIVIAL(debug) << "Slicing objects - removing top empty layers";
     while (! m_layers.empty()) {
         const Layer *layer = m_layers.back();
-        for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id)
-            if (layer->m_regions[region_id] != nullptr && ! layer->m_regions[region_id]->slices.empty())
-                // Non empty layer.
-                goto end;
+        if (! layer->empty())
+            goto end;
         delete layer;
         m_layers.pop_back();
 		if (! m_layers.empty())

From d6471e7b071129a49f936a85697d5e8c3759730f Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Fri, 14 Dec 2018 17:19:17 +0100
Subject: [PATCH 07/10] Fix of SLADisplayOrientation updates

---
 src/libslic3r/PrintConfig.cpp | 6 ++++--
 src/libslic3r/PrintConfig.hpp | 4 ++--
 src/slic3r/GUI/Field.cpp      | 2 ++
 src/slic3r/GUI/GUI.cpp        | 2 ++
 4 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index ab26f5d54..8a564b6b5 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -2394,8 +2394,10 @@ void PrintConfigDef::init_sla_params()
     def->tooltip = L("Display orientation");
     def->cli = "display-orientation=s";
     def->enum_keys_map = &ConfigOptionEnum<SLADisplayOrientation>::get_enum_values();
-    def->enum_values.push_back("Landscape");
-    def->enum_values.push_back("Portrait");
+    def->enum_values.push_back("landscape");
+    def->enum_values.push_back("portrait");
+    def->enum_labels.push_back(L("Landscape"));
+    def->enum_labels.push_back(L("Portrait"));
     def->default_value = new ConfigOptionEnum<SLADisplayOrientation>(sladoPortrait);
 
     def = this->add("printer_correction", coFloats);
diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp
index f639cad76..1949a8ac8 100644
--- a/src/libslic3r/PrintConfig.hpp
+++ b/src/libslic3r/PrintConfig.hpp
@@ -155,8 +155,8 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<FilamentType>::ge
 
 template<> inline const t_config_enum_values& ConfigOptionEnum<SLADisplayOrientation>::get_enum_values() {
     static const t_config_enum_values keys_map = {
-        { "Landscape", sladoLandscape},
-        { "Portrait",  sladoPortrait}
+        { "landscape", sladoLandscape},
+        { "portrait",  sladoPortrait}
     };
 
     return keys_map;
diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp
index ebc7f3665..d4126d933 100644
--- a/src/slic3r/GUI/Field.cpp
+++ b/src/slic3r/GUI/Field.cpp
@@ -638,6 +638,8 @@ boost::any& Choice::get_value()
 			m_value = static_cast<SeamPosition>(ret_enum);
 		else if (m_opt_id.compare("host_type") == 0)
 			m_value = static_cast<PrintHostType>(ret_enum);
+		else if (m_opt_id.compare("display_orientation") == 0)
+			m_value = static_cast<SLADisplayOrientation>(ret_enum);
 	}	
 
 	return m_value;
diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp
index bc7ea9899..fb6676aed 100644
--- a/src/slic3r/GUI/GUI.cpp
+++ b/src/slic3r/GUI/GUI.cpp
@@ -195,6 +195,8 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
 				config.set_key_value(opt_key, new ConfigOptionEnum<SeamPosition>(boost::any_cast<SeamPosition>(value)));
 			else if (opt_key.compare("host_type") == 0)
 				config.set_key_value(opt_key, new ConfigOptionEnum<PrintHostType>(boost::any_cast<PrintHostType>(value)));
+			else if (opt_key.compare("display_orientation") == 0)
+				config.set_key_value(opt_key, new ConfigOptionEnum<SLADisplayOrientation>(boost::any_cast<SLADisplayOrientation>(value)));
 			}
 			break;
 		case coPoints:{

From 77d37f108c3ba68afaebda9f54933f2b4185aaab Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Fri, 14 Dec 2018 19:29:58 +0100
Subject: [PATCH 08/10] Iterative, not recursive, version of the
 Douglas-Peucker-Ramer algorithm based on the work by @fuchstraumer
 https://github.com/slic3r/Slic3r/pull/3825
 https://gist.github.com/fuchstraumer/9421573fc281b946e5f561758961212a which
 was based on
 http://anis-moussa.blogspot.com/2014/03/ramer-douglas-peucker-algorithm-for.html

---
 src/libslic3r/Line.cpp       | 23 +++++------
 src/libslic3r/Line.hpp       |  6 ++-
 src/libslic3r/MultiPoint.cpp | 78 +++++++++++++++++++-----------------
 3 files changed, 58 insertions(+), 49 deletions(-)

diff --git a/src/libslic3r/Line.cpp b/src/libslic3r/Line.cpp
index 35cfa2b76..02f1cb7c2 100644
--- a/src/libslic3r/Line.cpp
+++ b/src/libslic3r/Line.cpp
@@ -34,23 +34,22 @@ bool Line::intersection_infinite(const Line &other, Point* point) const
     return true;
 }
 
-/* distance to the closest point of line */
-double Line::distance_to(const Point &point) const
+// Distance to the closest point of line.
+double Line::distance_to_squared(const Point &point, const Point &a, const Point &b)
 {
-    const Line   &line = *this;
-    const Vec2d   v  = (line.b - line.a).cast<double>();
-    const Vec2d   va = (point  - line.a).cast<double>();
+    const Vec2d   v  = (b - a).cast<double>();
+    const Vec2d   va = (point  - a).cast<double>();
     const double  l2 = v.squaredNorm();  // avoid a sqrt
     if (l2 == 0.0) 
-        // line.a == line.b case
-        return va.norm();
-    // Consider the line extending the segment, parameterized as line.a + t (line.b - line.a).
+        // a == b case
+        return va.squaredNorm();
+    // Consider the line extending the segment, parameterized as a + t (b - a).
     // We find projection of this point onto the line. 
-    // It falls where t = [(this-line.a) . (line.b-line.a)] / |line.b-line.a|^2
+    // It falls where t = [(this-a) . (b-a)] / |b-a|^2
     const double t = va.dot(v) / l2;
-    if (t < 0.0)      return va.norm();  // beyond the 'a' end of the segment
-    else if (t > 1.0) return (point - line.b).cast<double>().norm();  // beyond the 'b' end of the segment
-    return (t * v - va).norm();
+    if (t < 0.0)      return va.squaredNorm();  // beyond the 'a' end of the segment
+    else if (t > 1.0) return (point - b).cast<double>().squaredNorm();  // beyond the 'b' end of the segment
+    return (t * v - va).squaredNorm();
 }
 
 double Line::perp_distance_to(const Point &point) const
diff --git a/src/libslic3r/Line.hpp b/src/libslic3r/Line.hpp
index 36e02247c..559ca946a 100644
--- a/src/libslic3r/Line.hpp
+++ b/src/libslic3r/Line.hpp
@@ -31,7 +31,8 @@ public:
     Point  midpoint() const { return (this->a + this->b) / 2; }
     bool   intersection_infinite(const Line &other, Point* point) const;
     bool   operator==(const Line &rhs) const { return this->a == rhs.a && this->b == rhs.b; }
-    double distance_to(const Point &point) const;
+    double distance_to_squared(const Point &point) const { return distance_to_squared(point, this->a, this->b); }
+    double distance_to(const Point &point) const { return distance_to(point, this->a, this->b); }
     double perp_distance_to(const Point &point) const;
     bool   parallel_to(double angle) const;
     bool   parallel_to(const Line &line) const { return this->parallel_to(line.direction()); }
@@ -43,6 +44,9 @@ public:
     bool   intersection(const Line& line, Point* intersection) const;
     double ccw(const Point& point) const { return point.ccw(*this); }
 
+    static double distance_to_squared(const Point &point, const Point &a, const Point &b);
+    static double distance_to(const Point &point, const Point &a, const Point &b) { return sqrt(distance_to_squared(point, a, b)); }
+
     Point a;
     Point b;
 };
diff --git a/src/libslic3r/MultiPoint.cpp b/src/libslic3r/MultiPoint.cpp
index 93c63c4cf..795ee38c2 100644
--- a/src/libslic3r/MultiPoint.cpp
+++ b/src/libslic3r/MultiPoint.cpp
@@ -162,45 +162,51 @@ bool MultiPoint::first_intersection(const Line& line, Point* intersection) const
     return found;
 }
 
-//FIXME This is very inefficient in term of memory use.
-// The recursive algorithm shall run in place, not allocating temporary data in each recursion.
-Points
-MultiPoint::_douglas_peucker(const Points &points, const double tolerance)
+std::vector<Point> MultiPoint::_douglas_peucker(const std::vector<Point>& pts, const double tolerance)
 {
-    assert(points.size() >= 2);
-    Points results;
-    double dmax = 0;
-    size_t index = 0;
-    Line full(points.front(), points.back());
-    for (Points::const_iterator it = points.begin() + 1; it != points.end(); ++it) {
-        // we use shortest distance, not perpendicular distance
-        double d = full.distance_to(*it);
-        if (d > dmax) {
-            index = it - points.begin();
-            dmax = d;
+    std::vector<Point> result_pts;
+    if (! pts.empty()) {
+        const Point  *anchor      = &pts.front();
+        size_t        anchor_idx  = 0;
+        const Point  *floater     = &pts.back();
+        size_t        floater_idx = pts.size() - 1;
+        result_pts.reserve(pts.size());
+        result_pts.emplace_back(*anchor);
+        if (anchor_idx != floater_idx) {
+            assert(pts.size() > 1);
+            std::vector<size_t> dpStack;
+            dpStack.reserve(pts.size());
+            dpStack.emplace_back(floater_idx);
+            for (;;) {
+                double max_distSq   = 0.0;
+                size_t furthest_idx = anchor_idx;
+                // find point furthest from line seg created by (anchor, floater) and note it
+                for (size_t i = anchor_idx + 1; i < floater_idx; ++ i) {
+                    double dist = Line::distance_to_squared(pts[i], *anchor, *floater);
+                    if (dist > max_distSq) {
+                        max_distSq   = dist;
+                        furthest_idx = i;
+                    }
+                }
+                // remove point if less than tolerance
+                if (max_distSq <= tolerance) {
+                    result_pts.emplace_back(*floater);
+                    anchor_idx = floater_idx;
+                    anchor     = floater;
+                    assert(dpStack.back() == floater_idx);
+                    dpStack.pop_back();
+                    if (dpStack.empty())
+                        break;
+                    floater_idx = dpStack.back();
+                } else {
+                    floater_idx = furthest_idx;
+                    dpStack.emplace_back(floater_idx);
+                }
+                floater = &pts[floater_idx];
+            }
         }
     }
-    if (dmax >= tolerance) {
-        Points dp0;
-        dp0.reserve(index + 1);
-        dp0.insert(dp0.end(), points.begin(), points.begin() + index + 1);
-        // Recursive call.
-        Points dp1 = MultiPoint::_douglas_peucker(dp0, tolerance);
-        results.reserve(results.size() + dp1.size() - 1);
-        results.insert(results.end(), dp1.begin(), dp1.end() - 1);
-        
-        dp0.clear();
-        dp0.reserve(points.size() - index);
-        dp0.insert(dp0.end(), points.begin() + index, points.end());
-        // Recursive call.
-        dp1 = MultiPoint::_douglas_peucker(dp0, tolerance);
-        results.reserve(results.size() + dp1.size());
-        results.insert(results.end(), dp1.begin(), dp1.end());
-    } else {
-        results.push_back(points.front());
-        results.push_back(points.back());
-    }
-    return results;
+    return result_pts;
 }
 
 // Visivalingam simplification algorithm https://github.com/slic3r/Slic3r/pull/3825

From 37806c020a1e4bcc54d9349ba009c7d4acd0d73b Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Fri, 14 Dec 2018 19:40:02 +0100
Subject: [PATCH 09/10] Temporarily disabled the following check: "Levitating
 objects cannot be printed without support" until the unit tests are adjusted.

---
 src/libslic3r/PrintObject.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index 772d930aa..fdf950ee5 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -385,11 +385,13 @@ void PrintObject::generate_support_material()
             this->_generate_support_material();
             m_print->throw_if_canceled();
         } else {
+#if 0
             // Printing without supports. Empty layer means some objects or object parts are levitating,
             // therefore they cannot be printed without supports.
             for (const Layer *layer : m_layers)
                 if (layer->empty())
                     throw std::runtime_error("Levitating objects cannot be printed without supports.");
+#endif
         }
         this->set_done(posSupportMaterial);
     }

From 6da83c797690afbb4c455e2a90e54fe3d6cc9ed3 Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Fri, 14 Dec 2018 20:09:10 +0100
Subject: [PATCH 10/10] Make the increase of extruder motor current during MM
 filament exchange sequences configurable.

---
 src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 24 +++++++++++++-----------
 src/libslic3r/GCode/WipeTowerPrusaMM.hpp |  5 ++++-
 src/libslic3r/Print.cpp                  |  4 +++-
 src/libslic3r/PrintConfig.cpp            |  9 +++++++++
 src/libslic3r/PrintConfig.hpp            |  2 ++
 src/slic3r/GUI/Preset.cpp                |  3 ++-
 src/slic3r/GUI/Tab.cpp                   |  1 +
 7 files changed, 34 insertions(+), 14 deletions(-)

diff --git a/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/src/libslic3r/GCode/WipeTowerPrusaMM.cpp
index 5c24cd71c..db38a7462 100644
--- a/src/libslic3r/GCode/WipeTowerPrusaMM.cpp
+++ b/src/libslic3r/GCode/WipeTowerPrusaMM.cpp
@@ -505,8 +505,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(
 		  .speed_override(100);
 
 	writer.set_initial_position(xy(0.f, 0.f))	// Always move to the starting position
-		.travel(cleaning_box.ld, 7200)
-		.set_extruder_trimpot(750); 			// Increase the extruder driver current to allow fast ramming.
+		.travel(cleaning_box.ld, 7200);
+	if (m_set_extruder_trimpot)
+		writer.set_extruder_trimpot(750); 			// Increase the extruder driver current to allow fast ramming.
 
     for (size_t idx_tool = 0; idx_tool < tools.size(); ++ idx_tool) {
         unsigned int tool = tools[idx_tool];
@@ -533,8 +534,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(
                             // in the output gcode - we should not remember emitting them (we will output them twice in the worst case)
 
 	// Reset the extruder current to a normal value.
-	writer.set_extruder_trimpot(550)
-		  .feedrate(6000)
+	if (m_set_extruder_trimpot)
+		writer.set_extruder_trimpot(550);
+	writer.feedrate(6000)
 		  .flush_planner_queue()
 		  .reset_extruder()
 		  .append("; CP PRIMING END\n"
@@ -607,7 +609,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo
     writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
 
     // Increase the extruder driver current to allow fast ramming.
-    writer.set_extruder_trimpot(750);
+	if (m_set_extruder_trimpot)
+		writer.set_extruder_trimpot(550);
 
     // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
     if (tool != (unsigned int)-1){ 			// This is not the last change.
@@ -635,8 +638,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo
         }
     }
 
-    writer.set_extruder_trimpot(550)    // Reset the extruder current to a normal value.
-          .feedrate(6000)
+	if (m_set_extruder_trimpot)
+		writer.set_extruder_trimpot(550);    // Reset the extruder current to a normal value.
+    writer.feedrate(6000)
           .flush_planner_queue()
           .reset_extruder()
           .append("; CP TOOLCHANGE END\n"
@@ -916,12 +920,10 @@ void WipeTowerPrusaMM::toolchange_Load(
 		  .resume_preview();
 
 	// Reset the extruder current to the normal value.
-	writer.set_extruder_trimpot(550);
+	if (m_set_extruder_trimpot)
+		writer.set_extruder_trimpot(550);
 }
 
-
-
-
 // Wipe the newly loaded filament until the end of the assigned wipe area.
 void WipeTowerPrusaMM::toolchange_Wipe(
 	PrusaMultiMaterial::Writer &writer,
diff --git a/src/libslic3r/GCode/WipeTowerPrusaMM.hpp b/src/libslic3r/GCode/WipeTowerPrusaMM.hpp
index 06625d189..c0aeee3ae 100644
--- a/src/libslic3r/GCode/WipeTowerPrusaMM.hpp
+++ b/src/libslic3r/GCode/WipeTowerPrusaMM.hpp
@@ -44,7 +44,8 @@ public:
 	// width		-- width of wipe tower in mm ( default 60 mm - leave as it is )
 	// wipe_area	-- space available for one toolchange in mm
 	WipeTowerPrusaMM(float x, float y, float width, float rotation_angle, float cooling_tube_retraction,
-                     float cooling_tube_length, float parking_pos_retraction, float extra_loading_move, float bridging,
+                     float cooling_tube_length, float parking_pos_retraction, float extra_loading_move, 
+                     float bridging, bool set_extruder_trimpot,
                      const std::vector<std::vector<float>>& wiping_matrix, unsigned int initial_tool) :
     m_wipe_tower_pos(x, y),
 		m_wipe_tower_width(width),
@@ -57,6 +58,7 @@ public:
         m_parking_pos_retraction(parking_pos_retraction),
         m_extra_loading_move(extra_loading_move),
 		m_bridging(bridging),
+		m_set_extruder_trimpot(set_extruder_trimpot),
         m_current_tool(initial_tool),
         wipe_volumes(wiping_matrix)
         {}
@@ -212,6 +214,7 @@ private:
     float           m_parking_pos_retraction    = 0.f;
     float           m_extra_loading_move        = 0.f;
     float           m_bridging                  = 0.f;
+    bool            m_set_extruder_trimpot      = false;
     bool            m_adhesion                  = true;
 
 	float m_perimeter_width = 0.4 * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill.
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index 77cf9c0f6..e3382573c 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -213,6 +213,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
             || opt_key == "filament_cooling_final_speed"
             || opt_key == "filament_ramming_parameters"
             || opt_key == "gcode_flavor"
+            || opt_key == "high_current_on_filament_swap"
             || opt_key == "infill_first"
             || opt_key == "single_extruder_multi_material"
             || opt_key == "spiral_vase"
@@ -1768,7 +1769,8 @@ void Print::_make_wipe_tower()
         float(m_config.wipe_tower_width.value),
         float(m_config.wipe_tower_rotation_angle.value), float(m_config.cooling_tube_retraction.value),
         float(m_config.cooling_tube_length.value), float(m_config.parking_pos_retraction.value),
-        float(m_config.extra_loading_move.value), float(m_config.wipe_tower_bridging), wipe_volumes,
+        float(m_config.extra_loading_move.value), float(m_config.wipe_tower_bridging), 
+        m_config.high_current_on_filament_swap.value, wipe_volumes,
         m_wipe_tower_data.tool_ordering.first_extruder());
 
     //wipe_tower.set_retract();
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index 8a564b6b5..f24d40fed 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -925,6 +925,15 @@ void PrintConfigDef::init_fff_params()
     def->mode = comExpert;
     def->default_value = new ConfigOptionEnum<GCodeFlavor>(gcfRepRap);
 
+    def = this->add("high_current_on_filament_swap", coBool);
+    def->label = L("High extruder current on filament swap");
+    def->tooltip = L("It may be beneficial to increase the extruder motor current during the filament exchange"
+                   " sequence to allow for rapid ramming feed rates and to overcome resistance when loading"
+                   " a filament with an ugly shaped tip.");
+    def->cli = "high-current-on-filament-swap!";
+    def->mode = comExpert;
+    def->default_value = new ConfigOptionBool(0);
+
     def = this->add("infill_acceleration", coFloat);
     def->label = L("Infill");
     def->tooltip = L("This is the acceleration your printer will use for infill. Set zero to disable "
diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp
index 1949a8ac8..487e35bf2 100644
--- a/src/libslic3r/PrintConfig.hpp
+++ b/src/libslic3r/PrintConfig.hpp
@@ -627,6 +627,7 @@ public:
     ConfigOptionBool                variable_layer_height;
     ConfigOptionFloat               cooling_tube_retraction;
     ConfigOptionFloat               cooling_tube_length;
+    ConfigOptionBool                high_current_on_filament_swap;
     ConfigOptionFloat               parking_pos_retraction;
     ConfigOptionBool                remaining_times;
     ConfigOptionBool                silent_mode;
@@ -695,6 +696,7 @@ protected:
         OPT_PTR(variable_layer_height);
         OPT_PTR(cooling_tube_retraction);
         OPT_PTR(cooling_tube_length);
+        OPT_PTR(high_current_on_filament_swap);
         OPT_PTR(parking_pos_retraction);
         OPT_PTR(remaining_times);
         OPT_PTR(silent_mode);
diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp
index 639f70cf7..90372ecd4 100644
--- a/src/slic3r/GUI/Preset.cpp
+++ b/src/slic3r/GUI/Preset.cpp
@@ -366,7 +366,8 @@ const std::vector<std::string>& Preset::printer_options()
             "host_type", "print_host", "printhost_apikey", "printhost_cafile",
             "single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
             "between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction",
-            "cooling_tube_length", "parking_pos_retraction", "extra_loading_move", "max_print_height", "default_print_profile", "inherits",
+            "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "max_print_height", 
+            "default_print_profile", "inherits",
             "remaining_times", "silent_mode", "machine_max_acceleration_extruding", "machine_max_acceleration_retracting",
 			"machine_max_acceleration_x", "machine_max_acceleration_y", "machine_max_acceleration_z", "machine_max_acceleration_e",
         	"machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e",
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index 6372f7321..30d83d845 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -2041,6 +2041,7 @@ void TabPrinter::build_extruder_pages()
 		optgroup->append_single_option_line("cooling_tube_length");
 		optgroup->append_single_option_line("parking_pos_retraction");
         optgroup->append_single_option_line("extra_loading_move");
+        optgroup->append_single_option_line("high_current_on_filament_swap");
 		m_pages.insert(m_pages.end() - n_after_single_extruder_MM, page);
 		m_has_single_extruder_MM_page = true;
 	}