From 99aaedffc1d605c9471a680165f08b5f53b572a0 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Thu, 30 Aug 2018 10:42:55 +0200
Subject: [PATCH 01/27] Added PrusaDoubleSlider on 3DPreview

---
 lib/Slic3r/GUI/Plater/3DPreview.pm    | 18 +++++-
 xs/src/slic3r/GUI/GUI.cpp             |  6 --
 xs/src/slic3r/GUI/GUI.hpp             |  2 -
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp | 80 +++++++++++++++++++++++++++
 xs/src/slic3r/GUI/GUI_ObjectParts.hpp | 10 +++-
 xs/src/slic3r/GUI/wxExtensions.cpp    | 19 +++++++
 xs/src/slic3r/GUI/wxExtensions.hpp    |  5 +-
 xs/xsp/GUI.xsp                        | 17 ++++--
 8 files changed, 138 insertions(+), 19 deletions(-)

diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm
index 09c2f0b8c..c2c5e08b4 100644
--- a/lib/Slic3r/GUI/Plater/3DPreview.pm
+++ b/lib/Slic3r/GUI/Plater/3DPreview.pm
@@ -10,7 +10,7 @@ use base qw(Wx::Panel Class::Accessor);
 
 use Wx::Locale gettext => 'L';
 
-__PACKAGE__->mk_accessors(qw(print gcode_preview_data enabled _loaded canvas slider_low slider_high single_layer));
+__PACKAGE__->mk_accessors(qw(print gcode_preview_data enabled _loaded canvas slider_low slider_high single_layer double_slider_sizer));
 
 sub new {
     my $class = shift;
@@ -102,6 +102,12 @@ sub new {
                         .L("Wipe tower")."|"
                         .L("Custom");
     Slic3r::GUI::create_combochecklist($combochecklist_features, $feature_text, $feature_items, 1);
+
+    # ****************  EXP  ******************
+    my $double_slider_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
+    Slic3r::GUI::create_double_slider($self, $double_slider_sizer, $self->canvas);
+    $self->double_slider_sizer($double_slider_sizer);
+    # ****************  EXP  ******************
     
     my $checkbox_travel         = $self->{checkbox_travel}          = Wx::CheckBox->new($self, -1, L("Travel"));
     my $checkbox_retractions    = $self->{checkbox_retractions}     = Wx::CheckBox->new($self, -1, L("Retractions"));    
@@ -120,6 +126,9 @@ sub new {
     $vsizer->Add($z_label_high_idx, 0, wxALIGN_CENTER_HORIZONTAL, 0);
     $vsizer->Add($z_label_high, 0, 0, 0);
     $hsizer->Add($vsizer, 0, wxEXPAND, 0);
+    # ****************  EXP  ******************
+    $hsizer->Add($double_slider_sizer, 0, wxEXPAND, 0);
+    # ****************  EXP  ******************
     $vsizer_outer->Add($hsizer, 3, wxALIGN_CENTER_HORIZONTAL, 0);
     $vsizer_outer->Add($checkbox_singlelayer, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, 5);
 
@@ -385,6 +394,7 @@ sub load_print {
        }
 
         $self->update_sliders($n_layers) if ($n_layers > 0);
+        Slic3r::GUI::update_double_slider($self->{force_sliders_full_range}) if ($n_layers > 0);
         $self->_loaded(1);
     }
 }
@@ -399,6 +409,9 @@ sub reset_sliders {
     $self->{z_label_high}->SetLabel("");
     $self->{z_label_low_idx}->SetLabel("");
     $self->{z_label_high_idx}->SetLabel("");
+
+    Slic3r::GUI::reset_double_slider();
+    $self->double_slider_sizer->Hide(0);
 }
 
 sub update_sliders
@@ -448,6 +461,9 @@ sub update_sliders
     $self->slider_low->Show;
     $self->slider_high->Show;
     $self->set_z_range($self->{layers_z}[$z_idx_low], $self->{layers_z}[$z_idx_high]);
+
+    $self->double_slider_sizer->Show(0);
+
     $self->Layout;    
 }
 
diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp
index 4592e6433..34865fa63 100644
--- a/xs/src/slic3r/GUI/GUI.cpp
+++ b/xs/src/slic3r/GUI/GUI.cpp
@@ -116,7 +116,6 @@ wxNotebook  *g_wxTabPanel   = nullptr;
 AppConfig	*g_AppConfig	= nullptr;
 PresetBundle *g_PresetBundle= nullptr;
 PresetUpdater *g_PresetUpdater = nullptr;
-_3DScene	*g_3DScene		= nullptr;
 wxColour    g_color_label_modified;
 wxColour    g_color_label_sys;
 wxColour    g_color_label_default;
@@ -222,11 +221,6 @@ void set_preset_updater(PresetUpdater *updater)
 	g_PresetUpdater = updater;
 }
 
-void set_3DScene(_3DScene *scene)
-{
-	g_3DScene = scene;
-}
-
 void set_objects_from_perl(	wxWindow* parent, wxBoxSizer *frequently_changed_parameters_sizer,
 							wxBoxSizer *expert_mode_part_sizer, wxBoxSizer *scrolled_window_sizer,
 							wxButton *btn_export_gcode,
diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp
index 69e83eaab..22ea3edb0 100644
--- a/xs/src/slic3r/GUI/GUI.hpp
+++ b/xs/src/slic3r/GUI/GUI.hpp
@@ -35,7 +35,6 @@ class AppConfig;
 class PresetUpdater;
 class DynamicPrintConfig;
 class TabIface;
-class _3DScene;
 
 #define _(s)    Slic3r::GUI::I18N::translate((s))
 
@@ -101,7 +100,6 @@ void set_tab_panel(wxNotebook *tab_panel);
 void set_app_config(AppConfig *app_config);
 void set_preset_bundle(PresetBundle *preset_bundle);
 void set_preset_updater(PresetUpdater *updater);
-void set_3DScene(_3DScene *scene);
 void set_objects_from_perl(	wxWindow* parent,
 							wxBoxSizer *frequently_changed_parameters_sizer,
 							wxBoxSizer *expert_mode_part_sizer,
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index 94555f50e..9b1214b38 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -13,6 +13,9 @@
 #include "Geometry.hpp"
 #include "slic3r/Utils/FixModelByWin10.hpp"
 
+#include <wx/glcanvas.h>
+#include "3DScene.hpp"
+
 namespace Slic3r
 {
 namespace GUI
@@ -23,6 +26,8 @@ wxSizer		*m_sizer_object_movers = nullptr;
 wxDataViewCtrl				*m_objects_ctrl = nullptr;
 PrusaObjectDataViewModel	*m_objects_model = nullptr;
 wxCollapsiblePane			*m_collpane_settings = nullptr;
+PrusaDoubleSlider           *m_slider = nullptr;
+wxGLCanvas                  *m_preview_canvas = nullptr;
 
 wxIcon		m_icon_modifiermesh;
 wxIcon		m_icon_solidmesh;
@@ -1668,5 +1673,80 @@ void update_objects_list_extruder_column(int extruders_count)
     set_extruder_column_hidden(extruders_count <= 1);
 }
 
+void create_double_slider(wxWindow* parent, wxBoxSizer* sizer, wxGLCanvas* canvas)
+{
+    m_slider = new PrusaDoubleSlider(parent, wxID_ANY, 0, 0, 0, 100);
+    sizer->Add(m_slider, 0, wxEXPAND, 0);
+
+    m_preview_canvas = canvas;
+
+    m_slider->Bind(wxEVT_SCROLL_CHANGED, [parent](wxEvent& event) {
+        _3DScene::set_toolpaths_range(m_preview_canvas, m_slider->GetLowerValueD() - 1e-6, m_slider->GetHigherValueD() + 1e-6);
+        if (parent->IsShown())
+            m_preview_canvas->Refresh();
+    });
+}
+
+void fill_slider_values(std::vector<std::pair<int, double>> &values, 
+                        const std::vector<double> &layers_z)
+{
+    std::vector<double> layers_all_z = _3DScene::get_current_print_zs(m_preview_canvas, false);
+    if (layers_all_z.size() == layers_z.size())
+        for (int i = 0; i < layers_z.size(); i++)
+            values.push_back(std::pair<int, double>(i+1, layers_z[i]));
+    else if (layers_all_z.size() > layers_z.size()) {
+        int cur_id = 0;
+        for (int i = 0; i < layers_z.size(); i++)
+            for (int j = cur_id; j < layers_all_z.size(); j++)
+                if (layers_z[i] - 1e-6 < layers_all_z[j] && layers_all_z[j] < layers_z[i] + 1e-6) {
+                    values.push_back(std::pair<int, double>(j+1, layers_z[i]));
+                    cur_id = j;
+                    break;
+                }
+    }
+}
+
+void set_double_slider_thumbs(  const bool force_sliders_full_range, 
+                                const std::vector<double> &layers_z, 
+                                const double z_low, const double z_high)
+{
+    if (force_sliders_full_range) {
+        m_slider->SetLowerValue(0);
+        m_slider->SetHigherValue(layers_z.size() - 1);
+        return;
+    }
+    
+    for (int i = layers_z.size() - 1; i >= 0; i--)
+        if (z_low >= layers_z[i]) {
+            m_slider->SetLowerValue(i);
+            break;
+        }
+    for (int i = layers_z.size() - 1; i >= 0 ; i--)
+        if (z_high >= layers_z[i]) {
+            m_slider->SetHigherValue(i);
+            break;
+        }
+}
+
+void update_double_slider(bool force_sliders_full_range)
+{
+    std::vector<std::pair<int, double>> values;
+    std::vector<double> layers_z = _3DScene::get_current_print_zs(m_preview_canvas, true);
+    fill_slider_values(values, layers_z);
+
+    const double z_low = m_slider->GetLowerValueD();
+    const double z_high = m_slider->GetHigherValueD();
+    m_slider->SetMaxValue(layers_z.size() - 1);
+    m_slider->SetSliderValues(values);
+
+    set_double_slider_thumbs(force_sliders_full_range, layers_z, z_low, z_high);
+}
+
+void reset_double_slider()
+{
+    m_slider->SetHigherValue(0);
+    m_slider->SetLowerValue(0);
+}
+
 } //namespace GUI
 } //namespace Slic3r 
\ No newline at end of file
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.hpp b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
index 82bfe4a6c..f659cf404 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
@@ -9,13 +9,14 @@ class wxArrayString;
 class wxMenu;
 class wxDataViewEvent;
 class wxKeyEvent;
-class wxControl;
+class wxGLCanvas;
 
 namespace Slic3r {
 class ModelObject;
 class Model;
 
 namespace GUI {
+//class wxGLCanvas;
 
 enum ogGroup{
 	ogFrequentlyChangingParameters,
@@ -69,8 +70,6 @@ void select_current_object(int idx);
 // Remove objects/sub-object from the list
 void remove();
 
-//void create_double_slider(wxWindow* parent, wxControl* slider);
-
 void object_ctrl_selection_changed();
 void object_ctrl_context_menu();
 void object_ctrl_key_event(wxKeyEvent& event);
@@ -123,6 +122,11 @@ void on_drop(wxDataViewEvent &event);
 // update extruder column for objects_ctrl according to extruders count
 void update_objects_list_extruder_column(int extruders_count);
 
+// Create/Update/Reset double slider on 3dPreview
+void create_double_slider(wxWindow* parent, wxBoxSizer* sizer, wxGLCanvas* canvas);
+void update_double_slider(bool force_sliders_full_range);
+void reset_double_slider();
+
 } //namespace GUI
 } //namespace Slic3r 
 #endif  //slic3r_GUI_ObjectParts_hpp_
\ No newline at end of file
diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index e646ed0ec..685c4d8d0 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -832,6 +832,10 @@ void PrusaDoubleSlider::SetLowerValue(const int lower_val)
     m_lower_value = lower_val;
     Refresh();
     Update();
+
+    wxCommandEvent e(wxEVT_SCROLL_CHANGED);
+    e.SetEventObject(this);
+    ProcessWindowEvent(e);
 }
 
 void PrusaDoubleSlider::SetHigherValue(const int higher_val)
@@ -839,6 +843,10 @@ void PrusaDoubleSlider::SetHigherValue(const int higher_val)
     m_higher_value = higher_val;
     Refresh();
     Update();
+
+    wxCommandEvent e(wxEVT_SCROLL_CHANGED);
+    e.SetEventObject(this);
+    ProcessWindowEvent(e);
 }
 
 void PrusaDoubleSlider::SetMaxValue(const int max_value)
@@ -905,6 +913,13 @@ void PrusaDoubleSlider::get_size(int *w, int *h)
     is_horizontal() ? *w -= m_lock_icon_dim : *h -= m_lock_icon_dim;
 }
 
+double PrusaDoubleSlider::get_double_value(const SelectedSlider& selection) const
+{
+    if (m_values.empty())
+        return 0.0;
+    return m_values[selection == ssLower ? m_lower_value : m_higher_value].second;
+}
+
 void PrusaDoubleSlider::get_lower_and_higher_position(int& lower_pos, int& higher_pos)
 {
     const double step = get_scroll_step();
@@ -1245,6 +1260,10 @@ void PrusaDoubleSlider::OnMotion(wxMouseEvent& event)
     Refresh();
     Update();
     event.Skip();
+
+    wxCommandEvent e(wxEVT_SCROLL_CHANGED);
+    e.SetEventObject(this);
+    ProcessWindowEvent(e);
 }
 
 void PrusaDoubleSlider::OnLeftUp(wxMouseEvent& event)
diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp
index 76e59f2eb..00973e74f 100644
--- a/xs/src/slic3r/GUI/wxExtensions.hpp
+++ b/xs/src/slic3r/GUI/wxExtensions.hpp
@@ -516,7 +516,7 @@ public:
         int maxValue,
         const wxPoint& pos = wxDefaultPosition,
         const wxSize& size = wxDefaultSize,
-        long style = wxSL_HORIZONTAL,
+        long style = wxSL_VERTICAL,
         const wxValidator& val = wxDefaultValidator,
         const wxString& name = wxEmptyString);
     ~PrusaDoubleSlider(){}
@@ -528,6 +528,8 @@ public:
         return m_higher_value;
     }
     int GetActiveValue() const;
+    double GetLowerValueD()  const { return get_double_value(ssLower); }
+    double GetHigherValueD() const { return get_double_value(ssHigher); }
     wxSize DoGetBestSize() const override;
     void SetLowerValue(const int lower_val);
     void SetHigherValue(const int higher_val);
@@ -583,6 +585,7 @@ protected:
     wxCoord     get_position_from_value(const int value);
     wxSize      get_size();
     void        get_size(int *w, int *h);
+    double      get_double_value(const SelectedSlider& selection) const;
 
 private:
     int         m_min_value;
diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp
index c18fce44d..3e967bb86 100644
--- a/xs/xsp/GUI.xsp
+++ b/xs/xsp/GUI.xsp
@@ -173,16 +173,21 @@ void desktop_open_datadir_folder()
 void fix_model_by_win10_sdk_gui(ModelObject *model_object_src, Print *print, Model *model_dst)
     %code%{ Slic3r::fix_model_by_win10_sdk_gui(*model_object_src, *print, *model_dst); %};
 
-void set_3DScene(SV *scene)
-    %code%{ Slic3r::GUI::set_3DScene((_3DScene *)wxPli_sv_2_object(aTHX_ scene, "Slic3r::Model::3DScene") ); %};
-
 void register_on_request_update_callback(SV* callback)
     %code%{ Slic3r::GUI::g_on_request_update_callback.register_callback(callback); %};
 
 void deregister_on_request_update_callback()
     %code%{ Slic3r::GUI::g_on_request_update_callback.deregister_callback(); %};
 
-//void create_double_slider(SV *ui_parent, SV *ui_ds)
-//    %code%{ Slic3r::GUI::create_double_slider(  (wxWindow*)wxPli_sv_2_object(aTHX_ ui_parent, "Wx::Window"),
-//                                                (wxControl*)wxPli_sv_2_object(aTHX_ ui_ds, "Wx::Control")); %};
+void create_double_slider(SV *ui_parent, SV *ui_sizer, SV *ui_canvas)
+    %code%{ Slic3r::GUI::create_double_slider(  (wxWindow*)wxPli_sv_2_object(aTHX_ ui_parent, "Wx::Window"),
+                                                (wxBoxSizer*)wxPli_sv_2_object(aTHX_ ui_sizer, "Wx::BoxSizer"),
+                                                (wxGLCanvas*)wxPli_sv_2_object(aTHX_ ui_canvas, "Wx::GLCanvas")); %};
+
+void update_double_slider(bool force_sliders_full_range)
+    %code%{ Slic3r::GUI::update_double_slider(force_sliders_full_range); %};
+
+void reset_double_slider()
+    %code%{ Slic3r::GUI::reset_double_slider(); %};
+
 

From 1358c8efd24255d75196194bc7cc7fd1a094c7ce Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Thu, 30 Aug 2018 15:30:31 +0200
Subject: [PATCH 02/27] Removed old sliders from 3DPreview

---
 lib/Slic3r/GUI/Plater/3DPreview.pm    | 348 +++++++++++++-------------
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp |  25 +-
 xs/src/slic3r/GUI/GUI_ObjectParts.hpp |   2 +
 xs/src/slic3r/GUI/wxExtensions.cpp    |  18 ++
 xs/src/slic3r/GUI/wxExtensions.hpp    |   1 +
 5 files changed, 221 insertions(+), 173 deletions(-)

diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm
index c2c5e08b4..06d1a798b 100644
--- a/lib/Slic3r/GUI/Plater/3DPreview.pm
+++ b/lib/Slic3r/GUI/Plater/3DPreview.pm
@@ -5,7 +5,7 @@ use utf8;
 
 use Slic3r::Print::State ':steps';
 use Wx qw(:misc :sizer :slider :statictext :keycode wxWHITE wxCB_READONLY);
-use Wx::Event qw(EVT_SLIDER EVT_KEY_DOWN EVT_CHECKBOX EVT_CHOICE EVT_CHECKLISTBOX);
+use Wx::Event qw(EVT_SLIDER EVT_KEY_DOWN EVT_CHECKBOX EVT_CHOICE EVT_CHECKLISTBOX EVT_SIZE);
 use base qw(Wx::Panel Class::Accessor);
 
 use Wx::Locale gettext => 'L';
@@ -27,47 +27,47 @@ sub new {
     Slic3r::GUI::_3DScene::enable_shader($canvas, 1);
     Slic3r::GUI::_3DScene::set_config($canvas, $config);
     $self->canvas($canvas);
-    my $slider_low = Wx::Slider->new(
-        $self, -1,
-        0,                              # default
-        0,                              # min
+#    my $slider_low = Wx::Slider->new(
+#        $self, -1,
+#        0,                              # default
+#        0,                              # min
         # we set max to a bogus non-zero value because the MSW implementation of wxSlider
         # will skip drawing the slider if max <= min:
-        1,                              # max
-        wxDefaultPosition,
-        wxDefaultSize,
-        wxVERTICAL | wxSL_INVERSE,
-    );
-    $self->slider_low($slider_low);
-    my $slider_high = Wx::Slider->new(
-        $self, -1,
-        0,                              # default
-        0,                              # min
+#        1,                              # max
+#        wxDefaultPosition,
+#        wxDefaultSize,
+#        wxVERTICAL | wxSL_INVERSE,
+#    );
+#    $self->slider_low($slider_low);
+#    my $slider_high = Wx::Slider->new(
+#        $self, -1,
+#        0,                              # default
+#        0,                              # min
         # we set max to a bogus non-zero value because the MSW implementation of wxSlider
         # will skip drawing the slider if max <= min:
-        1,                              # max
-        wxDefaultPosition,
-        wxDefaultSize,
-        wxVERTICAL | wxSL_INVERSE,
-    );
-    $self->slider_high($slider_high);
+#        1,                              # max
+#        wxDefaultPosition,
+#        wxDefaultSize,
+#        wxVERTICAL | wxSL_INVERSE,
+#    );
+#    $self->slider_high($slider_high);
     
-    my $z_label_low = $self->{z_label_low} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
-        [40,-1], wxALIGN_CENTRE_HORIZONTAL);
-    $z_label_low->SetFont($Slic3r::GUI::small_font);
-    my $z_label_high = $self->{z_label_high} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
-        [40,-1], wxALIGN_CENTRE_HORIZONTAL);
-    $z_label_high->SetFont($Slic3r::GUI::small_font);
+#    my $z_label_low = $self->{z_label_low} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
+#        [40,-1], wxALIGN_CENTRE_HORIZONTAL);
+#    $z_label_low->SetFont($Slic3r::GUI::small_font);
+#    my $z_label_high = $self->{z_label_high} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
+#        [40,-1], wxALIGN_CENTRE_HORIZONTAL);
+#    $z_label_high->SetFont($Slic3r::GUI::small_font);
 
-    my $z_label_low_idx = $self->{z_label_low_idx} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
-        [40,-1], wxALIGN_CENTRE_HORIZONTAL);
-    $z_label_low_idx->SetFont($Slic3r::GUI::small_font);
-    my $z_label_high_idx = $self->{z_label_high_idx} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
-        [40,-1], wxALIGN_CENTRE_HORIZONTAL);
-    $z_label_high_idx->SetFont($Slic3r::GUI::small_font);
+#    my $z_label_low_idx = $self->{z_label_low_idx} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
+#        [40,-1], wxALIGN_CENTRE_HORIZONTAL);
+#    $z_label_low_idx->SetFont($Slic3r::GUI::small_font);
+#    my $z_label_high_idx = $self->{z_label_high_idx} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
+#        [40,-1], wxALIGN_CENTRE_HORIZONTAL);
+#    $z_label_high_idx->SetFont($Slic3r::GUI::small_font);
         
-    $self->single_layer(0);
-    my $checkbox_singlelayer = $self->{checkbox_singlelayer} = Wx::CheckBox->new($self, -1, L("1 Layer"));
+#    $self->single_layer(0);
+#    my $checkbox_singlelayer = $self->{checkbox_singlelayer} = Wx::CheckBox->new($self, -1, L("1 Layer"));
     
     my $label_view_type = $self->{label_view_type} = Wx::StaticText->new($self, -1, L("View"));
     
@@ -103,34 +103,30 @@ sub new {
                         .L("Custom");
     Slic3r::GUI::create_combochecklist($combochecklist_features, $feature_text, $feature_items, 1);
 
-    # ****************  EXP  ******************
     my $double_slider_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
     Slic3r::GUI::create_double_slider($self, $double_slider_sizer, $self->canvas);
     $self->double_slider_sizer($double_slider_sizer);
-    # ****************  EXP  ******************
     
     my $checkbox_travel         = $self->{checkbox_travel}          = Wx::CheckBox->new($self, -1, L("Travel"));
     my $checkbox_retractions    = $self->{checkbox_retractions}     = Wx::CheckBox->new($self, -1, L("Retractions"));    
     my $checkbox_unretractions  = $self->{checkbox_unretractions}   = Wx::CheckBox->new($self, -1, L("Unretractions"));
     my $checkbox_shells         = $self->{checkbox_shells}          = Wx::CheckBox->new($self, -1, L("Shells"));
 
-    my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL);
-    my $vsizer = Wx::BoxSizer->new(wxVERTICAL);
-    my $vsizer_outer = Wx::BoxSizer->new(wxVERTICAL);
-    $vsizer->Add($slider_low, 3, wxALIGN_CENTER_HORIZONTAL, 0);
-    $vsizer->Add($z_label_low_idx, 0, wxALIGN_CENTER_HORIZONTAL, 0);
-    $vsizer->Add($z_label_low, 0, wxALIGN_CENTER_HORIZONTAL, 0);
-    $hsizer->Add($vsizer, 0, wxEXPAND, 0);
-    $vsizer = Wx::BoxSizer->new(wxVERTICAL);
-    $vsizer->Add($slider_high, 3, wxALIGN_CENTER_HORIZONTAL, 0);
-    $vsizer->Add($z_label_high_idx, 0, wxALIGN_CENTER_HORIZONTAL, 0);
-    $vsizer->Add($z_label_high, 0, 0, 0);
-    $hsizer->Add($vsizer, 0, wxEXPAND, 0);
-    # ****************  EXP  ******************
-    $hsizer->Add($double_slider_sizer, 0, wxEXPAND, 0);
-    # ****************  EXP  ******************
-    $vsizer_outer->Add($hsizer, 3, wxALIGN_CENTER_HORIZONTAL, 0);
-    $vsizer_outer->Add($checkbox_singlelayer, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, 5);
+#    my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL);
+#    my $vsizer = Wx::BoxSizer->new(wxVERTICAL);
+#    my $vsizer_outer = Wx::BoxSizer->new(wxVERTICAL);
+#    $vsizer->Add($slider_low, 3, wxALIGN_CENTER_HORIZONTAL, 0);
+#    $vsizer->Add($z_label_low_idx, 0, wxALIGN_CENTER_HORIZONTAL, 0);
+#    $vsizer->Add($z_label_low, 0, wxALIGN_CENTER_HORIZONTAL, 0);
+#    $hsizer->Add($vsizer, 0, wxEXPAND, 0);
+#    $vsizer = Wx::BoxSizer->new(wxVERTICAL);
+#    $vsizer->Add($slider_high, 3, wxALIGN_CENTER_HORIZONTAL, 0);
+#    $vsizer->Add($z_label_high_idx, 0, wxALIGN_CENTER_HORIZONTAL, 0);
+#    $vsizer->Add($z_label_high, 0, 0, 0);
+#    $hsizer->Add($vsizer, 0, wxEXPAND, 0);
+#    $vsizer_outer->Add($hsizer, 3, wxALIGN_CENTER_HORIZONTAL, 0);
+#    $vsizer_outer->Add($double_slider_sizer, 3, wxEXPAND, 0);
+#    $vsizer_outer->Add($checkbox_singlelayer, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, 5);
 
     my $bottom_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
     $bottom_sizer->Add($label_view_type, 0, wxALIGN_CENTER_VERTICAL, 5);
