From 6ce1011a09943d084f82e96156805fae7fb6a24b Mon Sep 17 00:00:00 2001
From: bubnikv <bubnikv@gmail.com>
Date: Thu, 19 Sep 2019 17:16:37 +0200
Subject: [PATCH 01/12] Slic3r -> PrusaSlicer in config snapshot dialog.

---
 src/slic3r/GUI/ConfigSnapshotDialog.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/slic3r/GUI/ConfigSnapshotDialog.cpp b/src/slic3r/GUI/ConfigSnapshotDialog.cpp
index 836a0a4d3..c89e4895e 100644
--- a/src/slic3r/GUI/ConfigSnapshotDialog.cpp
+++ b/src/slic3r/GUI/ConfigSnapshotDialog.cpp
@@ -42,7 +42,7 @@ static wxString generate_html_row(const Config::Snapshot &snapshot, bool row_eve
         text += " (" + wxString::FromUTF8(snapshot.comment.data()) + ")";
     text += "</b></font><br>";
     // End of row header.
-    text += _(L("slic3r version")) + ": " + snapshot.slic3r_version_captured.to_string() + "<br>";
+    text += _(L("PrusaSlicer version")) + ": " + snapshot.slic3r_version_captured.to_string() + "<br>";
     text += _(L("print")) + ": " + snapshot.print + "<br>";
     text += _(L("filaments")) + ": " + snapshot.filaments.front() + "<br>";
     text += _(L("printer")) + ": " + snapshot.printer + "<br>";
@@ -50,9 +50,9 @@ static wxString generate_html_row(const Config::Snapshot &snapshot, bool row_eve
     bool compatible = true;
     for (const Config::Snapshot::VendorConfig &vc : snapshot.vendor_configs) {
         text += _(L("vendor")) + ": " + vc.name +", " + _(L("version")) + ": " + vc.version.config_version.to_string() + 
-				", " + _(L("min slic3r version")) + ": " + vc.version.min_slic3r_version.to_string();
+				", " + _(L("min PrusaSlicer version")) + ": " + vc.version.min_slic3r_version.to_string();
         if (vc.version.max_slic3r_version != Semver::inf())
-            text += ", " + _(L("max slic3r version")) + ": " + vc.version.max_slic3r_version.to_string();
+            text += ", " + _(L("max PrusaSlicer version")) + ": " + vc.version.max_slic3r_version.to_string();
         text += "<br>";
         for (const std::pair<std::string, std::set<std::string>> &model : vc.models_variants_installed) {
             text += _(L("model")) + ": " + model.first + ", " + _(L("variants")) + ": ";

From 9e09c52ab008f6e8346972f0591a60e248d78ddb Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Fri, 20 Sep 2019 09:53:35 +0200
Subject: [PATCH 02/12] #2948 - Max zoom takes in account custom bed model size

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

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index edb9c7830..08e47f30b 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -3372,7 +3372,7 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
 void GLCanvas3D::set_camera_zoom(double zoom)
 {
     const Size& cnv_size = get_canvas_size();
-    m_camera.set_zoom(zoom, _max_bounding_box(false, false), cnv_size.get_width(), cnv_size.get_height());
+    m_camera.set_zoom(zoom, _max_bounding_box(false, true), cnv_size.get_width(), cnv_size.get_height());
     m_dirty = true;
 }
 

From 8aaff083557a79a041ee17f1d6879a5574e62599 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 20 Sep 2019 09:57:27 +0200
Subject: [PATCH 03/12] Added Possibility to create "shape" as an independent
 object from 3dScene, using right click on empty place

---
 src/slic3r/GUI/GLCanvas3D.cpp | 12 ++++-
 src/slic3r/GUI/GLCanvas3D.hpp |  5 +-
 src/slic3r/GUI/Plater.cpp     | 91 ++++++++++++++++++++---------------
 3 files changed, 66 insertions(+), 42 deletions(-)

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index edb9c7830..6d069df29 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -1094,7 +1094,7 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const
 wxDEFINE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent);
 wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
 wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
-wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent);
+wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
 wxDEFINE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
 wxDEFINE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent);
 wxDEFINE_EVENT(EVT_GLCANVAS_SELECT_ALL, SimpleEvent);
@@ -3012,15 +3012,23 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
                     wxGetApp().obj_manipul()->set_dirty();
                     // forces a frame render to update the view before the context menu is shown
                     render();
-
+/*  #et_FIXME
                     Vec2d logical_pos = pos.cast<double>();
 #if ENABLE_RETINA_GL
                     const float factor = m_retina_helper->get_scale_factor();
                     logical_pos = logical_pos.cwiseQuotient(Vec2d(factor, factor));
 #endif // ENABLE_RETINA_GL
                     post_event(Vec2dEvent(EVT_GLCANVAS_RIGHT_CLICK, logical_pos));
+*/
                 }
             }
+            // #et_FIXME
+            Vec2d logical_pos = pos.cast<double>();
+#if ENABLE_RETINA_GL
+            const float factor = m_retina_helper->get_scale_factor();
+            logical_pos = logical_pos.cwiseQuotient(Vec2d(factor, factor));
+#endif // ENABLE_RETINA_GL
+            post_event(RBtnEvent(EVT_GLCANVAS_RIGHT_CLICK, {logical_pos, m_hover_volume_idxs.empty()}));
         }
 
         mouse_up_cleanup();
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index b15402a52..e6b10e9ca 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -71,6 +71,9 @@ public:
 wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
 
 using Vec2dEvent = Event<Vec2d>;
+// #et_FIXME : RBtnEvent is used instead of Vec2dEvent on EVT_GLCANVAS_RIGHT_CLICK
+// _bool_ value is used as a indicator of selection in the 3DScene
+using RBtnEvent = Event<std::pair<Vec2d, bool>>;
 template <size_t N> using Vec2dsEvent = ArrayEvent<Vec2d, N>;
 
 using Vec3dEvent = Event<Vec3d>;
@@ -78,7 +81,7 @@ template <size_t N> using Vec3dsEvent = ArrayEvent<Vec3d, N>;
 
 wxDECLARE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent);
 wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
-wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent);
+wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
 wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
 wxDECLARE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent);
 wxDECLARE_EVENT(EVT_GLCANVAS_SELECT_ALL, SimpleEvent);
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 524034ea9..18bc08d27 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -1340,6 +1340,8 @@ struct Plater::priv
     MenuWithSeparators part_menu;
     // SLA-Object popup menu
     MenuWithSeparators sla_object_menu;
+    // Default popup menu (when nothing is selected on 3DScene)
+    MenuWithSeparators default_menu;
 
     // Removed/Prepended Items according to the view mode
     std::vector<wxMenuItem*> items_increase;
@@ -1879,7 +1881,7 @@ struct Plater::priv
     void on_action_layersediting(SimpleEvent&);
 
     void on_object_select(SimpleEvent&);
-    void on_right_click(Vec2dEvent&);
+    void on_right_click(RBtnEvent&);
     void on_wipetower_moved(Vec3dEvent&);
     void on_wipetower_rotated(Vec3dEvent&);
     void on_update_geometry(Vec3dsEvent<2>&);
@@ -3446,57 +3448,66 @@ void Plater::priv::on_object_select(SimpleEvent& evt)
     selection_changed();
 }
 
-void Plater::priv::on_right_click(Vec2dEvent& evt)
+void Plater::priv::on_right_click(RBtnEvent& evt)
 {
     int obj_idx = get_selected_object_idx();
+
+    wxMenu* menu = nullptr;
+
     if (obj_idx == -1)
-        return;
-
-    wxMenu* menu = printer_technology == ptSLA ? &sla_object_menu :
-                   get_selection().is_single_full_instance() ? // show "Object menu" for each FullInstance instead of FullObject
-                   &object_menu : &part_menu;
-
-    sidebar->obj_list()->append_menu_item_settings(menu);
-
-    if (printer_technology != ptSLA)
-        sidebar->obj_list()->append_menu_item_change_extruder(menu);
-
-    if (menu != &part_menu)
+        menu = &default_menu;
+    else
     {
-        /* Remove/Prepend "increase/decrease instances" menu items according to the view mode.
-         * Suppress to show those items for a Simple mode
-         */
-        const MenuIdentifier id = printer_technology == ptSLA ? miObjectSLA : miObjectFFF;
-        if (wxGetApp().get_mode() == comSimple) {
-            if (menu->FindItem(_(L("Add instance"))) != wxNOT_FOUND)
-            {
-                /* Detach an items from the menu, but don't delete them
-                 * so that they can be added back later
-                 * (after switching to the Advanced/Expert mode)
-                 */
-                menu->Remove(items_increase[id]);
-                menu->Remove(items_decrease[id]);
-                menu->Remove(items_set_number_of_copies[id]);
+        // If in 3DScene is(are) selected volume(s), but right button was clicked on empty space
+        if (evt.data.second)
+            return; 
+
+        menu = printer_technology == ptSLA ? &sla_object_menu :
+               get_selection().is_single_full_instance() ? // show "Object menu" for each FullInstance instead of FullObject
+               &object_menu : &part_menu;
+
+        sidebar->obj_list()->append_menu_item_settings(menu);
+
+        if (printer_technology != ptSLA)
+            sidebar->obj_list()->append_menu_item_change_extruder(menu);
+
+        if (menu != &part_menu)
+        {
+            /* Remove/Prepend "increase/decrease instances" menu items according to the view mode.
+             * Suppress to show those items for a Simple mode
+             */
+            const MenuIdentifier id = printer_technology == ptSLA ? miObjectSLA : miObjectFFF;
+            if (wxGetApp().get_mode() == comSimple) {
+                if (menu->FindItem(_(L("Add instance"))) != wxNOT_FOUND)
+                {
+                    /* Detach an items from the menu, but don't delete them
+                     * so that they can be added back later
+                     * (after switching to the Advanced/Expert mode)
+                     */
+                    menu->Remove(items_increase[id]);
+                    menu->Remove(items_decrease[id]);
+                    menu->Remove(items_set_number_of_copies[id]);
+                }
             }
-        }
-        else {
-            if (menu->FindItem(_(L("Add instance"))) == wxNOT_FOUND)
-            {
-                // Prepend items to the menu, if those aren't not there
-                menu->Prepend(items_set_number_of_copies[id]);
-                menu->Prepend(items_decrease[id]);
-                menu->Prepend(items_increase[id]);
+            else {
+                if (menu->FindItem(_(L("Add instance"))) == wxNOT_FOUND)
+                {
+                    // Prepend items to the menu, if those aren't not there
+                    menu->Prepend(items_set_number_of_copies[id]);
+                    menu->Prepend(items_decrease[id]);
+                    menu->Prepend(items_increase[id]);
+                }
             }
         }
     }
 
-    if (q != nullptr) {
+    if (q != nullptr && menu) {
 #ifdef __linux__
         // For some reason on Linux the menu isn't displayed if position is specified
         // (even though the position is sane).
         q->PopupMenu(menu);
 #else
-        q->PopupMenu(menu, (int)evt.data.x(), (int)evt.data.y());
+        q->PopupMenu(menu, (int)evt.data.first.x(), (int)evt.data.first.y());
 #endif
     }
 }
@@ -3548,12 +3559,14 @@ bool Plater::priv::init_object_menu()
     init_common_menu(&part_menu, true);
     complit_init_part_menu();
 
+    sidebar->obj_list()->create_default_popupmenu(&default_menu);
+
     return true;
 }
 
 void Plater::priv::msw_rescale_object_menu()
 {
-    for (MenuWithSeparators* menu : { &object_menu, &sla_object_menu, &part_menu })
+    for (MenuWithSeparators* menu : { &object_menu, &sla_object_menu, &part_menu, &default_menu })
         msw_rescale_menu(dynamic_cast<wxMenu*>(menu));
 }
 

From b241ba16ed403492dad83068e655fec1723305e3 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Fri, 20 Sep 2019 10:53:50 +0200
Subject: [PATCH 04/12] Fixed layer profile equality check for wipe tower
 validation (fixup of b43003d)

---
 src/libslic3r/Print.cpp | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index cbbbf1f1a..4d8482743 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -1236,7 +1236,8 @@ std::string Print::validate() const
 
                     // The comparison of the profiles is not just about element-wise equality, some layers may not be
                     // explicitely included. Always remember z and height of last reference layer that in the vector
-                    // and compare to that.
+                    // and compare to that. In case some layers are in the vectors multiple times, only the last entry is
+                    // taken into account and compared.
                     size_t i = 0; // index into tested profile
                     size_t j = 0; // index into reference profile
                     coordf_t ref_z = -1.;
@@ -1244,8 +1245,12 @@ std::string Print::validate() const
                     coordf_t ref_height = -1.;
                     while (i < layer_height_profile.size()) {
                         coordf_t this_z = layer_height_profile[i];
+                        // find the last entry with this z
+                        while (i+2 < layer_height_profile.size() && layer_height_profile[i+2] == this_z)
+                            i += 2;
+
                         coordf_t this_height = layer_height_profile[i+1];
-                        if (next_ref_z < this_z + EPSILON) {
+                        if (ref_height < -1. || next_ref_z < this_z + EPSILON) {
                             ref_z = next_ref_z;
                             do { // one layer can be in the vector several times
                                 ref_height = layer_height_profile_tallest[j+1];

From d66bf7e1e198b66feb78af9d7787490428995015 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Fri, 20 Sep 2019 11:19:06 +0200
Subject: [PATCH 05/12] Follow-up of 8aaff083557a79a041ee17f1d6879a5574e62599
 -> Do not show the new context menu when the user pans the scene + cleanup

---
 src/slic3r/GUI/GLCanvas3D.cpp | 13 +++----------
 src/slic3r/GUI/GLCanvas3D.hpp |  1 -
 2 files changed, 3 insertions(+), 11 deletions(-)

diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 21cd72a22..715d9f806 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -3012,23 +3012,16 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
                     wxGetApp().obj_manipul()->set_dirty();
                     // forces a frame render to update the view before the context menu is shown
                     render();
-/*  #et_FIXME
-                    Vec2d logical_pos = pos.cast<double>();
-#if ENABLE_RETINA_GL
-                    const float factor = m_retina_helper->get_scale_factor();
-                    logical_pos = logical_pos.cwiseQuotient(Vec2d(factor, factor));
-#endif // ENABLE_RETINA_GL
-                    post_event(Vec2dEvent(EVT_GLCANVAS_RIGHT_CLICK, logical_pos));
-*/
                 }
             }
-            // #et_FIXME
             Vec2d logical_pos = pos.cast<double>();
 #if ENABLE_RETINA_GL
             const float factor = m_retina_helper->get_scale_factor();
             logical_pos = logical_pos.cwiseQuotient(Vec2d(factor, factor));
 #endif // ENABLE_RETINA_GL
-            post_event(RBtnEvent(EVT_GLCANVAS_RIGHT_CLICK, {logical_pos, m_hover_volume_idxs.empty()}));
+            if (!m_mouse.dragging)
+                // do not post the event if the user is panning the scene
+                post_event(RBtnEvent(EVT_GLCANVAS_RIGHT_CLICK, { logical_pos, m_hover_volume_idxs.empty() }));
         }
 
         mouse_up_cleanup();
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index e6b10e9ca..fb767360c 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -71,7 +71,6 @@ public:
 wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
 
 using Vec2dEvent = Event<Vec2d>;
-// #et_FIXME : RBtnEvent is used instead of Vec2dEvent on EVT_GLCANVAS_RIGHT_CLICK
 // _bool_ value is used as a indicator of selection in the 3DScene
 using RBtnEvent = Event<std::pair<Vec2d, bool>>;
 template <size_t N> using Vec2dsEvent = ArrayEvent<Vec2d, N>;

From 7e060f84bd534fb027bdc3a1f4b48cce912090bd Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 20 Sep 2019 11:30:29 +0200
Subject: [PATCH 06/12] Forcing of explicit SetWidth for the columns under OSX,
 as an attempt to fix a narrow column width on 4(5)K monitors under OSX

---
 src/slic3r/GUI/GUI_ObjectList.cpp | 31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 47be4b5eb..1d5d8f1a5 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -255,21 +255,30 @@ void ObjectList::create_objects_ctrl()
     EnableDropTarget(wxDF_UNICODETEXT);
 #endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
 
+    const int em = wxGetApp().em_unit();
+
     // column ItemName(Icon+Text) of the view control: 
     // And Icon can be consisting of several bitmaps
     AppendColumn(new wxDataViewColumn(_(L("Name")), new BitmapTextRenderer(),
-        colName, 20*wxGetApp().em_unit()/*200*/, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE));
+        colName, 20*em, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE));
 
     // column PrintableProperty (Icon) of the view control:
-    AppendBitmapColumn(" ", colPrint, wxDATAVIEW_CELL_INERT, int(2 * wxGetApp().em_unit()),
+    AppendBitmapColumn(" ", colPrint, wxDATAVIEW_CELL_INERT, 3*em,
         wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
 
     // column Extruder of the view control:
     AppendColumn(create_objects_list_extruder_column(4));
 
     // column ItemEditing of the view control:
-    AppendBitmapColumn(_(L("Editing")), colEditing, wxDATAVIEW_CELL_INERT, int(2.5 * wxGetApp().em_unit())/*25*/,
+    AppendBitmapColumn(_(L("Editing")), colEditing, wxDATAVIEW_CELL_INERT, 3*em,
         wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
+
+    if (wxOSX)
+    {
+        GetColumn(colName)->SetWidth(20*em);
+        GetColumn(colPrint)->SetWidth(3*em);
+        GetColumn(colExtruder)->SetWidth(8*em);
+    }
 }
 
 void ObjectList::create_popup_menus()
@@ -822,12 +831,18 @@ void ObjectList::list_manipulation(bool evt_context_menu/* = false*/)
         show_context_menu(evt_context_menu);
     else if (title == _("Name"))
     {
-        int obj_idx, vol_idx;
-        get_selected_item_indexes(obj_idx, vol_idx, item);
+        if (wxOSX)
+            show_context_menu(evt_context_menu); // return context menu under OSX (related to #2909)
 
-        if (is_windows10() && get_mesh_errors_count(obj_idx, vol_idx) > 0 && 
-            pt.x > 2*wxGetApp().em_unit() && pt.x < 4*wxGetApp().em_unit() )
-            fix_through_netfabb();
+        if (is_windows10())
+        {
+            int obj_idx, vol_idx;
+            get_selected_item_indexes(obj_idx, vol_idx, item);
+
+            if (get_mesh_errors_count(obj_idx, vol_idx) > 0 && 
+                pt.x > 2*wxGetApp().em_unit() && pt.x < 4*wxGetApp().em_unit() )
+                fix_through_netfabb();
+        }
     }
 
 #ifndef __WXMSW__

From 656569b0e9e836c628f85cabc16e6805382ac729 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Fri, 20 Sep 2019 16:45:43 +0200
Subject: [PATCH 07/12] Fix of
 https://github.com/prusa3d/PrusaSlicer/issues/2953

printf-like function argument mismatch: num was long, which was obfuscated by the auto keyword
---
 src/slic3r/GUI/Plater.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 18bc08d27..28474cac9 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -4336,14 +4336,14 @@ void Plater::set_number_of_copies(/*size_t num*/)
 
     ModelObject* model_object = p->model.objects[obj_idx];
 
-    const auto num = wxGetNumberFromUser( " ", _("Enter the number of copies:"),
+    const int num = wxGetNumberFromUser( " ", _("Enter the number of copies:"),
                                     _("Copies of the selected object"), model_object->instances.size(), 0, 1000, this );
     if (num < 0)
         return;
 
     Plater::TakeSnapshot snapshot(this, wxString::Format(_(L("Set numbers of copies to %d")), num));
 
-    int diff = (int)num - (int)model_object->instances.size();
+    int diff = num - (int)model_object->instances.size();
     if (diff > 0)
         increase_instances(diff);
     else if (diff < 0)

From 927ad5776ce309ed4155e8b6a36500738304f2bb Mon Sep 17 00:00:00 2001
From: Vojtech Kral <vojtech@kral.hk>
Date: Fri, 20 Sep 2019 17:14:28 +0200
Subject: [PATCH 08/12] avrdude: Cherry-pick rev 1421 from upstream:

Submitted by Reinhard Max patch #8311: Add IPv6 support to the
-Pnet:host:port option * ser_posix.c (net_open):
Rewrite to use getaddrinfo() rather than gethostbyname()

Fix #2918
---
 src/avrdude/ChangeLog        |  9 ++++
 src/avrdude/avrdude.1        |  7 +++
 src/avrdude/configure.ac     |  2 +-
 src/avrdude/doc/avrdude.texi |  5 ++
 src/avrdude/ser_posix.c      | 99 +++++++++++++++++++++---------------
 5 files changed, 81 insertions(+), 41 deletions(-)

diff --git a/src/avrdude/ChangeLog b/src/avrdude/ChangeLog
index 975f52317..879fbf957 100644
--- a/src/avrdude/ChangeLog
+++ b/src/avrdude/ChangeLog
@@ -1,3 +1,12 @@
+2018-01-17  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+(cherry-picked)
+	Submitted by Reinhard Max
+	patch #8311: Add IPv6 support to the -Pnet:host:port option
+	* ser_posix.c (net_open): Rewrite to use getaddrinfo()
+	rather than gethostbyname()
+	* avrdude.1: Document IPv6 feature
+	* doc/avrdude.texi: (Dito)
+
 2016-05-10  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
 
 	Submitted by Hannes Jochriem:
diff --git a/src/avrdude/avrdude.1 b/src/avrdude/avrdude.1
index 65fc7b1d6..47ca4edde 100644
--- a/src/avrdude/avrdude.1
+++ b/src/avrdude/avrdude.1
@@ -505,12 +505,19 @@ network connection to (TCP)
 on
 .Ar host
 is established.
+Square brackets may be placed around
+.Ar host
+to improve readability, for numeric IPv6 addresses (e.g.
+.Li net:[2001:db8::42]:1337 ) .
 The remote endpoint is assumed to be a terminal or console server
 that connects the network stream to a local serial port where the
 actual programmer has been attached to.
 The port is assumed to be properly configured, for example using a
 transparent 8-bit data connection without parity at 115200 Baud
 for a STK500.
+.Pp
+Note: The ability to handle IPv6 hostnames and addresses is limited to
+Posix systems (by now).
 .It Fl q
 Disable (or quell) output of the progress bar while reading or writing
 to the device.  Specify it a second time for even quieter operation.
diff --git a/src/avrdude/configure.ac b/src/avrdude/configure.ac
index a23a959f2..d14fc545f 100644
--- a/src/avrdude/configure.ac
+++ b/src/avrdude/configure.ac
@@ -214,7 +214,7 @@ AC_HEADER_TIME
 AC_CHECK_LIB([ws2_32], [puts])
 
 # Checks for library functions.
-AC_CHECK_FUNCS([memset select strcasecmp strdup strerror strncasecmp strtol strtoul gettimeofday usleep])
+AC_CHECK_FUNCS([memset select strcasecmp strdup strerror strncasecmp strtol strtoul gettimeofday usleep getaddrinfo])
 
 AC_MSG_CHECKING([for a Win32 HID libray])
 SAVED_LIBS="${LIBS}"
diff --git a/src/avrdude/doc/avrdude.texi b/src/avrdude/doc/avrdude.texi
index 6941389df..7062a9920 100644
--- a/src/avrdude/doc/avrdude.texi
+++ b/src/avrdude/doc/avrdude.texi
@@ -557,6 +557,9 @@ higher level protocol (as opposed to bit-bang style programmers),
 In this case, instead of trying to open a local device, a TCP
 network connection to (TCP) @var{port} on @var{host}
 is established.
+Square brackets may be placed around @var{host} to improve
+readability for numeric IPv6 addresses (e.g.
+@code{net:[2001:db8::42]:1337}).
 The remote endpoint is assumed to be a terminal or console server
 that connects the network stream to a local serial port where the
 actual programmer has been attached to.
@@ -564,6 +567,8 @@ The port is assumed to be properly configured, for example using a
 transparent 8-bit data connection without parity at 115200 Baud
 for a STK500.
 
+Note: The ability to handle IPv6 hostnames and addresses is limited to
+Posix systems (by now).
 
 @item -q
 Disable (or quell) output of the progress bar while reading or writing
diff --git a/src/avrdude/ser_posix.c b/src/avrdude/ser_posix.c
index 9992f78e3..dfa02f9fe 100644
--- a/src/avrdude/ser_posix.c
+++ b/src/avrdude/ser_posix.c
@@ -150,6 +150,7 @@ static int ser_setspeed(union filedescriptor *fd, long baud)
   return 0;
 }
 
+#include "ac_cfg.h"
 
 // Timeout read & write variants
 // Additionally to the regular -1 on I/O error, they return -2 on timeout
@@ -221,23 +222,35 @@ ssize_t write_timeout(int fd, const void *buf, size_t count, long timeout)
 static int
 net_open(const char *port, union filedescriptor *fdp)
 {
-  char *hstr, *pstr, *end;
-  unsigned int pnum;
-  int fd;
-  struct sockaddr_in sockaddr;
-  struct hostent *hp;
+#ifdef HAVE_GETADDRINFO
+  char *hp, *hstr, *pstr;
+  int s, fd, ret = -1;
+  struct addrinfo hints;
+  struct addrinfo *result, *rp;
 
-  if ((hstr = strdup(port)) == NULL) {
+  if ((hstr = hp = strdup(port)) == NULL) {
     avrdude_message(MSG_INFO, "%s: net_open(): Out of memory!\n",
 	    progname);
     return -1;
   }
 
-  if (((pstr = strchr(hstr, ':')) == NULL) || (pstr == hstr)) {
+  /*
+   * As numeric IPv6 addresses use colons as separators, we need to
+   * look for the last colon here, which separates the port number or
+   * service name from the host or IP address.
+   */
+  if (((pstr = strrchr(hstr, ':')) == NULL) || (pstr == hstr)) {
     avrdude_message(MSG_INFO, "%s: net_open(): Mangled host:port string \"%s\"\n",
 	    progname, hstr);
-    free(hstr);
-    return -1;
+    goto error;
+  }
+
+  /*
+   * Remove brackets from the host part, if present.
+   */
+  if (*hstr == '[' && *(pstr-1) == ']') {
+    hstr++;
+    *(pstr-1) = '\0';
   }
 
   /*
@@ -245,43 +258,49 @@ net_open(const char *port, union filedescriptor *fdp)
    */
   *pstr++ = '\0';
 
-  pnum = strtoul(pstr, &end, 10);
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = AF_UNSPEC;
+  hints.ai_socktype = SOCK_STREAM;
+  s = getaddrinfo(hstr, pstr, &hints, &result);
 
-  if ((*pstr == '\0') || (*end != '\0') || (pnum == 0) || (pnum > 65535)) {
-    avrdude_message(MSG_INFO, "%s: net_open(): Bad port number \"%s\"\n",
-	    progname, pstr);
-    free(hstr);
-    return -1;
+  if (s != 0) {
+    avrdude_message(MSG_INFO,
+	    "%s: net_open(): Cannot resolve "
+	    "host=\"%s\", port=\"%s\": %s\n",
+	    progname, hstr, pstr, gai_strerror(s));
+    goto error;
   }
-
-  if ((hp = gethostbyname(hstr)) == NULL) {
-    avrdude_message(MSG_INFO, "%s: net_open(): unknown host \"%s\"\n",
-	    progname, hstr);
-    free(hstr);
-    return -1;
+  for (rp = result; rp != NULL; rp = rp->ai_next) {
+    fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+    if (fd == -1) {
+      /* This one failed, loop over */
+      continue;
+    }
+    if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) {
+      /* Success, we are connected */
+      break;
+    }
+    close(fd);
   }
-
-  free(hstr);
-
-  if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
-    avrdude_message(MSG_INFO, "%s: net_open(): Cannot open socket: %s\n",
-	    progname, strerror(errno));
-    return -1;
+  if (rp == NULL) {
+    avrdude_message(MSG_INFO, "%s: net_open(): Cannot connect: %s\n",
+      progname, strerror(errno));
   }
-
-  memset(&sockaddr, 0, sizeof(struct sockaddr_in));
-  sockaddr.sin_family = AF_INET;
-  sockaddr.sin_port = htons(pnum);
-  memcpy(&(sockaddr.sin_addr.s_addr), hp->h_addr, sizeof(struct in_addr));
-
-  if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
-    avrdude_message(MSG_INFO, "%s: net_open(): Connect failed: %s\n",
-	    progname, strerror(errno));
-    return -1;
+  else {
+    fdp->ifd = fd;
+    ret = 0;
   }
+  freeaddrinfo(result);
 
-  fdp->ifd = fd;
-  return 0;
+error:
+  free(hp);
+  return ret;
+#else
+  avrdude_message(MSG_INFO,
+    "%s: Networking is not supported on your platform.\n"
+    "If you need it, please open a bug report.\n", progname);
+  return -1;
+#endif /* HAVE_GETADDRINFO */
 }
 
 

From 4e22761f95e4490a90353600c4569eee71fceb13 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 23 Sep 2019 10:17:53 +0200
Subject: [PATCH 09/12] Fix of #2977

---
 src/slic3r/GUI/GUI_ObjectList.cpp | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 1d5d8f1a5..d4766ee72 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -810,8 +810,13 @@ void ObjectList::list_manipulation(bool evt_context_menu/* = false*/)
      */
 
     if (!item) {
-        if (wxOSX && col == nullptr)
-            UnselectAll();
+        if (col == nullptr) {
+            if (wxOSX)
+                UnselectAll();
+            else
+                return;
+        }
+
         if (evt_context_menu) {
             show_context_menu(evt_context_menu);
             return;
@@ -1330,7 +1335,7 @@ wxMenu* ObjectList::append_submenu_add_generic(wxMenu* menu, const ModelVolumeTy
 
     for (auto& item : { L("Box"), L("Cylinder"), L("Sphere"), L("Slab") })
     {
-        if (type == ModelVolumeType::INVALID && item == "Slab")
+        if (type == ModelVolumeType::INVALID && strncmp(item, "Slab", 4) == 0)
             continue;
         append_menu_item(sub_menu, wxID_ANY, _(item), "",
             [this, type, item](wxCommandEvent&) { load_generic_subobject(item, type); }, "", menu);

From 4aec14ddabf35537cc53678e6cb21d6eb9410dd0 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 23 Sep 2019 11:11:43 +0200
Subject: [PATCH 10/12] =?UTF-8?q?Replace=20"mm3/s"=20with=20"mm=C2=B3/s"?=
 =?UTF-8?q?=20in=20preview=20legend=20for=20a=20"Volumetric=20flow=20rate"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/libslic3r/GCode/PreviewData.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libslic3r/GCode/PreviewData.cpp b/src/libslic3r/GCode/PreviewData.cpp
index 74de2f532..76f21daeb 100644
--- a/src/libslic3r/GCode/PreviewData.cpp
+++ b/src/libslic3r/GCode/PreviewData.cpp
@@ -359,7 +359,7 @@ std::string GCodePreviewData::get_legend_title() const
     case Extrusion::Feedrate:
         return L("Speed (mm/s)");
     case Extrusion::VolumetricRate:
-        return L("Volumetric flow rate (mm3/s)");
+        return L("Volumetric flow rate (mm³/s)");
     case Extrusion::Tool:
         return L("Tool");
     case Extrusion::ColorPrint:

From a6f5fe7bea91e4b89e9a462df1fec2d371b1a30d Mon Sep 17 00:00:00 2001
From: tamasmeszaros <meszaros.q@gmail.com>
Date: Mon, 23 Sep 2019 11:58:39 +0200
Subject: [PATCH 11/12] Fix arrange crash with incorrect geometries. Guard the
 case with tests.

---
 .../libnest2d/backends/clipper/geometries.hpp | 19 ++--
 .../include/libnest2d/geometry_traits.hpp     |  2 +-
 .../include/libnest2d/placers/nfpplacer.hpp   | 73 +-------------
 .../selections/selection_boilerplate.hpp      |  2 +-
 src/libnest2d/tests/test.cpp                  | 98 +++++++++++++------
 src/libslic3r/Arrange.cpp                     | 18 ++--
 6 files changed, 92 insertions(+), 120 deletions(-)

diff --git a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp
index 56330e15e..57da6ec12 100644
--- a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp
+++ b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp
@@ -81,17 +81,16 @@ inline void offset(PolygonImpl& sh, TCoord<PointImpl> distance, const PolygonTag
     using ClipperLib::etClosedPolygon;
     using ClipperLib::Paths;
 
-    // If the input is not at least a triangle, we can not do this algorithm
-    if(sh.Contour.size() <= 3 ||
-       std::any_of(sh.Holes.begin(), sh.Holes.end(),
-                   [](const PathImpl& p) { return p.size() <= 3; })
-       ) throw GeometryException(GeomErr::OFFSET);
-
-    ClipperOffset offs;
     Paths result;
-    offs.AddPath(sh.Contour, jtMiter, etClosedPolygon);
-    offs.AddPaths(sh.Holes, jtMiter, etClosedPolygon);
-    offs.Execute(result, static_cast<double>(distance));
+    
+    try {
+        ClipperOffset offs;
+        offs.AddPath(sh.Contour, jtMiter, etClosedPolygon);
+        offs.AddPaths(sh.Holes, jtMiter, etClosedPolygon);
+        offs.Execute(result, static_cast<double>(distance));
+    } catch (ClipperLib::clipperException &) {
+        throw GeometryException(GeomErr::OFFSET);
+    }
 
     // Offsetting reverts the orientation and also removes the last vertex
     // so boost will not have a closed polygon.
diff --git a/src/libnest2d/include/libnest2d/geometry_traits.hpp b/src/libnest2d/include/libnest2d/geometry_traits.hpp
index 827e2d8ba..72e239a70 100644
--- a/src/libnest2d/include/libnest2d/geometry_traits.hpp
+++ b/src/libnest2d/include/libnest2d/geometry_traits.hpp
@@ -1144,7 +1144,7 @@ inline bool isInside(const TBGuest& ibb, const TBHost& box,
     auto minY = getY(box.minCorner());
     auto maxY = getY(box.maxCorner());
 
-    return iminX > minX && imaxX < maxX && iminY > minY && imaxY < maxY;
+    return iminX >= minX && imaxX <= maxX && iminY >= minY && imaxY <= maxY;
 }
 
 template<class S, class TB>
diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp
index 1a341d691..686857a87 100644
--- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp
+++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp
@@ -3,9 +3,6 @@
 
 #include <cassert>
 
-// For caching nfps
-#include <unordered_map>
-
 // For parallel for
 #include <functional>
 #include <iterator>
@@ -76,55 +73,6 @@ inline void enumerate(
 
 }
 
-namespace __itemhash {
-
-using Key = size_t;
-
-template<class S>
-Key hash(const _Item<S>& item) {
-    using Point = TPoint<S>;
-    using Segment = _Segment<Point>;
-
-    static const int N = 26;
-    static const int M = N*N - 1;
-
-    std::string ret;
-    auto& rhs = item.rawShape();
-    auto& ctr = sl::contour(rhs);
-    auto it = ctr.begin();
-    auto nx = std::next(it);
-
-    double circ = 0;
-    while(nx != ctr.end()) {
-        Segment seg(*it++, *nx++);
-        Radians a = seg.angleToXaxis();
-        double deg = Degrees(a);
-        int ms = 'A', ls = 'A';
-        while(deg > N) { ms++; deg -= N; }
-        ls += int(deg);
-        ret.push_back(char(ms)); ret.push_back(char(ls));
-        circ += std::sqrt(seg.template sqlength<double>());
-    }
-
-    it = ctr.begin(); nx = std::next(it);
-
-    while(nx != ctr.end()) {
-        Segment seg(*it++, *nx++);
-        auto l = int(M * std::sqrt(seg.template sqlength<double>()) / circ);
-        int ms = 'A', ls = 'A';
-        while(l > N) { ms++; l -= N; }
-        ls += l;
-        ret.push_back(char(ms)); ret.push_back(char(ls));
-    }
-
-    return std::hash<std::string>()(ret);
-}
-
-template<class S>
-using Hash = std::unordered_map<Key, nfp::NfpResult<S>>;
-
-}
-
 namespace placers {
 
 template<class RawShape>
@@ -529,17 +477,9 @@ class _NofitPolyPlacer: public PlacerBoilerplate<_NofitPolyPlacer<RawShape, TBin
 
     using MaxNfpLevel = nfp::MaxNfpLevel<RawShape>;
 
-    using ItemKeys = std::vector<__itemhash::Key>;
-
     // Norming factor for the optimization function
     const double norm_;
 
-    // Caching calculated nfps
-    __itemhash::Hash<RawShape> nfpcache_;
-
-    // Storing item hash keys
-    ItemKeys item_keys_;
-
 public:
 
     using Pile = nfp::Shapes<RawShape>;
@@ -636,15 +576,12 @@ public:
 private:
 
     using Shapes = TMultiShape<RawShape>;
-    using ItemRef = std::reference_wrapper<Item>;
-    using ItemWithHash = const std::pair<ItemRef, __itemhash::Key>;
 
-    Shapes calcnfp(const ItemWithHash itsh, Lvl<nfp::NfpLevel::CONVEX_ONLY>)
+    Shapes calcnfp(const Item &trsh, Lvl<nfp::NfpLevel::CONVEX_ONLY>)
     {
         using namespace nfp;
 
         Shapes nfps(items_.size());
-        const Item& trsh = itsh.first;
 
         // /////////////////////////////////////////////////////////////////////
         // TODO: this is a workaround and should be solved in Item with mutexes
@@ -678,12 +615,11 @@ private:
 
 
     template<class Level>
-    Shapes calcnfp( const ItemWithHash itsh, Level)
+    Shapes calcnfp(const Item &trsh, Level)
     { // Function for arbitrary level of nfp implementation
         using namespace nfp;
 
         Shapes nfps;
-        const Item& trsh = itsh.first;
 
         auto& orb = trsh.transformedShape();
         bool orbconvex = trsh.isContourConvex();
@@ -849,8 +785,6 @@ private:
             remlist.insert(remlist.end(), remaining.from, remaining.to);
         }
 
-        size_t itemhash = __itemhash::hash(item);
-
         if(items_.empty()) {
             setInitialPosition(item);
             best_overfit = overfit(item.transformedShape(), bin_);
@@ -875,7 +809,7 @@ private:
                 // it is disjunct from the current merged pile
                 placeOutsideOfBin(item);
 
-                nfps = calcnfp({item, itemhash}, Lvl<MaxNfpLevel::value>());
+                nfps = calcnfp(item, Lvl<MaxNfpLevel::value>());
 
                 auto iv = item.referenceVertex();
 
@@ -1112,7 +1046,6 @@ private:
 
         if(can_pack) {
             ret = PackResult(item);
-            item_keys_.emplace_back(itemhash);
         } else {
             ret = PackResult(best_overfit);
         }
diff --git a/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp b/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp
index 2df9a26c3..36fec7164 100644
--- a/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp
+++ b/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp
@@ -43,7 +43,7 @@ protected:
             
             Placer p{bin};
             p.configure(pcfg);
-            if (!p.pack(cpy)) it = c.erase(it);
+            if (itm.area() <= 0 || !p.pack(cpy)) it = c.erase(it);
             else it++;
         }
     }
diff --git a/src/libnest2d/tests/test.cpp b/src/libnest2d/tests/test.cpp
index 4a6691415..5ba28228a 100644
--- a/src/libnest2d/tests/test.cpp
+++ b/src/libnest2d/tests/test.cpp
@@ -40,7 +40,7 @@ struct NfpImpl<S, NfpLevel::CONVEX_ONLY>
 }
 }
 
-std::vector<libnest2d::Item>& prusaParts() {
+static std::vector<libnest2d::Item>& prusaParts() {
     static std::vector<libnest2d::Item> ret;
     
     if(ret.empty()) {
@@ -51,7 +51,7 @@ std::vector<libnest2d::Item>& prusaParts() {
     return ret;
 }
 
-TEST(BasicFunctionality, Angles)
+TEST(GeometryAlgorithms, Angles)
 {
     
     using namespace libnest2d;
@@ -109,7 +109,7 @@ TEST(BasicFunctionality, Angles)
 }
 
 // Simple test, does not use gmock
-TEST(BasicFunctionality, creationAndDestruction)
+TEST(Nesting, ItemCreationAndDestruction)
 {
     using namespace libnest2d;
     
@@ -572,26 +572,74 @@ TEST(GeometryAlgorithms, convexHull) {
 }
 
 
-TEST(GeometryAlgorithms, NestTest) {
+TEST(Nesting, NestPrusaPartsShouldFitIntoTwoBins) {
+    
+    // Get the input items and define the bin.
     std::vector<Item> input = prusaParts();
-
-    libnest2d::nest(input, Box(250000000, 210000000), [](unsigned cnt) {
-        std::cout << "parts left: " << cnt << std::endl;
+    auto bin = Box(250000000, 210000000);
+    
+    // Do the nesting. Check in each step if the remaining items are less than
+    // in the previous step. (Some algorithms can place more items in one step)
+    size_t pcount = input.size();
+    libnest2d::nest(input, bin, [&pcount](unsigned cnt) {
+        ASSERT_TRUE(cnt < pcount);
+        pcount = cnt;
     });
-
+    
+    // Get the number of logical bins: search for the max binId...
     auto max_binid_it = std::max_element(input.begin(), input.end(),
                                          [](const Item &i1, const Item &i2) {
                                              return i1.binId() < i2.binId();
                                          });
-
-    size_t bins = max_binid_it == input.end() ? 0 : max_binid_it->binId() + 1;
     
-    ASSERT_EQ(bins, 2u);
-
+    auto bins = size_t(max_binid_it == input.end() ? 0 :
+                                                     max_binid_it->binId() + 1);
+    
+    // For prusa parts, 2 bins should be enough...
+    ASSERT_LE(bins, 2u);
+    
+    // All parts should be processed by the algorithm
     ASSERT_TRUE(
         std::all_of(input.begin(), input.end(), [](const Item &itm) {
             return itm.binId() != BIN_ID_UNSET;
         }));
+    
+    // Gather the items into piles of arranged polygons...
+    using Pile = TMultiShape<ClipperLib::Polygon>;
+    std::vector<Pile> piles(bins);
+    
+    for (auto &itm : input)
+        piles[size_t(itm.binId())].emplace_back(itm.transformedShape());
+    
+    // Now check all the piles, the bounding box of each pile should be inside
+    // the defined bin.
+    for (auto &pile : piles) {
+        auto bb = sl::boundingBox(pile);
+        ASSERT_TRUE(sl::isInside(bb, bin));
+    }
+}
+
+TEST(Nesting, NestEmptyItemShouldBeUntouched) {
+    auto bin = Box(250000000, 210000000); // dummy bin
+    
+    std::vector<Item> items;
+    items.emplace_back(Item{});   // Emplace empty item
+    items.emplace_back(Item{0, 200, 0});   // Emplace zero area item
+    
+    libnest2d::nest(items, bin);
+    
+    for (auto &itm : items) ASSERT_EQ(itm.binId(), BIN_ID_UNSET);
+}
+
+TEST(Nesting, NestLargeItemShouldBeUntouched) {
+    auto bin = Box(250000000, 210000000); // dummy bin
+    
+    std::vector<Item> items;
+    items.emplace_back(Rectangle{250000001, 210000001});  // Emplace large item
+    
+    libnest2d::nest(items, bin);
+    
+    ASSERT_EQ(items.front().binId(), BIN_ID_UNSET);
 }
 
 namespace {
@@ -966,26 +1014,20 @@ using Ratio = boost::rational<boost::multiprecision::int128_t>;
 
 }
 
-TEST(RotatingCalipers, MinAreaBBCClk) {
-    auto u = [](ClipperLib::cInt n) { return n*1000000; };
-    PolygonImpl poly({ {u(0), u(0)}, {u(4), u(1)}, {u(2), u(4)}});
+//TEST(GeometryAlgorithms, MinAreaBBCClk) {
+//    auto u = [](ClipperLib::cInt n) { return n*1000000; };
+//    PolygonImpl poly({ {u(0), u(0)}, {u(4), u(1)}, {u(2), u(4)}});
     
-    long double arearef = refMinAreaBox(poly);
-    long double area = minAreaBoundingBox<PolygonImpl, Unit, Ratio>(poly).area();
+//    long double arearef = refMinAreaBox(poly);
+//    long double area = minAreaBoundingBox<PolygonImpl, Unit, Ratio>(poly).area();
     
-    ASSERT_LE(std::abs(area - arearef), 500e6 );
-}
+//    ASSERT_LE(std::abs(area - arearef), 500e6 );
+//}
 
-TEST(RotatingCalipers, AllPrusaMinBB) {
-    //    /size_t idx = 0;
+TEST(GeometryAlgorithms, MinAreaBBWithRotatingCalipers) {
     long double err_epsilon = 500e6l;
     
     for(ClipperLib::Path rinput : PRINTER_PART_POLYGONS) {
-        //        ClipperLib::Path rinput = PRINTER_PART_POLYGONS[idx];
-        //        rinput.pop_back();
-        //        std::reverse(rinput.begin(), rinput.end());
-        
-        //        PolygonImpl poly(removeCollinearPoints<PathImpl, PointImpl, Unit>(rinput, 1000000));
         PolygonImpl poly(rinput);
         
         long double arearef = refMinAreaBox(poly);
@@ -993,8 +1035,6 @@ TEST(RotatingCalipers, AllPrusaMinBB) {
         long double area = cast<long double>(bb.area());
         
         bool succ = std::abs(arearef - area) < err_epsilon;
-        //        std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: " 
-//                  << arearef << " actual: " << area << std::endl;
         
         ASSERT_TRUE(succ);
     }
@@ -1011,8 +1051,6 @@ TEST(RotatingCalipers, AllPrusaMinBB) {
         
         
         bool succ = std::abs(arearef - area) < err_epsilon;
-        //        std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: " 
-//                  << arearef << " actual: " << area << std::endl;
         
         ASSERT_TRUE(succ);
     }
diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp
index 52168c929..20dfd8926 100644
--- a/src/libslic3r/Arrange.cpp
+++ b/src/libslic3r/Arrange.cpp
@@ -618,19 +618,21 @@ void arrange(ArrangePolygons &             arrangables,
     items.reserve(arrangables.size());
     
     // Create Item from Arrangeable
-    auto process_arrangeable =
-        [](const ArrangePolygon &arrpoly, std::vector<Item> &outp)
+    auto process_arrangeable = [](const ArrangePolygon &arrpoly,
+                                  std::vector<Item> &   outp)
     {
-        Polygon p        = arrpoly.poly.contour;
-        const Vec2crd &  offs     = arrpoly.translation;
-        double           rotation = arrpoly.rotation;
+        Polygon        p        = arrpoly.poly.contour;
+        const Vec2crd &offs     = arrpoly.translation;
+        double         rotation = arrpoly.rotation;
 
         if (p.is_counter_clockwise()) p.reverse();
 
         clppr::Polygon clpath(Slic3rMultiPoint_to_ClipperPath(p));
-
-        auto firstp = clpath.Contour.front();
-        clpath.Contour.emplace_back(firstp);
+        
+        if (!clpath.Contour.empty()) {
+            auto firstp = clpath.Contour.front();
+            clpath.Contour.emplace_back(firstp);
+        }
 
         outp.emplace_back(std::move(clpath));
         outp.back().rotation(rotation);

From c0c937425f17a03a484ac6af28a2a515dbf4d17b Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 23 Sep 2019 14:24:53 +0200
Subject: [PATCH 12/12] Added missed comment to
 https://github.com/prusa3d/PrusaSlicer/commit/7e060f84bd534fb027bdc3a1f4b48cce912090bd

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

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index d4766ee72..573fbe980 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -273,6 +273,8 @@ void ObjectList::create_objects_ctrl()
     AppendBitmapColumn(_(L("Editing")), colEditing, wxDATAVIEW_CELL_INERT, 3*em,
         wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
 
+    // For some reason under OSX on 4K(5K) monitors in wxDataViewColumn constructor doesn't set width of column.
+    // Therefore, force set column width.
     if (wxOSX)
     {
         GetColumn(colName)->SetWidth(20*em);
@@ -3682,10 +3684,10 @@ void ObjectList::msw_rescale()
     // update min size !!! A width of control shouldn't be a wxDefaultCoord
     SetMinSize(wxSize(1, 15 * em));
 
-    GetColumn(colName)->SetWidth(19 * em);
-    GetColumn(colPrint)->SetWidth( 2 * em);
+    GetColumn(colName    )->SetWidth(20 * em);
+    GetColumn(colPrint   )->SetWidth( 3 * em);
     GetColumn(colExtruder)->SetWidth( 8 * em);
-    GetColumn(colEditing)->SetWidth( 2 * em);
+    GetColumn(colEditing )->SetWidth( 3 * em);
 
     // rescale all icons, used by ObjectList
     msw_rescale_icons();