@@ -149,81 +145,83 @@ sub new {
     
     my $sizer = Wx::BoxSizer->new(wxHORIZONTAL);
     $sizer->Add($canvas, 1, wxALL | wxEXPAND, 0);
-    $sizer->Add($vsizer_outer, 0, wxTOP | wxBOTTOM | wxEXPAND, 5);
+#    $sizer->Add($vsizer_outer, 0, wxTOP | wxBOTTOM | wxEXPAND, 5);
+    $sizer->Add($double_slider_sizer, 0, wxEXPAND, 0);#wxTOP | wxBOTTOM | wxEXPAND, 5);
 
     my $main_sizer = Wx::BoxSizer->new(wxVERTICAL);
     $main_sizer->Add($sizer, 1, wxALL | wxEXPAND, 0);
     $main_sizer->Add($bottom_sizer, 0, wxALL | wxEXPAND, 0); 
     
-    EVT_SLIDER($self, $slider_low,  sub {
-        $slider_high->SetValue($slider_low->GetValue) if $self->single_layer;
-        $self->set_z_idx_low ($slider_low ->GetValue)
-    });
-    EVT_SLIDER($self, $slider_high, sub { 
-        $slider_low->SetValue($slider_high->GetValue) if $self->single_layer;
-        $self->set_z_idx_high($slider_high->GetValue) 
-    });
-    EVT_KEY_DOWN($canvas, sub {
-        my ($s, $event) = @_;
-        my $key = $event->GetKeyCode;
-        if ($event->HasModifiers) {
-            $event->Skip;
-        } else {
-            if ($key == ord('U')) {
-                $slider_high->SetValue($slider_high->GetValue + 1);
-                $slider_low->SetValue($slider_high->GetValue) if ($event->ShiftDown());
-                $self->set_z_idx_high($slider_high->GetValue);
-            } elsif ($key == ord('D')) {
-                $slider_high->SetValue($slider_high->GetValue - 1);
-                $slider_low->SetValue($slider_high->GetValue) if ($event->ShiftDown());
-                $self->set_z_idx_high($slider_high->GetValue);
-            } elsif ($key == ord('S')) {
-                $checkbox_singlelayer->SetValue(! $checkbox_singlelayer->GetValue());
-                $self->single_layer($checkbox_singlelayer->GetValue());
-                if ($self->single_layer) {
-                    $slider_low->SetValue($slider_high->GetValue);
-                    $self->set_z_idx_high($slider_high->GetValue);
-                }
-            } else {
-                $event->Skip;
-            }
-        }
-    });
-    EVT_KEY_DOWN($slider_low, sub {
-        my ($s, $event) = @_;
-        my $key = $event->GetKeyCode;
-        if ($event->HasModifiers) {
-            $event->Skip;
-        } else {
-            if ($key == WXK_LEFT) {
-            } elsif ($key == WXK_RIGHT) {
-                $slider_high->SetFocus;
-            } else {
-                $event->Skip;
-            }
-        }
-    });
-    EVT_KEY_DOWN($slider_high, sub {
-        my ($s, $event) = @_;
-        my $key = $event->GetKeyCode;
-        if ($event->HasModifiers) {
-            $event->Skip;
-        } else {
-            if ($key == WXK_LEFT) {
-                $slider_low->SetFocus;
-            } elsif ($key == WXK_RIGHT) {
-            } else {
-                $event->Skip;
-            }
-        }
-    });
-    EVT_CHECKBOX($self, $checkbox_singlelayer, sub {
-        $self->single_layer($checkbox_singlelayer->GetValue());
-        if ($self->single_layer) {
-            $slider_low->SetValue($slider_high->GetValue);
-            $self->set_z_idx_high($slider_high->GetValue);
-        }
-    });
+#    EVT_SLIDER($self, $slider_low,  sub {
+#        $slider_high->SetValue($slider_low->GetValue) if $self->single_layer;
+#        $self->set_z_idx_low ($slider_low ->GetValue)
+#    });
+#    EVT_SLIDER($self, $slider_high, sub { 
+#        $slider_low->SetValue($slider_high->GetValue) if $self->single_layer;
+#        $self->set_z_idx_high($slider_high->GetValue) 
+#    });
+#    EVT_KEY_DOWN($canvas, sub {
+#        my ($s, $event) = @_;
+#        Slic3r::GUI::update_double_slider_from_canvas($event);
+#        my $key = $event->GetKeyCode;
+#        if ($event->HasModifiers) {
+#            $event->Skip;
+#        } else {
+#            if ($key == ord('U')) {
+#                $slider_high->SetValue($slider_high->GetValue + 1);
+#                $slider_low->SetValue($slider_high->GetValue) if ($event->ShiftDown());
+#                $self->set_z_idx_high($slider_high->GetValue);
+#            } elsif ($key == ord('D')) {
+#                $slider_high->SetValue($slider_high->GetValue - 1);
+#                $slider_low->SetValue($slider_high->GetValue) if ($event->ShiftDown());
+#                $self->set_z_idx_high($slider_high->GetValue);
+#            } elsif ($key == ord('S')) {
+#                $checkbox_singlelayer->SetValue(! $checkbox_singlelayer->GetValue());
+#                $self->single_layer($checkbox_singlelayer->GetValue());
+#                if ($self->single_layer) {
+#                    $slider_low->SetValue($slider_high->GetValue);
+#                    $self->set_z_idx_high($slider_high->GetValue);
+#                }
+#            } else {
+#                $event->Skip;
+#            }
+#        }
+#    });
+#    EVT_KEY_DOWN($slider_low, sub {
+#        my ($s, $event) = @_;
+#        my $key = $event->GetKeyCode;
+#        if ($event->HasModifiers) {
+#            $event->Skip;
+#        } else {
+#            if ($key == WXK_LEFT) {
+#            } elsif ($key == WXK_RIGHT) {
+#                $slider_high->SetFocus;
+#            } else {
+#                $event->Skip;
+#            }
+#        }
+#    });
+#    EVT_KEY_DOWN($slider_high, sub {
+#        my ($s, $event) = @_;
+#        my $key = $event->GetKeyCode;
+#        if ($event->HasModifiers) {
+#            $event->Skip;
+#        } else {
+#            if ($key == WXK_LEFT) {
+#                $slider_low->SetFocus;
+#            } elsif ($key == WXK_RIGHT) {
+#            } else {
+#                $event->Skip;
+#            }
+#        }
+#    });
+#    EVT_CHECKBOX($self, $checkbox_singlelayer, sub {
+#        $self->single_layer($checkbox_singlelayer->GetValue());
+#        if ($self->single_layer) {
+#            $slider_low->SetValue($slider_high->GetValue);
+#            $self->set_z_idx_high($slider_high->GetValue);
+#        }
+#    });
     EVT_CHOICE($self, $choice_view_type, sub {
         my $selection = $choice_view_type->GetCurrentSelection();
         $self->{preferred_color_mode} = ($selection == $self->{tool_idx}) ? 'tool' : 'feature';
@@ -252,6 +250,12 @@ sub new {
         $self->gcode_preview_data->set_shells_visible($checkbox_shells->IsChecked());
         $self->refresh_print;
     });
+
+    EVT_SIZE($self, sub {
+        my ($s, $event) = @_;
+        $event->Skip;
+        $self->Refresh;
+    });
     
     $self->SetSizer($main_sizer);
     $self->SetMinSize($self->GetSize);
@@ -394,7 +398,6 @@ sub load_print {
        }
 
         $self->update_sliders($n_layers) if ($n_layers > 0);
-        Slic3r::GUI::update_double_slider($self->{force_sliders_full_range}) if ($n_layers > 0);
         $self->_loaded(1);
     }
 }
@@ -402,13 +405,13 @@ sub load_print {
 sub reset_sliders {
     my ($self) = @_;
     $self->enabled(0);
-    $self->set_z_range(0,0);
-    $self->slider_low->Hide;
-    $self->slider_high->Hide;
-    $self->{z_label_low}->SetLabel("");
-    $self->{z_label_high}->SetLabel("");
-    $self->{z_label_low_idx}->SetLabel("");
-    $self->{z_label_high_idx}->SetLabel("");
+#    $self->set_z_range(0,0);
+#    $self->slider_low->Hide;
+#    $self->slider_high->Hide;
+#    $self->{z_label_low}->SetLabel("");
+#    $self->{z_label_high}->SetLabel("");
+#    $self->{z_label_low_idx}->SetLabel("");
+#    $self->{z_label_high_idx}->SetLabel("");
 
     Slic3r::GUI::reset_double_slider();
     $self->double_slider_sizer->Hide(0);
@@ -418,50 +421,51 @@ sub update_sliders
 {
     my ($self, $n_layers) = @_;
         
-    my $z_idx_low = $self->slider_low->GetValue;
-    my $z_idx_high = $self->slider_high->GetValue;
+#    my $z_idx_low = $self->slider_low->GetValue;
+#    my $z_idx_high = $self->slider_high->GetValue;
     $self->enabled(1);
-    $self->slider_low->SetRange(0, $n_layers - 1);
-    $self->slider_high->SetRange(0, $n_layers - 1);
+#    $self->slider_low->SetRange(0, $n_layers - 1);
+#    $self->slider_high->SetRange(0, $n_layers - 1);
     
-    if ($self->{force_sliders_full_range}) {
-        $z_idx_low = 0;
-        $z_idx_high = $n_layers - 1;
-    } elsif ($z_idx_high < $n_layers && ($self->single_layer || $z_idx_high != 0)) {
-        # search new indices for nearest z (size of $self->{layers_z} may change in dependence of what is shown)
-        if (defined($self->{z_low})) {
-            for (my $i = scalar(@{$self->{layers_z}}) - 1; $i >= 0; $i -= 1) {
-                if ($self->{layers_z}[$i] <= $self->{z_low}) {
-                    $z_idx_low = $i;
-                    last;
-                }
-            }
-        }
-        if (defined($self->{z_high})) {
-            for (my $i = scalar(@{$self->{layers_z}}) - 1; $i >= 0; $i -= 1) {
-                if ($self->{layers_z}[$i] <= $self->{z_high}) {
-                    $z_idx_high = $i;
-                    last;
-                }
-            }
-        }
-    } elsif ($z_idx_high >= $n_layers) {
-        # Out of range. Disable 'single layer' view.
-        $self->single_layer(0);
-        $self->{checkbox_singlelayer}->SetValue(0);
-        $z_idx_low = 0;
-        $z_idx_high = $n_layers - 1;
-    } else {
-        $z_idx_low = 0;
-        $z_idx_high = $n_layers - 1;
-    }
+#    if ($self->{force_sliders_full_range}) {
+#        $z_idx_low = 0;
+#        $z_idx_high = $n_layers - 1;
+#    } elsif ($z_idx_high < $n_layers && ($self->single_layer || $z_idx_high != 0)) {
+#        # search new indices for nearest z (size of $self->{layers_z} may change in dependence of what is shown)
+#        if (defined($self->{z_low})) {
+#            for (my $i = scalar(@{$self->{layers_z}}) - 1; $i >= 0; $i -= 1) {
+#                if ($self->{layers_z}[$i] <= $self->{z_low}) {
+#                    $z_idx_low = $i;
+#                    last;
+#                }
+#            }
+#        }
+#        if (defined($self->{z_high})) {
+#            for (my $i = scalar(@{$self->{layers_z}}) - 1; $i >= 0; $i -= 1) {
+#                if ($self->{layers_z}[$i] <= $self->{z_high}) {
+#                    $z_idx_high = $i;
+#                    last;
+#                }
+#            }
+#        }
+#    } elsif ($z_idx_high >= $n_layers) {
+#        # Out of range. Disable 'single layer' view.
+#        $self->single_layer(0);
+#        $self->{checkbox_singlelayer}->SetValue(0);
+#        $z_idx_low = 0;
+#        $z_idx_high = $n_layers - 1;
+#    } else {
+#        $z_idx_low = 0;
+#        $z_idx_high = $n_layers - 1;
+#    }
     
-    $self->slider_low->SetValue($z_idx_low);
-    $self->slider_high->SetValue($z_idx_high);
-    $self->slider_low->Show;
-    $self->slider_high->Show;
-    $self->set_z_range($self->{layers_z}[$z_idx_low], $self->{layers_z}[$z_idx_high]);
+#    $self->slider_low->SetValue($z_idx_low);
+#    $self->slider_high->SetValue($z_idx_high);
+#    $self->slider_low->Show;
+#    $self->slider_high->Show;
+#    $self->set_z_range($self->{layers_z}[$z_idx_low], $self->{layers_z}[$z_idx_high]);
 
+    Slic3r::GUI::update_double_slider($self->{force_sliders_full_range});
     $self->double_slider_sizer->Show(0);
 
     $self->Layout;    
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index 9b1214b38..e175d41eb 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -1679,6 +1679,7 @@ void create_double_slider(wxWindow* parent, wxBoxSizer* sizer, wxGLCanvas* canva
     sizer->Add(m_slider, 0, wxEXPAND, 0);
 
     m_preview_canvas = canvas;
+    m_preview_canvas->Bind(wxEVT_KEY_DOWN, update_double_slider_from_canvas);
 
     m_slider->Bind(wxEVT_SCROLL_CHANGED, [parent](wxEvent& event) {
         _3DScene::set_toolpaths_range(m_preview_canvas, m_slider->GetLowerValueD() - 1e-6, m_slider->GetHigherValueD() + 1e-6);
@@ -1710,7 +1711,9 @@ void set_double_slider_thumbs(  const bool force_sliders_full_range,
                                 const std::vector<double> &layers_z, 
                                 const double z_low, const double z_high)
 {
-    if (force_sliders_full_range) {
+    // Force slider full range only when slider is created.
+    // Support selected diapason on the all next steps
+    if (/*force_sliders_full_range*/z_high == 0.0) { 
         m_slider->SetLowerValue(0);
         m_slider->SetHigherValue(layers_z.size() - 1);
         return;
@@ -1748,5 +1751,25 @@ void reset_double_slider()
     m_slider->SetLowerValue(0);
 }
 
+void update_double_slider_from_canvas(wxKeyEvent& event)
+{
+    if (event.HasModifiers()) {
+        event.Skip();
+        return;
+    }
+
+    const auto key = event.GetKeyCode();
+
+    if (key == 'U' || key == 'D') {
+        const int new_pos = key == 'U' ? m_slider->GetHigherValue() + 1 : m_slider->GetHigherValue() - 1;
+        m_slider->SetHigherValue(new_pos);
+        if (event.ShiftDown()) m_slider->SetLowerValue(m_slider->GetHigherValue());
+    }
+    else if (key == 'S')
+        m_slider->ChangeOneLayerLock();
+    else
+        event.Skip();
+}
+
 } //namespace GUI
 } //namespace Slic3r 
\ No newline at end of file
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.hpp b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
index f659cf404..5a3b96761 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
@@ -126,6 +126,8 @@ void update_objects_list_extruder_column(int extruders_count);
 void create_double_slider(wxWindow* parent, wxBoxSizer* sizer, wxGLCanvas* canvas);
 void update_double_slider(bool force_sliders_full_range);
 void reset_double_slider();
+// update DoubleSlider after keyDown in canvas
+void update_double_slider_from_canvas(wxKeyEvent& event);
 
 } //namespace GUI
 } //namespace Slic3r 
diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index 685c4d8d0..73e6f0877 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -829,7 +829,9 @@ wxSize PrusaDoubleSlider::DoGetBestSize() const
 
 void PrusaDoubleSlider::SetLowerValue(const int lower_val)
 {
+    m_selection = ssLower;
     m_lower_value = lower_val;
+    correct_lower_value();
     Refresh();
     Update();
 
@@ -840,7 +842,9 @@ void PrusaDoubleSlider::SetLowerValue(const int lower_val)
 
 void PrusaDoubleSlider::SetHigherValue(const int higher_val)
 {
+    m_selection = ssHigher;
     m_higher_value = higher_val;
+    correct_higher_value();
     Refresh();
     Update();
 
@@ -1193,6 +1197,20 @@ bool PrusaDoubleSlider::is_point_in_rect(const wxPoint& pt, const wxRect& rect)
     return false;
 }
 
+void PrusaDoubleSlider::ChangeOneLayerLock()
+{
+    m_is_one_layer = !m_is_one_layer;
+    m_selection == ssLower ? correct_lower_value() : correct_higher_value();
+    if (!m_selection) m_selection = ssHigher;
+
+    Refresh();
+    Update();
+
+    wxCommandEvent e(wxEVT_SCROLL_CHANGED);
+    e.SetEventObject(this);
+    ProcessWindowEvent(e);
+}
+
 void PrusaDoubleSlider::OnLeftDown(wxMouseEvent& event)
 {
     this->CaptureMouse();
diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp
index 00973e74f..d1747e434 100644
--- a/xs/src/slic3r/GUI/wxExtensions.hpp
+++ b/xs/src/slic3r/GUI/wxExtensions.hpp
@@ -540,6 +540,7 @@ public:
     void SetSliderValues(const std::vector<std::pair<int, double>>& values) {
         m_values = values;
     }
+    void ChangeOneLayerLock();
 
     void OnPaint(wxPaintEvent& ){ render();}
     void OnLeftDown(wxMouseEvent& event);

From a3c2c511f0514456b8856bf0e3b78210985ee7cd Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 31 Aug 2018 10:57:21 +0200
Subject: [PATCH 03/27] Reorganized right panel

---
 lib/Slic3r/GUI/Plater.pm  | 163 ++++++++++++++++++++++----------------
 xs/src/slic3r/GUI/GUI.cpp |  99 +++++++++++++----------
 xs/src/slic3r/GUI/GUI.hpp |  18 ++---
 xs/xsp/GUI.xsp            |  33 ++++----
 4 files changed, 171 insertions(+), 142 deletions(-)

diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm
index 1a769a87e..4548fd391 100644
--- a/lib/Slic3r/GUI/Plater.pm
+++ b/lib/Slic3r/GUI/Plater.pm
@@ -109,10 +109,11 @@ sub new {
     # callback to enable/disable action buttons
     my $enable_action_buttons = sub {
         my ($enable) = @_;
-        $self->{btn_export_gcode}->Enable($enable);
-        $self->{btn_reslice}->Enable($enable);
-        $self->{btn_print}->Enable($enable);
-        $self->{btn_send_gcode}->Enable($enable);
+        Slic3r::GUI::enable_action_buttons($enable);
+#        $self->{btn_export_gcode}->Enable($enable);
+#        $self->{btn_reslice}->Enable($enable);
+#        $self->{btn_print}->Enable($enable);
+#        $self->{btn_send_gcode}->Enable($enable);
     };
 
     # callback to react to gizmo scale
@@ -363,26 +364,35 @@ sub new {
 #    }
 
     ### Panel for right column
-#    $self->{right_panel} = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
-    $self->{right_panel} = Wx::ScrolledWindow->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
-    $self->{right_panel}->SetScrollbars(0, 1, 1, 1);
+    $self->{right_panel} = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
+#    $self->{right_panel} = Wx::ScrolledWindow->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
+#    $self->{right_panel}->SetScrollbars(0, 1, 1, 1);
+
+    ### Scrolled Window for panel without "Export G-code" and "Slice now" buttons
+    my $scrolled_window_sizer = $self->{scrolled_window_sizer} = Wx::BoxSizer->new(wxVERTICAL);
+    $scrolled_window_sizer->SetMinSize([320, -1]);
+    my $scrolled_window_panel = $self->{scrolled_window_panel} = Wx::ScrolledWindow->new($self->{right_panel}, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
+    $scrolled_window_panel->SetSizer($scrolled_window_sizer);
+    $scrolled_window_panel->SetScrollbars(0, 1, 1, 1);
     
     # right pane buttons
     $self->{btn_export_gcode} = Wx::Button->new($self->{right_panel}, -1, L("Export G-code…"), wxDefaultPosition, [-1, 30], wxNO_BORDER);#, wxBU_LEFT);
-    $self->{btn_reslice} = Wx::Button->new($self->{right_panel}, -1, L("Slice now"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
-    $self->{btn_print} = Wx::Button->new($self->{right_panel}, -1, L("Print…"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
-    $self->{btn_send_gcode} = Wx::Button->new($self->{right_panel}, -1, L("Send to printer"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
-    $self->{btn_export_stl} = Wx::Button->new($self->{right_panel}, -1, L("Export STL…"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
+    $self->{btn_reslice} = Wx::Button->new($self->{right_panel}, -1, L("Slice now"), wxDefaultPosition, [-1, 30], wxNO_BORDER);#, wxBU_LEFT);
+#    $self->{btn_print} = Wx::Button->new($self->{right_panel}, -1, L("Print…"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
+#    $self->{btn_send_gcode} = Wx::Button->new($self->{right_panel}, -1, L("Send to printer"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
+    $self->{btn_print} = Wx::Button->new($scrolled_window_panel, -1, L("Print…"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
+    $self->{btn_send_gcode} = Wx::Button->new($scrolled_window_panel, -1, L("Send to printer"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
+    #$self->{btn_export_stl} = Wx::Button->new($self->{right_panel}, -1, L("Export STL…"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
     #$self->{btn_export_gcode}->SetFont($Slic3r::GUI::small_font);
     #$self->{btn_export_stl}->SetFont($Slic3r::GUI::small_font);
     $self->{btn_print}->Hide;
     $self->{btn_send_gcode}->Hide;
     
 #       export_gcode    cog_go.png
+#!        reslice         reslice.png
     my %icons = qw(
         print           arrow_up.png
         send_gcode      arrow_up.png
-        reslice         reslice.png
         export_stl      brick_go.png
     );
     for (grep $self->{"btn_$_"}, keys %icons) {
@@ -499,9 +509,11 @@ sub new {
             # $self->{preset_choosers}{$group}[$idx]
             $self->{preset_choosers} = {};
             for my $group (qw(print filament sla_material printer)) {
-                my $text = Wx::StaticText->new($self->{right_panel}, -1, "$group_labels{$group}:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
+#                my $text = Wx::StaticText->new($self->{right_panel}, -1, "$group_labels{$group}:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
+                my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$group_labels{$group}:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
                 $text->SetFont($Slic3r::GUI::small_font);
-                my $choice = Wx::BitmapComboBox->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, [], wxCB_READONLY);
+#                my $choice = Wx::BitmapComboBox->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, [], wxCB_READONLY);
+                my $choice = Wx::BitmapComboBox->new($scrolled_window_panel, -1, "", wxDefaultPosition, wxDefaultSize, [], wxCB_READONLY);
                 if ($group eq 'filament') {
                     EVT_LEFT_DOWN($choice, sub { $self->filament_color_box_lmouse_down(0, @_); } );
                 }
@@ -520,26 +532,13 @@ sub new {
         }
 
         my $frequently_changed_parameters_sizer = $self->{frequently_changed_parameters_sizer} = Wx::BoxSizer->new(wxVERTICAL);
-        Slic3r::GUI::add_frequently_changed_parameters($self->{right_panel}, $frequently_changed_parameters_sizer, $presets);
-
-        my $expert_mode_part_sizer = Wx::BoxSizer->new(wxVERTICAL);
-        Slic3r::GUI::add_expert_mode_part(  $self->{right_panel}, $expert_mode_part_sizer, 
-                                            $self->{model},
-                                            $self->{event_object_selection_changed},
-                                            $self->{event_object_settings_changed},
-                                            $self->{event_remove_object},
-                                            $self->{event_update_scene});
-#        if ($expert_mode_part_sizer->IsShown(2)==1) 
-#        { 
-#           $expert_mode_part_sizer->Layout;
-#            $expert_mode_part_sizer->Show(2, 0); # ? Why doesn't work
-#            $self->{right_panel}->Layout;
-#       }
+#!        Slic3r::GUI::add_frequently_changed_parameters($self->{right_panel}, $frequently_changed_parameters_sizer, $presets);
+        Slic3r::GUI::add_frequently_changed_parameters($self->{scrolled_window_panel}, $frequently_changed_parameters_sizer, $presets);
 
         my $object_info_sizer;
         {
-#            my $box = Wx::StaticBox->new($scrolled_window_panel, -1, L("Info"));
-            my $box = Wx::StaticBox->new($self->{right_panel}, -1, L("Info"));
+            my $box = Wx::StaticBox->new($scrolled_window_panel, -1, L("Info"));
+#            my $box = Wx::StaticBox->new($self->{right_panel}, -1, L("Info"));
             $box->SetFont($Slic3r::GUI::small_bold_font);
             $object_info_sizer = Wx::StaticBoxSizer->new($box, wxVERTICAL);
             $object_info_sizer->SetMinSize([300,-1]);
@@ -559,17 +558,17 @@ sub new {
             );
             while (my $field = shift @info) {
                 my $label = shift @info;
-#                my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
-                my $text = Wx::StaticText->new($self->{right_panel}, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+                my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+#                my $text = Wx::StaticText->new($self->{right_panel}, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
                 $text->SetFont($Slic3r::GUI::small_font);
                 #!$grid_sizer->Add($text, 0);
                 
-#                $self->{"object_info_$field"} = Wx::StaticText->new($scrolled_window_panel, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
-                $self->{"object_info_$field"} = Wx::StaticText->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+                $self->{"object_info_$field"} = Wx::StaticText->new($scrolled_window_panel, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+#                $self->{"object_info_$field"} = Wx::StaticText->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
                 $self->{"object_info_$field"}->SetFont($Slic3r::GUI::small_font);
                 if ($field eq 'manifold') {
-#                    $self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($scrolled_window_panel, -1, Wx::Bitmap->new(Slic3r::var("error.png"), wxBITMAP_TYPE_PNG));
-                    $self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($self->{right_panel}, -1, Wx::Bitmap->new(Slic3r::var("error.png"), wxBITMAP_TYPE_PNG));
+                    $self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($scrolled_window_panel, -1, Wx::Bitmap->new(Slic3r::var("error.png"), wxBITMAP_TYPE_PNG));
+#                    $self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($self->{right_panel}, -1, Wx::Bitmap->new(Slic3r::var("error.png"), wxBITMAP_TYPE_PNG));
                     #$self->{object_info_manifold_warning_icon}->Hide;
                     $self->{"object_info_manifold_warning_icon_show"} = sub {
                         if ($self->{object_info_manifold_warning_icon}->IsShown() != $_[0]) {
@@ -595,18 +594,19 @@ sub new {
             }
         }
 
-        my $print_info_sizer = $self->{print_info_sizer} = Wx::StaticBoxSizer->new(
-#                Wx::StaticBox->new($scrolled_window_panel, -1, L("Sliced Info")), wxVERTICAL);
-                Wx::StaticBox->new($self->{right_panel}, -1, L("Sliced Info")), wxVERTICAL);
+        my $print_info_box = Wx::StaticBox->new($scrolled_window_panel, -1, L("Sliced Info"));
+        $print_info_box->SetFont($Slic3r::GUI::small_bold_font);
+        my $print_info_sizer = $self->{print_info_sizer} = Wx::StaticBoxSizer->new($print_info_box, wxVERTICAL);
+#                Wx::StaticBox->new($self->{right_panel}, -1, L("Sliced Info")), wxVERTICAL);
         $print_info_sizer->SetMinSize([300,-1]);
         
         my $buttons_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
         $self->{buttons_sizer} = $buttons_sizer;
         $buttons_sizer->AddStretchSpacer(1);
-        $buttons_sizer->Add($self->{btn_export_stl}, 0, wxALIGN_RIGHT, 0);
-        $buttons_sizer->Add($self->{btn_reslice}, 0, wxALIGN_RIGHT, 0);
-        $buttons_sizer->Add($self->{btn_print}, 0, wxALIGN_RIGHT, 0);
-        $buttons_sizer->Add($self->{btn_send_gcode}, 0, wxALIGN_RIGHT, 0);
+#        $buttons_sizer->Add($self->{btn_export_stl}, 0, wxALIGN_RIGHT, 0);
+#!        $buttons_sizer->Add($self->{btn_reslice}, 0, wxALIGN_RIGHT, 0);
+        $buttons_sizer->Add($self->{btn_print}, 0, wxALIGN_RIGHT | wxBOTTOM | wxTOP, 5);
+        $buttons_sizer->Add($self->{btn_send_gcode}, 0, wxALIGN_RIGHT | wxBOTTOM | wxTOP, 5);
         
 #        $scrolled_window_sizer->Add($self->{list}, 1, wxEXPAND, 5);
 #        $scrolled_window_sizer->Add($object_info_sizer, 0, wxEXPAND, 0);
@@ -616,24 +616,39 @@ sub new {
         ### Sizer for info boxes
         my $info_sizer = $self->{info_sizer} = Wx::BoxSizer->new(wxVERTICAL);
         $info_sizer->SetMinSize([318, -1]);        
-        $info_sizer->Add($object_info_sizer, 0, wxEXPAND | wxBOTTOM, 5);
-        $info_sizer->Add($print_info_sizer, 0, wxEXPAND | wxBOTTOM, 5);
+        $info_sizer->Add($object_info_sizer, 0, wxEXPAND | wxTOP, 20);
+        $info_sizer->Add($print_info_sizer, 0, wxEXPAND | wxTOP, 20);
+
+        $scrolled_window_sizer->Add($presets, 0, wxEXPAND | wxLEFT, 2) if defined $presets;
+        $scrolled_window_sizer->Add($frequently_changed_parameters_sizer, 1, wxEXPAND | wxLEFT, 0) if defined $frequently_changed_parameters_sizer;
+        $scrolled_window_sizer->Add($buttons_sizer, 0, wxEXPAND, 0);
+        $scrolled_window_sizer->Add($info_sizer, 0, wxEXPAND | wxLEFT, 20);
+        # Show the box initially, let it be shown after the slicing is finished.
+        $self->print_info_box_show(0);
+
+        ### Sizer for "Export G-code" & "Slice now" buttons
+        my $btns_sizer = Wx::BoxSizer->new(wxVERTICAL);
+        $btns_sizer->SetMinSize([318, -1]);
+        $btns_sizer->Add($self->{btn_reslice}, 0, wxEXPAND, 0);
+        $btns_sizer->Add($self->{btn_export_gcode}, 0, wxEXPAND | wxTOP, 5);  
 
         my $right_sizer = Wx::BoxSizer->new(wxVERTICAL);
         $self->{right_panel}->SetSizer($right_sizer);
         $right_sizer->SetMinSize([320, -1]);
-        $right_sizer->Add($presets, 0, wxEXPAND | wxTOP, 10) if defined $presets;
-        $right_sizer->Add($frequently_changed_parameters_sizer, 1, wxEXPAND | wxTOP, 0) if defined $frequently_changed_parameters_sizer;
-        $right_sizer->Add($expert_mode_part_sizer, 0, wxEXPAND | wxTOP, 10) if defined $expert_mode_part_sizer;
-        $right_sizer->Add($buttons_sizer, 0, wxEXPAND | wxBOTTOM | wxTOP, 10);
-        $right_sizer->Add($info_sizer, 0, wxEXPAND | wxLEFT, 20);
+#!        $right_sizer->Add($presets, 0, wxEXPAND | wxTOP, 10) if defined $presets;
+#!        $right_sizer->Add($frequently_changed_parameters_sizer, 1, wxEXPAND | wxTOP, 0) if defined $frequently_changed_parameters_sizer;
+#!        $right_sizer->Add($buttons_sizer, 0, wxEXPAND | wxBOTTOM | wxTOP, 10);
+#!        $right_sizer->Add($info_sizer, 0, wxEXPAND | wxLEFT, 20);
         # Show the box initially, let it be shown after the slicing is finished.
-        $self->print_info_box_show(0);
-        $right_sizer->Add($self->{btn_export_gcode}, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 20);
+#!        $self->print_info_box_show(0);
+        $right_sizer->Add($scrolled_window_panel, 1, wxEXPAND | wxTOP, 5);
+#        $right_sizer->Add($self->{btn_reslice}, 0, wxEXPAND | wxLEFT | wxTOP, 20);
+#        $right_sizer->Add($self->{btn_export_gcode}, 0, wxEXPAND | wxLEFT | wxTOP, 20);
+        $right_sizer->Add($btns_sizer, 0, wxEXPAND | wxLEFT | wxTOP, 20);
 
         my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL);
         $hsizer->Add($self->{preview_notebook}, 1, wxEXPAND | wxTOP, 1);
-        $hsizer->Add($self->{right_panel}, 0, wxEXPAND | wxLEFT | wxRIGHT, 3);
+        $hsizer->Add($self->{right_panel}, 0, wxEXPAND | wxLEFT | wxRIGHT, 0);#3);
 
         my $sizer = Wx::BoxSizer->new(wxVERTICAL);
 #        $sizer->Add($self->{htoolbar}, 0, wxEXPAND, 0) if $self->{htoolbar};
@@ -644,16 +659,21 @@ sub new {
         $self->SetSizer($sizer);
 
         # Send sizers/buttons to C++
-        Slic3r::GUI::set_objects_from_perl( $self->{right_panel},
-                                $frequently_changed_parameters_sizer,
-                                $expert_mode_part_sizer,
-                                $info_sizer,
-                                $self->{btn_export_gcode},
-                                $self->{btn_export_stl},
-                                $self->{btn_reslice},
-                                $self->{btn_print},
-                                $self->{btn_send_gcode},
-                                $self->{object_info_manifold_warning_icon} );
+        Slic3r::GUI::set_objects_from_perl( $self->{scrolled_window_panel},
+                                            $frequently_changed_parameters_sizer,
+                                            $info_sizer,
+                                            $self->{btn_export_gcode},
+            #                                $self->{btn_export_stl},
+                                            $self->{btn_reslice},
+                                            $self->{btn_print},
+                                            $self->{btn_send_gcode},
+                                            $self->{object_info_manifold_warning_icon} );
+
+        Slic3r::GUI::set_model_events_from_perl(  $self->{model},
+                                            $self->{event_object_selection_changed},
+                                            $self->{event_object_settings_changed},
+                                            $self->{event_remove_object},
+                                            $self->{event_update_scene});
     }
 
     # Last correct selected item for each preset
@@ -1724,14 +1744,16 @@ sub print_info_box_show {
 #    my $scrolled_window_panel = $self->{scrolled_window_panel}; 
 #    my $scrolled_window_sizer = $self->{scrolled_window_sizer};
 #    return if (!$show && ($scrolled_window_sizer->IsShown(2) == $show));
-    my $panel = $self->{right_panel};
+    my $panel = $self->{scrolled_window_panel};#$self->{right_panel};
     my $sizer = $self->{info_sizer};
-    return if (!$sizer || !$show && ($sizer->IsShown(1) == $show));
+#    return if (!$sizer || !$show && ($sizer->IsShown(1) == $show));
+    return if (!$sizer);
 
     Slic3r::GUI::set_show_print_info($show);
-    return if (wxTheApp->{app_config}->get("view_mode") eq "simple");
+#    return if (wxTheApp->{app_config}->get("view_mode") eq "simple");
 
-    if ($show) {
+#    if ($show) 
+    {
         my $print_info_sizer = $self->{print_info_sizer};
         $print_info_sizer->Clear(1);
         my $grid_sizer = Wx::FlexGridSizer->new(2, 2, 5, 5);
@@ -1769,7 +1791,7 @@ sub print_info_box_show {
 
 #    $scrolled_window_sizer->Show(2, $show);
 #    $scrolled_window_panel->Layout;
-    $sizer->Show(1, $show);
+    $sizer->Show(1, $show && wxTheApp->{app_config}->get("view_mode") ne "simple");
 
     $self->Layout;
     $panel->Refresh;
@@ -2011,7 +2033,8 @@ sub on_extruders_change {
         my @presets = $choices->[0]->GetStrings;
         
         # initialize new choice
-        my $choice = Wx::BitmapComboBox->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, [@presets], wxCB_READONLY);
+#        my $choice = Wx::BitmapComboBox->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, [@presets], wxCB_READONLY);
+        my $choice = Wx::BitmapComboBox->new($self->{scrolled_window_panel}, -1, "", wxDefaultPosition, wxDefaultSize, [@presets], wxCB_READONLY);
         my $extruder_idx = scalar @$choices;
         EVT_LEFT_DOWN($choice, sub { $self->filament_color_box_lmouse_down($extruder_idx, @_); } );
         push @$choices, $choice;
diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp
index 34865fa63..315a4bada 100644
--- a/xs/src/slic3r/GUI/GUI.cpp
+++ b/xs/src/slic3r/GUI/GUI.cpp
@@ -135,14 +135,9 @@ wxButton*	g_wiping_dialog_button = nullptr;
 //showed/hided controls according to the view mode
 wxWindow	*g_right_panel = nullptr;
 wxBoxSizer	*g_frequently_changed_parameters_sizer = nullptr;
-wxBoxSizer	*g_expert_mode_part_sizer = nullptr;
-wxBoxSizer	*g_scrolled_window_sizer = nullptr;
+wxBoxSizer	*g_info_sizer = nullptr;
 wxBoxSizer	*g_object_list_sizer = nullptr;
-wxButton	*g_btn_export_gcode = nullptr;
-wxButton	*g_btn_export_stl = nullptr;
-wxButton	*g_btn_reslice = nullptr;
-wxButton	*g_btn_print = nullptr;
-wxButton	*g_btn_send_gcode = nullptr;
+std::vector<wxButton*> g_buttons;
 wxStaticBitmap	*g_manifold_warning_icon = nullptr;
 bool		g_show_print_info = false;
 bool		g_show_manifold_warning_icon = false;
@@ -221,22 +216,36 @@ void set_preset_updater(PresetUpdater *updater)
 	g_PresetUpdater = updater;
 }
 
-void set_objects_from_perl(	wxWindow* parent, wxBoxSizer *frequently_changed_parameters_sizer,
-							wxBoxSizer *expert_mode_part_sizer, wxBoxSizer *scrolled_window_sizer,
+enum ActionButtons
+{
+    abExportGCode,
+    abReslice,
+    abPrint,
+    abSendGCode,
+};
+
+void set_objects_from_perl(	wxWindow* parent, 
+                            wxBoxSizer *frequently_changed_parameters_sizer,
+							wxBoxSizer *info_sizer,
 							wxButton *btn_export_gcode,
-							wxButton *btn_export_stl, wxButton *btn_reslice, 
-							wxButton *btn_print, wxButton *btn_send_gcode,
+                            wxButton *btn_reslice, 
+							wxButton *btn_print, 
+                            wxButton *btn_send_gcode,
 							wxStaticBitmap *manifold_warning_icon)
 {
-	g_right_panel = parent;
+	g_right_panel = parent->GetParent();
 	g_frequently_changed_parameters_sizer = frequently_changed_parameters_sizer;
-	g_expert_mode_part_sizer = expert_mode_part_sizer;
-	g_scrolled_window_sizer = scrolled_window_sizer;
-	g_btn_export_gcode = btn_export_gcode;
-	g_btn_export_stl = btn_export_stl;
-	g_btn_reslice = btn_reslice;
-	g_btn_print = btn_print;
-	g_btn_send_gcode = btn_send_gcode;
+	g_info_sizer = info_sizer;
+
+    g_buttons.push_back(btn_export_gcode);
+    g_buttons.push_back(btn_reslice);
+    g_buttons.push_back(btn_print);
+    g_buttons.push_back(btn_send_gcode);
+
+    // Update font style for buttons
+    for (auto btn : g_buttons)
+        btn->SetFont(bold_font());
+
 	g_manifold_warning_icon = manifold_warning_icon;
 }
 
@@ -930,12 +939,11 @@ wxString from_u8(const std::string &str)
 	return wxString::FromUTF8(str.c_str());
 }
 
-void add_expert_mode_part(	wxWindow* parent, wxBoxSizer* sizer, 
-							Model &model,
-							int event_object_selection_changed,
-							int event_object_settings_changed,
-							int event_remove_object, 
-							int event_update_scene)
+void set_model_events_from_perl(Model &model,
+							    int event_object_selection_changed,
+							    int event_object_settings_changed,
+							    int event_remove_object, 
+							    int event_update_scene)
 {
 	set_event_object_selection_changed(event_object_selection_changed);
 	set_event_object_settings_changed(event_object_settings_changed);
@@ -1072,7 +1080,7 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl
 		};
 		optgroup->append_line(line);
 
-	sizer->Add(optgroup->sizer, 0, wxEXPAND | wxBOTTOM, 2);
+	sizer->Add(optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT, 2);
 
 	m_optgroups.push_back(optgroup);// ogFrequentlyChangingParameters
 
@@ -1099,15 +1107,14 @@ void show_frequently_changed_parameters(bool show)
 
 void show_buttons(bool show)
 {
-	g_btn_export_stl->Show(show);
-	g_btn_reslice->Show(show);
+    g_buttons[abReslice]->Show(show);
 	for (size_t i = 0; i < g_wxTabPanel->GetPageCount(); ++i) {
 		TabPrinter *tab = dynamic_cast<TabPrinter*>(g_wxTabPanel->GetPage(i));
 		if (!tab)
 			continue;
         if (g_PresetBundle->printers.get_selected_preset().printer_technology() == ptFFF) {
-            g_btn_print->Show(show && !tab->m_config->opt_string("serial_port").empty());
-            g_btn_send_gcode->Show(show && !tab->m_config->opt_string("print_host").empty());
+            g_buttons[abPrint]->Show(show && !tab->m_config->opt_string("serial_port").empty());
+            g_buttons[abSendGCode]->Show(show && !tab->m_config->opt_string("print_host").empty());
         }
 		break;
 	}
@@ -1115,8 +1122,8 @@ void show_buttons(bool show)
 
 void show_info_sizer(bool show)
 {
-	g_scrolled_window_sizer->Show(static_cast<size_t>(0), show); 
-	g_scrolled_window_sizer->Show(1, show && g_show_print_info);
+	g_info_sizer->Show(static_cast<size_t>(0), show); 
+	g_info_sizer->Show(1, show && g_show_print_info);
 	g_manifold_warning_icon->Show(show && g_show_manifold_warning_icon);
 }
 
@@ -1129,20 +1136,10 @@ void show_object_name(bool show)
 
 void update_mode()
 {
-	wxWindowUpdateLocker noUpdates(g_right_panel);
-
-	// TODO There is a not the best place of it!
-	//*** Update style of the "Export G-code" button****
-	if (g_btn_export_gcode->GetFont() != bold_font()){
-		g_btn_export_gcode->SetBackgroundColour(wxColour(252, 77, 1));
-		g_btn_export_gcode->SetFont(bold_font());
-	}
-	// ***********************************
+    wxWindowUpdateLocker noUpdates(g_right_panel->GetParent());
 
 	ConfigMenuIDs mode = get_view_mode();
 
-// 	show_frequently_changed_parameters(mode >= ConfigMenuModeRegular);
-// 	g_expert_mode_part_sizer->Show(mode == ConfigMenuModeExpert);
 	g_object_list_sizer->Show(mode == ConfigMenuModeExpert);
 	show_info_sizer(mode == ConfigMenuModeExpert);
 	show_buttons(mode == ConfigMenuModeExpert);
@@ -1153,7 +1150,7 @@ void update_mode()
 // 	show_collpane_settings(mode == ConfigMenuModeExpert);
 	// *************************
     g_right_panel->Layout();
-	g_right_panel->GetParent()->GetParent()->Layout();
+	g_right_panel->GetParent()->Layout();
 }
 
 bool is_expert_mode(){
@@ -1229,6 +1226,20 @@ void get_current_screen_size(unsigned &width, unsigned &height)
 	height = disp_size.GetHeight();
 }
 
+void enable_action_buttons(bool enable)
+{
+    if (g_buttons.empty())
+        return;
+
+    // Update background colour for buttons
+    const wxColour bgrd_color = enable ? wxColour(255, 96, 0) : wxColour(204, 204, 204);
+
+    for (auto btn : g_buttons) {
+        btn->Enable(enable);
+        btn->SetBackgroundColour(bgrd_color);
+    }
+}
+
 void about()
 {
     AboutDialog dlg;
diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp
index 22ea3edb0..ceb004f8c 100644
--- a/xs/src/slic3r/GUI/GUI.hpp
+++ b/xs/src/slic3r/GUI/GUI.hpp
@@ -102,10 +102,8 @@ void set_preset_bundle(PresetBundle *preset_bundle);
 void set_preset_updater(PresetUpdater *updater);
 void set_objects_from_perl(	wxWindow* parent,
 							wxBoxSizer *frequently_changed_parameters_sizer,
-							wxBoxSizer *expert_mode_part_sizer,
-							wxBoxSizer *scrolled_window_sizer,
+							wxBoxSizer *info_sizer,
 							wxButton *btn_export_gcode,
-							wxButton *btn_export_stl,
 							wxButton *btn_reslice,
 							wxButton *btn_print,
 							wxButton *btn_send_gcode,
@@ -202,12 +200,11 @@ wxString	L_str(const std::string &str);
 // Return wxString from std::string in UTF8
 wxString	from_u8(const std::string &str);
 
-void add_expert_mode_part(	wxWindow* parent, wxBoxSizer* sizer, 
-							Model &model,
-							int event_object_selection_changed,
-							int event_object_settings_changed,
-							int event_remove_object, 
-							int event_update_scene);
+void set_model_events_from_perl(Model &model,
+							    int event_object_selection_changed,
+							    int event_object_settings_changed,
+							    int event_remove_object, 
+							    int event_update_scene);
 void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFlexGridSizer* preset_sizer);
 // Update view mode according to selected menu 
 void update_mode();
@@ -226,6 +223,9 @@ int get_export_option(wxFileDialog* dlg);
 // Returns the dimensions of the screen on which the main frame is displayed
 void get_current_screen_size(unsigned &width, unsigned &height);
 
+// Update buttons view according to enable/disable
+void enable_action_buttons(bool enable);
+
 // Display an About dialog
 extern void about();
 // Ask the destop to open the datadir using the default file explorer.
diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp
index 3e967bb86..7b0aadab5 100644
--- a/xs/xsp/GUI.xsp
+++ b/xs/xsp/GUI.xsp
@@ -87,26 +87,21 @@ void add_frequently_changed_parameters(SV *ui_parent, SV *ui_sizer, SV *ui_p_siz
                                                            (wxBoxSizer*)wxPli_sv_2_object(aTHX_ ui_sizer, "Wx::BoxSizer"),
                                                            (wxFlexGridSizer*)wxPli_sv_2_object(aTHX_ ui_p_sizer, "Wx::FlexGridSizer")); %};
 
-void add_expert_mode_part(  SV *ui_parent, SV *ui_sizer, 
-                            Model *model,
-                            int event_object_selection_changed,
-                            int event_object_settings_changed,
-                            int event_remove_object, 
-                            int event_update_scene)
-    %code%{ Slic3r::GUI::add_expert_mode_part(  (wxWindow*)wxPli_sv_2_object(aTHX_ ui_parent, "Wx::Window"),
-                                                (wxBoxSizer*)wxPli_sv_2_object(aTHX_ ui_sizer, "Wx::BoxSizer"), 
-                                                *model,  
-                                                event_object_selection_changed,
-                                                event_object_settings_changed,
-                                                event_remove_object, 
-                                                event_update_scene); %};
+void set_model_events_from_perl(Model *model,
+                                int event_object_selection_changed,
+                                int event_object_settings_changed,
+                                int event_remove_object, 
+                                int event_update_scene)
+    %code%{ Slic3r::GUI::set_model_events_from_perl(*model,  
+                                                    event_object_selection_changed,
+                                                    event_object_settings_changed,
+                                                    event_remove_object, 
+                                                    event_update_scene); %};
 
 void set_objects_from_perl( SV *ui_parent, 
                             SV *frequently_changed_parameters_sizer,
-                            SV *expert_mode_part_sizer,
-                            SV *scrolled_window_sizer,
+                            SV *info_sizer,
                             SV *btn_export_gcode,
-                            SV *btn_export_stl,
                             SV *btn_reslice,
                             SV *btn_print,
                             SV *btn_send_gcode,
@@ -114,10 +109,8 @@ void set_objects_from_perl( SV *ui_parent,
     %code%{ Slic3r::GUI::set_objects_from_perl(
                             (wxWindow *)wxPli_sv_2_object(aTHX_ ui_parent, "Wx::Window"),
                             (wxBoxSizer *)wxPli_sv_2_object(aTHX_ frequently_changed_parameters_sizer, "Wx::BoxSizer"),
-                            (wxBoxSizer *)wxPli_sv_2_object(aTHX_ expert_mode_part_sizer, "Wx::BoxSizer"),
-                            (wxBoxSizer *)wxPli_sv_2_object(aTHX_ scrolled_window_sizer, "Wx::BoxSizer"),
+                            (wxBoxSizer *)wxPli_sv_2_object(aTHX_ info_sizer, "Wx::BoxSizer"),
                             (wxButton *)wxPli_sv_2_object(aTHX_ btn_export_gcode, "Wx::Button"),
-                            (wxButton *)wxPli_sv_2_object(aTHX_ btn_export_stl, "Wx::Button"),
                             (wxButton *)wxPli_sv_2_object(aTHX_ btn_reslice, "Wx::Button"),
                             (wxButton *)wxPli_sv_2_object(aTHX_ btn_print, "Wx::Button"),
                             (wxButton *)wxPli_sv_2_object(aTHX_ btn_send_gcode, "Wx::Button"),
@@ -190,4 +183,6 @@ void update_double_slider(bool force_sliders_full_range)
 void reset_double_slider()
     %code%{ Slic3r::GUI::reset_double_slider(); %};
 
+void enable_action_buttons(bool enable)
+    %code%{ Slic3r::GUI::enable_action_buttons(enable); %};
 

From 3075364da1f77879af61a071d04b8810f2a8690c Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 31 Aug 2018 14:15:26 +0200
Subject: [PATCH 04/27] Fixed bug with crashing after part split for single
 material object

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

diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index e175d41eb..66436abc3 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -238,7 +238,7 @@ wxDataViewColumn* object_ctrl_create_extruder_column(int extruders_count)
 void create_objects_ctrl(wxWindow* win, wxBoxSizer*& objects_sz)
 {
 	m_objects_ctrl = new wxDataViewCtrl(win, wxID_ANY, wxDefaultPosition, wxDefaultSize);
-	m_objects_ctrl->SetInitialSize(wxSize(-1, 150)); // TODO - Set correct height according to the opened/closed objects
+	m_objects_ctrl->SetMinSize(wxSize(-1, 150)); // TODO - Set correct height according to the opened/closed objects
 
 	objects_sz = new wxBoxSizer(wxVERTICAL);
 	objects_sz->Add(m_objects_ctrl, 1, wxGROW | wxLEFT, 20);
@@ -1304,7 +1304,8 @@ void on_btn_split(const bool split_part)
         for (auto id = 0; id < model_object->volumes.size(); id++)
             m_objects_model->AddChild(parent, model_object->volumes[id]->name,
                                       model_object->volumes[id]->modifier ? m_icon_modifiermesh : m_icon_solidmesh,
-                                      model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value, 
+                                      model_object->volumes[id]->config.has("extruder") ?
+                                        model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value : 0,
                                       false);
 
         m_objects_ctrl->Expand(parent);
@@ -1313,7 +1314,8 @@ void on_btn_split(const bool split_part)
         for (auto id = 0; id < model_object->volumes.size(); id++)
             m_objects_model->AddChild(item, model_object->volumes[id]->name, 
                                       m_icon_solidmesh,
-                                      model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value, 
+                                      model_object->volumes[id]->config.has("extruder") ?
+                                        model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value : 0, 
                                       false);
         m_objects_ctrl->Expand(item);
     }

From 78cedb34d4161085e554a46fa0867d60365c35f7 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 3 Sep 2018 09:58:35 +0200
Subject: [PATCH 05/27] Fixed bug with no-slicing of some parts of the object

+ Removed text drawing for equal values in DoubleSlider
+ Added functions for adding of the settings item for objects
---
 lib/Slic3r/GUI/Plater.pm              |  1 +
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp | 39 ++++++++++++++++-------
 xs/src/slic3r/GUI/wxExtensions.cpp    | 46 ++++++++++++++++++++++++---
 xs/src/slic3r/GUI/wxExtensions.hpp    | 26 ++++++++++++---
 4 files changed, 90 insertions(+), 22 deletions(-)

diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm
index 4548fd391..d7b9b92f1 100644
--- a/lib/Slic3r/GUI/Plater.pm
+++ b/lib/Slic3r/GUI/Plater.pm
@@ -2061,6 +2061,7 @@ sub on_extruders_change {
         $choices->[-1]->Destroy;
         pop @$choices;
     }
+    $self->{right_panel}->Layout;
     $self->Layout;
 }
 
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index 66436abc3..1820af155 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -870,8 +870,11 @@ void update_settings_list()
 		{
 			auto opt_key = (line.get_options())[0].opt_id;  //we assume that we have one option per line
 
-			auto btn = new wxBitmapButton(parent, wxID_ANY, wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("erase.png")), wxBITMAP_TYPE_PNG),
+			auto btn = new wxBitmapButton(parent, wxID_ANY, wxBitmap(from_u8(var("colorchange_delete_on.png")), wxBITMAP_TYPE_PNG),
 				wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
+#ifdef __WXMSW__
+            btn->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
+#endif // __WXMSW__
 			btn->Bind(wxEVT_BUTTON, [opt_key](wxEvent &event){
 				(*m_config)->erase(opt_key);
 				wxTheApp->CallAfter([]() { update_settings_list(); });
@@ -928,8 +931,8 @@ void update_settings_list()
 	no_updates.reset(nullptr);
 #endif
 
-    /*get_right_panel()*/parent->Layout();
-    get_right_panel()->GetParent()->GetParent()->Layout();
+    parent->Layout();
+    get_right_panel()->GetParent()->Layout();
 }
 
 void get_settings_choice(wxMenu *menu, int id, bool is_part)
@@ -982,6 +985,16 @@ void get_settings_choice(wxMenu *menu, int id, bool is_part)
 			(*m_config)->set_key_value(opt_key, m_default_config.get()->option(opt_key)->clone());
 	}
 
+
+    // ***  EXPERIMINT  ***
+//     const auto item = m_objects_ctrl->GetSelection();
+//     if (item)
+//     {
+//         if (!m_objects_model->HasSettings(item))
+//             m_objects_model->AddSettingsChild(item);
+//     }
+    // ********************
+
 	update_settings_list();
 }
 
@@ -1108,17 +1121,13 @@ wxMenu *create_add_settings_popupmenu(bool is_part)
 
 void show_context_menu()
 {
-    auto item = m_objects_ctrl->GetSelection();
+    const auto item = m_objects_ctrl->GetSelection();
     if (item)
     {
-        if (m_objects_model->GetParent(item) == wxDataViewItem(0))				{
-            auto menu = create_add_part_popupmenu();
-            get_tab_panel()->GetPage(0)->PopupMenu(menu);
-        }
-        else {
-            auto menu = create_part_settings_popupmenu();
-            get_tab_panel()->GetPage(0)->PopupMenu(menu);
-        }
+        const auto menu = m_objects_model->GetParent(item) == wxDataViewItem(0) ? 
+                            create_add_part_popupmenu() : 
+                            create_part_settings_popupmenu();
+        get_tab_panel()->GetPage(0)->PopupMenu(menu);
     }
 }
 
@@ -1319,6 +1328,9 @@ void on_btn_split(const bool split_part)
                                       false);
         m_objects_ctrl->Expand(item);
     }
+
+    m_parts_changed = true;
+    parts_changed(m_selected_object_id);
 }
 
 void on_btn_move_up(){
@@ -1659,6 +1671,9 @@ void on_drop(wxDataViewEvent &event)
     for (int id = from_volume_id; cnt < abs(from_volume_id - to_volume_id); id+=delta, cnt++)
         std::swap(volumes[id], volumes[id +delta]);
 
+    m_parts_changed = true;
+    parts_changed(m_selected_object_id);
+
     g_prevent_list_events = false;
 }
 
diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index 73e6f0877..2588dd3d6 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -357,6 +357,10 @@ void  PrusaObjectDataViewModelNode::set_part_action_icon() {
 	m_action_icon = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("cog.png")), wxBITMAP_TYPE_PNG);
 }
 
+void PrusaObjectDataViewModelNode::set_settings_list_icon(const wxIcon& icon) {
+    m_icon = icon;
+}
+
 // *****************************************************************************
 // ----------------------------------------------------------------------------
 // PrusaObjectDataViewModel
@@ -414,6 +418,19 @@ wxDataViewItem PrusaObjectDataViewModel::AddChild(	const wxDataViewItem &parent_
 	return child;
 }
 
+wxDataViewItem PrusaObjectDataViewModel::AddSettingsChild(const wxDataViewItem &parent_item)
+{
+    PrusaObjectDataViewModelNode *root = (PrusaObjectDataViewModelNode*)parent_item.GetID();
+    if (!root) return wxDataViewItem(0);
+
+    const auto node = new PrusaObjectDataViewModelNode(root);
+    root->Insert(node, 0);
+    // notify control
+    const wxDataViewItem child((void*)node);
+    ItemAdded(parent_item, child);
+    return child;
+}
+
 wxDataViewItem PrusaObjectDataViewModel::Delete(const wxDataViewItem &item)
 {
 	auto ret_item = wxDataViewItem(0);
@@ -683,10 +700,14 @@ wxDataViewItem PrusaObjectDataViewModel::ReorganizeChildren(int current_volume_i
     return wxDataViewItem(node_parent->GetNthChild(new_volume_id));
 }
 
-// bool MyObjectTreeModel::IsEnabled(const wxDataViewItem &item, unsigned int col) const
-// {
-// 
-// }
+bool PrusaObjectDataViewModel::IsEnabled(const wxDataViewItem &item, unsigned int col) const
+{
+    wxASSERT(item.IsOk());
+    PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+
+    // disable extruder selection for the "Settings" item
+    return !(col == 2 && node->m_extruder.IsEmpty());
+}
 
 wxDataViewItem PrusaObjectDataViewModel::GetParent(const wxDataViewItem &item) const
 {
@@ -738,6 +759,21 @@ unsigned int PrusaObjectDataViewModel::GetChildren(const wxDataViewItem &parent,
 	return count;
 }
 
+bool PrusaObjectDataViewModel::HasSettings(const wxDataViewItem &item) const
+{
+    if (!item.IsOk())
+        return false;
+
+    PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+    if (node->GetChildCount() == 0)
+        return false;
+
+    auto& children = node->GetChildren();
+    if (children[0]->m_type == "settings")
+        return true;
+
+    return false;
+}
 
 // ----------------------------------------------------------------------------
 // PrusaDoubleSlider
@@ -1029,7 +1065,7 @@ wxString PrusaDoubleSlider::get_label(const SelectedSlider& selection) const
 
 void PrusaDoubleSlider::draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const
 {
-    if (m_is_one_layer && selection != m_selection || !selection) 
+    if ((m_is_one_layer || m_higher_value==m_lower_value) && selection != m_selection || !selection) 
         return;
     wxCoord text_width, text_height;
     const wxString label = get_label(selection);
diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp
index d1747e434..13fc764ce 100644
--- a/xs/src/slic3r/GUI/wxExtensions.hpp
+++ b/xs/src/slic3r/GUI/wxExtensions.hpp
@@ -183,9 +183,22 @@ public:
 		m_icon		= icon;
 		m_type		= "volume";
 		m_volume_id = volume_id;
-        m_extruder  = extruder;
+        m_extruder = extruder;
+#ifdef __WXGTK__
+        // it's necessary on GTK because of control have to know if this item will be container
+        // in another case you couldn't to add subitem for this item
+        // it will be produce "segmentation fault"
+        m_container = true;
+#endif  //__WXGTK__
 		set_part_action_icon();
-	}
+    }
+
+    PrusaObjectDataViewModelNode(   PrusaObjectDataViewModelNode* parent) :
+                                    m_parent(parent),
+                                    m_name("SETTINGS LIST"),
+                                    m_copy(wxEmptyString),
+                                    m_type("settings"),
+                                    m_extruder(wxEmptyString) {}
 
 	~PrusaObjectDataViewModelNode()
 	{
@@ -202,7 +215,7 @@ public:
 	wxIcon&					m_icon = m_empty_icon;
 	wxString				m_copy;
 	std::string				m_type;
-	int						m_volume_id;
+	int						m_volume_id = -2;
 	bool					m_container = false;
 	wxString				m_extruder = "default";
 	wxBitmap				m_action_icon;
@@ -326,6 +339,7 @@ public:
 	// Set action icons for node
 	void set_object_action_icon();
 	void set_part_action_icon();
+    void set_settings_list_icon(const wxIcon& icon);
 };
 
 // ----------------------------------------------------------------------------
@@ -350,6 +364,7 @@ public:
                             const wxIcon& icon,
                             const int = 0,
                             const bool create_frst_child = true);
+	wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
 	wxDataViewItem Delete(const wxDataViewItem &item);
 	void DeleteAll();
     void DeleteChildren(wxDataViewItem& parent);
@@ -383,8 +398,7 @@ public:
                                       int new_volume_id,
                                       const wxDataViewItem &parent);
 
-// 	virtual bool IsEnabled(const wxDataViewItem &item,
-// 		unsigned int col) const override;
+	virtual bool IsEnabled(const wxDataViewItem &item, unsigned int col) const override;
 
 	virtual wxDataViewItem GetParent(const wxDataViewItem &item) const override;
 	virtual bool IsContainer(const wxDataViewItem &item) const override;
@@ -394,6 +408,8 @@ public:
 	// Is the container just a header or an item with all columns
 	// In our case it is an item with all columns 
 	virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override {	return true; }
+
+    bool    HasSettings(const wxDataViewItem &item) const;
 };
 
 

From fb3a4015f61b96ba9f5cef306a1a2178adb0ecf4 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 3 Sep 2018 16:21:08 +0200
Subject: [PATCH 06/27] Implemented "Settings to modified" as a subobject for
 objects and parts

---
 lib/Slic3r/GUI/Plater.pm              |   3 +-
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp | 228 ++++++++++++++++----------
 xs/src/slic3r/GUI/OptionsGroup.cpp    |   2 +-
 xs/src/slic3r/GUI/wxExtensions.cpp    |  52 ++++--
 xs/src/slic3r/GUI/wxExtensions.hpp    |   7 +-
 5 files changed, 185 insertions(+), 107 deletions(-)

diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm
index d7b9b92f1..9b9cc74c6 100644
--- a/lib/Slic3r/GUI/Plater.pm
+++ b/lib/Slic3r/GUI/Plater.pm
@@ -1975,7 +1975,7 @@ sub _get_export_file {
 # (i.e. when an object is added/removed/moved/rotated/scaled)
 sub update {
     my ($self, $force_autocenter) = @_;
-
+    $self->Freeze;
     if (wxTheApp->{app_config}->get("autocenter") || $force_autocenter) {
         $self->{model}->center_instances_around_point($self->bed_centerf);
     }
@@ -2001,6 +2001,7 @@ sub update {
     Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0);
     $self->{preview3D}->reset_gcode_preview_data if $self->{preview3D};
     $self->{preview3D}->reload_print if $self->{preview3D};
+    $self->Thaw;
 }
 
 # When a printer technology is changed, the UI needs to be updated to show/hide needed preset combo boxes.
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index 1820af155..c7d7f35f8 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -780,9 +780,9 @@ void object_ctrl_context_menu()
 {
     wxDataViewItem item;
     wxDataViewColumn* col;
-    printf("object_ctrl_context_menu\n");
+//     printf("object_ctrl_context_menu\n");
     const wxPoint pt = get_mouse_position_in_control();
-    printf("mouse_position_in_control: x = %d, y = %d\n", pt.x, pt.y);
+//     printf("mouse_position_in_control: x = %d, y = %d\n", pt.x, pt.y);
     m_objects_ctrl->HitTest(pt, item, col);
     if (!item)
 #ifdef __WXOSX__ // #ys_FIXME temporary workaround for OSX 
@@ -796,9 +796,9 @@ void object_ctrl_context_menu()
 #else
         return;
 #endif // __WXOSX__
-    printf("item exists\n");
+//     printf("item exists\n");
     const wxString title = col->GetTitle();
-    printf("title = *%s*\n", title.data().AsChar());
+//     printf("title = *%s*\n", title.data().AsChar());
 
     if (title == " ")
         show_context_menu();
@@ -844,6 +844,15 @@ void object_ctrl_item_value_change(wxDataViewEvent& event)
     }
 }
 
+void show_manipulation_og(const bool show)
+{
+    wxGridSizer* grid_sizer = get_optgroup(ogFrequentlyObjectSettings)->get_grid_sizer();
+    if (show == grid_sizer->IsShown(2))
+        return;
+    for (size_t id = 2; id < 12; id++)
+        grid_sizer->Show(id, show);
+}
+
 //update_optgroup
 void update_settings_list()
 {
@@ -864,8 +873,11 @@ void update_settings_list()
 
 	m_option_sizer->Clear(true);
 
-	if (m_config) 
+    bool show_manipulations = true;
+    const auto item = m_objects_ctrl->GetSelection();
+	if (m_config && m_objects_model->IsSettingsItem(item)) 
 	{
+        show_manipulations = false;
         auto extra_column = [](wxWindow* parent, const Line& line)
 		{
 			auto opt_key = (line.get_options())[0].opt_id;  //we assume that we have one option per line
@@ -884,49 +896,57 @@ void update_settings_list()
 
 		std::map<std::string, std::vector<std::string>> cat_options;
 		auto opt_keys = (*m_config)->keys();
-		if (opt_keys.size() == 1 && opt_keys[0] == "extruder")
-			return;
+        if (!(opt_keys.size() == 1 && opt_keys[0] == "extruder"))
+            // 			return;
+        {
+            auto extruders_cnt = get_preset_bundle()->printers.get_selected_preset().printer_technology() == ptSLA ? 1 :
+                get_preset_bundle()->printers.get_edited_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
 
-        auto extruders_cnt = get_preset_bundle()->printers.get_selected_preset().printer_technology() == ptSLA ? 1 :
-                             get_preset_bundle()->printers.get_edited_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
+            for (auto& opt_key : opt_keys) {
+                auto category = (*m_config)->def()->get(opt_key)->category;
+                if (category.empty() ||
+                    (category == "Extruders" && extruders_cnt == 1)) continue;
 
-		for (auto& opt_key : opt_keys) {
-			auto category = (*m_config)->def()->get(opt_key)->category;
-			if (category.empty() ||
-                (category == "Extruders" && extruders_cnt==1)) continue;
+                std::vector< std::string > new_category;
 
-			std::vector< std::string > new_category;
-
-			auto& cat_opt = cat_options.find(category) == cat_options.end() ? new_category : cat_options.at(category);
-			cat_opt.push_back(opt_key);
-			if (cat_opt.size() == 1)
-				cat_options[category] = cat_opt;
-		}
+                auto& cat_opt = cat_options.find(category) == cat_options.end() ? new_category : cat_options.at(category);
+                cat_opt.push_back(opt_key);
+                if (cat_opt.size() == 1)
+                    cat_options[category] = cat_opt;
+            }
 
 
-		m_og_settings.resize(0);
-		for (auto& cat : cat_options) {
-			if (cat.second.size() == 1 && cat.second[0] == "extruder")
-				continue;
+            m_og_settings.resize(0);
+            for (auto& cat : cat_options) {
+                if (cat.second.size() == 1 && cat.second[0] == "extruder")
+                    continue;
 
-			auto optgroup = std::make_shared<ConfigOptionsGroup>(parent, cat.first, *m_config, false, ogDEFAULT, extra_column);
-			optgroup->label_width = 100;
-			optgroup->sidetext_width = 70;
+                auto optgroup = std::make_shared<ConfigOptionsGroup>(parent, cat.first, *m_config, false, ogDEFAULT, extra_column);
+                optgroup->label_width = 150;
+                optgroup->sidetext_width = 70;
 
-			for (auto& opt : cat.second)
-			{
-				if (opt == "extruder")
-					continue;
-				Option option = optgroup->get_option(opt);
-				option.opt.width = 70;
-				optgroup->append_single_option_line(option);
-			}
-			optgroup->reload_config();
-			m_option_sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 0);
-			m_og_settings.push_back(optgroup);
-		}
+                for (auto& opt : cat.second)
+                {
+                    if (opt == "extruder")
+                        continue;
+                    Option option = optgroup->get_option(opt);
+                    option.opt.width = 70;
+                    optgroup->append_single_option_line(option);
+                }
+                optgroup->reload_config();
+                m_option_sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 0);
+                m_og_settings.push_back(optgroup);
+            }
+
+            if (m_og_settings.empty()) {
+                m_objects_ctrl->Select(m_objects_model->Delete(item));
+                show_manipulations = true;
+            }
+        }
 	}
 
+    show_manipulation_og(show_manipulations);
+
 #ifdef __linux__
 	no_updates.reset(nullptr);
 #endif
@@ -937,7 +957,7 @@ void update_settings_list()
 
 void get_settings_choice(wxMenu *menu, int id, bool is_part)
 {
-	auto category_name = menu->GetLabel(id);
+	const auto category_name = menu->GetLabel(id);
 
 	wxArrayString names;
 	wxArrayInt selections;
@@ -987,12 +1007,12 @@ void get_settings_choice(wxMenu *menu, int id, bool is_part)
 
 
     // ***  EXPERIMINT  ***
-//     const auto item = m_objects_ctrl->GetSelection();
-//     if (item)
-//     {
-//         if (!m_objects_model->HasSettings(item))
-//             m_objects_model->AddSettingsChild(item);
-//     }
+    const auto item = m_objects_ctrl->GetSelection();
+    if (item) {
+        const auto settings_item = m_objects_model->HasSettings(item);
+        m_objects_ctrl->Select(settings_item ? settings_item : 
+                               m_objects_model->AddSettingsChild(item));
+    }
     // ********************
 
 	update_settings_list();
@@ -1124,6 +1144,8 @@ void show_context_menu()
     const auto item = m_objects_ctrl->GetSelection();
     if (item)
     {
+        if (m_objects_model->IsSettingsItem(item))
+            return;
         const auto menu = m_objects_model->GetParent(item) == wxDataViewItem(0) ? 
                             create_add_part_popupmenu() : 
                             create_part_settings_popupmenu();
@@ -1251,36 +1273,58 @@ void on_btn_load(wxWindow* parent, bool is_modifier /*= false*/, bool is_lambda/
 #endif //__WXMSW__
 }
 
+void remove_settings_from_config()
+{
+    auto opt_keys = (*m_config)->keys();
+    if (opt_keys.size() == 1 && opt_keys[0] == "extruder")
+        return;
+    int extruder = -1;
+    if ((*m_config)->has("extruder"))
+        extruder = (*m_config)->option<ConfigOptionInt>("extruder")->value;
+
+    (*m_config)->clear();
+
+    if (extruder >=0 )
+        (*m_config)->set_key_value("extruder", new ConfigOptionInt(extruder));
+}
+
+bool remove_subobject_from_object(const int volume_id)
+{
+    const auto volume = (*m_objects)[m_selected_object_id]->volumes[volume_id];
+
+    // if user is deleting the last solid part, throw error
+    int solid_cnt = 0;
+    for (auto vol : (*m_objects)[m_selected_object_id]->volumes)
+        if (!vol->modifier)
+            ++solid_cnt;
+    if (!volume->modifier && solid_cnt == 1) {
+        Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last solid part from this object.")));
+        return false;
+    }
+
+    (*m_objects)[m_selected_object_id]->delete_volume(volume_id);
+    m_parts_changed = true;
+
+    parts_changed(m_selected_object_id);
+    return true;
+}
+
 void on_btn_del()
 {
 	auto item = m_objects_ctrl->GetSelection();
 	if (!item) return;
 
-	auto volume_id = m_objects_model->GetVolumeIdByItem(item);
-	if (volume_id < 0)
+	const auto volume_id = m_objects_model->GetVolumeIdByItem(item);
+	if (volume_id ==-1)
 		return;
-	auto volume = (*m_objects)[m_selected_object_id]->volumes[volume_id];
-
-	// if user is deleting the last solid part, throw error
-	int solid_cnt = 0;
-	for (auto vol : (*m_objects)[m_selected_object_id]->volumes)
-		if (!vol->modifier)
-			++solid_cnt;
-	if (!volume->modifier && solid_cnt == 1) {
-		Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last solid part from this object.")));
-		return;
-	}
-
-	(*m_objects)[m_selected_object_id]->delete_volume(volume_id);
-	m_parts_changed = true;
-
-	parts_changed(m_selected_object_id);
+    
+    if (volume_id ==-2)
+        remove_settings_from_config();
+	else if (!remove_subobject_from_object(volume_id)) 
+        return;
 
 	m_objects_ctrl->Select(m_objects_model->Delete(item));
 	part_selection_changed();
-// #ifdef __WXMSW__
-// 	object_ctrl_selection_changed();
-// #endif //__WXMSW__
 }
 
 void on_btn_split(const bool split_part)
@@ -1404,33 +1448,49 @@ void part_selection_changed()
 	auto item = m_objects_ctrl->GetSelection();
 	int obj_idx = -1;
 	auto og = get_optgroup(ogFrequentlyObjectSettings);
+    m_config = nullptr;
+    wxString object_name = wxEmptyString;
 	if (item)
 	{
+        const bool is_settings_item = m_objects_model->IsSettingsItem(item);
 		bool is_part = false;
-		if (m_objects_model->GetParent(item) == wxDataViewItem(0)) {
+        wxString og_name = wxEmptyString;
+        if (m_objects_model->GetParent(item) == wxDataViewItem(0)) {
 			obj_idx = m_objects_model->GetIdByItem(item);
-			og->set_name(" " + _(L("Object Settings")) + " ");
+			og_name = _(L("Object manipulation"));
 			m_config = std::make_shared<DynamicPrintConfig*>(&(*m_objects)[obj_idx]->config);
 		}
 		else {
 			auto parent = m_objects_model->GetParent(item);
-			// Take ID of the parent object to "inform" perl-side which object have to be selected on the scene
+            // Take ID of the parent object to "inform" perl-side which object have to be selected on the scene
 			obj_idx = m_objects_model->GetIdByItem(parent);
-			og->set_name(" " + _(L("Part Settings")) + " ");
-			is_part = true;
-			auto volume_id = m_objects_model->GetVolumeIdByItem(item);
-			m_config = std::make_shared<DynamicPrintConfig*>(&(*m_objects)[obj_idx]->volumes[volume_id]->config);
+			if (is_settings_item) {
+                if (m_objects_model->GetParent(parent) == wxDataViewItem(0)) {
+                    og_name = _(L("Object Settings to modify"));
+                    m_config = std::make_shared<DynamicPrintConfig*>(&(*m_objects)[obj_idx]->config);
+                }
+                else {
+                    og_name = _(L("Part Settings to modify"));
+			        is_part = true;
+                    auto main_parent = m_objects_model->GetParent(parent);
+                    obj_idx = m_objects_model->GetIdByItem(main_parent);
+			        const auto volume_id = m_objects_model->GetVolumeIdByItem(parent);
+			        m_config = std::make_shared<DynamicPrintConfig*>(&(*m_objects)[obj_idx]->volumes[volume_id]->config);
+                }
+            }
+            else {
+                og_name = _(L("Part manipulation"));
+                is_part = true;
+                const auto volume_id = m_objects_model->GetVolumeIdByItem(item);
+                m_config = std::make_shared<DynamicPrintConfig*>(&(*m_objects)[obj_idx]->volumes[volume_id]->config);
+            }
 		}
 
-		auto config = m_config;
-        og->set_value("object_name", m_objects_model->GetName(item));
+        og->set_name(" " + og_name + " ");
+        object_name = m_objects_model->GetName(item);
 		m_default_config = std::make_shared<DynamicPrintConfig>(*DynamicPrintConfig::new_from_defaults_keys(get_options(is_part)));
 	}
-    else {
-        wxString empty_str = wxEmptyString;
-        og->set_value("object_name", empty_str);
-        m_config = nullptr;
-    }
+    og->set_value("object_name", object_name);
 
 	update_settings_list();
 
@@ -1609,7 +1669,7 @@ void on_begin_drag(wxDataViewEvent &event)
     wxDataViewItem item(event.GetItem());
 
     // only allow drags for item, not containers
-    if (m_objects_model->GetParent(item) == wxDataViewItem(0)) {
+    if (m_objects_model->GetParent(item) == wxDataViewItem(0) || m_objects_model->IsSettingsItem(item)) {
         event.Veto();
         return;
     }
@@ -1633,7 +1693,7 @@ void on_drop_possible(wxDataViewEvent &event)
 
     // only allow drags for item or background, not containers
     if (item.IsOk() && m_objects_model->GetParent(item) == wxDataViewItem(0) ||
-        event.GetDataFormat() != wxDF_UNICODETEXT)
+        event.GetDataFormat() != wxDF_UNICODETEXT || m_objects_model->IsSettingsItem(item))
         event.Veto();
 }
 
@@ -1643,7 +1703,7 @@ void on_drop(wxDataViewEvent &event)
 
     // only allow drops for item, not containers
     if (item.IsOk() && m_objects_model->GetParent(item) == wxDataViewItem(0) ||
-        event.GetDataFormat() != wxDF_UNICODETEXT) {
+        event.GetDataFormat() != wxDF_UNICODETEXT || m_objects_model->IsSettingsItem(item)) {
         event.Veto();
         return;
     }    
diff --git a/xs/src/slic3r/GUI/OptionsGroup.cpp b/xs/src/slic3r/GUI/OptionsGroup.cpp
index 339c7358f..f2cfbd74e 100644
--- a/xs/src/slic3r/GUI/OptionsGroup.cpp
+++ b/xs/src/slic3r/GUI/OptionsGroup.cpp
@@ -158,7 +158,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText**	colored_Label/*
 	// if we have an extra column, build it
 	if (extra_column) {
 		if (extra_column) {
-			grid_sizer->Add(extra_column(parent(), line), 0, wxALIGN_CENTER_VERTICAL, 0);
+			grid_sizer->Add(extra_column(parent(), line), 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 3);
 		}
 		else {
 			// if the callback provides no sizer for the extra cell, put a spacer
diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index 2588dd3d6..a975ac4d6 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -397,23 +397,26 @@ wxDataViewItem PrusaObjectDataViewModel::AddChild(	const wxDataViewItem &parent_
 	PrusaObjectDataViewModelNode *root = (PrusaObjectDataViewModelNode*)parent_item.GetID();
 	if (!root) return wxDataViewItem(0);
 
-    wxString extruder_str = extruder == 0 ? "default" : wxString::Format("%d", extruder);
+    const wxString extruder_str = extruder == 0 ? "default" : wxString::Format("%d", extruder);
 
-    if (root->GetChildren().Count() == 0 && create_frst_child)
+    if (create_frst_child && (root->GetChildren().Count() == 0 || 
+                             (root->GetChildren().Count() == 1 && root->GetChildren().Item(0)->m_type == "settings")))
 	{
-		auto icon_solid_mesh = wxIcon(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG);
-		auto node = new PrusaObjectDataViewModelNode(root, root->m_name, icon_solid_mesh, extruder_str, 0);
+		const auto icon_solid_mesh = wxIcon(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG);
+		const auto node = new PrusaObjectDataViewModelNode(root, root->m_name, icon_solid_mesh, extruder_str, 0);
 		root->Append(node);
 		// notify control
-		wxDataViewItem child((void*)node);
+		const wxDataViewItem child((void*)node);
 		ItemAdded(parent_item, child);
 	}
 
-	auto volume_id = root->GetChildCount();
-	auto node = new PrusaObjectDataViewModelNode(root, name, icon, extruder_str, volume_id);
+    const auto volume_id =  root->GetChildren().Item(0)->m_type == "settings" ? 
+                            root->GetChildCount() - 1 : root->GetChildCount();
+
+	const auto node = new PrusaObjectDataViewModelNode(root, name, icon, extruder_str, volume_id);
 	root->Append(node);
 	// notify control
-	wxDataViewItem child((void*)node);
+	const wxDataViewItem child((void*)node);
 	ItemAdded(parent_item, child);
 	return child;
 }
@@ -455,7 +458,7 @@ wxDataViewItem PrusaObjectDataViewModel::Delete(const wxDataViewItem &item)
 
 		//update volume_id value for remaining child-nodes
 		auto children = node_parent->GetChildren();
-		for (size_t i = 0; i < node_parent->GetChildCount(); i++)
+        for (size_t i = 0; i < node_parent->GetChildCount() && v_id>=0; i++)
 		{
 			auto volume_id = children[i]->GetVolumeId();
 			if (volume_id > v_id)
@@ -684,20 +687,25 @@ wxDataViewItem PrusaObjectDataViewModel::ReorganizeChildren(int current_volume_i
     if (!node_parent)      // happens if item.IsOk()==false
         return ret_item;
 
-    PrusaObjectDataViewModelNode *deleted_node = node_parent->GetNthChild(current_volume_id);
+    const size_t shift = node_parent->GetChildren().Item(0)->m_type == "settings" ? 1 : 0;
+
+    PrusaObjectDataViewModelNode *deleted_node = node_parent->GetNthChild(current_volume_id+shift);
     node_parent->GetChildren().Remove(deleted_node);
     ItemDeleted(parent, wxDataViewItem(deleted_node));
-    node_parent->Insert(deleted_node, new_volume_id);
+    node_parent->Insert(deleted_node, new_volume_id+shift);
     ItemAdded(parent, wxDataViewItem(deleted_node));
+    const auto settings_item = HasSettings(wxDataViewItem(deleted_node));
+    if (settings_item)
+        ItemAdded(wxDataViewItem(deleted_node), settings_item);
 
     //update volume_id value for child-nodes
     auto children = node_parent->GetChildren();
     int id_frst = current_volume_id < new_volume_id ? current_volume_id : new_volume_id;
     int id_last = current_volume_id > new_volume_id ? current_volume_id : new_volume_id;
     for (int id = id_frst; id <= id_last; ++id)
-        children[id]->SetVolumeId(id);
+        children[id+shift]->SetVolumeId(id);
 
-    return wxDataViewItem(node_parent->GetNthChild(new_volume_id));
+    return wxDataViewItem(node_parent->GetNthChild(new_volume_id+shift));
 }
 
 bool PrusaObjectDataViewModel::IsEnabled(const wxDataViewItem &item, unsigned int col) const
@@ -759,20 +767,28 @@ unsigned int PrusaObjectDataViewModel::GetChildren(const wxDataViewItem &parent,
 	return count;
 }
 
-bool PrusaObjectDataViewModel::HasSettings(const wxDataViewItem &item) const
+wxDataViewItem PrusaObjectDataViewModel::HasSettings(const wxDataViewItem &item) const
 {
     if (!item.IsOk())
-        return false;
+        return wxDataViewItem(0);
 
     PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
     if (node->GetChildCount() == 0)
-        return false;
+        return wxDataViewItem(0);
 
     auto& children = node->GetChildren();
     if (children[0]->m_type == "settings")
-        return true;
+        return wxDataViewItem((void*)children[0]);;
 
-    return false;
+    return wxDataViewItem(0);
+}
+
+bool PrusaObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const
+{
+    if (!item.IsOk())
+        return false;
+    PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+    return node->m_type == "settings";
 }
 
 // ----------------------------------------------------------------------------
diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp
index 13fc764ce..3ead72f2f 100644
--- a/xs/src/slic3r/GUI/wxExtensions.hpp
+++ b/xs/src/slic3r/GUI/wxExtensions.hpp
@@ -195,7 +195,7 @@ public:
 
     PrusaObjectDataViewModelNode(   PrusaObjectDataViewModelNode* parent) :
                                     m_parent(parent),
-                                    m_name("SETTINGS LIST"),
+                                    m_name("Settings to modified"),
                                     m_copy(wxEmptyString),
                                     m_type("settings"),
                                     m_extruder(wxEmptyString) {}
@@ -362,7 +362,7 @@ public:
 	wxDataViewItem AddChild(const wxDataViewItem &parent_item, 
 							const wxString &name, 
                             const wxIcon& icon,
-                            const int = 0,
+                            const int extruder = 0,
                             const bool create_frst_child = true);
 	wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
 	wxDataViewItem Delete(const wxDataViewItem &item);
@@ -409,7 +409,8 @@ public:
 	// In our case it is an item with all columns 
 	virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override {	return true; }
 
-    bool    HasSettings(const wxDataViewItem &item) const;
+    wxDataViewItem    HasSettings(const wxDataViewItem &item) const;
+    bool    IsSettingsItem(const wxDataViewItem &item) const;
 };
 
 

From af6a312feab69aea43e988e4add81fb423264f65 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 4 Sep 2018 09:25:54 +0200
Subject: [PATCH 07/27] Fix to last commit

---
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp | 20 ++++++++++----------
 xs/src/slic3r/GUI/wxExtensions.cpp    |  5 +++--
 2 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index c7d7f35f8..119d73470 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -877,7 +877,6 @@ void update_settings_list()
     const auto item = m_objects_ctrl->GetSelection();
 	if (m_config && m_objects_model->IsSettingsItem(item)) 
 	{
-        show_manipulations = false;
         auto extra_column = [](wxWindow* parent, const Line& line)
 		{
 			auto opt_key = (line.get_options())[0].opt_id;  //we assume that we have one option per line
@@ -896,8 +895,8 @@ void update_settings_list()
 
 		std::map<std::string, std::vector<std::string>> cat_options;
 		auto opt_keys = (*m_config)->keys();
-        if (!(opt_keys.size() == 1 && opt_keys[0] == "extruder"))
-            // 			return;
+        m_og_settings.resize(0);
+        if (!(opt_keys.size() == 1 && opt_keys[0] == "extruder"))// return;
         {
             auto extruders_cnt = get_preset_bundle()->printers.get_selected_preset().printer_technology() == ptSLA ? 1 :
                 get_preset_bundle()->printers.get_edited_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
@@ -915,8 +914,6 @@ void update_settings_list()
                     cat_options[category] = cat_opt;
             }
 
-
-            m_og_settings.resize(0);
             for (auto& cat : cat_options) {
                 if (cat.second.size() == 1 && cat.second[0] == "extruder")
                     continue;
@@ -937,12 +934,14 @@ void update_settings_list()
                 m_option_sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 0);
                 m_og_settings.push_back(optgroup);
             }
-
-            if (m_og_settings.empty()) {
-                m_objects_ctrl->Select(m_objects_model->Delete(item));
-                show_manipulations = true;
-            }
         }
+
+        if (m_og_settings.empty()) {
+            m_objects_ctrl->Select(m_objects_model->Delete(item));
+            part_selection_changed();
+        }
+        else
+            show_manipulations = false;
 	}
 
     show_manipulation_og(show_manipulations);
@@ -1012,6 +1011,7 @@ void get_settings_choice(wxMenu *menu, int id, bool is_part)
         const auto settings_item = m_objects_model->HasSettings(item);
         m_objects_ctrl->Select(settings_item ? settings_item : 
                                m_objects_model->AddSettingsChild(item));
+        part_selection_changed();
     }
     // ********************
 
diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index a975ac4d6..0dfc21e16 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -480,9 +480,10 @@ wxDataViewItem PrusaObjectDataViewModel::Delete(const wxDataViewItem &item)
 	delete node;
 
 	// set m_containet to FALSE if parent has no child
-	if (node_parent && node_parent->GetChildCount() == 0){
+	if (node_parent) {
 #ifndef __WXGTK__
-		node_parent->m_container = false;
+        if (node_parent->GetChildCount() == 0)
+            node_parent->m_container = false;
 #endif //__WXGTK__
 		ret_item = parent;
 	}

From f471362e86aacd73bbf63de649bcf6f8b526d897 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 4 Sep 2018 13:15:27 +0200
Subject: [PATCH 08/27] Added SettingsDigest

---
 xs/src/slic3r/GUI/GUI.hpp             |  2 +
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp | 19 ++++++----
 xs/src/slic3r/GUI/GUI_ObjectParts.hpp |  4 ++
 xs/src/slic3r/GUI/wxExtensions.cpp    | 54 +++++++++++++++++++++++++++
 xs/src/slic3r/GUI/wxExtensions.hpp    | 13 +++----
 5 files changed, 78 insertions(+), 14 deletions(-)

diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp
index ceb004f8c..dd4387039 100644
--- a/xs/src/slic3r/GUI/GUI.hpp
+++ b/xs/src/slic3r/GUI/GUI.hpp
@@ -182,6 +182,8 @@ bool select_language(wxArrayString & names, wxArrayLong & identifiers);
 // update right panel of the Plater according to view mode
 void update_mode();
 
+void show_info_sizer(bool show);
+
 std::vector<Tab *>& get_tabs_list();
 bool checked_tab(Tab* tab);
 void delete_tab_from_list(Tab* tab);
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index 119d73470..092ba2756 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -69,8 +69,6 @@ bool m_part_settings_changed = false;
     wxString g_selected_extruder = "";
 #endif //__WXOSX__
 
-// typedef std::map<std::string, std::string> t_category_icon;
-typedef std::map<std::string, wxBitmap> t_category_icon;
 inline t_category_icon& get_category_icon() {
 	static t_category_icon CATEGORY_ICON;
 	if (CATEGORY_ICON.empty()){
@@ -896,6 +894,7 @@ void update_settings_list()
 		std::map<std::string, std::vector<std::string>> cat_options;
 		auto opt_keys = (*m_config)->keys();
         m_og_settings.resize(0);
+        std::vector<std::string> categories;
         if (!(opt_keys.size() == 1 && opt_keys[0] == "extruder"))// return;
         {
             auto extruders_cnt = get_preset_bundle()->printers.get_selected_preset().printer_technology() == ptSLA ? 1 :
@@ -933,6 +932,8 @@ void update_settings_list()
                 optgroup->reload_config();
                 m_option_sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 0);
                 m_og_settings.push_back(optgroup);
+
+                categories.push_back(cat.first);
             }
         }
 
@@ -940,11 +941,15 @@ void update_settings_list()
             m_objects_ctrl->Select(m_objects_model->Delete(item));
             part_selection_changed();
         }
-        else
+        else {
+            if (!categories.empty())
+                m_objects_model->UpdateSettingsDigest(item, categories);
             show_manipulations = false;
+        }
 	}
 
     show_manipulation_og(show_manipulations);
+    show_info_sizer(show_manipulations);
 
 #ifdef __linux__
 	no_updates.reset(nullptr);
@@ -1032,11 +1037,11 @@ wxMenuItem* menu_item_split(wxMenu* menu, int id) {
     return menu_item;
 }
 
-wxMenuItem* menu_item_settings(wxMenu* menu, int id) {
+wxMenuItem* menu_item_settings(wxMenu* menu, int id, const bool is_part) {
     auto  menu_item = new wxMenuItem(menu, id, _(L("Add settings")));
     menu_item->SetBitmap(m_bmp_cog);
 
-    auto sub_menu = create_add_settings_popupmenu(false);
+    auto sub_menu = create_add_settings_popupmenu(is_part);
     menu_item->SetSubMenu(sub_menu);
     return menu_item;
 }
@@ -1063,7 +1068,7 @@ wxMenu *create_add_part_popupmenu()
 
     menu->AppendSeparator();
     // Append settings popupmenu
-    menu->Append(menu_item_settings(menu, config_id_base + i + 1));
+    menu->Append(menu_item_settings(menu, config_id_base + i + 1, false));
 
 	wxWindow* win = get_tab_panel()->GetPage(0);
 
@@ -1099,7 +1104,7 @@ wxMenu *create_part_settings_popupmenu()
 
     menu->AppendSeparator();
     // Append settings popupmenu
-    menu->Append(menu_item_settings(menu, config_id_base + 1));
+    menu->Append(menu_item_settings(menu, config_id_base + 1, true));
 
     menu->Bind(wxEVT_MENU, [config_id_base, menu](wxEvent &event){
         switch (event.GetId() - config_id_base) {
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.hpp b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
index 5a3b96761..630912fb4 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
@@ -10,6 +10,7 @@ class wxMenu;
 class wxDataViewEvent;
 class wxKeyEvent;
 class wxGLCanvas;
+class wxBitmap;
 
 namespace Slic3r {
 class ModelObject;
@@ -45,6 +46,9 @@ struct OBJECT_PARAMETERS
 	double			slab_z = 0.0;
 };
 
+typedef std::map<std::string, wxBitmap> t_category_icon;
+inline t_category_icon& get_category_icon();
+
 void add_collapsible_panes(wxWindow* parent, wxBoxSizer* sizer);
 void add_objects_list(wxWindow* parent, wxBoxSizer* sizer);
 void add_object_settings(wxWindow* parent, wxBoxSizer* sizer);
diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index 0dfc21e16..1642828fb 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -2,6 +2,7 @@
 
 #include "GUI.hpp"
 #include "../../libslic3r/Utils.hpp"
+#include "BitmapCache.hpp"
 
 #include <wx/sizer.h>
 #include <wx/statline.h>
@@ -361,11 +362,52 @@ void PrusaObjectDataViewModelNode::set_settings_list_icon(const wxIcon& icon) {
     m_icon = icon;
 }
 
+Slic3r::GUI::BitmapCache *m_bitmap_cache = nullptr;
+bool PrusaObjectDataViewModelNode::update_settings_digest(const std::vector<std::string>& categories)
+{
+    if (m_type != "settings" || m_opt_categories == categories)
+        return false;
+
+    m_opt_categories = categories;
+    m_name = wxEmptyString;
+    m_icon = m_empty_icon;
+
+    auto categories_icon = Slic3r::GUI::get_category_icon();
+
+    for (auto& cat : m_opt_categories)
+        m_name += cat + "; ";
+
+    wxBitmap *bmp = m_bitmap_cache->find(m_name.ToStdString());
+    if (bmp == nullptr) {
+        std::vector<wxBitmap> bmps;
+        for (auto& cat : m_opt_categories)
+            bmps.emplace_back(categories_icon.find(cat) == categories_icon.end() ?
+                              wxNullBitmap : categories_icon.at(cat));
+        bmp = m_bitmap_cache->insert(m_name.ToStdString(), bmps);
+    }
+    m_icon.CopyFromBitmap(*bmp);
+
+    return true;
+}
+
 // *****************************************************************************
 // ----------------------------------------------------------------------------
 // PrusaObjectDataViewModel
 // ----------------------------------------------------------------------------
 
+PrusaObjectDataViewModel::PrusaObjectDataViewModel()
+{
+    m_bitmap_cache = new Slic3r::GUI::BitmapCache;
+}
+
+PrusaObjectDataViewModel::~PrusaObjectDataViewModel()
+{
+    for (auto object : m_objects)
+			delete object;
+    delete m_bitmap_cache;
+    m_bitmap_cache = nullptr;
+}
+
 wxDataViewItem PrusaObjectDataViewModel::Add(const wxString &name)
 {
 	auto root = new PrusaObjectDataViewModelNode(name);
@@ -792,6 +834,18 @@ bool PrusaObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const
     return node->m_type == "settings";
 }
 
+
+
+void PrusaObjectDataViewModel::UpdateSettingsDigest(const wxDataViewItem &item, 
+                                                    const std::vector<std::string>& categories)
+{
+    if (!item.IsOk()) return;
+    PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+    if (!node->update_settings_digest(categories))
+        return;
+    ItemChanged(item);
+}
+
 // ----------------------------------------------------------------------------
 // PrusaDoubleSlider
 // ----------------------------------------------------------------------------
diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp
index 3ead72f2f..cefe680aa 100644
--- a/xs/src/slic3r/GUI/wxExtensions.hpp
+++ b/xs/src/slic3r/GUI/wxExtensions.hpp
@@ -155,7 +155,8 @@ class PrusaObjectDataViewModelNode
 {
 	PrusaObjectDataViewModelNode*	m_parent;
 	MyObjectTreeModelNodePtrArray   m_children;
-    wxIcon                          m_empty_icon; 
+    wxIcon                          m_empty_icon;
+    std::vector< std::string >      m_opt_categories;
 public:
 	PrusaObjectDataViewModelNode(const wxString &name, const int instances_count=1) {
 		m_parent	= NULL;
@@ -340,6 +341,7 @@ public:
 	void set_object_action_icon();
 	void set_part_action_icon();
     void set_settings_list_icon(const wxIcon& icon);
+    bool update_settings_digest(const std::vector<std::string>& categories);
 };
 
 // ----------------------------------------------------------------------------
@@ -350,12 +352,8 @@ class PrusaObjectDataViewModel :public wxDataViewModel
 {
 	std::vector<PrusaObjectDataViewModelNode*> m_objects;
 public:
-	PrusaObjectDataViewModel(){}
-	~PrusaObjectDataViewModel()
-	{
-		for (auto object : m_objects)
-			delete object;		
-	}
+    PrusaObjectDataViewModel();
+    ~PrusaObjectDataViewModel();
 
 	wxDataViewItem Add(const wxString &name);
 	wxDataViewItem Add(const wxString &name, const int instances_count);
@@ -411,6 +409,7 @@ public:
 
     wxDataViewItem    HasSettings(const wxDataViewItem &item) const;
     bool    IsSettingsItem(const wxDataViewItem &item) const;
+    void    UpdateSettingsDigest(const wxDataViewItem &item, const std::vector<std::string>& categories);
 };
 
 

From 4e9e59fd806c96ab8b0f9677c2424f0a92d34161 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Thu, 6 Sep 2018 10:15:57 +0200
Subject: [PATCH 09/27] Disable "Split" menu item for non-splittable objects

---
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp | 69 ++++++++++++++++++---------
 xs/src/slic3r/GUI/GUI_ObjectParts.hpp |  1 +
 xs/src/slic3r/GUI/wxExtensions.cpp    |  6 +--
 xs/src/slic3r/GUI/wxExtensions.hpp    |  2 +-
 4 files changed, 52 insertions(+), 26 deletions(-)

diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index 092ba2756..4e92c4570 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -1023,14 +1023,6 @@ void get_settings_choice(wxMenu *menu, int id, bool is_part)
 	update_settings_list();
 }
 
-bool cur_item_hase_children()
-{
-    wxDataViewItemArray children;
-    if (m_objects_model->GetChildren(m_objects_ctrl->GetSelection(), children) > 0)
-        return true;
-    return false;
-}
-
 wxMenuItem* menu_item_split(wxMenu* menu, int id) {
     auto menu_item = new wxMenuItem(menu, id, _(L("Split to parts")));
     menu_item->SetBitmap(m_bmp_split);
@@ -1064,7 +1056,7 @@ wxMenu *create_add_part_popupmenu()
     menu->AppendSeparator();
     auto menu_item = menu_item_split(menu, config_id_base + i);
     menu->Append(menu_item);
-    menu_item->Enable(!cur_item_hase_children());
+    menu_item->Enable(is_splittable_object(false));
 
     menu->AppendSeparator();
     // Append settings popupmenu
@@ -1100,7 +1092,9 @@ wxMenu *create_part_settings_popupmenu()
     wxMenu *menu = new wxMenu;
     wxWindowID config_id_base = wxWindow::NewControlId(2);
 
-    menu->Append(menu_item_split(menu, config_id_base));
+    auto menu_item = menu_item_split(menu, config_id_base);
+    menu->Append(menu_item);
+    menu_item->Enable(is_splittable_object(true));
 
     menu->AppendSeparator();
     // Append settings popupmenu
@@ -1332,23 +1326,54 @@ void on_btn_del()
 	part_selection_changed();
 }
 
+bool get_volume_by_item(const bool split_part, const wxDataViewItem& item, ModelVolume*& volume)
+{
+    if (!item || m_selected_object_id < 0)
+        return false;
+    const auto volume_id = m_objects_model->GetVolumeIdByItem(item);
+    if (volume_id < 0) {
+        if (split_part) return false;
+        volume = (*m_objects)[m_selected_object_id]->volumes[0]; 
+    }
+    else
+        volume = (*m_objects)[m_selected_object_id]->volumes[volume_id];
+    if (volume)
+        return true;
+    return false;
+}
+
+bool is_splittable_object(const bool split_part)
+{
+    const wxDataViewItem item = m_objects_ctrl->GetSelection();
+    if (!item) return false;
+
+    wxDataViewItemArray children;
+    if (!split_part && m_objects_model->GetChildren(item, children) > 0)
+        return false;
+
+    ModelVolume* volume;
+    if (!get_volume_by_item(split_part, item, volume) || !volume)
+        return false;
+
+    TriangleMeshPtrs meshptrs = volume->mesh.split();
+    if (meshptrs.size() <= 1) {
+        delete meshptrs.front();
+        return false;
+    }
+
+    return true;
+}
+
 void on_btn_split(const bool split_part)
 {
-	auto item = m_objects_ctrl->GetSelection();
+	const auto item = m_objects_ctrl->GetSelection();
 	if (!item || m_selected_object_id<0)
 		return;
-	auto volume_id = m_objects_model->GetVolumeIdByItem(item);
     ModelVolume* volume;
-    if (volume_id < 0) {
-        if (split_part) return;
-        else
-            volume = (*m_objects)[m_selected_object_id]->volumes[0]; }
-    else
-	    volume = (*m_objects)[m_selected_object_id]->volumes[volume_id];
- 	DynamicPrintConfig&	config = get_preset_bundle()->printers.get_edited_preset().config;
-    auto nozzle_dmrs_cnt = config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
-    auto split_rez = volume->split(nozzle_dmrs_cnt);
-    if (split_rez == 1) {
+    if (!get_volume_by_item(split_part, item, volume)) return;
+    DynamicPrintConfig&	config = get_preset_bundle()->printers.get_edited_preset().config;
+    const auto nozzle_dmrs_cnt = config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
+    if (volume->split(nozzle_dmrs_cnt) == 1) {
         wxMessageBox(_(L("The selected object couldn't be split because it contains only one part.")));
         return;
     }
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.hpp b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
index 630912fb4..5d94ecc3d 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
@@ -79,6 +79,7 @@ void object_ctrl_context_menu();
 void object_ctrl_key_event(wxKeyEvent& event);
 void object_ctrl_item_value_change(wxDataViewEvent& event);
 void show_context_menu();
+bool is_splittable_object(const bool split_part);
 
 void init_mesh_icons();
 void set_event_object_selection_changed(const int& event);
diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index 1642828fb..54454fbf7 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -442,7 +442,7 @@ wxDataViewItem PrusaObjectDataViewModel::AddChild(	const wxDataViewItem &parent_
     const wxString extruder_str = extruder == 0 ? "default" : wxString::Format("%d", extruder);
 
     if (create_frst_child && (root->GetChildren().Count() == 0 || 
-                             (root->GetChildren().Count() == 1 && root->GetChildren().Item(0)->m_type == "settings")))
+                             (root->GetChildren().Count() == 1 && root->GetNthChild(0)->m_type == "settings")))
 	{
 		const auto icon_solid_mesh = wxIcon(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG);
 		const auto node = new PrusaObjectDataViewModelNode(root, root->m_name, icon_solid_mesh, extruder_str, 0);
@@ -452,7 +452,7 @@ wxDataViewItem PrusaObjectDataViewModel::AddChild(	const wxDataViewItem &parent_
 		ItemAdded(parent_item, child);
 	}
 
-    const auto volume_id =  root->GetChildren().Item(0)->m_type == "settings" ? 
+    const auto volume_id =  root->GetChildCount() > 0 && root->GetNthChild(0)->m_type == "settings" ?
                             root->GetChildCount() - 1 : root->GetChildCount();
 
 	const auto node = new PrusaObjectDataViewModelNode(root, name, icon, extruder_str, volume_id);
@@ -597,7 +597,7 @@ int PrusaObjectDataViewModel::GetIdByItem(wxDataViewItem& item)
 	return it - m_objects.begin();
 }
 
-int PrusaObjectDataViewModel::GetVolumeIdByItem(wxDataViewItem& item)
+int PrusaObjectDataViewModel::GetVolumeIdByItem(const wxDataViewItem& item)
 {
 	wxASSERT(item.IsOk());
 
diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp
index cefe680aa..4236e0915 100644
--- a/xs/src/slic3r/GUI/wxExtensions.hpp
+++ b/xs/src/slic3r/GUI/wxExtensions.hpp
@@ -368,7 +368,7 @@ public:
     void DeleteChildren(wxDataViewItem& parent);
 	wxDataViewItem GetItemById(int obj_idx);
 	int GetIdByItem(wxDataViewItem& item);
-	int GetVolumeIdByItem(wxDataViewItem& item);
+	int GetVolumeIdByItem(const wxDataViewItem& item);
 	bool IsEmpty() { return m_objects.empty(); }
 
 	// helper method for wxLog

From 27f196be59dcf9bf3eecdc5d48dfb78cca1a5923 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Thu, 6 Sep 2018 16:36:10 +0200
Subject: [PATCH 10/27] Implement "Add generic" menu item like submenu instead
 of selection dialog

---
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp    | 103 ++++++++++++++++++-----
 xs/src/slic3r/GUI/GUI_ObjectParts.hpp    |   9 +-
 xs/src/slic3r/GUI/LambdaObjectDialog.cpp |  55 ++++++++----
 xs/src/slic3r/GUI/LambdaObjectDialog.hpp |   9 +-
 4 files changed, 131 insertions(+), 45 deletions(-)

diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index 4e92c4570..240f76612 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -319,15 +319,15 @@ wxBoxSizer* create_edit_object_buttons(wxWindow* win)
 
 	//*** button's functions
 	btn_load_part->Bind(wxEVT_BUTTON, [win](wxEvent&) {
-		on_btn_load(win);
+// 		on_btn_load(win);
 	});
 
 	btn_load_modifier->Bind(wxEVT_BUTTON, [win](wxEvent&) {
-		on_btn_load(win, true);
+// 		on_btn_load(win, true);
 	});
 
 	btn_load_lambda_modifier->Bind(wxEVT_BUTTON, [win](wxEvent&) {
-		on_btn_load(win, true, true);
+// 		on_btn_load(win, true, true);
 	});
 
 	btn_delete		->Bind(wxEVT_BUTTON, [](wxEvent&) { on_btn_del(); });
@@ -1010,7 +1010,7 @@ void get_settings_choice(wxMenu *menu, int id, bool is_part)
 	}
 
 
-    // ***  EXPERIMINT  ***
+    // Add settings item for object
     const auto item = m_objects_ctrl->GetSelection();
     if (item) {
         const auto settings_item = m_objects_model->HasSettings(item);
@@ -1018,11 +1018,20 @@ void get_settings_choice(wxMenu *menu, int id, bool is_part)
                                m_objects_model->AddSettingsChild(item));
         part_selection_changed();
     }
-    // ********************
 
 	update_settings_list();
 }
 
+void menu_item_add_generic(wxMenuItem* &menu, int id) {
+    auto sub_menu = new wxMenu;
+
+    std::vector<std::string> menu_items = { L("Box"), L("Cylinder"), L("Sphere"), L("Slab") };
+    for (auto& item : menu_items)
+        sub_menu->Append(new wxMenuItem(sub_menu, ++id, _(item)));
+
+    menu->SetSubMenu(sub_menu);
+}
+
 wxMenuItem* menu_item_split(wxMenu* menu, int id) {
     auto menu_item = new wxMenuItem(menu, id, _(L("Split to parts")));
     menu_item->SetBitmap(m_bmp_split);
@@ -1043,39 +1052,45 @@ wxMenu *create_add_part_popupmenu()
 	wxMenu *menu = new wxMenu;
 	std::vector<std::string> menu_items = { L("Add part"), L("Add modifier"), L("Add generic") };
 
-	wxWindowID config_id_base = wxWindow::NewControlId(menu_items.size()+2);
+	wxWindowID config_id_base = wxWindow::NewControlId(menu_items.size()+4+2);
 
 	int i = 0;
 	for (auto& item : menu_items) {
 		auto menu_item = new wxMenuItem(menu, config_id_base + i, _(item));
 		menu_item->SetBitmap(i == 0 ? m_icon_solidmesh : m_icon_modifiermesh);
-		menu->Append(menu_item);
+        if (item == "Add generic")
+            menu_item_add_generic(menu_item, config_id_base + i);
+        menu->Append(menu_item);
 		i++;
     }
 
     menu->AppendSeparator();
-    auto menu_item = menu_item_split(menu, config_id_base + i);
+    auto menu_item = menu_item_split(menu, config_id_base + i + 4);
     menu->Append(menu_item);
     menu_item->Enable(is_splittable_object(false));
 
     menu->AppendSeparator();
     // Append settings popupmenu
-    menu->Append(menu_item_settings(menu, config_id_base + i + 1, false));
+    menu->Append(menu_item_settings(menu, config_id_base + i + 5, false));
 
-	wxWindow* win = get_tab_panel()->GetPage(0);
-
-	menu->Bind(wxEVT_MENU, [config_id_base, win, menu](wxEvent &event){
+	menu->Bind(wxEVT_MENU, [config_id_base, menu](wxEvent &event){
 		switch (event.GetId() - config_id_base) {
 		case 0:
-			on_btn_load(win);
+			on_btn_load();
 			break;
 		case 1:
-			on_btn_load(win, true);
+			on_btn_load(true);
 			break;
 		case 2:
-			on_btn_load(win, true, true);
+// 			on_btn_load(true, true);
 			break;
-		case 3:
+        case 3:
+        case 4:
+        case 5:
+        case 6:
+            load_lambda(menu->GetLabel(event.GetId()).ToStdString());
+            break;
+ 	    case 7: //3:
 			on_btn_split(false);
 			break;
 		default:{
@@ -1154,9 +1169,11 @@ void show_context_menu()
 
 // ******
 
-void load_part(	wxWindow* parent, ModelObject* model_object, 
+void load_part(	ModelObject* model_object, 
 				wxArrayString& part_names, const bool is_modifier)
 {
+    wxWindow* parent = get_tab_panel()->GetPage(0);
+
 	wxArrayString input_files;
 	open_model(parent, input_files);
 	for (int i = 0; i < input_files.size(); ++i) {
@@ -1194,10 +1211,10 @@ void load_part(	wxWindow* parent, ModelObject* model_object,
 	}
 }
 
-void load_lambda(	wxWindow* parent, ModelObject* model_object,
+void load_lambda(	ModelObject* model_object,
 					wxArrayString& part_names, const bool is_modifier)
 {
-	auto dlg = new LambdaObjectDialog(parent);
+    auto dlg = new LambdaObjectDialog(m_objects_ctrl->GetMainWindow());
 	if (dlg->ShowModal() == wxID_CANCEL) {
 		return;
 	}
@@ -1243,7 +1260,49 @@ void load_lambda(	wxWindow* parent, ModelObject* model_object,
 	m_parts_changed = true;
 }
 
-void on_btn_load(wxWindow* parent, bool is_modifier /*= false*/, bool is_lambda/* = false*/)
+void load_lambda(const std::string& type_name)
+{
+    if (m_selected_object_id < 0) return;
+
+    auto dlg = new LambdaObjectDialog(m_objects_ctrl->GetMainWindow(), type_name);
+    if (dlg->ShowModal() == wxID_CANCEL)
+        return;
+
+    const std::string name = "lambda-"+type_name;
+    TriangleMesh mesh;
+
+    const auto params = dlg->ObjectParameters();
+    if (type_name == _("Box"))
+        mesh = make_cube(params.dim[0], params.dim[1], params.dim[2]);
+    else if (type_name == _("Cylinder"))
+        mesh = make_cylinder(params.cyl_r, params.cyl_h);
+    else if (type_name == _("Sphere"))
+        mesh = make_sphere(params.sph_rho);
+    else if (type_name == _("Slab")){
+        const auto& size = (*m_objects)[m_selected_object_id]->bounding_box().size();
+        mesh = make_cube(size(0)*1.5, size(1)*1.5, params.slab_h);
+        // box sets the base coordinate at 0, 0, move to center of plate and move it up to initial_z
+        mesh.translate(-size(0)*1.5 / 2.0, -size(1)*1.5 / 2.0, params.slab_z);
+    }
+    mesh.repair();
+
+    auto new_volume = (*m_objects)[m_selected_object_id]->add_volume(mesh);
+    new_volume->modifier = true;
+    new_volume->name = name;
+    // set a default extruder value, since user can't add it manually
+    new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
+
+    m_parts_changed = true;
+    parts_changed(m_selected_object_id);
+
+    m_objects_ctrl->Select(m_objects_model->AddChild(m_objects_ctrl->GetSelection(), 
+                                                     name, m_icon_modifiermesh));
+#ifdef __WXMSW__
+    object_ctrl_selection_changed();
+#endif //__WXMSW__
+}
+
+void on_btn_load(bool is_modifier /*= false*/, bool is_lambda/* = false*/)
 {
 	auto item = m_objects_ctrl->GetSelection();
 	if (!item)
@@ -1257,9 +1316,9 @@ void on_btn_load(wxWindow* parent, bool is_modifier /*= false*/, bool is_lambda/
 	if (obj_idx < 0) return;
 	wxArrayString part_names;
 	if (is_lambda)
-		load_lambda(parent, (*m_objects)[obj_idx], part_names, is_modifier);
+		load_lambda((*m_objects)[obj_idx], part_names, is_modifier);
 	else
-		load_part(parent, (*m_objects)[obj_idx], part_names, is_modifier);
+		load_part((*m_objects)[obj_idx], part_names, is_modifier);
 
 	parts_changed(obj_idx);
 
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.hpp b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
index 5d94ecc3d..ae12a4b2e 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
@@ -91,13 +91,14 @@ void set_objects_from_model(Model &model);
 bool is_parts_changed();
 bool is_part_settings_changed();
 
-void load_part(	wxWindow* parent, ModelObject* model_object, 
+void load_part(	ModelObject* model_object, 
 				wxArrayString& part_names, const bool is_modifier); 
 
-void load_lambda(wxWindow* parent, ModelObject* model_object, 
-				wxArrayString& part_names, const bool is_modifier);
+void load_lambda( ModelObject* model_object, 
+				wxArrayString& part_names, const bool is_modifier); 
+void load_lambda( const std::string& type_name);
 
-void on_btn_load(wxWindow* parent, bool is_modifier = false, bool is_lambda = false);
+void on_btn_load(bool is_modifier = false, bool is_lambda = false);
 void on_btn_del();
 void on_btn_split(const bool split_part);
 void on_btn_move_up();
diff --git a/xs/src/slic3r/GUI/LambdaObjectDialog.cpp b/xs/src/slic3r/GUI/LambdaObjectDialog.cpp
index 7543821c0..7d741be7f 100644
--- a/xs/src/slic3r/GUI/LambdaObjectDialog.cpp
+++ b/xs/src/slic3r/GUI/LambdaObjectDialog.cpp
@@ -10,10 +10,12 @@ namespace GUI
 {
 static wxString dots("…", wxConvUTF8);
 
-LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent)
+LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent,
+                                       const wxString type_name):
+                                       m_type_name(type_name)
 {
 	Create(parent, wxID_ANY, _(L("Lambda Object")),
-		wxDefaultPosition, wxDefaultSize,
+        parent->GetScreenPosition(), wxDefaultSize,
 		wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
 
 	// instead of double dim[3] = { 1.0, 1.0, 1.0 };
@@ -24,11 +26,20 @@ LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent)
 	sizer = new wxBoxSizer(wxVERTICAL);
 
 	// modificator options
-	m_modificator_options_book = new wxChoicebook(	this, wxID_ANY, wxDefaultPosition, 
-													wxDefaultSize, wxCHB_TOP);
-	sizer->Add(m_modificator_options_book, 1, wxEXPAND| wxALL, 10);
+    if (m_type_name == wxEmptyString) {
+        m_modificator_options_book = new wxChoicebook(  this, wxID_ANY, wxDefaultPosition,
+                                                        wxDefaultSize, wxCHB_TOP);
+        sizer->Add(m_modificator_options_book, 1, wxEXPAND | wxALL, 10);
+    }
+    else {
+        m_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
+        sizer->Add(m_panel, 1, wxEXPAND | wxALL, 10);
+    }
 
+    ConfigOptionDef def;
+    def.width = 70;
 	auto optgroup = init_modificator_options_page(_(L("Box")));
+    if (optgroup){
 		optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value){
 			int opt_id =	opt_key == "l" ? 0 :
 							opt_key == "w" ? 1 : 
@@ -37,8 +48,6 @@ LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent)
 			object_parameters.dim[opt_id] = boost::any_cast<double>(value);
 		};
 
-		ConfigOptionDef def;
-		def.width = 70;
 		def.type = coFloat;
 		def.default_value = new ConfigOptionFloat{ 1.0 };
 		def.label = L("L");
@@ -52,8 +61,10 @@ LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent)
 		def.label = L("H");
 		option = Option(def, "h");
 		optgroup->append_single_option_line(option);
+	}
 
 	optgroup = init_modificator_options_page(_(L("Cylinder")));
+	if (optgroup){
 		optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value){
 			int val = boost::any_cast<int>(value);
 			if (opt_key == "cyl_r")
@@ -66,14 +77,16 @@ LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent)
 		def.type = coInt;
 		def.default_value = new ConfigOptionInt{ 1 };
 		def.label = L("Radius");
-		option = Option(def, "cyl_r");
+		auto option = Option(def, "cyl_r");
 		optgroup->append_single_option_line(option);
 
 		def.label = L("Height");
 		option = Option(def, "cyl_h");
 		optgroup->append_single_option_line(option);
+    }
 
 	optgroup = init_modificator_options_page(_(L("Sphere")));
+	if (optgroup){
 		optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value){
 			if (opt_key == "sph_rho")
 				object_parameters.sph_rho = boost::any_cast<double>(value);
@@ -83,10 +96,12 @@ LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent)
 		def.type = coFloat;
 		def.default_value = new ConfigOptionFloat{ 1.0 };
 		def.label = L("Rho");
-		option = Option(def, "sph_rho");
+		auto option = Option(def, "sph_rho");
 		optgroup->append_single_option_line(option);
+	}
 
 	optgroup = init_modificator_options_page(_(L("Slab")));
+	if (optgroup){
 		optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value){
 			double val = boost::any_cast<double>(value);
 			if (opt_key == "slab_z")
@@ -96,13 +111,16 @@ LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent)
 			else return;
 		};
 
+		def.type = coFloat;
+		def.default_value = new ConfigOptionFloat{ 1.0 };
 		def.label = L("H");
-		option = Option(def, "slab_h");
+		auto option = Option(def, "slab_h");
 		optgroup->append_single_option_line(option);
 
 		def.label = L("Initial Z");
 		option = Option(def, "slab_z");
 		optgroup->append_single_option_line(option);
+	}
 
 	Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent e)
 	{
@@ -127,8 +145,7 @@ LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent)
 		}
 	}));
 
-
-	auto button_sizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL);
+	const auto button_sizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL);
 
 	wxButton* btn_OK = static_cast<wxButton*>(FindWindowById(wxID_OK, this));
 	btn_OK->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
@@ -155,9 +172,11 @@ LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent)
 
 // Called from the constructor.
 // Create a panel for a rectangular / circular / custom bed shape.
-ConfigOptionsGroupShp LambdaObjectDialog::init_modificator_options_page(wxString title){
+ConfigOptionsGroupShp LambdaObjectDialog::init_modificator_options_page(const wxString& title){
+    if (!m_type_name.IsEmpty() && m_type_name != title)
+        return nullptr;
 
-	auto panel = new wxPanel(m_modificator_options_book);
+    auto panel = m_type_name.IsEmpty() ? new wxPanel(m_modificator_options_book) : m_panel;
 
 	ConfigOptionsGroupShp optgroup;
 	optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Add")) + " " +title + " " +dots);
@@ -165,8 +184,12 @@ ConfigOptionsGroupShp LambdaObjectDialog::init_modificator_options_page(wxString
 
 	m_optgroups.push_back(optgroup);
 
-	panel->SetSizerAndFit(optgroup->sizer);
-	m_modificator_options_book->AddPage(panel, title);
+    if (m_type_name.IsEmpty()) {
+        panel->SetSizerAndFit(optgroup->sizer);
+        m_modificator_options_book->AddPage(panel, title);
+    }
+    else
+        panel->SetSizer(optgroup->sizer);
 
 	return optgroup;
 }
diff --git a/xs/src/slic3r/GUI/LambdaObjectDialog.hpp b/xs/src/slic3r/GUI/LambdaObjectDialog.hpp
index a70c12449..d9e2e430a 100644
--- a/xs/src/slic3r/GUI/LambdaObjectDialog.hpp
+++ b/xs/src/slic3r/GUI/LambdaObjectDialog.hpp
@@ -14,16 +14,19 @@ namespace GUI
 using ConfigOptionsGroupShp = std::shared_ptr<ConfigOptionsGroup>;
 class LambdaObjectDialog : public wxDialog
 {
-	wxChoicebook*	m_modificator_options_book;
+	wxChoicebook*	m_modificator_options_book = nullptr;
 	std::vector <ConfigOptionsGroupShp>	m_optgroups;
+    wxString        m_type_name;
+    wxPanel*        m_panel = nullptr;
 public:
-	LambdaObjectDialog(wxWindow* parent);
+    LambdaObjectDialog(wxWindow* parent, 
+                       const wxString type_name = wxEmptyString);
 	~LambdaObjectDialog(){}
 
 	bool CanClose() { return true; }	// ???
 	OBJECT_PARAMETERS& ObjectParameters(){ return object_parameters; }
 
-	ConfigOptionsGroupShp init_modificator_options_page(wxString title);
+	ConfigOptionsGroupShp init_modificator_options_page(const wxString& title);
 	
 	// Note whether the window was already closed, so a pending update is not executed.
 	bool m_already_closed = false;

From 2efc8c705eaf20019ccabd16ad94cd97a2d37a10 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 7 Sep 2018 09:09:24 +0200
Subject: [PATCH 11/27] Try to fix 1204

---
 lib/Slic3r/GUI/Plater/OverrideSettingsPanel.pm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/Slic3r/GUI/Plater/OverrideSettingsPanel.pm b/lib/Slic3r/GUI/Plater/OverrideSettingsPanel.pm
index 3b10ed99f..ea4ce7132 100644
--- a/lib/Slic3r/GUI/Plater/OverrideSettingsPanel.pm
+++ b/lib/Slic3r/GUI/Plater/OverrideSettingsPanel.pm
@@ -136,7 +136,7 @@ sub update_optgroup {
             full_labels     => 1,
             label_font      => $Slic3r::GUI::small_font,
             sidetext_font   => $Slic3r::GUI::small_font,
-            label_width     => 120,
+            label_width     => 150,
             on_change       => sub { $self->{on_change}->() if $self->{on_change} },
             extra_column    => sub {
                 my ($line) = @_;

From 810b48887d229a7c875b6435a89b85fabe99bb3f Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 7 Sep 2018 16:16:11 +0200
Subject: [PATCH 12/27] Fixed Adding generic modifiers on GTK & OSX

+ Try to fix correct settings adding on GTK & OSX
+ Fixed Linux compilation
---
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp    | 35 +++++++++++++++---------
 xs/src/slic3r/GUI/LambdaObjectDialog.hpp |  2 ++
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index 240f76612..0114fa2f9 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -281,7 +281,7 @@ wxBoxSizer* create_objects_list(wxWindow *win)
 
     m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_CONTEXT_MENU, [](wxDataViewEvent& event) {
         object_ctrl_context_menu();
-		event.Skip();
+//		event.Skip();
 	});
 
     m_objects_ctrl->Bind(wxEVT_CHAR, [](wxKeyEvent& event) { object_ctrl_key_event(event); }); // doesn't work on OSX
@@ -1018,7 +1018,7 @@ void get_settings_choice(wxMenu *menu, int id, bool is_part)
                                m_objects_model->AddSettingsChild(item));
         part_selection_changed();
     }
-
+    else
 	update_settings_list();
 }
 
@@ -1029,6 +1029,12 @@ void menu_item_add_generic(wxMenuItem* &menu, int id) {
     for (auto& item : menu_items)
         sub_menu->Append(new wxMenuItem(sub_menu, ++id, _(item)));
 
+#ifndef __WXMSW__
+    sub_menu->Bind(wxEVT_MENU, [sub_menu](wxEvent &event) {
+        load_lambda(menu->GetLabel(event.GetId()).ToStdString());
+    });
+#endif //no __WXMSW__
+
     menu->SetSubMenu(sub_menu);
 }
 
@@ -1088,14 +1094,18 @@ wxMenu *create_add_part_popupmenu()
         case 4:
         case 5:
         case 6:
-            load_lambda(menu->GetLabel(event.GetId()).ToStdString());
+#ifdef __WXMSW__
+		    load_lambda(menu->GetLabel(event.GetId()).ToStdString());
+#endif // __WXMSW__
             break;
- 	    case 7: //3:
+		case 7: //3:
 			on_btn_split(false);
 			break;
-		default:{
+		default:
+#ifdef __WXMSW__
 			get_settings_choice(menu, event.GetId(), false);
-			break;}
+#endif // __WXMSW__
+			break;
 		}
 	});
 
@@ -1145,11 +1155,11 @@ wxMenu *create_add_settings_popupmenu(bool is_part)
 								wxNullBitmap : categories.at(cat.first));
 		menu->Append(menu_item);
 	}
-
+#ifndef __WXMSW__
 	menu->Bind(wxEVT_MENU, [menu](wxEvent &event) {
 		get_settings_choice(menu, event.GetId(), true);
 	});
-
+#endif //no __WXMSW__
 	return menu;
 }
 
@@ -1297,9 +1307,9 @@ void load_lambda(const std::string& type_name)
 
     m_objects_ctrl->Select(m_objects_model->AddChild(m_objects_ctrl->GetSelection(), 
                                                      name, m_icon_modifiermesh));
-#ifdef __WXMSW__
+#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
     object_ctrl_selection_changed();
-#endif //__WXMSW__
+#endif //no __WXOSX__ //__WXMSW__
 }
 
 void on_btn_load(bool is_modifier /*= false*/, bool is_lambda/* = false*/)
@@ -1325,10 +1335,9 @@ void on_btn_load(bool is_modifier /*= false*/, bool is_lambda/* = false*/)
 	for (int i = 0; i < part_names.size(); ++i)
 		m_objects_ctrl->Select(	m_objects_model->AddChild(item, part_names.Item(i), 
 								is_modifier ? m_icon_modifiermesh : m_icon_solidmesh));
-// 	part_selection_changed();
-#ifdef __WXMSW__
+#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
 	object_ctrl_selection_changed();
-#endif //__WXMSW__
+#endif //no __WXOSX__//__WXMSW__
 }
 
 void remove_settings_from_config()
diff --git a/xs/src/slic3r/GUI/LambdaObjectDialog.hpp b/xs/src/slic3r/GUI/LambdaObjectDialog.hpp
index d9e2e430a..8f3e8cd80 100644
--- a/xs/src/slic3r/GUI/LambdaObjectDialog.hpp
+++ b/xs/src/slic3r/GUI/LambdaObjectDialog.hpp
@@ -7,6 +7,8 @@
 #include <wx/sizer.h>
 #include <wx/choicebk.h>
 
+class wxPanel;
+
 namespace Slic3r
 {
 namespace GUI

From b7effbde17ad753299f4283459c92850cca860f6 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 7 Sep 2018 16:29:16 +0200
Subject: [PATCH 13/27] Fixed typo for last commit

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

diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index 0114fa2f9..867fae64d 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -1031,7 +1031,7 @@ void menu_item_add_generic(wxMenuItem* &menu, int id) {
 
 #ifndef __WXMSW__
     sub_menu->Bind(wxEVT_MENU, [sub_menu](wxEvent &event) {
-        load_lambda(menu->GetLabel(event.GetId()).ToStdString());
+        load_lambda(sub_menu->GetLabel(event.GetId()).ToStdString());
     });
 #endif //no __WXMSW__
 

From a59a84f237417430a56a2cbd590938cdea35d16f Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 10 Sep 2018 09:28:37 +0200
Subject: [PATCH 14/27] Experiment with icon size

---
 xs/src/slic3r/GUI/wxExtensions.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index 54454fbf7..a67a6b6cd 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -386,6 +386,10 @@ bool PrusaObjectDataViewModelNode::update_settings_digest(const std::vector<std:
         bmp = m_bitmap_cache->insert(m_name.ToStdString(), bmps);
     }
     m_icon.CopyFromBitmap(*bmp);
+#ifdef __WXOSX__
+    m_icon.SetHeight(bmp->GetHeight());
+    m_icon.SetWidth(bmp->GetWidth());
+#endif // __WXOSX__
 
     return true;
 }

From e914a719f8b3ffd1c44b1e42f0e0c1267b60fbee Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 10 Sep 2018 12:17:41 +0200
Subject: [PATCH 15/27] Added printfs for code debugging on OSX

---
 xs/src/slic3r/GUI/GUI.cpp             | 4 ++--
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp | 3 +++
 xs/src/slic3r/GUI/wxExtensions.cpp    | 7 +++----
 3 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp
index 315a4bada..956a0008a 100644
--- a/xs/src/slic3r/GUI/GUI.cpp
+++ b/xs/src/slic3r/GUI/GUI.cpp
@@ -1232,11 +1232,11 @@ void enable_action_buttons(bool enable)
         return;
 
     // Update background colour for buttons
-    const wxColour bgrd_color = enable ? wxColour(255, 96, 0) : wxColour(204, 204, 204);
+//     const wxColour bgrd_color = enable ? wxColour(255, 96, 0) : wxColour(204, 204, 204);
 
     for (auto btn : g_buttons) {
         btn->Enable(enable);
-        btn->SetBackgroundColour(bgrd_color);
+//         btn->SetBackgroundColour(bgrd_color);
     }
 }
 
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index 867fae64d..ee57b4a0a 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -1014,9 +1014,12 @@ void get_settings_choice(wxMenu *menu, int id, bool is_part)
     const auto item = m_objects_ctrl->GetSelection();
     if (item) {
         const auto settings_item = m_objects_model->HasSettings(item);
+        settings_item ? printf("settings_item exist\n") : printf("settings_item will be created\n");
         m_objects_ctrl->Select(settings_item ? settings_item : 
                                m_objects_model->AddSettingsChild(item));
+#ifndef __WXOSX__
         part_selection_changed();
+#endif //no __WXOSX__
     }
     else
 	update_settings_list();
diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index a67a6b6cd..737833abd 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -386,10 +386,6 @@ bool PrusaObjectDataViewModelNode::update_settings_digest(const std::vector<std:
         bmp = m_bitmap_cache->insert(m_name.ToStdString(), bmps);
     }
     m_icon.CopyFromBitmap(*bmp);
-#ifdef __WXOSX__
-    m_icon.SetHeight(bmp->GetHeight());
-    m_icon.SetWidth(bmp->GetWidth());
-#endif // __WXOSX__
 
     return true;
 }
@@ -477,6 +473,9 @@ wxDataViewItem PrusaObjectDataViewModel::AddSettingsChild(const wxDataViewItem &
     // notify control
     const wxDataViewItem child((void*)node);
     ItemAdded(parent_item, child);
+
+    if (child)
+        printf("SettingsChild is created\n");
     return child;
 }
 

From 9c433f8e08df6192d1991b9d2ffb338142392a4c Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 10 Sep 2018 13:59:44 +0200
Subject: [PATCH 16/27] Try to fix AddSettingsChild on OSX

---
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp | 1 +
 xs/src/slic3r/GUI/wxExtensions.hpp    | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index ee57b4a0a..7820eec43 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -1553,6 +1553,7 @@ void part_selection_changed()
     wxString object_name = wxEmptyString;
 	if (item)
 	{
+        printf("item exists\n");
         const bool is_settings_item = m_objects_model->IsSettingsItem(item);
 		bool is_part = false;
         wxString og_name = wxEmptyString;
diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp
index 4236e0915..08c899a19 100644
--- a/xs/src/slic3r/GUI/wxExtensions.hpp
+++ b/xs/src/slic3r/GUI/wxExtensions.hpp
@@ -240,6 +240,8 @@ public:
 	}
 	void Insert(PrusaObjectDataViewModelNode* child, unsigned int n)
 	{
+		if (!m_container)
+			m_container = true;
 		m_children.Insert(child, n);
 	}
 	void Append(PrusaObjectDataViewModelNode* child)

From e3bb829e428b2838786010d88705f4bd57c32b20 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 11 Sep 2018 09:51:56 +0200
Subject: [PATCH 17/27] Try to use PrusaIconTextRenderer(CustomRenderer) for
 IconText Rendering

+ experiments with button's color
+ removed "strange control part" from topLeft corner of the right panel
---
 xs/src/slic3r/GUI/GUI.cpp             |  4 +--
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp | 10 +++---
 xs/src/slic3r/GUI/OptionsGroup.hpp    |  6 ++--
 xs/src/slic3r/GUI/wxExtensions.cpp    | 49 +++++++++++++++++++++++++--
 xs/src/slic3r/GUI/wxExtensions.hpp    | 23 +++++++++++++
 5 files changed, 81 insertions(+), 11 deletions(-)

diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp
index 956a0008a..c7eecea75 100644
--- a/xs/src/slic3r/GUI/GUI.cpp
+++ b/xs/src/slic3r/GUI/GUI.cpp
@@ -1232,11 +1232,11 @@ void enable_action_buttons(bool enable)
         return;
 
     // Update background colour for buttons
-//     const wxColour bgrd_color = enable ? wxColour(255, 96, 0) : wxColour(204, 204, 204);
+    const wxColour bgrd_color = enable ? wxColour(224, 224, 224/*255, 96, 0*/) : wxColour(204, 204, 204);
 
     for (auto btn : g_buttons) {
         btn->Enable(enable);
-//         btn->SetBackgroundColour(bgrd_color);
+        btn->SetBackgroundColour(bgrd_color);
     }
 }
 
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index 7820eec43..5af20564b 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -249,8 +249,12 @@ void create_objects_ctrl(wxWindow* win, wxBoxSizer*& objects_sz)
 #endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
 
 	// column 0(Icon+Text) of the view control:
-	m_objects_ctrl->AppendIconTextColumn(_(L("Name")), 0, wxDATAVIEW_CELL_INERT, 200,
-		wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE);
+    wxDataViewColumn *ret = new wxDataViewColumn(_(L("Name")),
+        new PrusaIconTextRenderer(wxT("PrusaDataViewIconText")),
+        0, 200, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE);
+    m_objects_ctrl->AppendColumn(ret);
+// 	m_objects_ctrl->AppendIconTextColumn(_(L("Name")), 0, wxDATAVIEW_CELL_INERT, 200,
+// 		wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE);
 
 	// column 1 of the view control:
 	m_objects_ctrl->AppendTextColumn(_(L("Copy")), 1, wxDATAVIEW_CELL_INERT, 45,
@@ -1014,7 +1018,6 @@ void get_settings_choice(wxMenu *menu, int id, bool is_part)
     const auto item = m_objects_ctrl->GetSelection();
     if (item) {
         const auto settings_item = m_objects_model->HasSettings(item);
-        settings_item ? printf("settings_item exist\n") : printf("settings_item will be created\n");
         m_objects_ctrl->Select(settings_item ? settings_item : 
                                m_objects_model->AddSettingsChild(item));
 #ifndef __WXOSX__
@@ -1553,7 +1556,6 @@ void part_selection_changed()
     wxString object_name = wxEmptyString;
 	if (item)
 	{
-        printf("item exists\n");
         const bool is_settings_item = m_objects_model->IsSettingsItem(item);
 		bool is_part = false;
         wxString og_name = wxEmptyString;
diff --git a/xs/src/slic3r/GUI/OptionsGroup.hpp b/xs/src/slic3r/GUI/OptionsGroup.hpp
index 5a18803a6..4941e5453 100644
--- a/xs/src/slic3r/GUI/OptionsGroup.hpp
+++ b/xs/src/slic3r/GUI/OptionsGroup.hpp
@@ -161,8 +161,10 @@ public:
 					ogDrawFlag flag = ogDEFAULT, column_t extra_clmn = nullptr) :
 					m_parent(_parent), title(title), m_show_modified_btns(is_tab_opt),
 					staticbox(title!=""), m_flag(flag), extra_column(extra_clmn){
-		stb = new wxStaticBox(_parent, wxID_ANY, title);
-		stb->SetFont(bold_font());
+        if (staticbox) {
+            stb = new wxStaticBox(_parent, wxID_ANY, title);
+            stb->SetFont(bold_font());
+        }
         sizer = (staticbox ? new wxStaticBoxSizer(stb, wxVERTICAL) : new wxBoxSizer(wxVERTICAL));
         auto num_columns = 1U;
         if (label_width != 0) num_columns++;
diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index 737833abd..f8fe5a582 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -473,9 +473,6 @@ wxDataViewItem PrusaObjectDataViewModel::AddSettingsChild(const wxDataViewItem &
     // notify control
     const wxDataViewItem child((void*)node);
     ItemAdded(parent_item, child);
-
-    if (child)
-        printf("SettingsChild is created\n");
     return child;
 }
 
@@ -849,6 +846,52 @@ void PrusaObjectDataViewModel::UpdateSettingsDigest(const wxDataViewItem &item,
     ItemChanged(item);
 }
 
+
+// ---------------------------------------------------------
+// PrusaIconTextRenderer
+// ---------------------------------------------------------
+
+bool PrusaIconTextRenderer::SetValue(const wxVariant &value)
+{
+    m_value << value;
+    return true;
+}
+
+bool PrusaIconTextRenderer::GetValue(wxVariant& WXUNUSED(value)) const
+{
+    return false;
+}
+
+bool PrusaIconTextRenderer::Render(wxRect rect, wxDC *dc, int state)
+{
+    int xoffset = 0;
+
+    const wxIcon& icon = m_value.GetIcon();
+    if (icon.IsOk())
+    {
+        dc->DrawIcon(icon, rect.x, rect.y + (rect.height - icon.GetHeight()) / 2);
+        xoffset = icon.GetWidth() + 4;
+    }
+
+    RenderText(m_value.GetText(), xoffset, rect, dc, state);
+
+    return true;
+}
+
+wxSize PrusaIconTextRenderer::GetSize() const
+{
+    if (!m_value.GetText().empty())
+    {
+        wxSize size = GetTextExtent(m_value.GetText());
+
+        if (m_value.GetIcon().IsOk())
+            size.x += m_value.GetIcon().GetWidth() + 4;
+        return size;
+    }
+    return wxSize(80, 20);
+}
+
+
 // ----------------------------------------------------------------------------
 // PrusaDoubleSlider
 // ----------------------------------------------------------------------------
diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp
index 08c899a19..5e5afe6dc 100644
--- a/xs/src/slic3r/GUI/wxExtensions.hpp
+++ b/xs/src/slic3r/GUI/wxExtensions.hpp
@@ -415,6 +415,29 @@ public:
 };
 
 
+// ----------------------------------------------------------------------------
+// PrusaIconTextRenderer
+// ----------------------------------------------------------------------------
+
+class PrusaIconTextRenderer : public wxDataViewCustomRenderer
+{
+public:
+    PrusaIconTextRenderer(  const wxString &varianttype = wxT("PrusaDataViewIconText"),
+                            wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT,
+                            int align = wxDVR_DEFAULT_ALIGNMENT) {}
+
+    bool SetValue(const wxVariant &value);
+    bool GetValue(wxVariant &value) const;
+
+    virtual bool Render(wxRect cell, wxDC *dc, int state);
+    virtual wxSize GetSize() const;
+
+    virtual bool HasEditorCtrl() const { return false; }
+
+private:
+    wxDataViewIconText   m_value;
+};
+
 
 // ----------------------------------------------------------------------------
 // MyCustomRenderer

From 775b86a3d867b94e0203fa60a71475fcd633c858 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 11 Sep 2018 11:39:13 +0200
Subject: [PATCH 18/27] Fix to last commit (vertical expanding of the icon to
 correct rendering on OSX)

---
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp | 6 ++----
 xs/src/slic3r/GUI/wxExtensions.cpp    | 5 +++++
 xs/src/slic3r/GUI/wxExtensions.hpp    | 6 +++---
 3 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index 5af20564b..c4ed9c0be 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -249,10 +249,8 @@ void create_objects_ctrl(wxWindow* win, wxBoxSizer*& objects_sz)
 #endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
 
 	// column 0(Icon+Text) of the view control:
-    wxDataViewColumn *ret = new wxDataViewColumn(_(L("Name")),
-        new PrusaIconTextRenderer(wxT("PrusaDataViewIconText")),
-        0, 200, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE);
-    m_objects_ctrl->AppendColumn(ret);
+    m_objects_ctrl->AppendColumn(new wxDataViewColumn(_(L("Name")), new PrusaIconTextRenderer(),
+                                 0, 200, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE));
 // 	m_objects_ctrl->AppendIconTextColumn(_(L("Name")), 0, wxDATAVIEW_CELL_INERT, 200,
 // 		wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE);
 
diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index f8fe5a582..80da9a148 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -385,8 +385,13 @@ bool PrusaObjectDataViewModelNode::update_settings_digest(const std::vector<std:
                               wxNullBitmap : categories_icon.at(cat));
         bmp = m_bitmap_cache->insert(m_name.ToStdString(), bmps);
     }
+
     m_icon.CopyFromBitmap(*bmp);
 
+#ifdef __WXOSX__
+    if (m_icon.GetWidth() != m_icon.GetHeight())
+        m_icon.SetHeight(m_icon.GetWidth());
+#endif // __WXOSX__
     return true;
 }
 
diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp
index 5e5afe6dc..e47681d6c 100644
--- a/xs/src/slic3r/GUI/wxExtensions.hpp
+++ b/xs/src/slic3r/GUI/wxExtensions.hpp
@@ -422,9 +422,9 @@ public:
 class PrusaIconTextRenderer : public wxDataViewCustomRenderer
 {
 public:
-    PrusaIconTextRenderer(  const wxString &varianttype = wxT("PrusaDataViewIconText"),
-                            wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT,
-                            int align = wxDVR_DEFAULT_ALIGNMENT) {}
+    PrusaIconTextRenderer(  wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT,
+                            int align = wxDVR_DEFAULT_ALIGNMENT): 
+                            wxDataViewCustomRenderer(wxT("wxDataViewIconText"), mode, wxALIGN_CENTER) {}
 
     bool SetValue(const wxVariant &value);
     bool GetValue(wxVariant &value) const;

From 6106ce9ff025f2566cee77313f88802e7a32fc77 Mon Sep 17 00:00:00 2001
From: tamasmeszaros <meszaros.q@gmail.com>
Date: Tue, 11 Sep 2018 12:36:24 +0200
Subject: [PATCH 19/27] Abort semantics added.

Signed-off-by: tamasmeszaros <meszaros.q@gmail.com>
---
 xs/src/libnest2d/libnest2d/libnest2d.hpp      |  8 ++++
 .../libnest2d/selections/djd_heuristic.hpp    | 14 ++++---
 .../libnest2d/libnest2d/selections/filler.hpp |  2 +-
 .../libnest2d/selections/firstfit.hpp         | 11 +++--
 .../selections/selection_boilerplate.hpp      |  8 ++--
 xs/src/libslic3r/ModelArrange.hpp             | 40 ++++++++++++-------
 xs/src/slic3r/AppController.cpp               | 23 ++++++++---
 xs/src/slic3r/AppController.hpp               |  1 +
 xs/src/slic3r/AppControllerWx.cpp             |  2 +-
 9 files changed, 74 insertions(+), 35 deletions(-)

diff --git a/xs/src/libnest2d/libnest2d/libnest2d.hpp b/xs/src/libnest2d/libnest2d/libnest2d.hpp
index 4d1e62f99..8841d1b73 100644
--- a/xs/src/libnest2d/libnest2d/libnest2d.hpp
+++ b/xs/src/libnest2d/libnest2d/libnest2d.hpp
@@ -640,6 +640,7 @@ public:
 
 // The progress function will be called with the number of placed items
 using ProgressFunction = std::function<void(unsigned)>;
+using StopCondition = std::function<bool(void)>;
 
 /**
  * A wrapper interface (trait) class for any selections strategy provider.
@@ -674,6 +675,8 @@ public:
      */
     void progressIndicator(ProgressFunction fn) { impl_.progressIndicator(fn); }
 
+    void stopCondition(StopCondition cond) { impl_.stopCondition(cond); }
+
     /**
      * \brief A method to start the calculation on the input sequence.
      *
@@ -864,6 +867,11 @@ public:
         selector_.progressIndicator(func); return *this;
     }
 
+    /// Set a predicate to tell when to abort nesting.
+    inline Nester& stopCondition(StopCondition fn) {
+        selector_.stopCondition(fn); return *this;
+    }
+
     inline PackGroup lastResult() {
         PackGroup ret;
         for(size_t i = 0; i < selector_.binCount(); i++) {
diff --git a/xs/src/libnest2d/libnest2d/selections/djd_heuristic.hpp b/xs/src/libnest2d/libnest2d/selections/djd_heuristic.hpp
index ee93d0592..39761f557 100644
--- a/xs/src/libnest2d/libnest2d/selections/djd_heuristic.hpp
+++ b/xs/src/libnest2d/libnest2d/selections/djd_heuristic.hpp
@@ -551,7 +551,7 @@ public:
         // Safety test: try to pack each item into an empty bin. If it fails
         // then it should be removed from the not_packed list
         { auto it = store_.begin();
-            while (it != store_.end()) {
+            while (it != store_.end() && !this->stopcond_()) {
                 Placer p(bin); p.configure(pconfig);
                 if(!p.pack(*it, rem(it, store_))) {
                     it = store_.erase(it);
@@ -592,9 +592,11 @@ public:
 
         bool do_pairs = config_.try_pairs;
         bool do_triplets = config_.try_triplets;
+        StopCondition stopcond = this->stopcond_;
 
         // The DJD heuristic algorithm itself:
         auto packjob = [INITIAL_FILL_AREA, bin_area, w, do_triplets, do_pairs,
+                        stopcond,
                         &tryOneByOne,
                         &tryGroupsOfTwo,
                         &tryGroupsOfThree,
@@ -606,12 +608,12 @@ public:
             double waste = .0;
             bool lasttry = false;
 
-            while(!not_packed.empty()) {
+            while(!not_packed.empty() && !stopcond()) {
 
                 {// Fill the bin up to INITIAL_FILL_PROPORTION of its capacity
                     auto it = not_packed.begin();
 
-                    while(it != not_packed.end() &&
+                    while(it != not_packed.end() && !stopcond() &&
                           filled_area < INITIAL_FILL_AREA)
                     {
                         if(placer.pack(*it, rem(it, not_packed))) {
@@ -623,14 +625,14 @@ public:
                     }
                 }
 
-                // try pieses one by one
+                // try pieces one by one
                 while(tryOneByOne(placer, not_packed, waste, free_area,
                                   filled_area)) {
                     waste = 0; lasttry = false;
                     makeProgress(placer, idx, 1);
                 }
 
-                // try groups of 2 pieses
+                // try groups of 2 pieces
                 while(do_pairs &&
                       tryGroupsOfTwo(placer, not_packed, waste, free_area,
                                      filled_area)) {
@@ -638,7 +640,7 @@ public:
                     makeProgress(placer, idx, 2);
                 }
 
-                // try groups of 3 pieses
+                // try groups of 3 pieces
                 while(do_triplets &&
                       tryGroupsOfThree(placer, not_packed, waste, free_area,
                                        filled_area)) {
diff --git a/xs/src/libnest2d/libnest2d/selections/filler.hpp b/xs/src/libnest2d/libnest2d/selections/filler.hpp
index 0da7220a1..5f95a6eff 100644
--- a/xs/src/libnest2d/libnest2d/selections/filler.hpp
+++ b/xs/src/libnest2d/libnest2d/selections/filler.hpp
@@ -60,7 +60,7 @@ public:
         placer.configure(pconfig);
 
         auto it = store_.begin();
-        while(it != store_.end()) {
+        while(it != store_.end() && !this->stopcond_()) {
             if(!placer.pack(*it, {std::next(it), store_.end()}))  {
                 if(packed_bins_.back().empty()) ++it;
                 placer.clearItems();
diff --git a/xs/src/libnest2d/libnest2d/selections/firstfit.hpp b/xs/src/libnest2d/libnest2d/selections/firstfit.hpp
index bca7497db..6bb9c60e4 100644
--- a/xs/src/libnest2d/libnest2d/selections/firstfit.hpp
+++ b/xs/src/libnest2d/libnest2d/selections/firstfit.hpp
@@ -56,10 +56,12 @@ public:
             this->progress_(static_cast<unsigned>(--total));
         };
 
+        auto& cancelled = this->stopcond_;
+
         // Safety test: try to pack each item into an empty bin. If it fails
         // then it should be removed from the list
         { auto it = store_.begin();
-            while (it != store_.end()) {
+            while (it != store_.end() && !cancelled()) {
                 Placer p(bin); p.configure(pconfig);
                 if(!p.pack(*it)) {
                     it = store_.erase(it);
@@ -67,13 +69,14 @@ public:
             }
         }
 
+
         auto it = store_.begin();
 
-        while(it != store_.end()) {
+        while(it != store_.end() && !cancelled()) {
             bool was_packed = false;
             size_t j = 0;
-            while(!was_packed) {
-                for(; j < placers.size() && !was_packed; j++) {
+            while(!was_packed && !cancelled()) {
+                for(; j < placers.size() && !was_packed && !cancelled(); j++) {
                     if((was_packed = placers[j].pack(*it, rem(it, store_) )))
                             makeProgress(placers[j], j);
                 }
diff --git a/xs/src/libnest2d/libnest2d/selections/selection_boilerplate.hpp b/xs/src/libnest2d/libnest2d/selections/selection_boilerplate.hpp
index 05bbae658..cfb98a9c8 100644
--- a/xs/src/libnest2d/libnest2d/selections/selection_boilerplate.hpp
+++ b/xs/src/libnest2d/libnest2d/selections/selection_boilerplate.hpp
@@ -2,6 +2,7 @@
 #define SELECTION_BOILERPLATE_HPP
 
 #include "../libnest2d.hpp"
+#include <atomic>
 
 namespace libnest2d { namespace selections {
 
@@ -25,14 +26,15 @@ public:
         return packed_bins_[binIndex];
     }
 
-    inline void progressIndicator(ProgressFunction fn) {
-        progress_ = fn;
-    }
+    inline void progressIndicator(ProgressFunction fn) { progress_ = fn; }
+
+    inline void stopCondition(StopCondition cond) { stopcond_ = cond; }
 
 protected:
 
     PackGroup packed_bins_;
     ProgressFunction progress_ = [](unsigned){};
+    StopCondition stopcond_ = [](){ return false; };
 };
 
 }
diff --git a/xs/src/libslic3r/ModelArrange.hpp b/xs/src/libslic3r/ModelArrange.hpp
index 36bd8ed97..a8e7936d6 100644
--- a/xs/src/libslic3r/ModelArrange.hpp
+++ b/xs/src/libslic3r/ModelArrange.hpp
@@ -299,7 +299,8 @@ protected:
 public:
 
     _ArrBase(const TBin& bin, Distance dist,
-             std::function<void(unsigned)> progressind):
+             std::function<void(unsigned)> progressind,
+             std::function<bool(void)> stopcond):
        pck_(bin, dist), bin_area_(sl::area(bin)),
        norm_(std::sqrt(sl::area(bin)))
     {
@@ -330,6 +331,7 @@ public:
         };
 
         pck_.progressIndicator(progressind);
+        pck_.stopCondition(stopcond);
     }
 
     template<class...Args> inline IndexedPackGroup operator()(Args&&...args) {
@@ -343,8 +345,9 @@ class AutoArranger<Box>: public _ArrBase<Box> {
 public:
 
     AutoArranger(const Box& bin, Distance dist,
-                 std::function<void(unsigned)> progressind):
-        _ArrBase<Box>(bin, dist, progressind)
+                 std::function<void(unsigned)> progressind,
+                 std::function<bool(void)> stopcond):
+        _ArrBase<Box>(bin, dist, progressind, stopcond)
     {
 
         pconf_.object_function = [this, bin] (const Item &item) {
@@ -380,8 +383,9 @@ class AutoArranger<lnCircle>: public _ArrBase<lnCircle> {
 public:
 
     AutoArranger(const lnCircle& bin, Distance dist,
-                 std::function<void(unsigned)> progressind):
-        _ArrBase<lnCircle>(bin, dist, progressind) {
+                 std::function<void(unsigned)> progressind,
+                 std::function<bool(void)> stopcond):
+        _ArrBase<lnCircle>(bin, dist, progressind, stopcond) {
 
         pconf_.object_function = [this, &bin] (const Item &item) {
 
@@ -421,8 +425,9 @@ template<>
 class AutoArranger<PolygonImpl>: public _ArrBase<PolygonImpl> {
 public:
     AutoArranger(const PolygonImpl& bin, Distance dist,
-                 std::function<void(unsigned)> progressind):
-        _ArrBase<PolygonImpl>(bin, dist, progressind)
+                 std::function<void(unsigned)> progressind,
+                 std::function<bool(void)> stopcond):
+        _ArrBase<PolygonImpl>(bin, dist, progressind, stopcond)
     {
         pconf_.object_function = [this, &bin] (const Item &item) {
 
@@ -449,8 +454,9 @@ template<> // Specialization with no bin
 class AutoArranger<bool>: public _ArrBase<Box> {
 public:
 
-    AutoArranger(Distance dist, std::function<void(unsigned)> progressind):
-        _ArrBase<Box>(Box(0, 0), dist, progressind)
+    AutoArranger(Distance dist, std::function<void(unsigned)> progressind,
+                 std::function<bool(void)> stopcond):
+        _ArrBase<Box>(Box(0, 0), dist, progressind, stopcond)
     {
         this->pconf_.object_function = [this] (const Item &item) {
 
@@ -680,12 +686,16 @@ void applyResult(
  * remaining items which do not fit onto the print area next to the print
  * bed or leave them untouched (let the user arrange them by hand or remove
  * them).
+ * \param progressind Progress indicator callback called when an object gets
+ * 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, coordf_t min_obj_distance,
              const Slic3r::Polyline& bed,
              BedShapeHint bedhint,
              bool first_bin_only,
-             std::function<void(unsigned)> progressind)
+             std::function<void(unsigned)> progressind,
+             std::function<bool(void)> stopcondition)
 {
     using ArrangeResult = _IndexedPackGroup<PolygonImpl>;
 
@@ -710,6 +720,8 @@ bool arrange(Model &model, coordf_t min_obj_distance,
 
     BoundingBox bbb(bed);
 
+    auto& cfn = stopcondition;
+
     auto binbb = Box({
                          static_cast<libnest2d::Coord>(bbb.min(0)),
                          static_cast<libnest2d::Coord>(bbb.min(1))
@@ -723,7 +735,7 @@ bool arrange(Model &model, coordf_t min_obj_distance,
     case BedShapeType::BOX: {
 
         // Create the arranger for the box shaped bed
-        AutoArranger<Box> arrange(binbb, min_obj_distance, progressind);
+        AutoArranger<Box> arrange(binbb, min_obj_distance, progressind, cfn);
 
         // Arrange and return the items with their respective indices within the
         // input sequence.
@@ -735,7 +747,7 @@ bool arrange(Model &model, coordf_t min_obj_distance,
         auto c = bedhint.shape.circ;
         auto cc = lnCircle(c);
 
-        AutoArranger<lnCircle> arrange(cc, min_obj_distance, progressind);
+        AutoArranger<lnCircle> arrange(cc, min_obj_distance, progressind, cfn);
         result = arrange(shapes.begin(), shapes.end());
         break;
     }
@@ -747,7 +759,7 @@ bool arrange(Model &model, coordf_t min_obj_distance,
         auto ctour = Slic3rMultiPoint_to_ClipperPath(bed);
         P irrbed = sl::create<PolygonImpl>(std::move(ctour));
 
-        AutoArranger<P> arrange(irrbed, min_obj_distance, progressind);
+        AutoArranger<P> arrange(irrbed, min_obj_distance, progressind, cfn);
 
         // Arrange and return the items with their respective indices within the
         // input sequence.
@@ -756,7 +768,7 @@ bool arrange(Model &model, coordf_t min_obj_distance,
     }
     };
 
-    if(result.empty()) return false;
+    if(result.empty() || stopcondition()) return false;
 
     if(first_bin_only) {
         applyResult(result.front(), 0, shapemap);
diff --git a/xs/src/slic3r/AppController.cpp b/xs/src/slic3r/AppController.cpp
index 2cbf90d31..2c34a4749 100644
--- a/xs/src/slic3r/AppController.cpp
+++ b/xs/src/slic3r/AppController.cpp
@@ -438,6 +438,11 @@ void AppController::arrange_model()
 {
     using Coord = libnest2d::TCoord<libnest2d::PointImpl>;
 
+    if(arranging_.load()) return;
+
+    // to prevent UI reentrancies
+    arranging_.store(true);
+
     unsigned count = 0;
     for(auto obj : model_->objects) count += obj->instances.size();
 
@@ -451,8 +456,8 @@ void AppController::arrange_model()
         // Set the range of the progress to the object count
         pind->max(count);
 
-        pind->on_cancel([](){
-            std::cout << "Cannot be cancelled!" << std::endl;
+        pind->on_cancel([this](){
+            arranging_.store(false);
         });
     }
 
@@ -478,10 +483,12 @@ void AppController::arrange_model()
                       bed,
                       hint,
                       false, // create many piles not just one pile
-                      [pind, count](unsigned rem) {
+                      [this, pind, count](unsigned rem) {
             if(pind)
-                pind->update(count - rem, _(L("Arranging objects...")));
-        });
+                pind->update(count - rem, L("Arranging objects..."));
+
+            process_events();
+        }, [this] () { return !arranging_.load(); });
     } catch(std::exception& e) {
         std::cerr << e.what() << std::endl;
         report_issue(IssueType::ERR,
@@ -493,9 +500,13 @@ void AppController::arrange_model()
     // Restore previous max value
     if(pind) {
         pind->max(pmax);
-        pind->update(0, _(L("Arranging done.")));
+        pind->update(0, arranging_.load() ? L("Arranging done.") :
+                                            L("Arranging canceled."));
+
         pind->on_cancel(/*remove cancel function*/);
     }
+
+    arranging_.store(false);
 }
 
 }
diff --git a/xs/src/slic3r/AppController.hpp b/xs/src/slic3r/AppController.hpp
index f24444359..5a7294f79 100644
--- a/xs/src/slic3r/AppController.hpp
+++ b/xs/src/slic3r/AppController.hpp
@@ -237,6 +237,7 @@ public:
 class AppController: public AppControllerBoilerplate {
     Model *model_ = nullptr;
     PrintController::Ptr printctl;
+    std::atomic<bool> arranging_;
 public:
 
     /**
diff --git a/xs/src/slic3r/AppControllerWx.cpp b/xs/src/slic3r/AppControllerWx.cpp
index 39192e7d3..279b6d787 100644
--- a/xs/src/slic3r/AppControllerWx.cpp
+++ b/xs/src/slic3r/AppControllerWx.cpp
@@ -28,7 +28,7 @@ bool AppControllerBoilerplate::supports_asynch() const
 
 void AppControllerBoilerplate::process_events()
 {
-    wxSafeYield();
+    wxYieldIfNeeded();
 }
 
 AppControllerBoilerplate::PathList

From dbf18ed8d46b6fa5668fb808a85cacf6ec0285ea Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 11 Sep 2018 12:44:27 +0200
Subject: [PATCH 20/27] Another try to fix IconRendering on OSX

---
 xs/src/slic3r/GUI/GUI.cpp             | 4 ++--
 xs/src/slic3r/GUI/GUI.hpp             | 2 +-
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp | 2 +-
 xs/src/slic3r/GUI/wxExtensions.cpp    | 8 ++++----
 xs/src/slic3r/GUI/wxExtensions.hpp    | 2 +-
 5 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp
index fc38173ed..7d8a9b9d5 100644
--- a/xs/src/slic3r/GUI/GUI.cpp
+++ b/xs/src/slic3r/GUI/GUI.cpp
@@ -1118,11 +1118,11 @@ void show_buttons(bool show)
 	}
 }
 
-void show_info_sizer(bool show)
+void show_info_sizer(const bool show, const bool is_update_settings/* = false*/)
 {
 	g_info_sizer->Show(static_cast<size_t>(0), show); 
 	g_info_sizer->Show(1, show && g_show_print_info);
-	g_manifold_warning_icon->Show(show && g_show_manifold_warning_icon);
+	g_manifold_warning_icon->Show(show && (!is_update_settings && g_show_manifold_warning_icon));
 }
 
 void show_object_name(bool show)
diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp
index dd4387039..7e9acfabf 100644
--- a/xs/src/slic3r/GUI/GUI.hpp
+++ b/xs/src/slic3r/GUI/GUI.hpp
@@ -182,7 +182,7 @@ bool select_language(wxArrayString & names, wxArrayLong & identifiers);
 // update right panel of the Plater according to view mode
 void update_mode();
 
-void show_info_sizer(bool show);
+void show_info_sizer(const bool show, const bool is_update_settinfs = false);
 
 std::vector<Tab *>& get_tabs_list();
 bool checked_tab(Tab* tab);
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index 9343f667c..37f8fcf44 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -951,7 +951,7 @@ void update_settings_list()
 	}
 
     show_manipulation_og(show_manipulations);
-    show_info_sizer(show_manipulations);
+    show_info_sizer(show_manipulations, true);
 
 #ifdef __linux__
 	no_updates.reset(nullptr);
diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index 80da9a148..12d42e60c 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -386,12 +386,12 @@ bool PrusaObjectDataViewModelNode::update_settings_digest(const std::vector<std:
         bmp = m_bitmap_cache->insert(m_name.ToStdString(), bmps);
     }
 
-    m_icon.CopyFromBitmap(*bmp);
-
 #ifdef __WXOSX__
-    if (m_icon.GetWidth() != m_icon.GetHeight())
-        m_icon.SetHeight(m_icon.GetWidth());
+    if (bmp->GetWidth() != bmp->GetHeight())
+        bmp->SetHeight(bmp->GetWidth());
 #endif // __WXOSX__
+
+    m_icon.CopyFromBitmap(*bmp);
     return true;
 }
 
diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp
index e47681d6c..0dbf6f310 100644
--- a/xs/src/slic3r/GUI/wxExtensions.hpp
+++ b/xs/src/slic3r/GUI/wxExtensions.hpp
@@ -424,7 +424,7 @@ class PrusaIconTextRenderer : public wxDataViewCustomRenderer
 public:
     PrusaIconTextRenderer(  wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT,
                             int align = wxDVR_DEFAULT_ALIGNMENT): 
-                            wxDataViewCustomRenderer(wxT("wxDataViewIconText"), mode, wxALIGN_CENTER) {}
+                            wxDataViewCustomRenderer(wxT("wxDataViewIconText"), mode, align) {}
 
     bool SetValue(const wxVariant &value);
     bool GetValue(wxVariant &value) const;

From 0f4a2ee69aea54641f0c276b652a6f0920432990 Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Wed, 12 Sep 2018 10:56:39 +0200
Subject: [PATCH 21/27] Fixed size of scale 3d gizmo reference box

---
 xs/src/slic3r/GUI/GLGizmo.cpp | 7 +++----
 xs/src/slic3r/GUI/GLGizmo.hpp | 1 +
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/xs/src/slic3r/GUI/GLGizmo.cpp b/xs/src/slic3r/GUI/GLGizmo.cpp
index 50c93d72c..9c209035b 100644
--- a/xs/src/slic3r/GUI/GLGizmo.cpp
+++ b/xs/src/slic3r/GUI/GLGizmo.cpp
@@ -693,6 +693,7 @@ void GLGizmoRotate3D::on_render(const BoundingBoxf3& box) const
 }
 
 const float GLGizmoScale3D::Offset = 5.0f;
+const Vec3d GLGizmoScale3D::OffsetVec = (double)GLGizmoScale3D::Offset * Vec3d::Ones();
 
 GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent)
     : GLGizmoBase(parent)
@@ -742,7 +743,7 @@ void GLGizmoScale3D::on_start_dragging(const BoundingBoxf3& box)
     {
         m_starting_drag_position = m_grabbers[m_hover_id].center;
         m_show_starting_box = true;
-        m_starting_box = box;
+        m_starting_box = BoundingBoxf3(box.min - OffsetVec, box.max + OffsetVec);
     }
 }
 
@@ -776,9 +777,7 @@ void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const
 
     ::glEnable(GL_DEPTH_TEST);
 
-    Vec3d offset_vec = (double)Offset * Vec3d::Ones();
-
-    m_box = BoundingBoxf3(box.min - offset_vec, box.max + offset_vec);
+    m_box = BoundingBoxf3(box.min - OffsetVec, box.max + OffsetVec);
     const Vec3d& center = m_box.center();
 
     // x axis
diff --git a/xs/src/slic3r/GUI/GLGizmo.hpp b/xs/src/slic3r/GUI/GLGizmo.hpp
index d3cad05c6..fc2912d3a 100644
--- a/xs/src/slic3r/GUI/GLGizmo.hpp
+++ b/xs/src/slic3r/GUI/GLGizmo.hpp
@@ -235,6 +235,7 @@ protected:
 class GLGizmoScale3D : public GLGizmoBase
 {
     static const float Offset;
+    static const Vec3d OffsetVec;
 
     mutable BoundingBoxf3 m_box;
 

From fc5d62e76ee608312f7daefc8536c9b5455f884b Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Wed, 12 Sep 2018 11:29:59 +0200
Subject: [PATCH 22/27] Try to render wxBitmap instead of wxIcon in
 wxDataViewCtrl

---
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp | 17 +++---
 xs/src/slic3r/GUI/wxExtensions.cpp    | 44 ++++++++-------
 xs/src/slic3r/GUI/wxExtensions.hpp    | 79 +++++++++++++++++++++++----
 3 files changed, 99 insertions(+), 41 deletions(-)

diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index 37f8fcf44..73249edd5 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -29,9 +29,9 @@ wxCollapsiblePane			*m_collpane_settings = nullptr;
 PrusaDoubleSlider           *m_slider = nullptr;
 wxGLCanvas                  *m_preview_canvas = nullptr;
 
-wxIcon		m_icon_modifiermesh;
-wxIcon		m_icon_solidmesh;
-wxIcon		m_icon_manifold_warning;
+wxBitmap/*Icon*/		m_icon_modifiermesh;
+wxBitmap/*Icon*/		m_icon_solidmesh;
+wxBitmap/*Icon*/		m_icon_manifold_warning;
 wxBitmap	m_bmp_cog;
 wxBitmap	m_bmp_split;
 
@@ -141,11 +141,11 @@ void set_objects_from_model(Model &model) {
 }
 
 void init_mesh_icons(){
-	m_icon_modifiermesh = wxIcon(Slic3r::GUI::from_u8(Slic3r::var("lambda.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("plugin.png")), wxBITMAP_TYPE_PNG);
-	m_icon_solidmesh = wxIcon(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG);
+    m_icon_modifiermesh = wxBitmap/*wxIcon*/(Slic3r::GUI::from_u8(Slic3r::var("lambda.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("plugin.png")), wxBITMAP_TYPE_PNG);
+    m_icon_solidmesh = wxBitmap/*wxIcon*/(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG);
 
 	// init icon for manifold warning
-	m_icon_manifold_warning = wxIcon(Slic3r::GUI::from_u8(Slic3r::var("exclamation_mark_.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("error.png")), wxBITMAP_TYPE_PNG);
+    m_icon_manifold_warning = wxBitmap/*wxIcon*/(Slic3r::GUI::from_u8(Slic3r::var("exclamation_mark_.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("error.png")), wxBITMAP_TYPE_PNG);
 
 	// init bitmap for "Split to sub-objects" context menu
     m_bmp_split = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("split.png")), wxBITMAP_TYPE_PNG);
@@ -249,7 +249,7 @@ void create_objects_ctrl(wxWindow* win, wxBoxSizer*& objects_sz)
 #endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
 
 	// column 0(Icon+Text) of the view control:
-    m_objects_ctrl->AppendColumn(new wxDataViewColumn(_(L("Name")), new PrusaIconTextRenderer(),
+    m_objects_ctrl->AppendColumn(new wxDataViewColumn(_(L("Name")), new PrusaBitmapTextRenderer(),
                                  0, 200, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE));
 // 	m_objects_ctrl->AppendIconTextColumn(_(L("Name")), 0, wxDATAVIEW_CELL_INERT, 200,
 // 		wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE);
@@ -668,7 +668,8 @@ void add_object_to_list(const std::string &name, ModelObject* model_object)
 	int errors =	stats.degenerate_facets + stats.edges_fixed + stats.facets_removed + 
 					stats.facets_added + stats.facets_reversed + stats.backwards_edges;
 	if (errors > 0)		{
-		const wxDataViewIconText data(item_name, m_icon_manifold_warning);
+//		const wxDataViewIconText data(item_name, m_icon_manifold_warning);
+        const PrusaDataViewBitmapText data(item_name, m_icon_manifold_warning);
 		wxVariant variant;
 		variant << data;
 		m_objects_model->SetValue(variant, item, 0);
diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index 12d42e60c..6d03bb065 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -358,10 +358,6 @@ void  PrusaObjectDataViewModelNode::set_part_action_icon() {
 	m_action_icon = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("cog.png")), wxBITMAP_TYPE_PNG);
 }
 
-void PrusaObjectDataViewModelNode::set_settings_list_icon(const wxIcon& icon) {
-    m_icon = icon;
-}
-
 Slic3r::GUI::BitmapCache *m_bitmap_cache = nullptr;
 bool PrusaObjectDataViewModelNode::update_settings_digest(const std::vector<std::string>& categories)
 {
@@ -386,12 +382,9 @@ bool PrusaObjectDataViewModelNode::update_settings_digest(const std::vector<std:
         bmp = m_bitmap_cache->insert(m_name.ToStdString(), bmps);
     }
 
-#ifdef __WXOSX__
-    if (bmp->GetWidth() != bmp->GetHeight())
-        bmp->SetHeight(bmp->GetWidth());
-#endif // __WXOSX__
+    m_bmp = *bmp;
+//     m_icon.CopyFromBitmap(*bmp);
 
-    m_icon.CopyFromBitmap(*bmp);
     return true;
 }
 
@@ -437,7 +430,8 @@ wxDataViewItem PrusaObjectDataViewModel::Add(const wxString &name, const int ins
 
 wxDataViewItem PrusaObjectDataViewModel::AddChild(	const wxDataViewItem &parent_item,
 													const wxString &name,
-													const wxIcon& icon,
+// 													const wxIcon& icon,
+                                                    const wxBitmap& icon,
                                                     const int extruder/* = 0*/,
                                                     const bool create_frst_child/* = true*/)
 {
@@ -636,6 +630,12 @@ wxIcon& PrusaObjectDataViewModel::GetIcon(const wxDataViewItem &item) const
     return node->m_icon;
 }
 
+wxBitmap& PrusaObjectDataViewModel::GetBitmap(const wxDataViewItem &item) const
+{
+    PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+    return node->m_bmp;
+}
+
 void PrusaObjectDataViewModel::GetValue(wxVariant &variant, const wxDataViewItem &item, unsigned int col) const
 {
 	wxASSERT(item.IsOk());
@@ -644,8 +644,9 @@ void PrusaObjectDataViewModel::GetValue(wxVariant &variant, const wxDataViewItem
 	switch (col)
 	{
 	case 0:{
-		const wxDataViewIconText data(node->m_name, node->m_icon);
-		variant << data;
+// 		const wxDataViewIconText data(node->m_name, node->m_icon);
+        const PrusaDataViewBitmapText data(node->m_name, node->m_bmp);
+        variant << data;
 		break;}
 	case 1:
 		variant = node->m_copy;
@@ -851,30 +852,31 @@ void PrusaObjectDataViewModel::UpdateSettingsDigest(const wxDataViewItem &item,
     ItemChanged(item);
 }
 
-
+IMPLEMENT_VARIANT_OBJECT(PrusaDataViewBitmapText)
 // ---------------------------------------------------------
 // PrusaIconTextRenderer
 // ---------------------------------------------------------
 
-bool PrusaIconTextRenderer::SetValue(const wxVariant &value)
+bool PrusaBitmapTextRenderer::SetValue(const wxVariant &value)
 {
     m_value << value;
     return true;
 }
 
-bool PrusaIconTextRenderer::GetValue(wxVariant& WXUNUSED(value)) const
+bool PrusaBitmapTextRenderer::GetValue(wxVariant& WXUNUSED(value)) const
 {
     return false;
 }
 
-bool PrusaIconTextRenderer::Render(wxRect rect, wxDC *dc, int state)
+bool PrusaBitmapTextRenderer::Render(wxRect rect, wxDC *dc, int state)
 {
     int xoffset = 0;
 
-    const wxIcon& icon = m_value.GetIcon();
+    const /*wxIcon*/wxBitmap& icon = m_value.GetBitmap();// GetIcon();
     if (icon.IsOk())
     {
-        dc->DrawIcon(icon, rect.x, rect.y + (rect.height - icon.GetHeight()) / 2);
+//         dc->DrawIcon(icon, rect.x, rect.y + (rect.height - icon.GetHeight()) / 2);
+        dc->DrawBitmap(icon, rect.x, rect.y + (rect.height - icon.GetHeight()) / 2);
         xoffset = icon.GetWidth() + 4;
     }
 
@@ -883,14 +885,14 @@ bool PrusaIconTextRenderer::Render(wxRect rect, wxDC *dc, int state)
     return true;
 }
 
-wxSize PrusaIconTextRenderer::GetSize() const
+wxSize PrusaBitmapTextRenderer::GetSize() const
 {
     if (!m_value.GetText().empty())
     {
         wxSize size = GetTextExtent(m_value.GetText());
 
-        if (m_value.GetIcon().IsOk())
-            size.x += m_value.GetIcon().GetWidth() + 4;
+        if (m_value.GetBitmap()/*GetIcon()*/.IsOk())
+            size.x += m_value.GetBitmap()/*GetIcon()*/.GetWidth() + 4;
         return size;
     }
     return wxSize(80, 20);
diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp
index 0dbf6f310..174253ad4 100644
--- a/xs/src/slic3r/GUI/wxExtensions.hpp
+++ b/xs/src/slic3r/GUI/wxExtensions.hpp
@@ -144,6 +144,49 @@ public:
 #endif //__WXMSW__
 
 // *****************************************************************************
+
+// ----------------------------------------------------------------------------
+// PrusaDataViewBitmapText: helper class used by PrusaBitmapTextRenderer
+// ----------------------------------------------------------------------------
+
+class PrusaDataViewBitmapText : public wxObject
+{
+public:
+    PrusaDataViewBitmapText(const wxString &text = wxEmptyString,
+        const wxBitmap& bmp = wxNullBitmap) :
+        m_text(text), m_bmp(bmp)
+    { }
+
+    PrusaDataViewBitmapText(const PrusaDataViewBitmapText &other)
+        : wxObject(),
+        m_text(other.m_text),
+        m_bmp(other.m_bmp)
+    { }
+
+    void SetText(const wxString &text)      { m_text = text; }
+    wxString GetText() const                { return m_text; }
+    void SetBitmap(const wxIcon &icon)      { m_bmp = icon; }
+    const wxBitmap &GetBitmap() const       { return m_bmp; }
+
+    bool IsSameAs(const PrusaDataViewBitmapText& other) const {
+        return m_text == other.m_text && m_bmp.IsSameAs(other.m_bmp);
+    }
+
+    bool operator==(const PrusaDataViewBitmapText& other) const {
+        return IsSameAs(other);
+    }
+
+    bool operator!=(const PrusaDataViewBitmapText& other) const {
+        return !IsSameAs(other);
+    }
+
+private:
+    wxString    m_text;
+    wxBitmap    m_bmp;
+};
+DECLARE_VARIANT_OBJECT(PrusaDataViewBitmapText)
+
+
 // ----------------------------------------------------------------------------
 // PrusaObjectDataViewModelNode: a node inside PrusaObjectDataViewModel
 // ----------------------------------------------------------------------------
@@ -156,6 +199,7 @@ class PrusaObjectDataViewModelNode
 	PrusaObjectDataViewModelNode*	m_parent;
 	MyObjectTreeModelNodePtrArray   m_children;
     wxIcon                          m_empty_icon;
+    wxBitmap                        m_empty_bmp;
     std::vector< std::string >      m_opt_categories;
 public:
 	PrusaObjectDataViewModelNode(const wxString &name, const int instances_count=1) {
@@ -175,13 +219,15 @@ public:
 
 	PrusaObjectDataViewModelNode(	PrusaObjectDataViewModelNode* parent,
 									const wxString& sub_obj_name, 
-									const wxIcon& icon, 
+									const wxBitmap& bmp, 
+// 									const wxIcon& icon, 
                                     const wxString& extruder, 
 									const int volume_id=-1) {
 		m_parent	= parent;
 		m_name		= sub_obj_name;
 		m_copy		= wxEmptyString;
-		m_icon		= icon;
+// 		m_icon		= icon;
+		m_bmp		= bmp;
 		m_type		= "volume";
 		m_volume_id = volume_id;
         m_extruder = extruder;
@@ -214,6 +260,7 @@ public:
 	
 	wxString				m_name;
 	wxIcon&					m_icon = m_empty_icon;
+    wxBitmap&               m_bmp = m_empty_bmp;
 	wxString				m_copy;
 	std::string				m_type;
 	int						m_volume_id = -2;
@@ -274,9 +321,11 @@ public:
 		switch (col)
 		{
 		case 0:{
-			wxDataViewIconText data;
+// 			wxDataViewIconText data;
+            PrusaDataViewBitmapText data;
 			data << variant;
-			m_icon = data.GetIcon();
+// 			m_icon = data.GetIcon();
+            m_bmp = data.GetBitmap();
 			m_name = data.GetText();
 			return true;}
 		case 1:
@@ -297,6 +346,11 @@ public:
 	{
 		m_icon = icon;
 	}
+
+	void SetBitmap(const wxBitmap &icon)
+	{
+		m_bmp = icon;
+	}
 	
 	void SetType(const std::string& type){
 		m_type = type;
@@ -342,7 +396,6 @@ public:
 	// Set action icons for node
 	void set_object_action_icon();
 	void set_part_action_icon();
-    void set_settings_list_icon(const wxIcon& icon);
     bool update_settings_digest(const std::vector<std::string>& categories);
 };
 
@@ -361,7 +414,8 @@ public:
 	wxDataViewItem Add(const wxString &name, const int instances_count);
 	wxDataViewItem AddChild(const wxDataViewItem &parent_item, 
 							const wxString &name, 
-                            const wxIcon& icon,
+//                            const wxIcon& icon,
+                            const wxBitmap& icon,
                             const int extruder = 0,
                             const bool create_frst_child = true);
 	wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
@@ -378,6 +432,7 @@ public:
 	wxString GetName(const wxDataViewItem &item) const;
 	wxString GetCopy(const wxDataViewItem &item) const;
 	wxIcon&  GetIcon(const wxDataViewItem &item) const;
+    wxBitmap& GetBitmap(const wxDataViewItem &item) const;
 
 	// helper methods to change the model
 
@@ -414,17 +469,16 @@ public:
     void    UpdateSettingsDigest(const wxDataViewItem &item, const std::vector<std::string>& categories);
 };
 
-
 // ----------------------------------------------------------------------------
-// PrusaIconTextRenderer
+// PrusaBitmapTextRenderer
 // ----------------------------------------------------------------------------
 
-class PrusaIconTextRenderer : public wxDataViewCustomRenderer
+class PrusaBitmapTextRenderer : public wxDataViewCustomRenderer
 {
 public:
-    PrusaIconTextRenderer(  wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT,
+    PrusaBitmapTextRenderer(  wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT,
                             int align = wxDVR_DEFAULT_ALIGNMENT): 
-                            wxDataViewCustomRenderer(wxT("wxDataViewIconText"), mode, align) {}
+                            wxDataViewCustomRenderer(wxT("PrusaDataViewIconBitmapText"/*"wxDataViewIconText"*/), mode, align) {}
 
     bool SetValue(const wxVariant &value);
     bool GetValue(wxVariant &value) const;
@@ -435,7 +489,8 @@ public:
     virtual bool HasEditorCtrl() const { return false; }
 
 private:
-    wxDataViewIconText   m_value;
+//      wxDataViewIconText   m_value;
+    PrusaDataViewBitmapText m_value;
 };
 
 

From 77e09e683d219200b434aeeff08b6553f0cb1b8e Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Wed, 12 Sep 2018 13:22:13 +0200
Subject: [PATCH 23/27] Fixed bug with PrusaDataViewBitmapText ctor on Linux

+ Cleaned code from unusable comments
---
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp | 18 ++++++++----------
 xs/src/slic3r/GUI/wxExtensions.cpp    | 10 +++-------
 xs/src/slic3r/GUI/wxExtensions.hpp    |  7 +------
 3 files changed, 12 insertions(+), 23 deletions(-)

diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index 73249edd5..ed56aae40 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -29,9 +29,9 @@ wxCollapsiblePane			*m_collpane_settings = nullptr;
 PrusaDoubleSlider           *m_slider = nullptr;
 wxGLCanvas                  *m_preview_canvas = nullptr;
 
-wxBitmap/*Icon*/		m_icon_modifiermesh;
-wxBitmap/*Icon*/		m_icon_solidmesh;
-wxBitmap/*Icon*/		m_icon_manifold_warning;
+wxBitmap	m_icon_modifiermesh;
+wxBitmap	m_icon_solidmesh;
+wxBitmap	m_icon_manifold_warning;
 wxBitmap	m_bmp_cog;
 wxBitmap	m_bmp_split;
 
@@ -141,11 +141,11 @@ void set_objects_from_model(Model &model) {
 }
 
 void init_mesh_icons(){
-    m_icon_modifiermesh = wxBitmap/*wxIcon*/(Slic3r::GUI::from_u8(Slic3r::var("lambda.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("plugin.png")), wxBITMAP_TYPE_PNG);
-    m_icon_solidmesh = wxBitmap/*wxIcon*/(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG);
+    m_icon_modifiermesh = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("lambda.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("plugin.png")), wxBITMAP_TYPE_PNG);
+    m_icon_solidmesh = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG);
 
 	// init icon for manifold warning
-    m_icon_manifold_warning = wxBitmap/*wxIcon*/(Slic3r::GUI::from_u8(Slic3r::var("exclamation_mark_.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("error.png")), wxBITMAP_TYPE_PNG);
+    m_icon_manifold_warning = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("exclamation_mark_.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("error.png")), wxBITMAP_TYPE_PNG);
 
 	// init bitmap for "Split to sub-objects" context menu
     m_bmp_split = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("split.png")), wxBITMAP_TYPE_PNG);
@@ -248,11 +248,10 @@ void create_objects_ctrl(wxWindow* win, wxBoxSizer*& objects_sz)
 	m_objects_ctrl->EnableDropTarget(wxDF_UNICODETEXT);
 #endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
 
-	// column 0(Icon+Text) of the view control:
+	// column 0(Icon+Text) of the view control: 
+    // And Icon can be consisting of several bitmaps
     m_objects_ctrl->AppendColumn(new wxDataViewColumn(_(L("Name")), new PrusaBitmapTextRenderer(),
                                  0, 200, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE));
-// 	m_objects_ctrl->AppendIconTextColumn(_(L("Name")), 0, wxDATAVIEW_CELL_INERT, 200,
-// 		wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE);
 
 	// column 1 of the view control:
 	m_objects_ctrl->AppendTextColumn(_(L("Copy")), 1, wxDATAVIEW_CELL_INERT, 45,
@@ -668,7 +667,6 @@ void add_object_to_list(const std::string &name, ModelObject* model_object)
 	int errors =	stats.degenerate_facets + stats.edges_fixed + stats.facets_removed + 
 					stats.facets_added + stats.facets_reversed + stats.backwards_edges;
 	if (errors > 0)		{
-//		const wxDataViewIconText data(item_name, m_icon_manifold_warning);
         const PrusaDataViewBitmapText data(item_name, m_icon_manifold_warning);
 		wxVariant variant;
 		variant << data;
diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index 6d03bb065..5facf95c9 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -383,7 +383,6 @@ bool PrusaObjectDataViewModelNode::update_settings_digest(const std::vector<std:
     }
 
     m_bmp = *bmp;
-//     m_icon.CopyFromBitmap(*bmp);
 
     return true;
 }
@@ -430,7 +429,6 @@ wxDataViewItem PrusaObjectDataViewModel::Add(const wxString &name, const int ins
 
 wxDataViewItem PrusaObjectDataViewModel::AddChild(	const wxDataViewItem &parent_item,
 													const wxString &name,
-// 													const wxIcon& icon,
                                                     const wxBitmap& icon,
                                                     const int extruder/* = 0*/,
                                                     const bool create_frst_child/* = true*/)
@@ -644,7 +642,6 @@ void PrusaObjectDataViewModel::GetValue(wxVariant &variant, const wxDataViewItem
 	switch (col)
 	{
 	case 0:{
-// 		const wxDataViewIconText data(node->m_name, node->m_icon);
         const PrusaDataViewBitmapText data(node->m_name, node->m_bmp);
         variant << data;
 		break;}
@@ -872,10 +869,9 @@ bool PrusaBitmapTextRenderer::Render(wxRect rect, wxDC *dc, int state)
 {
     int xoffset = 0;
 
-    const /*wxIcon*/wxBitmap& icon = m_value.GetBitmap();// GetIcon();
+    const wxBitmap& icon = m_value.GetBitmap();
     if (icon.IsOk())
     {
-//         dc->DrawIcon(icon, rect.x, rect.y + (rect.height - icon.GetHeight()) / 2);
         dc->DrawBitmap(icon, rect.x, rect.y + (rect.height - icon.GetHeight()) / 2);
         xoffset = icon.GetWidth() + 4;
     }
@@ -891,8 +887,8 @@ wxSize PrusaBitmapTextRenderer::GetSize() const
     {
         wxSize size = GetTextExtent(m_value.GetText());
 
-        if (m_value.GetBitmap()/*GetIcon()*/.IsOk())
-            size.x += m_value.GetBitmap()/*GetIcon()*/.GetWidth() + 4;
+        if (m_value.GetBitmap().IsOk())
+            size.x += m_value.GetBitmap().GetWidth() + 4;
         return size;
     }
     return wxSize(80, 20);
diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp
index 174253ad4..b6f9777a0 100644
--- a/xs/src/slic3r/GUI/wxExtensions.hpp
+++ b/xs/src/slic3r/GUI/wxExtensions.hpp
@@ -220,13 +220,11 @@ public:
 	PrusaObjectDataViewModelNode(	PrusaObjectDataViewModelNode* parent,
 									const wxString& sub_obj_name, 
 									const wxBitmap& bmp, 
-// 									const wxIcon& icon, 
                                     const wxString& extruder, 
 									const int volume_id=-1) {
 		m_parent	= parent;
 		m_name		= sub_obj_name;
 		m_copy		= wxEmptyString;
-// 		m_icon		= icon;
 		m_bmp		= bmp;
 		m_type		= "volume";
 		m_volume_id = volume_id;
@@ -321,10 +319,8 @@ public:
 		switch (col)
 		{
 		case 0:{
-// 			wxDataViewIconText data;
             PrusaDataViewBitmapText data;
 			data << variant;
-// 			m_icon = data.GetIcon();
             m_bmp = data.GetBitmap();
 			m_name = data.GetText();
 			return true;}
@@ -414,7 +410,6 @@ public:
 	wxDataViewItem Add(const wxString &name, const int instances_count);
 	wxDataViewItem AddChild(const wxDataViewItem &parent_item, 
 							const wxString &name, 
-//                            const wxIcon& icon,
                             const wxBitmap& icon,
                             const int extruder = 0,
                             const bool create_frst_child = true);
@@ -478,7 +473,7 @@ class PrusaBitmapTextRenderer : public wxDataViewCustomRenderer
 public:
     PrusaBitmapTextRenderer(  wxDataViewCellMode mode = wxDATAVIEW_CELL_INERT,
                             int align = wxDVR_DEFAULT_ALIGNMENT): 
-                            wxDataViewCustomRenderer(wxT("PrusaDataViewIconBitmapText"/*"wxDataViewIconText"*/), mode, align) {}
+                            wxDataViewCustomRenderer(wxT("wxObject"), mode, align) {}
 
     bool SetValue(const wxVariant &value);
     bool GetValue(wxVariant &value) const;

From 2e734720b5008a71e2ca96c20498c12804f1726d Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Thu, 13 Sep 2018 08:35:26 +0200
Subject: [PATCH 24/27] GLCanvas3D child classes/structures set as private

---
 xs/src/slic3r/GUI/GLCanvas3D.hpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp
index a200e7fdb..c4b46c44d 100644
--- a/xs/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp
@@ -105,7 +105,6 @@ class GLCanvas3D
         void reset() { first_volumes.clear(); }
     };
 
-public:
     struct Camera
     {
         enum EType : unsigned char
@@ -441,7 +440,6 @@ public:
         void render(const GLCanvas3D& canvas) const;
     };
 
-private:
     wxGLCanvas* m_canvas;
     wxGLContext* m_context;
     LegendTexture m_legend_texture;

From b779c6492ed05461059d07ce6876ae875191653e Mon Sep 17 00:00:00 2001
From: Enrico Turri <enricoturri@seznam.cz>
Date: Thu, 13 Sep 2018 16:09:46 +0200
Subject: [PATCH 25/27] Added method int
 GLCanvas3D::get_in_object_volume_id(int scene_vol_idx) const

---
 xs/src/slic3r/GUI/3DScene.cpp           | 5 +++++
 xs/src/slic3r/GUI/3DScene.hpp           | 1 +
 xs/src/slic3r/GUI/GLCanvas3D.cpp        | 5 +++++
 xs/src/slic3r/GUI/GLCanvas3D.hpp        | 1 +
 xs/src/slic3r/GUI/GLCanvas3DManager.cpp | 6 ++++++
 xs/src/slic3r/GUI/GLCanvas3DManager.hpp | 1 +
 xs/xsp/GUI_3DScene.xsp                  | 9 +++++++++
 7 files changed, 28 insertions(+)

diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp
index ed2f8690d..968b5fbcb 100644
--- a/xs/src/slic3r/GUI/3DScene.cpp
+++ b/xs/src/slic3r/GUI/3DScene.cpp
@@ -2164,6 +2164,11 @@ int _3DScene::get_first_volume_id(wxGLCanvas* canvas, int obj_idx)
     return s_canvas_mgr.get_first_volume_id(canvas, obj_idx);
 }
 
+int _3DScene::get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx)
+{
+    return s_canvas_mgr.get_in_object_volume_id(canvas, scene_vol_idx);
+}
+
 void _3DScene::reload_scene(wxGLCanvas* canvas, bool force)
 {
     s_canvas_mgr.reload_scene(canvas, force);
diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp
index 6db58aa16..470383cac 100644
--- a/xs/src/slic3r/GUI/3DScene.hpp
+++ b/xs/src/slic3r/GUI/3DScene.hpp
@@ -577,6 +577,7 @@ public:
     static std::vector<int> load_object(wxGLCanvas* canvas, const Model* model, int obj_idx);
 
     static int get_first_volume_id(wxGLCanvas* canvas, int obj_idx);
+    static int get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx);
 
     static void reload_scene(wxGLCanvas* canvas, bool force);
 
diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp
index fdee693ee..9a780aa92 100644
--- a/xs/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp
@@ -2493,6 +2493,11 @@ int GLCanvas3D::get_first_volume_id(int obj_idx) const
     return -1;
 }
 
+int GLCanvas3D::get_in_object_volume_id(int scene_vol_idx) const
+{
+    return ((0 <= scene_vol_idx) && (scene_vol_idx < (int)m_volumes.volumes.size())) ? m_volumes.volumes[scene_vol_idx]->volume_idx() : -1;
+}
+
 void GLCanvas3D::reload_scene(bool force)
 {
     if ((m_canvas == nullptr) || (m_config == nullptr) || (m_model == nullptr))
diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp
index c4b46c44d..528f73fc1 100644
--- a/xs/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp
@@ -603,6 +603,7 @@ public:
     std::vector<int> load_object(const Model& model, int obj_idx);
 
     int get_first_volume_id(int obj_idx) const;
+    int get_in_object_volume_id(int scene_vol_idx) const;
 
     void reload_scene(bool force);
 
diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp
index 3445d4b65..495f49425 100644
--- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp
+++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp
@@ -548,6 +548,12 @@ int GLCanvas3DManager::get_first_volume_id(wxGLCanvas* canvas, int obj_idx) cons
     return (it != m_canvases.end()) ? it->second->get_first_volume_id(obj_idx) : -1;
 }
 
+int GLCanvas3DManager::get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx) const
+{
+    CanvasesMap::const_iterator it = _get_canvas(canvas);
+    return (it != m_canvases.end()) ? it->second->get_in_object_volume_id(scene_vol_idx) : -1;
+}
+
 void GLCanvas3DManager::reload_scene(wxGLCanvas* canvas, bool force)
 {
     CanvasesMap::iterator it = _get_canvas(canvas);
diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp
index b808c022e..4922b6171 100644
--- a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp
+++ b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp
@@ -138,6 +138,7 @@ public:
     std::vector<int> load_object(wxGLCanvas* canvas, const Model* model, int obj_idx);
 
     int get_first_volume_id(wxGLCanvas* canvas, int obj_idx) const;
+    int get_in_object_volume_id(wxGLCanvas* canvas, int scene_vol_idx) const;
 
     void reload_scene(wxGLCanvas* canvas, bool force);
 
diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp
index 4c3c5501e..c3e4ba3b7 100644
--- a/xs/xsp/GUI_3DScene.xsp
+++ b/xs/xsp/GUI_3DScene.xsp
@@ -767,6 +767,15 @@ get_first_volume_id(canvas, obj_idx)
     OUTPUT:
         RETVAL
 
+int
+get_in_object_volume_id(canvas, scene_vol_idx)
+        SV  *canvas;
+        int scene_vol_idx;
+    CODE:
+        RETVAL = _3DScene::get_in_object_volume_id((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), scene_vol_idx);
+    OUTPUT:
+        RETVAL
+
 std::vector<int>
 load_model(canvas, model, obj_idx)
         SV               *canvas;

From 06f395641bb1317a7a11b5e3f3f6045ebde1851f Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Thu, 13 Sep 2018 16:09:57 +0200
Subject: [PATCH 26/27] Object selection (from object list to 3DScene)

---
 lib/Slic3r/GUI/MainFrame.pm           |  8 ++--
 lib/Slic3r/GUI/Plater.pm              | 57 +++++++++++++++++++++++++--
 xs/src/slic3r/GUI/GLCanvas3D.cpp      |  1 +
 xs/src/slic3r/GUI/GUI_ObjectParts.cpp | 33 ++++++++++++++--
 xs/src/slic3r/GUI/GUI_ObjectParts.hpp |  2 +
 xs/src/slic3r/GUI/wxExtensions.cpp    | 20 ++++++++++
 xs/src/slic3r/GUI/wxExtensions.hpp    |  1 +
 xs/xsp/GUI.xsp                        |  3 ++
 8 files changed, 116 insertions(+), 9 deletions(-)

diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm
index 2c3d12b88..8928ad988 100644
--- a/lib/Slic3r/GUI/MainFrame.pm
+++ b/lib/Slic3r/GUI/MainFrame.pm
@@ -208,10 +208,12 @@ sub _init_tabpanel {
     EVT_COMMAND($self, -1, $OBJECT_SELECTION_CHANGED_EVENT, sub {
         my ($self, $event) = @_;
         my $obj_idx = $event->GetId;
-        my $child = $event->GetInt == 1 ? 1 : undef;
+#        my $child = $event->GetInt == 1 ? 1 : undef;
+#        $self->{plater}->select_object($obj_idx < 0 ? undef: $obj_idx, $child);
+#        $self->{plater}->item_changed_selection($obj_idx);
 
-        $self->{plater}->select_object($obj_idx < 0 ? undef: $obj_idx, $child);
-        $self->{plater}->item_changed_selection($obj_idx);
+        my $vol_idx = $event->GetInt;
+        $self->{plater}->select_object_from_cpp($obj_idx < 0 ? undef: $obj_idx, $vol_idx<0 ? -1 : $vol_idx);
     });
 
     # The following event is emited by the C++ GUI implementation on object settings change.
diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm
index bf63dfc88..13062c41e 100644
--- a/lib/Slic3r/GUI/Plater.pm
+++ b/lib/Slic3r/GUI/Plater.pm
@@ -240,7 +240,14 @@ sub new {
             my ($obj_idx, $object) = $self->selected_object;
             if (defined $obj_idx) {            
                 my $vol_idx = Slic3r::GUI::_3DScene::get_first_volume_id($self->{canvas3D}, $obj_idx);                 
-                Slic3r::GUI::_3DScene::select_volume($self->{canvas3D}, $vol_idx) if ($vol_idx != -1);
+                #Slic3r::GUI::_3DScene::select_volume($self->{canvas3D}, $vol_idx) if ($vol_idx != -1);
+                my $inst_cnt = $self->{model}->objects->[$obj_idx]->instances_count;
+                for (0..$inst_cnt-1){
+                    Slic3r::GUI::_3DScene::select_volume($self->{canvas3D}, $_ + $vol_idx) if ($vol_idx != -1);
+                }
+
+                #my $volume_idx = Slic3r::GUI::_3DScene::get_in_object_volume_id($self->{canvas3D}, $vol_idx);
+                #Slic3r::GUI::select_current_volume($obj_idx, $volume_idx) if ($volume_idx != -1);
             }
         }
     };
@@ -404,8 +411,8 @@ sub new {
     $scrolled_window_panel->SetScrollbars(0, 1, 1, 1);
     
     # right pane buttons
-    $self->{btn_export_gcode} = Wx::Button->new($self->{right_panel}, -1, L("Export G-code…"), wxDefaultPosition, [-1, 30], wxNO_BORDER);#, wxBU_LEFT);
-    $self->{btn_reslice} = Wx::Button->new($self->{right_panel}, -1, L("Slice now"), wxDefaultPosition, [-1, 30], wxNO_BORDER);#, wxBU_LEFT);
+    $self->{btn_export_gcode} = Wx::Button->new($self->{right_panel}, -1, L("Export G-code…"), wxDefaultPosition, [-1, 30],);# wxNO_BORDER);#, wxBU_LEFT);
+    $self->{btn_reslice} = Wx::Button->new($self->{right_panel}, -1, L("Slice now"), wxDefaultPosition, [-1, 30]);#, wxNO_BORDER);#, wxBU_LEFT);
 #    $self->{btn_print} = Wx::Button->new($self->{right_panel}, -1, L("Print…"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
 #    $self->{btn_send_gcode} = Wx::Button->new($self->{right_panel}, -1, L("Send to printer"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
     $self->{btn_print} = Wx::Button->new($scrolled_window_panel, -1, L("Print…"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
@@ -2480,6 +2487,50 @@ sub select_object {
     $self->selection_changed(1);
 }
 
+sub select_object_from_cpp {
+    my ($self, $obj_idx, $vol_idx) = @_;
+    
+    # remove current selection
+    foreach my $o (0..$#{$self->{objects}}) {
+        $self->{objects}->[$o]->selected(0);
+    }    
+
+    my $curr = Slic3r::GUI::_3DScene::get_select_by($self->{canvas3D});
+
+    if (defined $obj_idx) {
+        if ($vol_idx == -1){
+            if ($curr eq 'object') {
+                $self->{objects}->[$obj_idx]->selected(1);
+            }
+            elsif ($curr eq 'volume') {
+                Slic3r::GUI::_3DScene::set_select_by($self->{canvas3D}, 'object');
+            }
+
+            my $selections = $self->collect_selections;
+            Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
+            Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1);
+        }
+        else {
+            if ($curr eq 'object') {
+                Slic3r::GUI::_3DScene::set_select_by($self->{canvas3D}, 'volume');
+            }
+
+            my $selections = [];
+            Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
+            Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas3D});
+            Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1);
+            my $volume_idx = Slic3r::GUI::_3DScene::get_first_volume_id($self->{canvas3D}, $obj_idx);
+
+            my $inst_cnt = $self->{model}->objects->[$obj_idx]->instances_count;
+            for (0..$inst_cnt-1){
+                Slic3r::GUI::_3DScene::select_volume($self->{canvas3D}, $vol_idx*$inst_cnt + $_ + $volume_idx) if ($volume_idx != -1);
+            }
+        }
+    }
+
+    $self->selection_changed(1);
+}
+
 sub selected_object {
     my ($self) = @_;
     my $obj_idx = first { $self->{objects}[$_]->selected } 0..$#{ $self->{objects} };
diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp
index fdee693ee..62f24c516 100644
--- a/xs/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp
@@ -5403,6 +5403,7 @@ void GLCanvas3D::_on_select(int volume_idx, int object_idx)
     }
 
     m_on_select_object_callback.call(obj_id, vol_id);
+    Slic3r::GUI::select_current_volume(obj_id, vol_id);
 }
 
 std::vector<float> GLCanvas3D::_parse_colors(const std::vector<std::string>& colors)
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
index ed56aae40..ff69eaffe 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -740,6 +740,24 @@ void select_current_object(int idx)
 	g_prevent_list_events = false;
 }
 
+void select_current_volume(int idx, int vol_idx)
+{
+    if (vol_idx < 0) {
+        select_current_object(idx);
+        return;
+    }
+    g_prevent_list_events = true;
+    m_objects_ctrl->UnselectAll();
+    if (idx < 0) {
+        g_prevent_list_events = false;
+        return;
+    }
+
+    m_objects_ctrl->Select(m_objects_model->GetItemByVolumeId(idx, vol_idx));
+    part_selection_changed();
+    g_prevent_list_events = false;
+}
+
 void remove()
 {
 	auto item = m_objects_ctrl->GetSelection();
@@ -765,8 +783,17 @@ void object_ctrl_selection_changed()
 
 	if (m_event_object_selection_changed > 0) {
 		wxCommandEvent event(m_event_object_selection_changed);
-		event.SetInt(int(m_objects_model->GetParent(m_objects_ctrl->GetSelection()) != wxDataViewItem(0)));
-		event.SetId(m_selected_object_id);
+		event.SetId(m_selected_object_id); // set $obj_idx
+        const wxDataViewItem item = m_objects_ctrl->GetSelection();
+        if (!item || m_objects_model->GetParent(item) == wxDataViewItem(0))
+            event.SetInt(-1); // set $vol_idx
+        else {
+            const int vol_idx = m_objects_model->GetVolumeIdByItem(item);
+            if (vol_idx == -2) // is settings item
+                event.SetInt(m_objects_model->GetVolumeIdByItem(m_objects_model->GetParent(item))); // set $vol_idx
+            else
+                event.SetInt(vol_idx);
+        }
 		get_main_frame()->ProcessWindowEvent(event);
 	}
 
@@ -950,7 +977,7 @@ void update_settings_list()
 	}
 
     show_manipulation_og(show_manipulations);
-    show_info_sizer(show_manipulations, true);
+    show_info_sizer(show_manipulations && item && m_objects_model->GetParent(item) == wxDataViewItem(0));
 
 #ifdef __linux__
 	no_updates.reset(nullptr);
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.hpp b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
index d5f81d627..70c077bd7 100644
--- a/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
@@ -71,6 +71,8 @@ void set_object_count(int idx, int count);
 void unselect_objects();
 // Select current object in the list on c++ side
 void select_current_object(int idx);
+// Select current volume in the list on c++ side
+void select_current_volume(int idx, int vol_idx);
 // Remove objects/sub-object from the list
 void remove();
 
diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index 5facf95c9..13730a497 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -582,6 +582,26 @@ wxDataViewItem PrusaObjectDataViewModel::GetItemById(int obj_idx)
 }
 
 
+wxDataViewItem PrusaObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volume_idx)
+{
+	if (obj_idx >= m_objects.size()) {
+		printf("Error! Out of objects range.\n");
+		return wxDataViewItem(0);
+	}
+
+    auto parent = m_objects[obj_idx];
+    if (parent->GetChildCount() == 0) {
+        printf("Error! Object has no one volume.\n");
+        return wxDataViewItem(0);
+    }
+
+    for (size_t i = 0; i < parent->GetChildCount(); i++)
+        if (parent->GetNthChild(i)->m_volume_id == volume_idx)
+            return wxDataViewItem(parent->GetNthChild(i));
+
+    return wxDataViewItem(0);
+}
+
 int PrusaObjectDataViewModel::GetIdByItem(wxDataViewItem& item)
 {
 	wxASSERT(item.IsOk());
diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp
index b6f9777a0..51c02035c 100644
--- a/xs/src/slic3r/GUI/wxExtensions.hpp
+++ b/xs/src/slic3r/GUI/wxExtensions.hpp
@@ -418,6 +418,7 @@ public:
 	void DeleteAll();
     void DeleteChildren(wxDataViewItem& parent);
 	wxDataViewItem GetItemById(int obj_idx);
+	wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx);
 	int GetIdByItem(wxDataViewItem& item);
 	int GetVolumeIdByItem(const wxDataViewItem& item);
 	bool IsEmpty() { return m_objects.empty(); }
diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp
index 943937eaf..c19285d3e 100644
--- a/xs/xsp/GUI.xsp
+++ b/xs/xsp/GUI.xsp
@@ -145,6 +145,9 @@ void unselect_objects()
 void select_current_object(int idx)
     %code%{ Slic3r::GUI::select_current_object(idx); %};
 
+void select_current_volume(int idx, int vol_idx)
+    %code%{ Slic3r::GUI::select_current_volume(idx, vol_idx); %};
+
 void remove_obj()
     %code%{ Slic3r::GUI::remove(); %};
     

From 3903ca64d71c73ecf2f9b6d2d65ab52d9c30086c Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Thu, 13 Sep 2018 16:20:16 +0200
Subject: [PATCH 27/27] Added strings for correct volume selection

---
 lib/Slic3r/GUI/Plater.pm | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm
index 13062c41e..050d2dee8 100644
--- a/lib/Slic3r/GUI/Plater.pm
+++ b/lib/Slic3r/GUI/Plater.pm
@@ -246,8 +246,8 @@ sub new {
                     Slic3r::GUI::_3DScene::select_volume($self->{canvas3D}, $_ + $vol_idx) if ($vol_idx != -1);
                 }
 
-                #my $volume_idx = Slic3r::GUI::_3DScene::get_in_object_volume_id($self->{canvas3D}, $vol_idx);
-                #Slic3r::GUI::select_current_volume($obj_idx, $volume_idx) if ($volume_idx != -1);
+                my $volume_idx = Slic3r::GUI::_3DScene::get_in_object_volume_id($self->{canvas3D}, $vol_idx);
+                Slic3r::GUI::select_current_volume($obj_idx, $volume_idx) if ($volume_idx != -1);
             }
         }
     };