From dd70dd6e101dcadec70e0bd2e6ae7069ec5f3ad5 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 27 May 2019 13:07:37 +0200
Subject: [PATCH 01/34] Implemented LayerItem for ObjectList

---
 resources/icons/row.png           | Bin 0 -> 1923 bytes
 resources/icons/table.png         | Bin 0 -> 465 bytes
 src/slic3r/GUI/GUI_ObjectList.cpp |  28 +++++-
 src/slic3r/GUI/GUI_ObjectList.hpp |   4 +-
 src/slic3r/GUI/Plater.cpp         |   4 +
 src/slic3r/GUI/wxExtensions.cpp   | 142 ++++++++++++++++++++++++------
 src/slic3r/GUI/wxExtensions.hpp   |  18 ++--
 7 files changed, 156 insertions(+), 40 deletions(-)
 create mode 100644 resources/icons/row.png
 create mode 100644 resources/icons/table.png

diff --git a/resources/icons/row.png b/resources/icons/row.png
new file mode 100644
index 0000000000000000000000000000000000000000..18a6034fd597baffa886ed65145183a5627310d5
GIT binary patch
literal 1923
zcmV-}2YmR6P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV000GtdQ@0+Qek%>
zaB^>EX>4U6ba`-PAZ2)IW&i+q+SONCmh2`B{bv<ff`t%><uIO;9c1~r40e^Py7~=y
zKe4;aAR%;hLC~iC^LICY;jz|P<0Pn$-XC~ebkQbM^jOa->2UMA8^>9>^_xpz(Zwiv
zHGSLq3H|aI5Zvz1_kI(~wxin+U54kwW9Cucdb$m<UH!D%Chl>`J;B*OTejJ4{I%@@
zf>8zb*c#iI_`uhXSr{I0<b+c2wH)l|v8az{^y}BLGgtK`cvtNuc1PO%d=G^={8sQU
zG1~nkFa3N?V_#W2XTAwiIl}S$JjJf}s=c>`E;)}#d9y*CP-YE^8KLAk%;OFC3F=|K
z5w8Mb0b><xX1v8vB#UTwa#Sf%r#8z%1ui<<EW&NAEtY4WBK*;oNs1dUbsIoWHLT#I
zfHg+9y?miLZ=CZLQp{WlnwDT}u=w_xuR4F{y$tm}mM+nuSFGTd9cvnH4CclcS|Eh_
zj;YM}&euGxo8yUC27@xgtN@sfyi8=F$J*k_Geb`fXO6WsDAa8LA;R1OXNbYT;faMj
z9l_c_gg7erN$}jVvl$GKh^=HgxMB7nN9~v!V**WGD|U4wwSWj=&jHk61A#2(1nVa_
z#TrV&;*5xR38E4udG^kW_dfWMqf+4Df&?Ez&=5mXR;Qv~gQ`YN(MCoJljvhGQDclL
zVbTQC38ND<Qpz@Sc3HB|A#08~6)d0PiWFZ$(Gp9lwsOVxuf7ITwZ@tnH7up(nl#@+
z(-vFmSZkfT>(YG>U3={5Vr{c}XN_K%`<^x0tPRH8)C&*R&>g~Qf<`)#!5J8{j=*>r
z3}8Xq!P%kYoE^*!&W>oYDa3*`l0i<T!5A2HjjVLKxO*`7EpJBLFY#tSF=qyKe}XwP
zsN2lF^Y#U6HO&)+CqZKuj+h?Yk=US=tl|%8@%KyfUkosupVeHE*h=ACR})^!R7uq-
zts3_58b(_8c#2NQ;gq$b7$+noW{L6?S<<azPi5XB*z2?6EeK;;_2Oc8T1U%BBWf`=
zSEmf@gy>~Wj#K!Y^M|GRS;c!vrK}pckmGR4kTeUIs5#m$l@Jfwcz(V#zdB%*-p;@{
z&0L$;Nq;}I3(mEZ$j$}FlujvxM;AT$`>r%UQuwY!nm(5in*!(hIsNi&ud3RXZ)pp$
zSG2QV!WNGn>(dHd>xiq}wqoX{+DVpvQ7++aLD#g6OX>b-w4wFj`cYopZmnHz27ov&
z5EDbYVJOR^3q<=2g57eW1;#aGgHH#V8;toH4K8`Jl}d&3@=}pfYw|Zxy9G?<C^?>+
zsK^?gJuWRdZ^M>r;TGyMwx;$WbzHnR+oX2uy5DFDarF!UONb2Jf_vlM#f{w;Bs8QE
z+5XuPwKw%8geQmw^0j~X#Wyz1pz{?)dT67m@{lr6*c*tjg=V1mlmY3}l6LO{%-17B
z-RS~5Z{`bWI1M~?$8|MV7PDs-OD04cvU^A~ZUHMPBAWzlulxR?oMS80WF^jEN+huL
zrk<8h(j|rBsl?qxB1`(FEp_E1tdZCxcFuPg?hb=b7$G7r2DyY7ZOt=`a3**ihxJbI
z9tZqVy5MX8VWE+}=pQ=<lrGHzW3j~@!s=ru#SMLr6HHEN2PMRaOUA0>-$N7Y_OZi@
z=tF5w2o#apMis&FL3ii|c!_OOF@z@JT9LNYQDc2QFIw3yVCUxp#&_7Q3pMKNafE2*
zJDmIk=j||hL$Obh31bl6A21yL`M$%Dhfx36arDtpD7D^Vd@h<5<Ga+?y@Ax9n9JDx
zw+jaQz1w!)J^a;k-b#-1Vo(-#SB8$6N^W0J^c?2x;|?@#q*ogGcx5tw;Ij5VF~qpH
zM)NQ8u{BlU+MT=r000JJOGiWi{{a60|De66lK=n!32;bRa{vG?BLDy{BLR4&KXw2B
z00(qQO+^Re1se(>3F|1d^8f$=eMv+?R5;6}lfP>eaS+8nyPOg{@Cs48h+uV9gzJ*R
ze?TEk3T?&Uk3t2p5eq?xjgf;uuCc!qDe^a@NFkU)61#ALG>U<sS&Q9y&tmWPZtad6
zm|}SIee-7KJBe*(v1Iv0|LM}5&WF>?O&gG~L@2O~EF6Js96?B2zL=jM9-h43{<yNy
z=qz@+7v`Gj^|`4EH_x-^0vnAicbc94nOgea+$liAVctKuH8sJ*wE-o81;D%AG5B@~
zp6{$y@uzz|di!I1bpb*FK+41x=3DhD?fEtUqfK4CG{#g62}Vo+$7gkdgX4o5!Ov`h
zAWG%D`uxrRo21GkqUJ?W*tYM#*|BXJDitJ?J+I&0B<Zb`9|h2(KEJ;|sqj{N6G;Y0
zi#)G@g`2l)lDTrD7Pqc-s@x(k${Bdn3$TCmwNCJBP>auge5rD+;k#$uJ=<nlUw+vy
zXK->f*m}I4TM;NkL?DUCb0n2FpujP_3yERzEr4X!YfPEZ{sG~-EP|Z%oVWl0002ov
JPDHLkV1lKIrrrPm

literal 0
HcmV?d00001

diff --git a/resources/icons/table.png b/resources/icons/table.png
new file mode 100644
index 0000000000000000000000000000000000000000..3bc0bd32fceb21d70368f7842a00a53d6369ba48
GIT binary patch
literal 465
zcmV;?0WSWDP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt006JZ
zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzV@X6oR5;6}
zlif?gU=+sv7bPi)=!3$7q?JQqQvwMoh(bhK+J{k6%rsgQVNn!z(HBXQkd^mAH(hwA
z^Yotc=4S08nh!j@F!ub;!`WU30603a!#SmnFKE?TaOVx=ZRYd~NSn_P*eHX4{Rzai
z68Mrum`pr?uyhCB_zlR(s~YAA5Xn~cSpFUUYax26696aMv1k4Q2q33l!H$M!&p1HZ
zs?dXQ!8A(HJcd!rMboIk$jLW=EvyAdm3{&e#VDQ4W|M-siV5fsA9Db1`>zJNu3H-P
zO&@UpeyZQXi7jKe-Hk?r-sue;aDce_XqkvXP+W#F_*ot`jB?BS93Uw71|U^ZjLH<w
zh;-sq3Vy5@0GB_@0Tc0CO9QIe)}UUmTN-qU84mEqu5JAXPM->`yP%FO7U<6!nLCG}
z$SDlW<k^-FX;JQ=20hXqbO&;*_AZ;O0?VLP0(5*EI|Y0J3Jfj)lKW#`00000NkvXX
Hu0mjf{J_IH

literal 0
HcmV?d00001

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index dffa02e95..5e14459e2 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1137,6 +1137,12 @@ wxMenuItem* ObjectList::append_menu_item_split(wxMenu* menu)
         [this]() { return is_splittable(); }, wxGetApp().plater());
 }
 
+wxMenuItem* ObjectList::append_menu_item_layers_editing(wxMenu* menu) 
+{
+    return append_menu_item(menu, wxID_ANY, _(L("Edit Layers")), "",
+        [this](wxCommandEvent&) { layers_editing(); }, "table.png", menu);
+}
+
 wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_) 
 {
     MenuWithSeparators* menu = dynamic_cast<MenuWithSeparators*>(menu_);
@@ -1301,7 +1307,11 @@ void ObjectList::create_object_popupmenu(wxMenu *menu)
     append_menu_item_scale_selection_to_fit_print_volume(menu);
 
     // Split object to parts
-    m_menu_item_split = append_menu_item_split(menu);
+    append_menu_item_split(menu);
+    menu->AppendSeparator();
+
+    // Layers Editing for object
+    append_menu_item_layers_editing(menu);
     menu->AppendSeparator();
 
     // rest of a object_menu will be added later in:
@@ -1330,7 +1340,7 @@ void ObjectList::create_part_popupmenu(wxMenu *menu)
     append_menu_item_fix_through_netfabb(menu);
     append_menu_item_export_stl(menu);
 
-    m_menu_item_split_part = append_menu_item_split(menu);
+    append_menu_item_split(menu);
 
     // Append change part type
     menu->AppendSeparator();
@@ -1774,6 +1784,20 @@ void ObjectList::split()
     changed_object(obj_idx);
 }
 
+void ObjectList::layers_editing()
+{
+    const auto item = GetSelection();
+    const int obj_idx = get_selected_obj_idx();
+    if (!item || obj_idx < 0)
+        return;
+
+    wxDataViewItem layers_item = m_objects_model->GetItemByType(item, itLayerRoot);
+    if (!layers_item.IsOk())
+        layers_item = m_objects_model->AddLayersRoot(item);
+
+    select_item(layers_item);
+}
+
 bool ObjectList::get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume)
 {
     auto obj_idx = get_selected_obj_idx();
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 166606e2e..076ab5f13 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -119,8 +119,6 @@ class ObjectList : public wxDataViewCtrl
     MenuWithSeparators  m_menu_part;
     MenuWithSeparators  m_menu_sla_object;
     MenuWithSeparators  m_menu_instance;
-    wxMenuItem* m_menu_item_split { nullptr };
-    wxMenuItem* m_menu_item_split_part { nullptr };
     wxMenuItem* m_menu_item_settings { nullptr };
     wxMenuItem* m_menu_item_split_instances { nullptr };
 
@@ -199,6 +197,7 @@ public:
     wxMenu*             append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type);
     void                append_menu_items_add_volume(wxMenu* menu);
     wxMenuItem*         append_menu_item_split(wxMenu* menu);
+    wxMenuItem*         append_menu_item_layers_editing(wxMenu* menu);
     wxMenuItem*         append_menu_item_settings(wxMenu* menu);
     wxMenuItem*         append_menu_item_change_type(wxMenu* menu);
     wxMenuItem*         append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent);
@@ -226,6 +225,7 @@ public:
     void                del_instances_from_object(const int obj_idx);
     bool                del_subobject_from_object(const int obj_idx, const int idx, const int type);
     void                split();
+    void                layers_editing();
     bool                get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume);
     bool                is_splittable();
     bool                selected_instances_of_same_object();
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 64c698a9b..c0f267204 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -3066,6 +3066,10 @@ bool Plater::priv::complit_init_object_menu()
         [this]() { return can_split() && wxGetApp().get_mode() > comSimple; }, q);
     object_menu.AppendSeparator();
 
+    // Layers Editing for object
+    sidebar->obj_list()->append_menu_item_layers_editing(&object_menu);
+    object_menu.AppendSeparator();
+
     // "Add (volumes)" popupmenu will be added later in append_menu_items_add_volume()
 
     return true;
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index 76ba853dc..988d4a8ea 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -437,27 +437,44 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
     m_type(type),
     m_extruder(wxEmptyString)
 {
-    if (type == itSettings) {
+    if (type == itSettings)
         m_name = "Settings to modified";
-    }
-    else if (type == itInstanceRoot) {
+    else if (type == itInstanceRoot)
         m_name = _(L("Instances"));
-#ifdef __WXGTK__
-        m_container = true;
-#endif  //__WXGTK__
-    }
-    else if (type == itInstance) {
+    else if (type == itInstance)
+    {
         m_idx = parent->GetChildCount();
         m_name = wxString::Format(_(L("Instance %d")), m_idx + 1);
 
         set_action_icon();
     }
+    else if (type == itLayerRoot)
+    {
+        m_bmp = create_scaled_bitmap(nullptr, "table.png");    // FIXME: pass window ptr
+        m_name = _(L("Layers"));
+    }
+    else if (type == itLayer)
+    {
+        m_idx = parent->GetChildCount();
+        m_name = wxString::Format(_(L("Layer %d")), m_idx + 1);
+        m_bmp = create_scaled_bitmap(nullptr, "row.png");    // FIXME: pass window ptr
+
+        set_action_icon();
+    }
+
+#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"
+    if (type & (itInstanceRoot | itLayerRoot | itLayer))
+        m_container = true;
+#endif  //__WXGTK__
 }
 
 void ObjectDataViewModelNode::set_action_icon()
 {
-    m_action_icon_name = m_type == itObject ? "advanced_plus" : 
-                         m_type == itVolume ? "cog"           : "set_separate_obj";
+    m_action_icon_name = m_type & itObject              ? "advanced_plus" : 
+                         m_type & (itVolume | itLayer)  ? "cog" : /*m_type & itInstance*/ "set_separate_obj";
     m_action_icon = create_scaled_bitmap(nullptr, m_action_icon_name);    // FIXME: pass window ptr
 }
 
@@ -619,36 +636,62 @@ wxDataViewItem ObjectDataViewModel::AddSettingsChild(const wxDataViewItem &paren
     return child;
 }
 
-int get_istances_root_idx(ObjectDataViewModelNode *parent_node)
+static int get_root_idx(ObjectDataViewModelNode *parent_node, const ItemType root_type)
 {
-    // because of istance_root is a last item of the object
-    const int inst_root_idx = parent_node->GetChildCount()-1;
+    // because of istance_root and layers_root are at the end of the list, so
+    // start locking from the end
+    for (int root_idx = parent_node->GetChildCount() - 1; root_idx >= 0; root_idx--)
+    {
+        // if there is SettingsItem or VolumeItem, then RootItems don't exist in current ObjectItem 
+        if (parent_node->GetNthChild(root_idx)->GetType() & (itSettings | itVolume))
+            break;
+        if (parent_node->GetNthChild(root_idx)->GetType() & root_type)
+            return root_idx;
+    }
 
-    if (inst_root_idx < 0 || parent_node->GetNthChild(inst_root_idx)->GetType() == itInstanceRoot) 
-        return inst_root_idx;
-    
     return -1;
 }
 
+/* return values:
+ * true     => root_node is created and added to the parent_root
+ * false    => root node alredy exists
+*/
+static bool append_root_node(ObjectDataViewModelNode *parent_node, 
+                             ObjectDataViewModelNode **root_node, 
+                             const ItemType root_type)
+{
+    const int inst_root_id = get_root_idx(parent_node, root_type);
+
+    *root_node = inst_root_id < 0 ?
+                new ObjectDataViewModelNode(parent_node, root_type) :
+                parent_node->GetNthChild(inst_root_id);
+    
+    if (inst_root_id < 0) {
+        if ((root_type&itInstanceRoot) ||
+            (root_type&itLayerRoot) && get_root_idx(parent_node, itInstanceRoot)<0)
+            parent_node->Append(*root_node);
+        else if (root_type&itLayerRoot)
+            parent_node->Insert(*root_node, unsigned int(get_root_idx(parent_node, itInstanceRoot)));
+        return true;
+    }
+
+    return false;
+}
+
 wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num)
 {
     ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
     if (!parent_node) return wxDataViewItem(0);
 
-    // Check and create/get instances root node
-    const int inst_root_id = get_istances_root_idx(parent_node);
+    // get InstanceRoot node
+    ObjectDataViewModelNode *inst_root_node { nullptr };
 
-    ObjectDataViewModelNode *inst_root_node = inst_root_id < 0 ? 
-                                                   new ObjectDataViewModelNode(parent_node, itInstanceRoot) :
-                                                   parent_node->GetNthChild(inst_root_id);
+    const bool appended = append_root_node(parent_node, &inst_root_node, itInstanceRoot);
     const wxDataViewItem inst_root_item((void*)inst_root_node);
+    if (!inst_root_node) return wxDataViewItem(0);
 
-    if (inst_root_id < 0) {
-        parent_node->Append(inst_root_node);
-        // notify control
-        ItemAdded(parent_item, inst_root_item);
-//         if (num == 1) num++;
-    }
+    if (appended)
+        ItemAdded(parent_item, inst_root_item);// notify control
 
     // Add instance nodes
     ObjectDataViewModelNode *instance_node = nullptr;    
@@ -665,6 +708,47 @@ wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &paren
     return wxDataViewItem((void*)instance_node);
 }
 
+wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_item)
+{
+    ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
+    if (!parent_node) return wxDataViewItem(0);
+
+    // get LayerRoot node
+    ObjectDataViewModelNode *layer_root_node{ nullptr };
+    const bool appended = append_root_node(parent_node, &layer_root_node, itLayerRoot);
+    if (!layer_root_node) return wxDataViewItem(0);
+
+    const wxDataViewItem layer_root_item((void*)layer_root_node);
+
+    if (appended)
+        ItemAdded(parent_item, layer_root_item);// notify control
+
+    return wxDataViewItem((void*)layer_root_item);
+}
+
+wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item)
+{
+    ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
+    if (!parent_node) return wxDataViewItem(0);
+
+    // get LayerRoot node
+    const int root_idx = get_root_idx(parent_node, itLayerRoot);
+    if (root_idx < 0) return wxDataViewItem(0);
+    ObjectDataViewModelNode *layer_root_node = parent_node->GetNthChild(root_idx);
+
+    const wxDataViewItem layer_root_item((void*)layer_root_node);
+
+    // Add layer node
+    ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, itLayer);
+    layer_root_node->Append(layer_node);
+
+    // notify control
+    const wxDataViewItem instance_item((void*)layer_node);
+    ItemAdded(layer_root_item, instance_item);
+
+    return wxDataViewItem((void*)layer_node);
+}
+
 wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
 {
 	auto ret_item = wxDataViewItem(0);
@@ -817,7 +901,7 @@ wxDataViewItem ObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &par
     ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
     if (!parent_node) return ret_item;
 
-    const int inst_root_id = get_istances_root_idx(parent_node);
+    const int inst_root_id = get_root_idx(parent_node, itInstanceRoot);
     if (inst_root_id < 0) return ret_item;
 
     wxDataViewItemArray items;
@@ -2573,7 +2657,7 @@ ModeSizer::ModeSizer(wxWindow *parent, int hgap/* = 10*/) :
         m_mode_btns.push_back(new ModeButton(parent, wxID_ANY, button.second, button.first));;
 #endif // __WXOSX__
         
-        m_mode_btns.back()->Bind(wxEVT_BUTTON, std::bind(modebtnfn, std::placeholders::_1, m_mode_btns.size() - 1));
+        m_mode_btns.back()->Bind(wxEVT_BUTTON, std::bind(modebtnfn, std::placeholders::_1, int(m_mode_btns.size() - 1)));
         Add(m_mode_btns.back());
     }
 }
diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp
index 78fb7be55..424f7832a 100644
--- a/src/slic3r/GUI/wxExtensions.hpp
+++ b/src/slic3r/GUI/wxExtensions.hpp
@@ -159,12 +159,14 @@ DECLARE_VARIANT_OBJECT(DataViewBitmapText)
 // ----------------------------------------------------------------------------
 
 enum ItemType {
-    itUndef = 0,
-    itObject = 1,
-    itVolume = 2,
-    itInstanceRoot = 4,
-    itInstance = 8,
-    itSettings = 16
+    itUndef         = 0,
+    itObject        = 1,
+    itVolume        = 2,
+    itInstanceRoot  = 4,
+    itInstance      = 8,
+    itSettings      = 16,
+    itLayerRoot     = 32,
+    itLayer         = 64,
 };
 
 class ObjectDataViewModelNode;
@@ -348,7 +350,7 @@ public:
 	}
 
 	// Set action icons for node
-    void set_action_icon();
+    void        set_action_icon();
 
     void        update_settings_digest_bitmaps();
 	bool        update_settings_digest(const std::vector<std::string>& categories);
@@ -388,6 +390,8 @@ public:
                                     const bool create_frst_child = true);
     wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
     wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
+    wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
+    wxDataViewItem AddLayersChild(const wxDataViewItem &parent_item);
 	wxDataViewItem Delete(const wxDataViewItem &item);
 	wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
 	void DeleteAll();

From 9d19e3d2a72742fd3398174b01be7e1ad583407b Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 27 May 2019 16:13:24 +0200
Subject: [PATCH 02/34] Improved Delete() Add() ans Select() functions for
 Layer(s)Item

---
 src/slic3r/GUI/GUI_ObjectList.cpp | 19 ++++---
 src/slic3r/GUI/wxExtensions.cpp   | 84 ++++++++++++++++++++-----------
 2 files changed, 67 insertions(+), 36 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 5e14459e2..e180f1dfc 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1648,6 +1648,8 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
         del_settings_from_config();
     else if (type == itInstanceRoot && obj_idx != -1)
         del_instances_from_object(obj_idx);
+    else if ((type & itLayerRoot) && obj_idx != -1)
+        /*del_layers_from_object(obj_idx)*/;
     else if (idx == -1)
         return;
     else if (!del_subobject_from_object(obj_idx, idx, type))
@@ -1728,6 +1730,8 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con
         }
         object->delete_instance(idx);
     }
+    else if (type == itLayer) {
+    }
     else
         return false;
 
@@ -1791,9 +1795,11 @@ void ObjectList::layers_editing()
     if (!item || obj_idx < 0)
         return;
 
-    wxDataViewItem layers_item = m_objects_model->GetItemByType(item, itLayerRoot);
+    wxDataViewItem obj_item = m_objects_model->GetTopParent(item);
+
+    wxDataViewItem layers_item = m_objects_model->GetItemByType(obj_item, itLayerRoot);
     if (!layers_item.IsOk())
-        layers_item = m_objects_model->AddLayersRoot(item);
+        layers_item = m_objects_model->AddLayersRoot(obj_item);
 
     select_item(layers_item);
 }
@@ -2171,7 +2177,8 @@ void ObjectList::update_selections()
     m_selection_mode = smInstance;
 
     // We doesn't update selection if SettingsItem for the current object/part is selected
-    if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings )
+//     if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings )
+    if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) & (itSettings | itLayerRoot | itLayer))
     {
         const auto item = GetSelection();
         if (selection.is_single_full_object() && 
@@ -2294,8 +2301,8 @@ void ObjectList::update_selections_on_canvas()
     auto add_to_selection = [this](const wxDataViewItem& item, Selection& selection, int instance_idx, bool as_single_selection)
     {
         const ItemType& type = m_objects_model->GetItemType(item);
-        if ( type == itInstanceRoot || m_objects_model->GetParent(item) == wxDataViewItem(0) ) {
-            wxDataViewItem obj_item = type == itInstanceRoot ? m_objects_model->GetParent(item) : item;
+        if ( type == itLayerRoot || m_objects_model->GetParent(item) == wxDataViewItem(0) ) {
+            wxDataViewItem obj_item = type == itLayerRoot ? m_objects_model->GetParent(item) : item;
             selection.add_object(m_objects_model->GetIdByItem(obj_item), as_single_selection);
             return;
         }
@@ -2317,7 +2324,7 @@ void ObjectList::update_selections_on_canvas()
 
     if (sel_cnt == 1) {
         wxDataViewItem item = GetSelection();
-        if (m_objects_model->GetItemType(item) & (itSettings|itInstanceRoot))
+        if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer))
             add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, true);
         else
             add_to_selection(item, selection, instance_idx, true);
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index 988d4a8ea..7849f66dd 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -540,6 +540,22 @@ void ObjectDataViewModelNode::SetIdx(const int& idx)
 // ObjectDataViewModel
 // ----------------------------------------------------------------------------
 
+static int get_root_idx(ObjectDataViewModelNode *parent_node, const ItemType root_type)
+{
+    // because of istance_root and layers_root are at the end of the list, so
+    // start locking from the end
+    for (int root_idx = parent_node->GetChildCount() - 1; root_idx >= 0; root_idx--)
+    {
+        // if there is SettingsItem or VolumeItem, then RootItems don't exist in current ObjectItem 
+        if (parent_node->GetNthChild(root_idx)->GetType() & (itSettings | itVolume))
+            break;
+        if (parent_node->GetNthChild(root_idx)->GetType() & root_type)
+            return root_idx;
+    }
+
+    return -1;
+}
+
 ObjectDataViewModel::ObjectDataViewModel()
 {
     m_bitmap_cache = new Slic3r::GUI::BitmapCache;
@@ -584,10 +600,10 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent
 
     wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
 
-    // because of istance_root is a last item of the object
-    int insert_position = root->GetChildCount() - 1;
-    if (insert_position < 0 || root->GetNthChild(insert_position)->m_type != itInstanceRoot)
-        insert_position = -1;
+    // get insertion position according to the existed Layers and/or Instances Items
+    int insert_position = get_root_idx(root, itLayerRoot);
+    if (insert_position < 0)
+        insert_position = get_root_idx(root, itInstanceRoot);
 
     const bool obj_errors = root->m_bmp.IsOk();
 
@@ -603,7 +619,7 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent
 		ItemAdded(parent_item, child);
 
         root->m_volumes_cnt++;
-        if (insert_position > 0) insert_position++;
+        if (insert_position >= 0) insert_position++;
 	}
 
     const auto node = new ObjectDataViewModelNode(root, name, GetVolumeIcon(volume_type, has_errors), extruder_str, root->m_volumes_cnt);
@@ -636,22 +652,6 @@ wxDataViewItem ObjectDataViewModel::AddSettingsChild(const wxDataViewItem &paren
     return child;
 }
 
-static int get_root_idx(ObjectDataViewModelNode *parent_node, const ItemType root_type)
-{
-    // because of istance_root and layers_root are at the end of the list, so
-    // start locking from the end
-    for (int root_idx = parent_node->GetChildCount() - 1; root_idx >= 0; root_idx--)
-    {
-        // if there is SettingsItem or VolumeItem, then RootItems don't exist in current ObjectItem 
-        if (parent_node->GetNthChild(root_idx)->GetType() & (itSettings | itVolume))
-            break;
-        if (parent_node->GetNthChild(root_idx)->GetType() & root_type)
-            return root_idx;
-    }
-
-    return -1;
-}
-
 /* return values:
  * true     => root_node is created and added to the parent_root
  * false    => root node alredy exists
@@ -723,6 +723,8 @@ wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_i
     if (appended)
         ItemAdded(parent_item, layer_root_item);// notify control
 
+    AddLayersChild(layer_root_item);
+
     return wxDataViewItem((void*)layer_root_item);
 }
 
@@ -732,9 +734,15 @@ wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_
     if (!parent_node) return wxDataViewItem(0);
 
     // get LayerRoot node
-    const int root_idx = get_root_idx(parent_node, itLayerRoot);
-    if (root_idx < 0) return wxDataViewItem(0);
-    ObjectDataViewModelNode *layer_root_node = parent_node->GetNthChild(root_idx);
+    ObjectDataViewModelNode *layer_root_node;
+
+    if (parent_node->GetType() & itLayerRoot)
+        layer_root_node = parent_node;
+    else {
+        const int root_idx = get_root_idx(parent_node, itLayerRoot);
+        if (root_idx < 0) return wxDataViewItem(0);
+        layer_root_node = parent_node->GetNthChild(root_idx);
+    }
 
     const wxDataViewItem layer_root_item((void*)layer_root_node);
 
@@ -763,9 +771,9 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
 	// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
 	//       thus removing the node from it doesn't result in freeing it
 	if (node_parent) {
-        if (node->m_type == itInstanceRoot)
+        if (node->m_type & (itInstanceRoot|itLayerRoot))
         {
-            for (int i = node->GetChildCount() - 1; i > 0; i--)
+            for (int i = node->GetChildCount() - 1; i >= (node->m_type & itInstanceRoot ? 1 : 0); i--)
                 Delete(wxDataViewItem(node->GetNthChild(i)));
             return parent;
         }
@@ -774,7 +782,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
         auto idx = node->GetIdx();
 
 
-        if (node->m_type == itVolume) {
+        if (node->m_type & (itVolume|itLayer)) {
             node_parent->m_volumes_cnt--;
             DeleteSettings(item);
         }
@@ -810,6 +818,22 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
             delete node_parent;
             ret_item = wxDataViewItem(obj_node);
 
+#ifndef __WXGTK__
+            if (obj_node->GetChildCount() == 0)
+                obj_node->m_container = false;
+#endif //__WXGTK__
+            ItemDeleted(ret_item, wxDataViewItem(node_parent));
+            return ret_item;
+        }
+
+        // if there was last layer item, delete this one and layers root item
+        if (node_parent->GetChildCount() == 0 && node_parent->m_type == itLayerRoot)
+        {
+            ObjectDataViewModelNode *obj_node = node_parent->GetParent();
+            obj_node->GetChildren().Remove(node_parent);
+            delete node_parent;
+            ret_item = wxDataViewItem(obj_node);
+
 #ifndef __WXGTK__
             if (obj_node->GetChildCount() == 0)
                 obj_node->m_container = false;
@@ -819,7 +843,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
         }
 
         // if there is last volume item after deleting, delete this last volume too
-        if (node_parent->GetChildCount() <= 3)
+        if (node_parent->GetChildCount() <= 3) // 3??? #ys_FIXME
         {
             int vol_cnt = 0;
             int vol_idx = 0;
@@ -1120,7 +1144,7 @@ void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type
     type = itUndef;
 
     ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
-    if (!node || node->GetIdx() <-1 || node->GetIdx() ==-1 && !(node->GetType() & (itObject | itSettings | itInstanceRoot)))
+    if (!node || node->GetIdx() <-1 || node->GetIdx() == -1 && !(node->GetType() & (itObject | itSettings | itInstanceRoot | itLayerRoot/* | itLayer*/)))
         return;
 
     idx = node->GetIdx();
@@ -1128,7 +1152,7 @@ void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type
 
     ObjectDataViewModelNode *parent_node = node->GetParent();
     if (!parent_node) return;
-    if (type == itInstance)
+    if (type & (itInstance | itLayer))
         parent_node = node->GetParent()->GetParent();
     if (!parent_node || parent_node->m_type != itObject) { type = itUndef; return; }
 

From 765d4264ae9380a549bd84bd8d79d776858d8816 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 28 May 2019 16:38:04 +0200
Subject: [PATCH 03/34] Implemented ObjectLayers class + some code refactoring

---
 src/slic3r/GUI/GUI_App.cpp            |   5 +
 src/slic3r/GUI/GUI_App.hpp            |   1 +
 src/slic3r/GUI/GUI_ObjectLayers.cpp   | 150 ++++++++++++++++++++++++++
 src/slic3r/GUI/GUI_ObjectLayers.hpp   |  36 +++++++
 src/slic3r/GUI/GUI_ObjectList.cpp     |  29 ++++-
 src/slic3r/GUI/GUI_ObjectList.hpp     |  12 ++-
 src/slic3r/GUI/GUI_ObjectSettings.cpp |   4 +-
 src/slic3r/GUI/Plater.cpp             |  13 +++
 src/slic3r/GUI/Plater.hpp             |   2 +
 9 files changed, 243 insertions(+), 9 deletions(-)
 create mode 100644 src/slic3r/GUI/GUI_ObjectLayers.cpp
 create mode 100644 src/slic3r/GUI/GUI_ObjectLayers.hpp

diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp
index b75b946e6..405de3ae9 100644
--- a/src/slic3r/GUI/GUI_App.cpp
+++ b/src/slic3r/GUI/GUI_App.cpp
@@ -924,6 +924,11 @@ ObjectList* GUI_App::obj_list()
     return sidebar().obj_list();
 }
 
+ObjectLayers* GUI_App::obj_layers()
+{
+    return sidebar().obj_layers();
+}
+
 Plater* GUI_App::plater()
 {
     return plater_;
diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp
index b70f0dc16..675121824 100644
--- a/src/slic3r/GUI/GUI_App.hpp
+++ b/src/slic3r/GUI/GUI_App.hpp
@@ -155,6 +155,7 @@ public:
     ObjectManipulation* obj_manipul();
     ObjectSettings*     obj_settings();
     ObjectList*         obj_list();
+    ObjectLayers*       obj_layers();
     Plater*             plater();
     std::vector<ModelObject*> *model_objects();
 
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
new file mode 100644
index 000000000..31a17bbf6
--- /dev/null
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -0,0 +1,150 @@
+#include "GUI_ObjectLayers.hpp"
+#include "GUI_ObjectList.hpp"
+
+#include "OptionsGroup.hpp"
+#include "PresetBundle.hpp"
+#include "libslic3r/Model.hpp"
+
+#include <boost/algorithm/string.hpp>
+
+#include "I18N.hpp"
+
+#include <wx/wupdlock.h>
+
+namespace Slic3r
+{
+namespace GUI
+{    
+
+ObjectLayers::ObjectLayers(wxWindow* parent) :
+    OG_Settings(parent, true)
+{
+    m_og->label_width = 0;
+    m_og->set_grid_vgap(5);  
+    
+    // Legend for object layers
+    Line line = Line{ "", "" };
+
+    ConfigOptionDef def;
+    def.label = "";
+    def.gui_type = "legend";
+    def.type = coString;
+    def.width = field_width;
+
+    for (const std::string axis : { "Min Z", "Max Z", "Layer height" }) {
+        def.set_default_value(new ConfigOptionString{ axis });
+        std::string label = boost::algorithm::replace_all_copy(axis, " ", "_");
+        boost::algorithm::to_lower(label);
+        line.append_option(Option(def, label + "_legend"));
+    }
+
+    m_og->append_line(line);
+
+    m_bmp_delete    = ScalableBitmap(parent, "cross");
+    m_bmp_add       = ScalableBitmap(parent, "add_copies");
+}
+
+void ObjectLayers::update_layers_list()
+{
+    ObjectList* objects_ctrl   = wxGetApp().obj_list();
+    if (objects_ctrl->multiple_selection()) return;
+
+    const auto item = objects_ctrl->GetSelection();
+    if (!item) return;
+
+    const int obj_idx = objects_ctrl->get_selected_obj_idx();
+    if (obj_idx < 0) return;
+
+    const ItemType type = objects_ctrl->GetModel()->GetItemType(item);
+    if (!(type & (itLayerRoot | itLayer))) return;
+
+    ModelObject* object = objects_ctrl->object(obj_idx);
+    if (!object || object->layer_height_ranges.empty()) return;
+
+    auto grid_sizer = m_og->get_grid_sizer();
+
+    const int cols = grid_sizer->GetCols();
+    const int rows = grid_sizer->GetRows();
+    for (int idx = cols*rows-1; idx >= cols; idx--) {
+        grid_sizer->Remove(idx);
+    }
+
+    ConfigOptionDef def;
+    def.label = "";
+    def.gui_type = "";
+    def.type = coFloat;
+    def.width = field_width;
+
+    if (type & itLayerRoot)
+    {
+        auto create_btns = [this](wxWindow* parent) {
+            auto sizer = new wxBoxSizer(wxHORIZONTAL);
+            auto del_btn = new ScalableButton(parent, wxID_ANY, m_bmp_delete);
+            del_btn->SetToolTip(_(L("Remove layer")));
+
+            sizer->Add(del_btn, 0, wxRIGHT, em_unit(parent));
+
+            del_btn->Bind(wxEVT_BUTTON, [this](wxEvent &event) {
+                del_layer();
+//                 wxTheApp->CallAfter([this]() {
+//                     wxWindowUpdateLocker noUpdates(m_parent);
+//                     update_layers_list(); 
+//                     m_parent->Layout();
+//                 });
+            });
+
+            auto add_btn = new ScalableButton(parent, wxID_ANY, m_bmp_add);
+            add_btn->SetToolTip(_(L("Add layer")));
+
+            sizer->Add(add_btn, 0, wxRIGHT, em_unit(parent));
+
+            add_btn->Bind(wxEVT_BUTTON, [this](wxEvent &event) {
+                add_layer();
+//                 wxTheApp->CallAfter([this]() {
+//                     wxWindowUpdateLocker noUpdates(m_parent);
+//                     update_layers_list(); 
+//                     m_parent->Layout();
+//                 });
+            });
+
+            return sizer;
+        };
+
+        Line line{"",""};
+        for (const auto layer : object->layer_height_ranges)
+        {
+            std::string label = (boost::format("min_z_%.2f") % layer.first.first).str();
+            def.set_default_value(new ConfigOptionFloat(layer.first.first));
+            line.append_option(Option(def, label));
+           
+            label = (boost::format("max_z_%.2f") % layer.first.second).str();
+            def.set_default_value(new ConfigOptionFloat(layer.first.second));
+            line.append_option(Option(def, label));
+           
+            label = (boost::format("layer_height_%.2f_%.2f") % layer.first.first % layer.first.second).str();
+            def.set_default_value(new ConfigOptionFloat(layer.second));
+            line.append_option(Option(def, label));
+
+            line.append_widget(create_btns);
+        }
+
+        m_og->append_line(line);
+    }
+}
+
+void ObjectLayers::UpdateAndShow(const bool show)
+{
+    if (show)
+        update_layers_list();
+
+    OG_Settings::UpdateAndShow(show);
+}
+
+void ObjectLayers::msw_rescale()
+{
+    m_bmp_delete.msw_rescale();
+    m_bmp_add.msw_rescale();
+}
+
+} //namespace GUI
+} //namespace Slic3r 
\ No newline at end of file
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
new file mode 100644
index 000000000..8f8b55998
--- /dev/null
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -0,0 +1,36 @@
+#ifndef slic3r_GUI_ObjectLayers_hpp_
+#define slic3r_GUI_ObjectLayers_hpp_
+
+#include "GUI_ObjectSettings.hpp"
+#include "wxExtensions.hpp"
+
+class wxBoxSizer;
+
+namespace Slic3r {
+class ModelObject;
+
+namespace GUI {
+class ConfigOptionsGroup;
+
+class ObjectLayers : public OG_Settings
+{
+    ScalableBitmap m_bmp_delete;
+    ScalableBitmap m_bmp_add;
+
+    int             field_width {8};
+
+public:
+    ObjectLayers(wxWindow* parent);
+    ~ObjectLayers() {}
+
+    void        update_layers_list();
+    void        add_layer() {};
+    void        del_layer() {};
+
+    void        UpdateAndShow(const bool show) override;
+    void        msw_rescale();
+};
+
+}}
+
+#endif // slic3r_GUI_ObjectLayers_hpp_
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index e180f1dfc..080ebbe21 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1,6 +1,7 @@
 #include "libslic3r/libslic3r.h"
 #include "GUI_ObjectList.hpp"
 #include "GUI_ObjectManipulation.hpp"
+#include "GUI_ObjectLayers.hpp"
 #include "GUI_App.hpp"
 #include "I18N.hpp"
 
@@ -1799,7 +1800,11 @@ void ObjectList::layers_editing()
 
     wxDataViewItem layers_item = m_objects_model->GetItemByType(obj_item, itLayerRoot);
     if (!layers_item.IsOk())
+    {
+        const t_layer_height_range first_range = { 0.0f, 0.2f };
+        object(obj_idx)->layer_height_ranges[first_range] = 0.1f;
         layers_item = m_objects_model->AddLayersRoot(obj_item);
+    }
 
     select_item(layers_item);
 }
@@ -1873,6 +1878,7 @@ void ObjectList::part_selection_changed()
 
     bool update_and_show_manipulations = false;
     bool update_and_show_settings = false;
+    bool update_and_show_layers = false;
 
     const auto item = GetSelection();
 
@@ -1898,7 +1904,8 @@ void ObjectList::part_selection_changed()
                 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
                 obj_idx = m_objects_model->GetIdByItem(parent);
-                if (m_objects_model->GetItemType(item) == itSettings) {
+                const ItemType type = m_objects_model->GetItemType(item);
+                if (type & itSettings) {
                     if (m_objects_model->GetParent(parent) == wxDataViewItem(0)) {
                         og_name = _(L("Object Settings to modify"));
                         m_config = &(*m_objects)[obj_idx]->config;
@@ -1912,13 +1919,13 @@ void ObjectList::part_selection_changed()
                     }
                     update_and_show_settings = true;
                 }
-                else if (m_objects_model->GetItemType(item) == itVolume) {
+                else if (type & itVolume) {
                     og_name = _(L("Part manipulation"));
                     volume_id = m_objects_model->GetVolumeIdByItem(item);
                     m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
                     update_and_show_manipulations = true;
                 }
-                else if (m_objects_model->GetItemType(item) == itInstance) {
+                else if (type & itInstance) {
                     og_name = _(L("Instance manipulation"));
                     update_and_show_manipulations = true;
 
@@ -1926,6 +1933,10 @@ void ObjectList::part_selection_changed()
                     const int obj_idx_ = m_objects_model->GetObjectIdByItem(item);
                     m_config = &(*m_objects)[obj_idx_]->config;
                 }
+                else if (type & (itLayerRoot|itLayer)) {
+                    og_name = type & itLayerRoot ? _(L("Layers Editing")) : _(L("Layer Editing"));
+                    update_and_show_layers = true;
+                }
             }
         }
     }
@@ -1944,11 +1955,15 @@ void ObjectList::part_selection_changed()
     if (update_and_show_settings)
         wxGetApp().obj_settings()->get_og()->set_name(" " + og_name + " ");
 
+    if (update_and_show_layers)
+        wxGetApp().obj_layers()->get_og()->set_name(" " + og_name + " ");
+
     Sidebar& panel = wxGetApp().sidebar();
     panel.Freeze();
 
     wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations);
     wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings);
+    wxGetApp().obj_layers()  ->UpdateAndShow(update_and_show_layers);
     wxGetApp().sidebar().show_info_sizer();
 
     panel.Layout();
@@ -2946,5 +2961,13 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const
     wxGetApp().plater()->update();
 }
 
+ModelObject* ObjectList::object(const int obj_idx) const
+{
+    if (obj_idx < 0)
+        return nullptr;
+
+    return (*m_objects)[obj_idx];
+}
+
 } //namespace GUI
 } //namespace Slic3r 
\ No newline at end of file
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 076ab5f13..764aac1e8 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -122,6 +122,10 @@ class ObjectList : public wxDataViewCtrl
     wxMenuItem* m_menu_item_settings { nullptr };
     wxMenuItem* m_menu_item_split_instances { nullptr };
 
+    ObjectDataViewModel         *m_objects_model{ nullptr };
+    DynamicPrintConfig          *m_config {nullptr};
+    std::vector<ModelObject*>   *m_objects{ nullptr };
+
     std::vector<wxBitmap*> m_bmp_vector;
 
     int			m_selected_object_id = -1;
@@ -151,11 +155,11 @@ public:
 
     std::map<std::string, wxBitmap> CATEGORY_ICON;
 
-    ObjectDataViewModel	*m_objects_model{ nullptr };
-    DynamicPrintConfig          *m_config {nullptr};
-
-    std::vector<ModelObject*>   *m_objects{ nullptr };
+    ObjectDataViewModel*        GetModel() const    { return m_objects_model; }
+    DynamicPrintConfig*         config() const      { return m_config; }
+    std::vector<ModelObject*>*  objects() const     { return m_objects; }
 
+    ModelObject*                object(const int obj_idx) const ;
 
     void                create_objects_ctrl();
     void                create_popup_menus();
diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp
index 4107e872a..a4aa7dec2 100644
--- a/src/slic3r/GUI/GUI_ObjectSettings.cpp
+++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp
@@ -68,8 +68,8 @@ void ObjectSettings::update_settings_list()
     m_settings_list_sizer->Clear(true);
 
     auto objects_ctrl   = wxGetApp().obj_list();
-    auto objects_model  = wxGetApp().obj_list()->m_objects_model;
-    auto config         = wxGetApp().obj_list()->m_config;
+    auto objects_model  = wxGetApp().obj_list()->GetModel();
+    auto config         = wxGetApp().obj_list()->config();
 
     const auto item = objects_ctrl->GetSelection();
     if (item && !objects_ctrl->multiple_selection() && 
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index c0f267204..88abe9b83 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -43,6 +43,7 @@
 #include "GUI_App.hpp"
 #include "GUI_ObjectList.hpp"
 #include "GUI_ObjectManipulation.hpp"
+#include "GUI_ObjectLayers.hpp"
 #include "GUI_Utils.hpp"
 #include "wxExtensions.hpp"
 #include "MainFrame.hpp"
@@ -611,6 +612,7 @@ struct Sidebar::priv
     ObjectList          *object_list;
     ObjectManipulation  *object_manipulation;
     ObjectSettings      *object_settings;
+    ObjectLayers        *object_layers;
     ObjectInfo *object_info;
     SlicedInfo *sliced_info;
 
@@ -729,6 +731,11 @@ Sidebar::Sidebar(Plater *parent)
     p->object_settings = new ObjectSettings(p->scrolled);
     p->object_settings->Hide();
     p->sizer_params->Add(p->object_settings->get_sizer(), 0, wxEXPAND | wxTOP, margin_5);
+ 
+    // Object Layers
+    p->object_layers = new ObjectLayers(p->scrolled);
+    p->object_layers->Hide();
+    p->sizer_params->Add(p->object_layers->get_sizer(), 0, wxEXPAND | wxTOP, margin_5);
 
     // Info boxes
     p->object_info = new ObjectInfo(p->scrolled);
@@ -922,6 +929,7 @@ void Sidebar::msw_rescale()
     p->object_list->msw_rescale();
     p->object_manipulation->msw_rescale();
     p->object_settings->msw_rescale();
+    p->object_layers->msw_rescale();
 
     p->object_info->msw_rescale();
 
@@ -943,6 +951,11 @@ ObjectSettings* Sidebar::obj_settings()
     return p->object_settings;
 }
 
+ObjectLayers* Sidebar::obj_layers()
+{
+    return p->object_layers;
+}
+
 wxScrolledWindow* Sidebar::scrolled_panel()
 {
     return p->scrolled;
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index 16c9cbe64..3e50797a6 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -33,6 +33,7 @@ class MainFrame;
 class ConfigOptionsGroup;
 class ObjectManipulation;
 class ObjectSettings;
+class ObjectLayers;
 class ObjectList;
 class GLCanvas3D;
 
@@ -93,6 +94,7 @@ public:
     ObjectManipulation*     obj_manipul();
     ObjectList*             obj_list();
     ObjectSettings*         obj_settings();
+    ObjectLayers*           obj_layers();
     wxScrolledWindow*       scrolled_panel();
     wxPanel*                presets_panel();
 

From bf56d79354cd74d645ea3e030c476c41d9c649eb Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Thu, 30 May 2019 12:41:16 +0200
Subject: [PATCH 04/34] Layers sizer updating

---
 src/slic3r/GUI/GUI_ObjectLayers.cpp | 173 +++++++++++++++++-----------
 src/slic3r/GUI/GUI_ObjectLayers.hpp |   9 +-
 src/slic3r/GUI/GUI_ObjectList.cpp   |   4 +
 src/slic3r/GUI/OptionsGroup.cpp     |  11 ++
 src/slic3r/GUI/OptionsGroup.hpp     |   2 +
 5 files changed, 128 insertions(+), 71 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
index 31a17bbf6..80aa6bcca 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.cpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -14,13 +14,17 @@
 namespace Slic3r
 {
 namespace GUI
-{    
+{
+
+typedef std::map<t_layer_height_range, coordf_t> t_layer_height_ranges;
+
+#define field_width 8
 
 ObjectLayers::ObjectLayers(wxWindow* parent) :
     OG_Settings(parent, true)
 {
-    m_og->label_width = 0;
-    m_og->set_grid_vgap(5);  
+    m_og->label_width = 1;
+//     m_og->set_grid_vgap(5);
     
     // Legend for object layers
     Line line = Line{ "", "" };
@@ -36,6 +40,8 @@ ObjectLayers::ObjectLayers(wxWindow* parent) :
         std::string label = boost::algorithm::replace_all_copy(axis, " ", "_");
         boost::algorithm::to_lower(label);
         line.append_option(Option(def, label + "_legend"));
+
+        m_legends.push_back(label + "_legend");
     }
 
     m_og->append_line(line);
@@ -44,6 +50,83 @@ ObjectLayers::ObjectLayers(wxWindow* parent) :
     m_bmp_add       = ScalableBitmap(parent, "add_copies");
 }
 
+static Line create_new_layer(const t_layer_height_ranges::value_type& layer)
+{
+    Line line = Line{ "", "" };
+    ConfigOptionDef def;
+    def.label = "";
+    def.gui_type = "";
+    def.type = coFloat;
+    def.width = field_width;
+
+    std::string label = (boost::format("min_z_%.2f") % layer.first.first).str();
+    def.set_default_value(new ConfigOptionFloat(layer.first.first));
+    line.append_option(Option(def, label));
+
+    label = (boost::format("max_z_%.2f") % layer.first.second).str();
+    def.set_default_value(new ConfigOptionFloat(layer.first.second));
+    line.append_option(Option(def, label));
+
+    label = (boost::format("layer_height_%.2f_%.2f") % layer.first.first % layer.first.second).str();
+    def.set_default_value(new ConfigOptionFloat(layer.second));
+    line.append_option(Option(def, label));
+
+    return line;
+}
+
+void ObjectLayers::create_layers_list()
+{
+    auto create_btns = [this](wxWindow* parent) {
+        auto sizer = new wxBoxSizer(wxHORIZONTAL);
+
+        auto del_btn = new ScalableButton(parent, wxID_ANY, m_bmp_delete);
+        del_btn->SetToolTip(_(L("Remove layer")));
+
+        sizer->Add(del_btn, 0, wxRIGHT, em_unit(parent));
+
+        del_btn->Bind(wxEVT_BUTTON, [this](wxEvent &event) {
+            del_layer();
+//             wxTheApp->CallAfter([this]() {
+//                 wxWindowUpdateLocker noUpdates(m_parent);
+//                 update_layers_list(); 
+//                 m_parent->Layout();
+//             });
+        });
+
+        auto add_btn = new ScalableButton(parent, wxID_ANY, m_bmp_add);
+        add_btn->SetToolTip(_(L("Add layer")));
+
+        sizer->Add(add_btn, 0, wxRIGHT, em_unit(parent));
+
+        add_btn->Bind(wxEVT_BUTTON, [this](wxEvent &event) {
+            add_layer();
+//         wxTheApp->CallAfter([this]() {
+//             wxWindowUpdateLocker noUpdates(m_parent);
+//             update_layers_list(); 
+//             m_parent->Layout();
+//         });
+        });
+
+        return sizer;
+    };
+
+    for (const auto layer : m_object->layer_height_ranges)
+    {
+        Line line = create_new_layer(layer);
+        line.append_widget(create_btns);
+        m_og->append_line(line);
+    }
+}
+
+void ObjectLayers::create_layer()
+{
+    for (const auto layer : m_object->layer_height_ranges)
+    {
+        m_og->append_line(create_new_layer(layer));
+        break;
+    }
+}
+
 void ObjectLayers::update_layers_list()
 {
     ObjectList* objects_ctrl   = wxGetApp().obj_list();
@@ -58,78 +141,32 @@ void ObjectLayers::update_layers_list()
     const ItemType type = objects_ctrl->GetModel()->GetItemType(item);
     if (!(type & (itLayerRoot | itLayer))) return;
 
-    ModelObject* object = objects_ctrl->object(obj_idx);
-    if (!object || object->layer_height_ranges.empty()) return;
+    m_object = objects_ctrl->object(obj_idx);
+    if (!m_object || m_object->layer_height_ranges.empty()) return;
+
+    // Delete all controls from options group except of the legends
 
     auto grid_sizer = m_og->get_grid_sizer();
-
-    const int cols = grid_sizer->GetCols();
-    const int rows = grid_sizer->GetRows();
+    const int cols = grid_sizer->GetEffectiveColsCount();
+    const int rows = grid_sizer->GetEffectiveRowsCount();
     for (int idx = cols*rows-1; idx >= cols; idx--) {
-        grid_sizer->Remove(idx);
+        wxSizerItem* t = grid_sizer->GetItem(idx);
+        if (t->IsSizer())
+            t->GetSizer()->Clear(true);
+            grid_sizer->Remove(idx);
     }
 
-    ConfigOptionDef def;
-    def.label = "";
-    def.gui_type = "";
-    def.type = coFloat;
-    def.width = field_width;
+    m_og->clear_fields_except_of(m_legends);
+
+
+    // Add new control according to the selected item  
 
     if (type & itLayerRoot)
-    {
-        auto create_btns = [this](wxWindow* parent) {
-            auto sizer = new wxBoxSizer(wxHORIZONTAL);
-            auto del_btn = new ScalableButton(parent, wxID_ANY, m_bmp_delete);
-            del_btn->SetToolTip(_(L("Remove layer")));
-
-            sizer->Add(del_btn, 0, wxRIGHT, em_unit(parent));
-
-            del_btn->Bind(wxEVT_BUTTON, [this](wxEvent &event) {
-                del_layer();
-//                 wxTheApp->CallAfter([this]() {
-//                     wxWindowUpdateLocker noUpdates(m_parent);
-//                     update_layers_list(); 
-//                     m_parent->Layout();
-//                 });
-            });
-
-            auto add_btn = new ScalableButton(parent, wxID_ANY, m_bmp_add);
-            add_btn->SetToolTip(_(L("Add layer")));
-
-            sizer->Add(add_btn, 0, wxRIGHT, em_unit(parent));
-
-            add_btn->Bind(wxEVT_BUTTON, [this](wxEvent &event) {
-                add_layer();
-//                 wxTheApp->CallAfter([this]() {
-//                     wxWindowUpdateLocker noUpdates(m_parent);
-//                     update_layers_list(); 
-//                     m_parent->Layout();
-//                 });
-            });
-
-            return sizer;
-        };
-
-        Line line{"",""};
-        for (const auto layer : object->layer_height_ranges)
-        {
-            std::string label = (boost::format("min_z_%.2f") % layer.first.first).str();
-            def.set_default_value(new ConfigOptionFloat(layer.first.first));
-            line.append_option(Option(def, label));
-           
-            label = (boost::format("max_z_%.2f") % layer.first.second).str();
-            def.set_default_value(new ConfigOptionFloat(layer.first.second));
-            line.append_option(Option(def, label));
-           
-            label = (boost::format("layer_height_%.2f_%.2f") % layer.first.first % layer.first.second).str();
-            def.set_default_value(new ConfigOptionFloat(layer.second));
-            line.append_option(Option(def, label));
-
-            line.append_widget(create_btns);
-        }
-
-        m_og->append_line(line);
-    }
+        create_layers_list();
+    else
+        create_layer();
+    
+    m_parent->Layout();
 }
 
 void ObjectLayers::UpdateAndShow(const bool show)
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index 8f8b55998..13a3da911 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -14,15 +14,18 @@ class ConfigOptionsGroup;
 
 class ObjectLayers : public OG_Settings
 {
-    ScalableBitmap m_bmp_delete;
-    ScalableBitmap m_bmp_add;
+    ScalableBitmap  m_bmp_delete;
+    ScalableBitmap  m_bmp_add;
+    ModelObject*    m_object {nullptr};
 
-    int             field_width {8};
+    std::vector<std::string> m_legends;
 
 public:
     ObjectLayers(wxWindow* parent);
     ~ObjectLayers() {}
 
+    void        create_layers_list();
+    void        create_layer();
     void        update_layers_list();
     void        add_layer() {};
     void        del_layer() {};
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 080ebbe21..00eb3e7de 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1803,6 +1803,10 @@ void ObjectList::layers_editing()
     {
         const t_layer_height_range first_range = { 0.0f, 0.2f };
         object(obj_idx)->layer_height_ranges[first_range] = 0.1f;
+
+        const t_layer_height_range second_range = { 0.2f, 0.4f };
+        object(obj_idx)->layer_height_ranges[second_range] = 0.05f;
+
         layers_item = m_objects_model->AddLayersRoot(obj_item);
     }
 
diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp
index 2ac6b00af..67feefa3f 100644
--- a/src/slic3r/GUI/OptionsGroup.cpp
+++ b/src/slic3r/GUI/OptionsGroup.cpp
@@ -320,6 +320,17 @@ Line OptionsGroup::create_single_option_line(const Option& option) const {
     return retval;
 }
 
+void OptionsGroup::clear_fields_except_of(const std::vector<std::string> left_fields)
+{
+    auto it = m_fields.begin();
+    while (it != m_fields.end()) {
+        if (std::find(left_fields.begin(), left_fields.end(), it->first) == left_fields.end())
+            it = m_fields.erase(it);
+        else 
+            it++;
+    }
+}
+
 void OptionsGroup::on_set_focus(const std::string& opt_key)
 {
     if (m_set_focus != nullptr)
diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp
index 73b2c5110..422a5c2a2 100644
--- a/src/slic3r/GUI/OptionsGroup.hpp
+++ b/src/slic3r/GUI/OptionsGroup.hpp
@@ -160,6 +160,8 @@ public:
 		                m_show_modified_btns = show;
     }
 
+    void            clear_fields_except_of(const std::vector<std::string> left_fields);
+
 	OptionsGroup(	wxWindow* _parent, const wxString& title, bool is_tab_opt = false, 
 					column_t extra_clmn = nullptr) :
 					m_parent(_parent), title(title), 

From 080274c638de48ed771873d1936a8e375dd5196c Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Thu, 30 May 2019 13:08:05 +0200
Subject: [PATCH 05/34] Added missed files to the CMakeLists.txt

---
 src/slic3r/CMakeLists.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt
index 570e23baa..13f563fd0 100644
--- a/src/slic3r/CMakeLists.txt
+++ b/src/slic3r/CMakeLists.txt
@@ -81,6 +81,8 @@ set(SLIC3R_GUI_SOURCES
     GUI/GUI_ObjectManipulation.hpp
     GUI/GUI_ObjectSettings.cpp
     GUI/GUI_ObjectSettings.hpp
+    GUI/GUI_ObjectLayers.cpp
+    GUI/GUI_ObjectLayers.hpp
     GUI/LambdaObjectDialog.cpp
     GUI/LambdaObjectDialog.hpp
     GUI/Tab.cpp

From a516f76f94447e82eed066f022deedf769f07b42 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Thu, 30 May 2019 14:41:16 +0200
Subject: [PATCH 06/34] Improved layer sizer

+ fixed build under OSX and Linux
---
 src/slic3r/GUI/GUI_ObjectLayers.cpp | 17 ++++----
 src/slic3r/GUI/GUI_ObjectLayers.hpp |  2 +-
 src/slic3r/GUI/GUI_ObjectList.cpp   | 16 +++++---
 src/slic3r/GUI/wxExtensions.cpp     | 62 +++++++++++++++++++----------
 src/slic3r/GUI/wxExtensions.hpp     |  8 +++-
 5 files changed, 70 insertions(+), 35 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
index 80aa6bcca..f47260530 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.cpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -24,7 +24,7 @@ ObjectLayers::ObjectLayers(wxWindow* parent) :
     OG_Settings(parent, true)
 {
     m_og->label_width = 1;
-//     m_og->set_grid_vgap(5);
+    m_og->set_grid_vgap(5);
     
     // Legend for object layers
     Line line = Line{ "", "" };
@@ -118,13 +118,16 @@ void ObjectLayers::create_layers_list()
     }
 }
 
-void ObjectLayers::create_layer()
+void ObjectLayers::create_layer(int id)
 {
-    for (const auto layer : m_object->layer_height_ranges)
-    {
-        m_og->append_line(create_new_layer(layer));
-        break;
+    t_layer_height_ranges::iterator layer_range = m_object->layer_height_ranges.begin();
+
+    while (id > 0 && layer_range != m_object->layer_height_ranges.end()) {
+        layer_range++;
+        id--;
     }
+        
+    m_og->append_line(create_new_layer(*layer_range));
 }
 
 void ObjectLayers::update_layers_list()
@@ -164,7 +167,7 @@ void ObjectLayers::update_layers_list()
     if (type & itLayerRoot)
         create_layers_list();
     else
-        create_layer();
+        create_layer(objects_ctrl->GetModel()->GetLayerIdByItem(item));
     
     m_parent->Layout();
 }
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index 13a3da911..b9e9efb14 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -25,7 +25,7 @@ public:
     ~ObjectLayers() {}
 
     void        create_layers_list();
-    void        create_layer();
+    void        create_layer(int id);
     void        update_layers_list();
     void        add_layer() {};
     void        del_layer() {};
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 00eb3e7de..934ad34fb 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1801,15 +1801,21 @@ void ObjectList::layers_editing()
     wxDataViewItem layers_item = m_objects_model->GetItemByType(obj_item, itLayerRoot);
     if (!layers_item.IsOk())
     {
-        const t_layer_height_range first_range = { 0.0f, 0.2f };
-        object(obj_idx)->layer_height_ranges[first_range] = 0.1f;
-
-        const t_layer_height_range second_range = { 0.2f, 0.4f };
-        object(obj_idx)->layer_height_ranges[second_range] = 0.05f;
+        // --->>>--- Just for testing
+        object(obj_idx)->layer_height_ranges[{ 0.0f, 0.2f }] = 0.1f;
+        object(obj_idx)->layer_height_ranges[{ 0.2f, 0.4f }] = 0.05f;
+        object(obj_idx)->layer_height_ranges[{ 0.4f, 0.6f }] = 0.2f;
+        // ---<<<--- Just for testing
 
         layers_item = m_objects_model->AddLayersRoot(obj_item);
     }
 
+    for (const auto range : object(obj_idx)->layer_height_ranges) 
+    {
+        const std::string label = (boost::format("(%.2f-%.2f)") % range.first.first % range.first.second).str();
+        m_objects_model->AddLayersChild(layers_item, label);
+    }
+
     select_item(layers_item);
 }
 
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index 7849f66dd..989a97676 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -453,24 +453,39 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
         m_bmp = create_scaled_bitmap(nullptr, "table.png");    // FIXME: pass window ptr
         m_name = _(L("Layers"));
     }
-    else if (type == itLayer)
-    {
-        m_idx = parent->GetChildCount();
-        m_name = wxString::Format(_(L("Layer %d")), m_idx + 1);
-        m_bmp = create_scaled_bitmap(nullptr, "row.png");    // FIXME: pass window ptr
-
-        set_action_icon();
-    }
 
 #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"
-    if (type & (itInstanceRoot | itLayerRoot | itLayer))
+    if (type & (itInstanceRoot | itLayerRoot))
         m_container = true;
 #endif  //__WXGTK__
 }
 
+ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, 
+                                                 const wxString& label_range, 
+                                                 const wxString& extruder, 
+                                                 const int idx /*= -1 */) :
+    m_parent(parent),
+    m_type(itLayer),
+    m_idx(idx),
+    m_extruder(extruder)
+{
+    m_idx = parent->GetChildCount();
+    m_name = wxString::Format(_(L("Layer %s")), label_range);
+    m_bmp = create_scaled_bitmap(nullptr, "row.png");    // FIXME: pass window ptr
+
+#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_action_icon();
+}
+
 void ObjectDataViewModelNode::set_action_icon()
 {
     m_action_icon_name = m_type & itObject              ? "advanced_plus" : 
@@ -671,7 +686,7 @@ static bool append_root_node(ObjectDataViewModelNode *parent_node,
             (root_type&itLayerRoot) && get_root_idx(parent_node, itInstanceRoot)<0)
             parent_node->Append(*root_node);
         else if (root_type&itLayerRoot)
-            parent_node->Insert(*root_node, unsigned int(get_root_idx(parent_node, itInstanceRoot)));
+            parent_node->Insert(*root_node, static_cast<unsigned int>(get_root_idx(parent_node, itInstanceRoot)));
         return true;
     }
 
@@ -723,38 +738,38 @@ wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_i
     if (appended)
         ItemAdded(parent_item, layer_root_item);// notify control
 
-    AddLayersChild(layer_root_item);
-
-    return wxDataViewItem((void*)layer_root_item);
+    return layer_root_item;
 }
 
-wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item)
+wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item, const std::string& label_range)
 {
     ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
     if (!parent_node) return wxDataViewItem(0);
 
     // get LayerRoot node
     ObjectDataViewModelNode *layer_root_node;
+    wxDataViewItem layer_root_item;
 
-    if (parent_node->GetType() & itLayerRoot)
+    if (parent_node->GetType() & itLayerRoot) {
         layer_root_node = parent_node;
+        layer_root_item = parent_item;
+    }
     else {
         const int root_idx = get_root_idx(parent_node, itLayerRoot);
         if (root_idx < 0) return wxDataViewItem(0);
         layer_root_node = parent_node->GetNthChild(root_idx);
+        layer_root_item = wxDataViewItem((void*)layer_root_node);
     }
 
-    const wxDataViewItem layer_root_item((void*)layer_root_node);
-
     // Add layer node
-    ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, itLayer);
+    ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, label_range);
     layer_root_node->Append(layer_node);
 
     // notify control
-    const wxDataViewItem instance_item((void*)layer_node);
-    ItemAdded(layer_root_item, instance_item);
+    const wxDataViewItem layer_item((void*)layer_node);
+    ItemAdded(layer_root_item, layer_item);
 
-    return wxDataViewItem((void*)layer_node);
+    return layer_item;
 }
 
 wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
@@ -1138,6 +1153,11 @@ int ObjectDataViewModel::GetInstanceIdByItem(const wxDataViewItem& item) const
     return GetIdByItemAndType(item, itInstance);
 }
 
+int ObjectDataViewModel::GetLayerIdByItem(const wxDataViewItem& item) const 
+{
+    return GetIdByItemAndType(item, itLayer);
+}
+
 void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx)
 {
     wxASSERT(item.IsOk());
diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp
index 424f7832a..b3d8ebc18 100644
--- a/src/slic3r/GUI/wxExtensions.hpp
+++ b/src/slic3r/GUI/wxExtensions.hpp
@@ -231,6 +231,11 @@ public:
         set_action_icon();
     }
 
+	ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
+							const wxString& label_range,
+                            const wxString& extruder = wxEmptyString,
+                            const int idx = -1 );
+
     ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type);
 
 	~ObjectDataViewModelNode()
@@ -391,7 +396,7 @@ public:
     wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
     wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
     wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
-    wxDataViewItem AddLayersChild(const wxDataViewItem &parent_item);
+    wxDataViewItem AddLayersChild(const wxDataViewItem &parent_item, const std::string& label_range);
 	wxDataViewItem Delete(const wxDataViewItem &item);
 	wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
 	void DeleteAll();
@@ -406,6 +411,7 @@ public:
     int  GetObjectIdByItem(const wxDataViewItem& item) const;
     int  GetVolumeIdByItem(const wxDataViewItem& item) const;
     int  GetInstanceIdByItem(const wxDataViewItem& item) const;
+    int  GetLayerIdByItem(const wxDataViewItem& item) const;
     void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx);
     int  GetRowByItem(const wxDataViewItem& item) const;
     bool IsEmpty() { return m_objects.empty(); }

From e531d224e8b4649ec1a16e58e2d060cc1be271d9 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Thu, 30 May 2019 16:53:17 +0200
Subject: [PATCH 07/34] Implemented delete_layers_from_object()

---
 src/slic3r/GUI/GUI_ObjectLayers.cpp |  2 +-
 src/slic3r/GUI/GUI_ObjectList.cpp   | 45 +++++++++++++++++++++++------
 src/slic3r/GUI/GUI_ObjectList.hpp   |  1 +
 src/slic3r/GUI/wxExtensions.cpp     |  7 +++--
 4 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
index f47260530..191a65386 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.cpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -46,7 +46,7 @@ ObjectLayers::ObjectLayers(wxWindow* parent) :
 
     m_og->append_line(line);
 
-    m_bmp_delete    = ScalableBitmap(parent, "cross");
+    m_bmp_delete    = ScalableBitmap(parent, "remove_copies"/*"cross"*/);
     m_bmp_add       = ScalableBitmap(parent, "add_copies");
 }
 
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 934ad34fb..8043ee565 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1141,7 +1141,7 @@ wxMenuItem* ObjectList::append_menu_item_split(wxMenu* menu)
 wxMenuItem* ObjectList::append_menu_item_layers_editing(wxMenu* menu) 
 {
     return append_menu_item(menu, wxID_ANY, _(L("Edit Layers")), "",
-        [this](wxCommandEvent&) { layers_editing(); }, "table.png", menu);
+        [this](wxCommandEvent&) { layers_editing(); }, "layers", menu);
 }
 
 wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_) 
@@ -1650,7 +1650,7 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
     else if (type == itInstanceRoot && obj_idx != -1)
         del_instances_from_object(obj_idx);
     else if ((type & itLayerRoot) && obj_idx != -1)
-        /*del_layers_from_object(obj_idx)*/;
+        del_layers_from_object(obj_idx);
     else if (idx == -1)
         return;
     else if (!del_subobject_from_object(obj_idx, idx, type))
@@ -1692,6 +1692,13 @@ void ObjectList::del_instances_from_object(const int obj_idx)
     changed_object(obj_idx);
 }
 
+void ObjectList::del_layers_from_object(const int obj_idx)
+{
+    object(obj_idx)->layer_height_ranges.clear(); // ? #ys_FIXME
+
+    changed_object(obj_idx);
+}
+
 bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, const int type)
 {
 	if (obj_idx == 1000)
@@ -1732,6 +1739,13 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con
         object->delete_instance(idx);
     }
     else if (type == itLayer) {
+        t_layer_height_ranges::iterator layer_range = object->layer_height_ranges.begin();
+        int id = idx;
+        while (id > 0 && layer_range != object->layer_height_ranges.end()) {
+            layer_range++;
+            id--;
+        }
+        object->layer_height_ranges.erase(layer_range);
     }
     else
         return false;
@@ -1808,12 +1822,12 @@ void ObjectList::layers_editing()
         // ---<<<--- Just for testing
 
         layers_item = m_objects_model->AddLayersRoot(obj_item);
-    }
 
-    for (const auto range : object(obj_idx)->layer_height_ranges) 
-    {
-        const std::string label = (boost::format("(%.2f-%.2f)") % range.first.first % range.first.second).str();
-        m_objects_model->AddLayersChild(layers_item, label);
+        for (const auto range : object(obj_idx)->layer_height_ranges)
+        {
+            const std::string label = (boost::format(" %.2f-%.2f ") % range.first.first % range.first.second).str();
+            m_objects_model->AddLayersChild(layers_item, label);
+        }
     }
 
     select_item(layers_item);
@@ -2168,9 +2182,22 @@ void ObjectList::remove()
         if (m_objects_model->GetParent(item) == wxDataViewItem(0))
             delete_from_model_and_list(itObject, m_objects_model->GetIdByItem(item), -1);
         else {
-            if (sels.size() == 1)
-                select_item(m_objects_model->GetParent(item));
+//             if (sels.size() == 1)
+//                 select_item(m_objects_model->GetParent(item));
+            wxDataViewItem  parent = m_objects_model->GetParent(item);
+            if (sels.size() == 1) {
+                if (!(m_objects_model->GetItemType(item) & itLayer)) {
+                    select_item(parent);
+                    parent = wxDataViewItem(0);
+                }
+                else if (m_objects_model->GetChildren(parent, wxDataViewItemArray()) == 1)
+                    parent = m_objects_model->GetTopParent(item);
+            }
+            
             del_subobject_item(item);
+
+            if (sels.size() == 1 && parent)
+                select_item(parent);
         }
     }
 }
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 764aac1e8..6963805e9 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -227,6 +227,7 @@ public:
     void                del_subobject_item(wxDataViewItem& item);
     void                del_settings_from_config();
     void                del_instances_from_object(const int obj_idx);
+    void                del_layers_from_object(const int obj_idx);
     bool                del_subobject_from_object(const int obj_idx, const int idx, const int type);
     void                split();
     void                layers_editing();
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index 989a97676..4511ab8ac 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -450,7 +450,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
     }
     else if (type == itLayerRoot)
     {
-        m_bmp = create_scaled_bitmap(nullptr, "table.png");    // FIXME: pass window ptr
+        m_bmp = create_scaled_bitmap(nullptr, "layers");    // FIXME: pass window ptr
         m_name = _(L("Layers"));
     }
 
@@ -473,8 +473,9 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
     m_extruder(extruder)
 {
     m_idx = parent->GetChildCount();
-    m_name = wxString::Format(_(L("Layer %s")), label_range);
-    m_bmp = create_scaled_bitmap(nullptr, "row.png");    // FIXME: pass window ptr
+//     m_name = wxString::Format(_(L("Layer %s (mm)")), label_range);
+    m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")";
+    m_bmp = create_scaled_bitmap(nullptr, "layers_white");    // FIXME: pass window ptr
 
 #ifdef __WXGTK__
     // it's necessary on GTK because of control have to know if this item will be container

From 38641ef5784f8607f6be77e3242970684fed3810 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 31 May 2019 10:54:52 +0200
Subject: [PATCH 08/34] ObjectLayers::del_layer_range() -> delete a layers
 range using "Del" button from ObjectLayers sizer

---
 src/slic3r/GUI/GUI_ObjectLayers.cpp | 61 ++++++++++++-----------------
 src/slic3r/GUI/GUI_ObjectLayers.hpp |  2 -
 src/slic3r/GUI/GUI_ObjectList.cpp   | 35 ++++++++++++++++-
 src/slic3r/GUI/GUI_ObjectList.hpp   |  2 +
 src/slic3r/GUI/wxExtensions.cpp     | 25 +++++++++---
 src/slic3r/GUI/wxExtensions.hpp     |  3 ++
 6 files changed, 84 insertions(+), 44 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
index 191a65386..5ff650e86 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.cpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -16,8 +16,6 @@ namespace Slic3r
 namespace GUI
 {
 
-typedef std::map<t_layer_height_range, coordf_t> t_layer_height_ranges;
-
 #define field_width 8
 
 ObjectLayers::ObjectLayers(wxWindow* parent) :
@@ -76,42 +74,32 @@ static Line create_new_layer(const t_layer_height_ranges::value_type& layer)
 
 void ObjectLayers::create_layers_list()
 {
-    auto create_btns = [this](wxWindow* parent) {
-        auto sizer = new wxBoxSizer(wxHORIZONTAL);
-
-        auto del_btn = new ScalableButton(parent, wxID_ANY, m_bmp_delete);
-        del_btn->SetToolTip(_(L("Remove layer")));
-
-        sizer->Add(del_btn, 0, wxRIGHT, em_unit(parent));
-
-        del_btn->Bind(wxEVT_BUTTON, [this](wxEvent &event) {
-            del_layer();
-//             wxTheApp->CallAfter([this]() {
-//                 wxWindowUpdateLocker noUpdates(m_parent);
-//                 update_layers_list(); 
-//                 m_parent->Layout();
-//             });
-        });
-
-        auto add_btn = new ScalableButton(parent, wxID_ANY, m_bmp_add);
-        add_btn->SetToolTip(_(L("Add layer")));
-
-        sizer->Add(add_btn, 0, wxRIGHT, em_unit(parent));
-
-        add_btn->Bind(wxEVT_BUTTON, [this](wxEvent &event) {
-            add_layer();
-//         wxTheApp->CallAfter([this]() {
-//             wxWindowUpdateLocker noUpdates(m_parent);
-//             update_layers_list(); 
-//             m_parent->Layout();
-//         });
-        });
-
-        return sizer;
-    };
-
     for (const auto layer : m_object->layer_height_ranges)
     {
+        auto create_btns = [this, layer](wxWindow* parent) {
+            auto sizer = new wxBoxSizer(wxHORIZONTAL);
+
+            auto del_btn = new ScalableButton(parent, wxID_ANY, m_bmp_delete);
+            del_btn->SetToolTip(_(L("Remove layer")));
+
+            sizer->Add(del_btn, 0, wxRIGHT, em_unit(parent));
+
+            del_btn->Bind(wxEVT_BUTTON, [this, layer](wxEvent &event) {
+                wxGetApp().obj_list()->del_layer_range(layer.first);
+            });
+
+            auto add_btn = new ScalableButton(parent, wxID_ANY, m_bmp_add);
+            add_btn->SetToolTip(_(L("Add layer")));
+
+            sizer->Add(add_btn, 0, wxRIGHT, em_unit(parent));
+
+            add_btn->Bind(wxEVT_BUTTON, [this, layer](wxEvent &event) {
+                wxGetApp().obj_list()->add_layer_range(layer.first);
+            });
+
+            return sizer;
+        };
+
         Line line = create_new_layer(layer);
         line.append_widget(create_btns);
         m_og->append_line(line);
@@ -122,6 +110,7 @@ void ObjectLayers::create_layer(int id)
 {
     t_layer_height_ranges::iterator layer_range = m_object->layer_height_ranges.begin();
 
+    // May be not a best solution #ys_FIXME
     while (id > 0 && layer_range != m_object->layer_height_ranges.end()) {
         layer_range++;
         id--;
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index b9e9efb14..0b209d523 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -27,8 +27,6 @@ public:
     void        create_layers_list();
     void        create_layer(int id);
     void        update_layers_list();
-    void        add_layer() {};
-    void        del_layer() {};
 
     void        UpdateAndShow(const bool show) override;
     void        msw_rescale();
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 8043ee565..cb815fc72 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1812,7 +1812,7 @@ void ObjectList::layers_editing()
 
     wxDataViewItem obj_item = m_objects_model->GetTopParent(item);
 
-    wxDataViewItem layers_item = m_objects_model->GetItemByType(obj_item, itLayerRoot);
+    wxDataViewItem layers_item = m_objects_model->GetLayerRootItem(obj_item);
     if (!layers_item.IsOk())
     {
         // --->>>--- Just for testing
@@ -2202,6 +2202,39 @@ void ObjectList::remove()
     }
 }
 
+void ObjectList::del_layer_range(const std::pair<coordf_t, coordf_t>& range)
+{
+    const int obj_idx = get_selected_obj_idx();
+    if (obj_idx < 0) return;
+
+    t_layer_height_ranges& ranges = object(obj_idx)->layer_height_ranges;
+
+    wxDataViewItem selectable_item = GetSelection();
+    int layer_idx = 0;
+
+    if (ranges.size() == 1)
+        selectable_item = m_objects_model->GetParent(selectable_item);
+    else {
+        // May be not a best solution #ys_FIXME
+        t_layer_height_ranges::iterator layer_selected = ranges.find(range);
+        t_layer_height_ranges::iterator it = ranges.begin();
+        while (it != layer_selected) {
+            it++;
+            layer_idx++;
+        }
+    }
+
+    wxDataViewItem layer_item = m_objects_model->GetItemByLayerId(obj_idx, layer_idx);
+    del_subobject_item(layer_item);
+
+    select_item(selectable_item);
+}
+
+void ObjectList::add_layer_range(const std::pair<coordf_t, coordf_t>& range)
+{
+
+}
+
 void ObjectList::init_objects()
 {
     m_objects = wxGetApp().model_objects();
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 6963805e9..388369137 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -270,6 +270,8 @@ public:
 
     // Remove objects/sub-object from the list
     void remove();
+    void del_layer_range(const std::pair<coordf_t, coordf_t>& range);
+    void add_layer_range(const std::pair<coordf_t, coordf_t>& range);
 
     void init_objects();
     bool multiple_selection() const ;
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index 4511ab8ac..dbe19dff5 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -1098,25 +1098,35 @@ wxDataViewItem ObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volume_id
     return wxDataViewItem(0);
 }
 
-wxDataViewItem ObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx)
+wxDataViewItem ObjectDataViewModel::GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type)
 {
     if (obj_idx >= m_objects.size() || obj_idx < 0) {
         printf("Error! Out of objects range.\n");
         return wxDataViewItem(0);
     }
 
-    auto instances_item = GetInstanceRootItem(wxDataViewItem(m_objects[obj_idx]));
-    if (!instances_item)
+    auto item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), parent_type);
+    if (!item)
         return wxDataViewItem(0);
 
-    auto parent = (ObjectDataViewModelNode*)instances_item.GetID();;
+    auto parent = (ObjectDataViewModelNode*)item.GetID();;
     for (size_t i = 0; i < parent->GetChildCount(); i++)
-        if (parent->GetNthChild(i)->m_idx == inst_idx)
+        if (parent->GetNthChild(i)->m_idx == sub_obj_idx)
             return wxDataViewItem(parent->GetNthChild(i));
 
     return wxDataViewItem(0);
 }
 
+wxDataViewItem ObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx)
+{
+    return GetItemById(obj_idx, inst_idx, itInstanceRoot);
+}
+
+wxDataViewItem ObjectDataViewModel::GetItemByLayerId(int obj_idx, int layer_idx)
+{
+    return GetItemById(obj_idx, layer_idx, itLayerRoot);
+}
+
 int ObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) const
 {
 	wxASSERT(item.IsOk());
@@ -1447,6 +1457,11 @@ wxDataViewItem ObjectDataViewModel::GetInstanceRootItem(const wxDataViewItem &it
     return GetItemByType(item, itInstanceRoot);
 }
 
+wxDataViewItem ObjectDataViewModel::GetLayerRootItem(const wxDataViewItem &item) const
+{
+    return GetItemByType(item, itLayerRoot);
+}
+
 bool ObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const
 {
     if (!item.IsOk())
diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp
index b3d8ebc18..23150a915 100644
--- a/src/slic3r/GUI/wxExtensions.hpp
+++ b/src/slic3r/GUI/wxExtensions.hpp
@@ -404,8 +404,10 @@ public:
     void DeleteVolumeChildren(wxDataViewItem& parent);
     void DeleteSettings(const wxDataViewItem& parent);
 	wxDataViewItem GetItemById(int obj_idx);
+    wxDataViewItem GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type);
 	wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx);
 	wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx);
+    wxDataViewItem GetItemByLayerId(int obj_idx, int layer_idx);
 	int  GetIdByItem(const wxDataViewItem& item) const;
     int  GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
     int  GetObjectIdByItem(const wxDataViewItem& item) const;
@@ -460,6 +462,7 @@ public:
                                     ItemType type) const;
     wxDataViewItem  GetSettingsItem(const wxDataViewItem &item) const;
     wxDataViewItem  GetInstanceRootItem(const wxDataViewItem &item) const;
+    wxDataViewItem  GetLayerRootItem(const wxDataViewItem &item) const;
     bool    IsSettingsItem(const wxDataViewItem &item) const;
     void    UpdateSettingsDigest(   const wxDataViewItem &item, 
                                     const std::vector<std::string>& categories);

From 5f4b7a5292dce6c5e531de06d850006b81f3214c Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 31 May 2019 15:29:09 +0200
Subject: [PATCH 09/34] ObjectLayers::add_layer_range() -> add a layers range
 using "Add" button from ObjectLayers sizer

---
 src/slic3r/GUI/GUI_ObjectList.cpp | 101 ++++++++++++++++++++++++++----
 src/slic3r/GUI/GUI_ObjectList.hpp |   4 ++
 src/slic3r/GUI/wxExtensions.cpp   |  25 ++++++--
 src/slic3r/GUI/wxExtensions.hpp   |   8 ++-
 4 files changed, 116 insertions(+), 22 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index cb815fc72..88d7df6cc 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1810,27 +1810,26 @@ void ObjectList::layers_editing()
     if (!item || obj_idx < 0)
         return;
 
-    wxDataViewItem obj_item = m_objects_model->GetTopParent(item);
-
+    const wxDataViewItem obj_item = m_objects_model->GetTopParent(item);
     wxDataViewItem layers_item = m_objects_model->GetLayerRootItem(obj_item);
+
+    // if it doesn't exist now
     if (!layers_item.IsOk())
     {
-        // --->>>--- Just for testing
-        object(obj_idx)->layer_height_ranges[{ 0.0f, 0.2f }] = 0.1f;
-        object(obj_idx)->layer_height_ranges[{ 0.2f, 0.4f }] = 0.05f;
-        object(obj_idx)->layer_height_ranges[{ 0.4f, 0.6f }] = 0.2f;
-        // ---<<<--- Just for testing
-
+        // create LayerRoor item
         layers_item = m_objects_model->AddLayersRoot(obj_item);
+        
+        if (object(obj_idx)->layer_height_ranges.empty())
+            object(obj_idx)->layer_height_ranges[{ 0.0f, 0.2f }] = 0.1f;// some default value
 
+        // and create Layer item(s) according to the layer_height_ranges
         for (const auto range : object(obj_idx)->layer_height_ranges)
-        {
-            const std::string label = (boost::format(" %.2f-%.2f ") % range.first.first % range.first.second).str();
-            m_objects_model->AddLayersChild(layers_item, label);
-        }
+            add_layer_item(range.first, layers_item);
     }
 
+    // select LayerRoor item and expand
     select_item(layers_item);
+    Expand(layers_item);
 }
 
 bool ObjectList::get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume)
@@ -2230,7 +2229,83 @@ void ObjectList::del_layer_range(const std::pair<coordf_t, coordf_t>& range)
     select_item(selectable_item);
 }
 
-void ObjectList::add_layer_range(const std::pair<coordf_t, coordf_t>& range)
+void ObjectList::add_layer_range(const t_layer_height_range& range)
+{
+    const int obj_idx = get_selected_obj_idx();
+    if (obj_idx < 0) return;
+
+    wxDataViewItem layers_item = GetSelection();
+
+    t_layer_height_ranges& ranges = object(obj_idx)->layer_height_ranges;
+
+    const t_layer_height_ranges::iterator selected_range = ranges.find(range);
+    const t_layer_height_ranges::iterator last_range = --ranges.end();   
+    
+    if (selected_range->first == last_range->first)
+    {
+        const t_layer_height_range new_range = { last_range->first.second, last_range->first.second + 0.2f };
+        ranges[new_range] = last_range->second;
+        add_layer_item(new_range, layers_item);
+    }
+    else
+    {
+        int layer_idx = 0;
+        t_layer_height_ranges::iterator next_range = ++ranges.find(range);
+
+        // May be not a best solution #ys_FIXME
+        t_layer_height_ranges::iterator it = ranges.begin();
+        while (it != next_range && it != ranges.end()) {
+            layer_idx++;
+            it++;
+        }
+
+        if (selected_range->first.second == next_range->first.first)
+        {
+            const coordf_t delta = (next_range->first.second - next_range->first.first);
+            if (delta < 0.05f) // next range devision has no mean 
+                return; 
+
+            const coordf_t midl_layer = next_range->first.first + 0.5f * delta;
+            const coordf_t old_height = next_range->second;
+            t_layer_height_range new_range = { midl_layer, next_range->first.second };
+
+            // delete old layer
+
+            wxDataViewItem layer_item = m_objects_model->GetItemByLayerId(obj_idx, layer_idx);
+            del_subobject_item(layer_item);
+
+            // create new 2 layers instead of deleted one
+
+            ranges[new_range] = old_height;
+            add_layer_item(new_range, layers_item, layer_idx);
+
+            new_range = { selected_range->first.second, midl_layer };
+            ranges[new_range] = selected_range->second;            
+            add_layer_item(new_range, layers_item, layer_idx);
+        }
+        else
+        {
+            const t_layer_height_range new_range = { selected_range->first.second, next_range->first.first };
+            ranges[new_range] = selected_range->second;
+            add_layer_item(new_range, layers_item, layer_idx);
+        }        
+    }
+
+    changed_object(obj_idx);
+
+    // select item to update layers sizer
+    select_item(layers_item);
+}
+
+void ObjectList::add_layer_item(const t_layer_height_range& range, 
+                                const wxDataViewItem layers_item, 
+                                const int layer_idx /* = -1*/)
+{
+    const std::string label = (boost::format(" %.2f-%.2f ") % range.first % range.second).str();
+    m_objects_model->AddLayersChild(layers_item, label, layer_idx);
+}
+
+void ObjectList::edit_layer_range(const std::pair<coordf_t, coordf_t>& range)
 {
 
 }
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 388369137..15cddd318 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -272,6 +272,10 @@ public:
     void remove();
     void del_layer_range(const std::pair<coordf_t, coordf_t>& range);
     void add_layer_range(const std::pair<coordf_t, coordf_t>& range);
+    void add_layer_item (const std::pair<coordf_t, coordf_t>& range, 
+                         const wxDataViewItem layers_item, 
+                         const int layer_idx = -1);
+    void edit_layer_range(const std::pair<coordf_t, coordf_t>& range);
 
     void init_objects();
     bool multiple_selection() const ;
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index dbe19dff5..adc2e6d07 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -465,14 +465,22 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
 
 ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, 
                                                  const wxString& label_range, 
-                                                 const wxString& extruder, 
-                                                 const int idx /*= -1 */) :
+                                                 const int idx /*= -1 */, 
+                                                 const wxString& extruder) :
     m_parent(parent),
     m_type(itLayer),
     m_idx(idx),
     m_extruder(extruder)
 {
-    m_idx = parent->GetChildCount();
+    const int children_cnt = parent->GetChildCount();
+    if (idx < 0)
+        m_idx = children_cnt;
+    else
+    {
+        // update indexes for another Laeyr Nodes
+        for (int i = m_idx; i < children_cnt; i++)
+            parent->GetNthChild(i)->SetIdx(i + 1);
+    }
 //     m_name = wxString::Format(_(L("Layer %s (mm)")), label_range);
     m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")";
     m_bmp = create_scaled_bitmap(nullptr, "layers_white");    // FIXME: pass window ptr
@@ -742,7 +750,9 @@ wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_i
     return layer_root_item;
 }
 
-wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item, const std::string& label_range)
+wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item, 
+                                                   const std::string& label_range, 
+                                                   const int index /* = -1*/)
 {
     ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
     if (!parent_node) return wxDataViewItem(0);
@@ -763,8 +773,11 @@ wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_
     }
 
     // Add layer node
-    ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, label_range);
-    layer_root_node->Append(layer_node);
+    ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, label_range, index);
+    if (index < 0)
+        layer_root_node->Append(layer_node);
+    else
+        layer_root_node->Insert(layer_node, index);
 
     // notify control
     const wxDataViewItem layer_item((void*)layer_node);
diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp
index 23150a915..775d89a3b 100644
--- a/src/slic3r/GUI/wxExtensions.hpp
+++ b/src/slic3r/GUI/wxExtensions.hpp
@@ -233,8 +233,8 @@ public:
 
 	ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
 							const wxString& label_range,
-                            const wxString& extruder = wxEmptyString,
-                            const int idx = -1 );
+                            const int idx = -1,
+                            const wxString& extruder = wxEmptyString );
 
     ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type);
 
@@ -396,7 +396,9 @@ public:
     wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
     wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
     wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
-    wxDataViewItem AddLayersChild(const wxDataViewItem &parent_item, const std::string& label_range);
+    wxDataViewItem AddLayersChild(  const wxDataViewItem &parent_item, 
+                                    const std::string& label_range, 
+                                    const int index = -1);
 	wxDataViewItem Delete(const wxDataViewItem &item);
 	wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
 	void DeleteAll();

From e09207e27e28d37e1873fe4f1c63bbbad3faf6d5 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 31 May 2019 15:36:38 +0200
Subject: [PATCH 10/34] Fixed OSX and Linux build

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

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 88d7df6cc..d9e1e8e82 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -2189,8 +2189,11 @@ void ObjectList::remove()
                     select_item(parent);
                     parent = wxDataViewItem(0);
                 }
-                else if (m_objects_model->GetChildren(parent, wxDataViewItemArray()) == 1)
-                    parent = m_objects_model->GetTopParent(item);
+                else {
+                    wxDataViewItemArray children;
+                    if (m_objects_model->GetChildren(parent, children) == 1)
+                        parent = m_objects_model->GetTopParent(item);
+                }
             }
             
             del_subobject_item(item);

From 51b18fddeb1b22310171e27b8e606cc0d621f17d Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 3 Jun 2019 15:35:21 +0200
Subject: [PATCH 11/34] Changed data types

---
 src/libslic3r/Model.hpp             |  2 ++
 src/libslic3r/Slicing.hpp           |  3 ++
 src/slic3r/GUI/GUI_ObjectLayers.cpp | 37 ++++++++++++++----------
 src/slic3r/GUI/GUI_ObjectLayers.hpp |  1 +
 src/slic3r/GUI/GUI_ObjectList.cpp   | 45 ++++++++++++++++-------------
 src/slic3r/GUI/GUI_ObjectList.hpp   |  1 +
 6 files changed, 54 insertions(+), 35 deletions(-)

diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp
index 41bf5bd4b..d3066f33f 100644
--- a/src/libslic3r/Model.hpp
+++ b/src/libslic3r/Model.hpp
@@ -179,6 +179,8 @@ public:
     DynamicPrintConfig      config;
     // Variation of a layer thickness for spans of Z coordinates.
     t_layer_height_ranges   layer_height_ranges;
+    // Variation of a layer thickness for spans of Z coordinates.
+    t_layer_config_ranges         layer_config_ranges;
     // Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
     // The pairs of <z, layer_height> are packed into a 1D array.
     std::vector<coordf_t>   layer_height_profile;
diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp
index fa5a12f9c..c3278dc0d 100644
--- a/src/libslic3r/Slicing.hpp
+++ b/src/libslic3r/Slicing.hpp
@@ -11,6 +11,8 @@
 
 #include "libslic3r.h"
 #include "Utils.hpp"
+#include "PrintConfig.hpp"
+
 namespace Slic3r
 {
 
@@ -129,6 +131,7 @@ inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters
 
 typedef std::pair<coordf_t,coordf_t> t_layer_height_range;
 typedef std::map<t_layer_height_range,coordf_t> t_layer_height_ranges;
+typedef std::map<t_layer_height_range, DynamicPrintConfig> t_layer_config_ranges;
 
 extern std::vector<coordf_t> layer_height_profile_from_ranges(
     const SlicingParameters     &slicing_params,
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
index 5ff650e86..8dae64f3c 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.cpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -23,6 +23,8 @@ ObjectLayers::ObjectLayers(wxWindow* parent) :
 {
     m_og->label_width = 1;
     m_og->set_grid_vgap(5);
+
+    m_og->m_on_change = std::bind(&ObjectLayers::on_change, this, std::placeholders::_1, std::placeholders::_2);
     
     // Legend for object layers
     Line line = Line{ "", "" };
@@ -33,9 +35,9 @@ ObjectLayers::ObjectLayers(wxWindow* parent) :
     def.type = coString;
     def.width = field_width;
 
-    for (const std::string axis : { "Min Z", "Max Z", "Layer height" }) {
-        def.set_default_value(new ConfigOptionString{ axis });
-        std::string label = boost::algorithm::replace_all_copy(axis, " ", "_");
+    for (const std::string col : { "Min Z", "Max Z", "Layer height" }) {
+        def.set_default_value(new ConfigOptionString{ col });
+        std::string label = boost::algorithm::replace_all_copy(col, " ", "_");
         boost::algorithm::to_lower(label);
         line.append_option(Option(def, label + "_legend"));
 
@@ -48,7 +50,7 @@ ObjectLayers::ObjectLayers(wxWindow* parent) :
     m_bmp_add       = ScalableBitmap(parent, "add_copies");
 }
 
-static Line create_new_layer(const t_layer_height_ranges::value_type& layer)
+static Line create_new_layer(const t_layer_config_ranges::value_type& layer, const int idx)
 {
     Line line = Line{ "", "" };
     ConfigOptionDef def;
@@ -57,16 +59,16 @@ static Line create_new_layer(const t_layer_height_ranges::value_type& layer)
     def.type = coFloat;
     def.width = field_width;
 
-    std::string label = (boost::format("min_z_%.2f") % layer.first.first).str();
+    std::string label = (boost::format("min_z_%d") % idx).str();
     def.set_default_value(new ConfigOptionFloat(layer.first.first));
     line.append_option(Option(def, label));
 
-    label = (boost::format("max_z_%.2f") % layer.first.second).str();
+    label = (boost::format("max_z_%d") % idx).str();
     def.set_default_value(new ConfigOptionFloat(layer.first.second));
     line.append_option(Option(def, label));
 
-    label = (boost::format("layer_height_%.2f_%.2f") % layer.first.first % layer.first.second).str();
-    def.set_default_value(new ConfigOptionFloat(layer.second));
+    label = (boost::format("layer_height_%d") % idx).str();
+    def.set_default_value(new ConfigOptionFloat(layer.second.option("layer_height")->getFloat()));
     line.append_option(Option(def, label));
 
     return line;
@@ -74,7 +76,7 @@ static Line create_new_layer(const t_layer_height_ranges::value_type& layer)
 
 void ObjectLayers::create_layers_list()
 {
-    for (const auto layer : m_object->layer_height_ranges)
+    for (const auto layer : m_object->layer_config_ranges)
     {
         auto create_btns = [this, layer](wxWindow* parent) {
             auto sizer = new wxBoxSizer(wxHORIZONTAL);
@@ -100,7 +102,7 @@ void ObjectLayers::create_layers_list()
             return sizer;
         };
 
-        Line line = create_new_layer(layer);
+        Line line = create_new_layer(layer, m_og->get_grid_sizer()->GetEffectiveRowsCount()-1);
         line.append_widget(create_btns);
         m_og->append_line(line);
     }
@@ -108,15 +110,15 @@ void ObjectLayers::create_layers_list()
 
 void ObjectLayers::create_layer(int id)
 {
-    t_layer_height_ranges::iterator layer_range = m_object->layer_height_ranges.begin();
+    t_layer_config_ranges::iterator layer_range = m_object->layer_config_ranges.begin();
 
     // May be not a best solution #ys_FIXME
-    while (id > 0 && layer_range != m_object->layer_height_ranges.end()) {
-        layer_range++;
+    while (id > 0 && layer_range != m_object->layer_config_ranges.end()) {
+        ++layer_range;
         id--;
     }
         
-    m_og->append_line(create_new_layer(*layer_range));
+    m_og->append_line(create_new_layer(*layer_range, m_og->get_grid_sizer()->GetEffectiveRowsCount()-1));
 }
 
 void ObjectLayers::update_layers_list()
@@ -134,7 +136,7 @@ void ObjectLayers::update_layers_list()
     if (!(type & (itLayerRoot | itLayer))) return;
 
     m_object = objects_ctrl->object(obj_idx);
-    if (!m_object || m_object->layer_height_ranges.empty()) return;
+    if (!m_object || m_object->layer_config_ranges.empty()) return;
 
     // Delete all controls from options group except of the legends
 
@@ -175,5 +177,10 @@ void ObjectLayers::msw_rescale()
     m_bmp_add.msw_rescale();
 }
 
+void ObjectLayers::on_change(t_config_option_key opt_key, const boost::any& value)
+{
+
+}
+
 } //namespace GUI
 } //namespace Slic3r 
\ No newline at end of file
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index 0b209d523..6280a7554 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -30,6 +30,7 @@ public:
 
     void        UpdateAndShow(const bool show) override;
     void        msw_rescale();
+    void        on_change(t_config_option_key opt_key, const boost::any& value);
 };
 
 }}
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index d9e1e8e82..9b826f5d8 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -700,10 +700,11 @@ void ObjectList::show_context_menu()
     if (item)
     {
         const ItemType type = m_objects_model->GetItemType(item);
-        if (!(type & (itObject | itVolume | itInstance)))
+        if (!(type & (itObject | itVolume | itLayer | itInstance)))
             return;
 
         wxMenu* menu = type & itInstance ? &m_menu_instance :
+                       type & itLayer ? &m_menu_layer :
                        m_objects_model->GetParent(item) != wxDataViewItem(0) ? &m_menu_part :
                        printer_technology() == ptFFF ? &m_menu_object : &m_menu_sla_object;
 
@@ -1694,7 +1695,7 @@ void ObjectList::del_instances_from_object(const int obj_idx)
 
 void ObjectList::del_layers_from_object(const int obj_idx)
 {
-    object(obj_idx)->layer_height_ranges.clear(); // ? #ys_FIXME
+    object(obj_idx)->layer_config_ranges.clear();
 
     changed_object(obj_idx);
 }
@@ -1739,13 +1740,13 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con
         object->delete_instance(idx);
     }
     else if (type == itLayer) {
-        t_layer_height_ranges::iterator layer_range = object->layer_height_ranges.begin();
+        t_layer_config_ranges::iterator layer_range = object->layer_config_ranges.begin();
         int id = idx;
-        while (id > 0 && layer_range != object->layer_height_ranges.end()) {
+        while (id > 0 && layer_range != object->layer_config_ranges.end()) {
             layer_range++;
             id--;
         }
-        object->layer_height_ranges.erase(layer_range);
+        object->layer_config_ranges.erase(layer_range);
     }
     else
         return false;
@@ -1816,14 +1817,16 @@ void ObjectList::layers_editing()
     // if it doesn't exist now
     if (!layers_item.IsOk())
     {
-        // create LayerRoor item
+        // create LayerRoot item
         layers_item = m_objects_model->AddLayersRoot(obj_item);
-        
-        if (object(obj_idx)->layer_height_ranges.empty())
-            object(obj_idx)->layer_height_ranges[{ 0.0f, 0.2f }] = 0.1f;// some default value
 
-        // and create Layer item(s) according to the layer_height_ranges
-        for (const auto range : object(obj_idx)->layer_height_ranges)
+        t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
+        
+        if (ranges.empty())
+            ranges[{ 0.0f, 0.2f }] = *DynamicPrintConfig::new_from_defaults_keys({"layer_height"});// some default value
+
+        // and create Layer item(s) according to the layer_config_ranges
+        for (const auto range : ranges)
             add_layer_item(range.first, layers_item);
     }
 
@@ -2239,10 +2242,10 @@ void ObjectList::add_layer_range(const t_layer_height_range& range)
 
     wxDataViewItem layers_item = GetSelection();
 
-    t_layer_height_ranges& ranges = object(obj_idx)->layer_height_ranges;
+    t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
 
-    const t_layer_height_ranges::iterator selected_range = ranges.find(range);
-    const t_layer_height_ranges::iterator last_range = --ranges.end();   
+    const t_layer_config_ranges::iterator selected_range = ranges.find(range);
+    const t_layer_config_ranges::iterator last_range = --ranges.end();   
     
     if (selected_range->first == last_range->first)
     {
@@ -2253,13 +2256,13 @@ void ObjectList::add_layer_range(const t_layer_height_range& range)
     else
     {
         int layer_idx = 0;
-        t_layer_height_ranges::iterator next_range = ++ranges.find(range);
+        t_layer_config_ranges::iterator next_range = ++ranges.find(range);
 
         // May be not a best solution #ys_FIXME
-        t_layer_height_ranges::iterator it = ranges.begin();
+        t_layer_config_ranges::iterator it = ranges.begin();
         while (it != next_range && it != ranges.end()) {
             layer_idx++;
-            it++;
+            ++it;
         }
 
         if (selected_range->first.second == next_range->first.first)
@@ -2269,7 +2272,8 @@ void ObjectList::add_layer_range(const t_layer_height_range& range)
                 return; 
 
             const coordf_t midl_layer = next_range->first.first + 0.5f * delta;
-            const coordf_t old_height = next_range->second;
+            // #ys_FIXME  May be it should be copied just a "layer_height" option
+            const /*coordf_t*/auto old_config = next_range->second;
             t_layer_height_range new_range = { midl_layer, next_range->first.second };
 
             // delete old layer
@@ -2279,7 +2283,7 @@ void ObjectList::add_layer_range(const t_layer_height_range& range)
 
             // create new 2 layers instead of deleted one
 
-            ranges[new_range] = old_height;
+            ranges[new_range] = old_config;
             add_layer_item(new_range, layers_item, layer_idx);
 
             new_range = { selected_range->first.second, midl_layer };
@@ -2996,7 +3000,8 @@ void ObjectList::msw_rescale()
     for (MenuWithSeparators* menu : { &m_menu_object, 
                                       &m_menu_part, 
                                       &m_menu_sla_object, 
-                                      &m_menu_instance })
+                                      &m_menu_instance, 
+                                      &m_menu_layer })
         msw_rescale_menu(menu);
 
     Layout();
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 15cddd318..5b4fd4c49 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -119,6 +119,7 @@ class ObjectList : public wxDataViewCtrl
     MenuWithSeparators  m_menu_part;
     MenuWithSeparators  m_menu_sla_object;
     MenuWithSeparators  m_menu_instance;
+    MenuWithSeparators  m_menu_layer;
     wxMenuItem* m_menu_item_settings { nullptr };
     wxMenuItem* m_menu_item_split_instances { nullptr };
 

From 79a89c4c8fd5b09374ba981fea7c3a3da6711236 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 4 Jun 2019 11:51:25 +0200
Subject: [PATCH 12/34] Some code review for avoid use of OptionsGroup

---
 src/slic3r/GUI/GUI_ObjectLayers.cpp | 145 ++++++++++++++--------------
 src/slic3r/GUI/GUI_ObjectLayers.hpp |   6 +-
 2 files changed, 77 insertions(+), 74 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
index 8dae64f3c..1bd57e0d8 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.cpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -21,90 +21,100 @@ namespace GUI
 ObjectLayers::ObjectLayers(wxWindow* parent) :
     OG_Settings(parent, true)
 {
-    m_og->label_width = 1;
-    m_og->set_grid_vgap(5);
+    m_grid_sizer = new wxFlexGridSizer(3, 5, 5); // "Min Z", "Max Z", "Layer height" & buttons sizer
+    m_grid_sizer->SetFlexibleDirection(wxHORIZONTAL);
 
-    m_og->m_on_change = std::bind(&ObjectLayers::on_change, this, std::placeholders::_1, std::placeholders::_2);
-    
     // Legend for object layers
-    Line line = Line{ "", "" };
-
-    ConfigOptionDef def;
-    def.label = "";
-    def.gui_type = "legend";
-    def.type = coString;
-    def.width = field_width;
-
     for (const std::string col : { "Min Z", "Max Z", "Layer height" }) {
-        def.set_default_value(new ConfigOptionString{ col });
-        std::string label = boost::algorithm::replace_all_copy(col, " ", "_");
-        boost::algorithm::to_lower(label);
-        line.append_option(Option(def, label + "_legend"));
+        auto temp = new wxStaticText(m_parent, wxID_ANY, _(L(col)), wxDefaultPosition, /*size*/wxDefaultSize, wxST_ELLIPSIZE_MIDDLE);
+        temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
+        temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
+        temp->SetFont(wxGetApp().bold_font());
 
-        m_legends.push_back(label + "_legend");
+        m_grid_sizer->Add(temp);
     }
 
-    m_og->append_line(line);
+    m_og->sizer->Clear(true);
+    m_og->sizer->Add(m_grid_sizer, 0, wxEXPAND | wxALL, wxOSX ? 0 : 5);
 
     m_bmp_delete    = ScalableBitmap(parent, "remove_copies"/*"cross"*/);
     m_bmp_add       = ScalableBitmap(parent, "add_copies");
 }
 
-static Line create_new_layer(const t_layer_config_ranges::value_type& layer, const int idx)
+wxSizer* ObjectLayers::create_layer_without_buttons(const t_layer_config_ranges::value_type& layer)
 {
-    Line line = Line{ "", "" };
-    ConfigOptionDef def;
-    def.label = "";
-    def.gui_type = "";
-    def.type = coFloat;
-    def.width = field_width;
+    auto size = wxSize(field_width * em_unit(m_parent), wxDefaultCoord);
 
-    std::string label = (boost::format("min_z_%d") % idx).str();
-    def.set_default_value(new ConfigOptionFloat(layer.first.first));
-    line.append_option(Option(def, label));
+    // Add control for the "Min Z"
+    wxString text_value = double_to_string(layer.first.first);
+    auto temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, wxTE_PROCESS_ENTER);
+    temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
 
-    label = (boost::format("max_z_%d") % idx).str();
-    def.set_default_value(new ConfigOptionFloat(layer.first.second));
-    line.append_option(Option(def, label));
+    temp->Bind(wxEVT_TEXT_ENTER, ([this, temp](wxEvent& e)
+    {
 
-    label = (boost::format("layer_height_%d") % idx).str();
-    def.set_default_value(new ConfigOptionFloat(layer.second.option("layer_height")->getFloat()));
-    line.append_option(Option(def, label));
+    }), temp->GetId());
 
-    return line;
+    temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent& e)
+    {
+
+    }), temp->GetId());
+
+
+    temp->Bind(wxEVT_CHAR, ([temp](wxKeyEvent& event)
+    {
+        // select all text using Ctrl+A
+        if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL))
+            temp->SetSelection(-1, -1); //select all
+        event.Skip();
+    }));
+
+    m_grid_sizer->Add(temp);
+
+    // Add control for the "Max Z"
+    text_value = double_to_string(layer.first.second);
+    temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, wxTE_PROCESS_ENTER);
+    temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
+    
+    m_grid_sizer->Add(temp);
+
+    // Add control for the "Layer height"
+    auto sizer = new wxBoxSizer(wxHORIZONTAL); 
+
+    text_value = double_to_string(layer.second.option("layer_height")->getFloat());
+    temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, wxTE_PROCESS_ENTER);
+    temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
+    sizer->Add(temp);
+
+    m_grid_sizer->Add(sizer);
+
+    return sizer;
 }
 
 void ObjectLayers::create_layers_list()
 {
     for (const auto layer : m_object->layer_config_ranges)
     {
-        auto create_btns = [this, layer](wxWindow* parent) {
-            auto sizer = new wxBoxSizer(wxHORIZONTAL);
+        auto sizer = create_layer_without_buttons(layer);
 
-            auto del_btn = new ScalableButton(parent, wxID_ANY, m_bmp_delete);
-            del_btn->SetToolTip(_(L("Remove layer")));
+        wxWindow* parent = m_parent;
+        auto del_btn = new ScalableButton(parent, wxID_ANY, m_bmp_delete);
+        del_btn->SetToolTip(_(L("Remove layer")));
 
-            sizer->Add(del_btn, 0, wxRIGHT, em_unit(parent));
+        sizer->Add(del_btn, 0, wxRIGHT | wxLEFT, em_unit(parent));
 
-            del_btn->Bind(wxEVT_BUTTON, [this, layer](wxEvent &event) {
-                wxGetApp().obj_list()->del_layer_range(layer.first);
-            });
+        del_btn->Bind(wxEVT_BUTTON, [this, layer](wxEvent &event) {
+            wxGetApp().obj_list()->del_layer_range(layer.first);
+        });
 
-            auto add_btn = new ScalableButton(parent, wxID_ANY, m_bmp_add);
-            add_btn->SetToolTip(_(L("Add layer")));
+        auto add_btn = new ScalableButton(parent, wxID_ANY, m_bmp_add);
+        add_btn->SetToolTip(_(L("Add layer")));
 
-            sizer->Add(add_btn, 0, wxRIGHT, em_unit(parent));
+        sizer->Add(add_btn, 0, wxRIGHT, em_unit(parent));
 
-            add_btn->Bind(wxEVT_BUTTON, [this, layer](wxEvent &event) {
-                wxGetApp().obj_list()->add_layer_range(layer.first);
-            });
-
-            return sizer;
-        };
-
-        Line line = create_new_layer(layer, m_og->get_grid_sizer()->GetEffectiveRowsCount()-1);
-        line.append_widget(create_btns);
-        m_og->append_line(line);
+        add_btn->Bind(wxEVT_BUTTON, [this, layer](wxEvent &event) {
+            wxGetApp().obj_list()->add_layer_range(layer.first);
+        });
     }
 }
 
@@ -117,8 +127,8 @@ void ObjectLayers::create_layer(int id)
         ++layer_range;
         id--;
     }
-        
-    m_og->append_line(create_new_layer(*layer_range, m_og->get_grid_sizer()->GetEffectiveRowsCount()-1));
+
+    create_layer_without_buttons(*layer_range);
 }
 
 void ObjectLayers::update_layers_list()
@@ -140,19 +150,17 @@ void ObjectLayers::update_layers_list()
 
     // Delete all controls from options group except of the legends
 
-    auto grid_sizer = m_og->get_grid_sizer();
-    const int cols = grid_sizer->GetEffectiveColsCount();
-    const int rows = grid_sizer->GetEffectiveRowsCount();
+    const int cols = m_grid_sizer->GetEffectiveColsCount();
+    const int rows = m_grid_sizer->GetEffectiveRowsCount();
     for (int idx = cols*rows-1; idx >= cols; idx--) {
-        wxSizerItem* t = grid_sizer->GetItem(idx);
+        wxSizerItem* t = m_grid_sizer->GetItem(idx);
         if (t->IsSizer())
             t->GetSizer()->Clear(true);
-            grid_sizer->Remove(idx);
+        else
+            t->DeleteWindows();
+        m_grid_sizer->Remove(idx);
     }
 
-    m_og->clear_fields_except_of(m_legends);
-
-
     // Add new control according to the selected item  
 
     if (type & itLayerRoot)
@@ -177,10 +185,5 @@ void ObjectLayers::msw_rescale()
     m_bmp_add.msw_rescale();
 }
 
-void ObjectLayers::on_change(t_config_option_key opt_key, const boost::any& value)
-{
-
-}
-
 } //namespace GUI
 } //namespace Slic3r 
\ No newline at end of file
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index 6280a7554..329452950 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -18,19 +18,19 @@ class ObjectLayers : public OG_Settings
     ScalableBitmap  m_bmp_add;
     ModelObject*    m_object {nullptr};
 
-    std::vector<std::string> m_legends;
+    wxFlexGridSizer*            m_grid_sizer;
 
 public:
     ObjectLayers(wxWindow* parent);
     ~ObjectLayers() {}
 
-    void        create_layers_list();
+    wxSizer*    create_layer_without_buttons(const std::map<std::pair<coordf_t, coordf_t>, DynamicPrintConfig>::value_type& layer);
     void        create_layer(int id);
+    void        create_layers_list();
     void        update_layers_list();
 
     void        UpdateAndShow(const bool show) override;
     void        msw_rescale();
-    void        on_change(t_config_option_key opt_key, const boost::any& value);
 };
 
 }}

From 475696167884ac80cf554b9dd6bad772facd3e8c Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 4 Jun 2019 15:22:29 +0200
Subject: [PATCH 13/34] Added LayerRangeEditor class for universally editing of
 the layer_range's parameters  + Implemented layer_height editing

---
 src/slic3r/GUI/GUI_ObjectLayers.cpp | 91 +++++++++++++++++++----------
 src/slic3r/GUI/GUI_ObjectLayers.hpp | 16 +++++
 src/slic3r/GUI/GUI_ObjectList.cpp   |  8 ++-
 src/slic3r/GUI/GUI_ObjectList.hpp   |  2 +-
 4 files changed, 85 insertions(+), 32 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
index 1bd57e0d8..bba39f76a 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.cpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -46,44 +46,21 @@ wxSizer* ObjectLayers::create_layer_without_buttons(const t_layer_config_ranges:
     auto size = wxSize(field_width * em_unit(m_parent), wxDefaultCoord);
 
     // Add control for the "Min Z"
-    wxString text_value = double_to_string(layer.first.first);
-    auto temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, wxTE_PROCESS_ENTER);
-    temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
-
-    temp->Bind(wxEVT_TEXT_ENTER, ([this, temp](wxEvent& e)
-    {
-
-    }), temp->GetId());
-
-    temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent& e)
-    {
-
-    }), temp->GetId());
-
-
-    temp->Bind(wxEVT_CHAR, ([temp](wxKeyEvent& event)
-    {
-        // select all text using Ctrl+A
-        if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL))
-            temp->SetSelection(-1, -1); //select all
-        event.Skip();
-    }));
-
+    auto temp = new LayerRangeEditor(m_parent, double_to_string(layer.first.first), size);
     m_grid_sizer->Add(temp);
 
     // Add control for the "Max Z"
-    text_value = double_to_string(layer.first.second);
-    temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, wxTE_PROCESS_ENTER);
-    temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
-    
+    temp = new LayerRangeEditor(m_parent, double_to_string(layer.first.second), size);    
     m_grid_sizer->Add(temp);
 
     // Add control for the "Layer height"
     auto sizer = new wxBoxSizer(wxHORIZONTAL); 
 
-    text_value = double_to_string(layer.second.option("layer_height")->getFloat());
-    temp = new wxTextCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size, wxTE_PROCESS_ENTER);
-    temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
+    const wxString text_value = double_to_string(layer.second.option("layer_height")->getFloat());
+
+    temp = new LayerRangeEditor(m_parent, text_value, size, [temp, layer](coordf_t layer_height) {
+        wxGetApp().obj_list()->edit_layer_range(layer.first, layer_height);
+    } );
     sizer->Add(temp);
 
     m_grid_sizer->Add(sizer);
@@ -185,5 +162,59 @@ void ObjectLayers::msw_rescale()
     m_bmp_add.msw_rescale();
 }
 
+LayerRangeEditor::LayerRangeEditor( wxWindow* parent,
+                                    const wxString& value,
+                                    const wxSize& size,
+                                    std::function<void(coordf_t)> edit_fn
+                                    ) :
+    wxTextCtrl(parent, wxID_ANY, value, wxDefaultPosition, size, wxTE_PROCESS_ENTER)
+{
+    this->SetFont(wxGetApp().normal_font());
+    
+    this->Bind(wxEVT_TEXT_ENTER, ([this, edit_fn](wxEvent& e)
+    {
+        edit_fn(get_value());
+        m_enter_pressed = true;
+    }), this->GetId());
+
+    this->Bind(wxEVT_KILL_FOCUS, ([this, edit_fn](wxEvent& e)
+    {
+        e.Skip();
+        if (!m_enter_pressed)
+            edit_fn(get_value());
+        m_enter_pressed = false;
+    }), this->GetId());
+
+
+    this->Bind(wxEVT_CHAR, ([this](wxKeyEvent& event)
+    {
+        // select all text using Ctrl+A
+        if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL))
+            this->SetSelection(-1, -1); //select all
+        event.Skip();
+    }));
+}
+
+coordf_t LayerRangeEditor::get_value()
+{
+    wxString str = GetValue();
+
+    coordf_t layer_height;
+    // Replace the first occurence of comma in decimal number.
+    str.Replace(",", ".", false);
+    if (str == ".")
+        layer_height = 0.0;
+    else
+    {
+        if (!str.ToCDouble(&layer_height) || layer_height < 0.0f)
+        {
+            show_error(m_parent, _(L("Invalid numeric input.")));
+            SetValue(double_to_string(layer_height));
+        }
+    }
+
+    return layer_height;
+}
+
 } //namespace GUI
 } //namespace Slic3r 
\ No newline at end of file
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index 329452950..3aa3cb967 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -12,6 +12,22 @@ class ModelObject;
 namespace GUI {
 class ConfigOptionsGroup;
 
+class LayerRangeEditor : public wxTextCtrl
+{
+    bool                m_enter_pressed { false };
+public:
+    LayerRangeEditor(   wxWindow* parent,
+                        const wxString& value = wxEmptyString,
+                        const wxSize& size = wxDefaultSize,
+                        std::function<void(coordf_t val)> edit_fn = [](coordf_t) {; }
+                        );
+    ~LayerRangeEditor() {}
+
+
+private:
+    coordf_t            get_value();
+};
+
 class ObjectLayers : public OG_Settings
 {
     ScalableBitmap  m_bmp_delete;
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 9b826f5d8..25df5c4fb 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -2312,9 +2312,15 @@ void ObjectList::add_layer_item(const t_layer_height_range& range,
     m_objects_model->AddLayersChild(layers_item, label, layer_idx);
 }
 
-void ObjectList::edit_layer_range(const std::pair<coordf_t, coordf_t>& range)
+void ObjectList::edit_layer_range(const t_layer_height_range& range, coordf_t layer_height)
 {
+    const int obj_idx = get_selected_obj_idx();
+    if (obj_idx < 0) return;
 
+    t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
+
+    DynamicPrintConfig* config = &ranges[range];
+    config->set_key_value("layer_height", new ConfigOptionFloat(layer_height));
 }
 
 void ObjectList::init_objects()
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 5b4fd4c49..5e24b9659 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -276,7 +276,7 @@ public:
     void add_layer_item (const std::pair<coordf_t, coordf_t>& range, 
                          const wxDataViewItem layers_item, 
                          const int layer_idx = -1);
-    void edit_layer_range(const std::pair<coordf_t, coordf_t>& range);
+    void edit_layer_range(const std::pair<coordf_t, coordf_t>& range, coordf_t layer_height);
 
     void init_objects();
     bool multiple_selection() const ;

From 213635f5596193008a96e1f910b8e2da507e9f9d Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 4 Jun 2019 17:30:44 +0200
Subject: [PATCH 14/34] Implemented range's min/max Z editing

---
 src/slic3r/GUI/GUI_ObjectLayers.cpp | 46 +++++++++++++++++------------
 src/slic3r/GUI/GUI_ObjectLayers.hpp |  4 +--
 src/slic3r/GUI/GUI_ObjectList.cpp   | 28 ++++++++++++++++++
 src/slic3r/GUI/GUI_ObjectList.hpp   |  2 ++
 4 files changed, 59 insertions(+), 21 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
index bba39f76a..de1c95fc9 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.cpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -43,26 +43,31 @@ ObjectLayers::ObjectLayers(wxWindow* parent) :
 
 wxSizer* ObjectLayers::create_layer_without_buttons(const t_layer_config_ranges::value_type& layer)
 {
-    auto size = wxSize(field_width * em_unit(m_parent), wxDefaultCoord);
-
     // Add control for the "Min Z"
-    auto temp = new LayerRangeEditor(m_parent, double_to_string(layer.first.first), size);
+    auto temp = new LayerRangeEditor(m_parent, double_to_string(layer.first.first),
+                                     [layer](coordf_t min_z) {
+        wxGetApp().obj_list()->edit_layer_range(layer.first, { min_z, layer.first.second });
+    });
+
     m_grid_sizer->Add(temp);
 
     // Add control for the "Max Z"
-    temp = new LayerRangeEditor(m_parent, double_to_string(layer.first.second), size);    
+    temp = new LayerRangeEditor(m_parent, double_to_string(layer.first.second),
+                                [layer](coordf_t max_z) {
+        wxGetApp().obj_list()->edit_layer_range(layer.first, { layer.first.first, max_z });
+    });
+    
     m_grid_sizer->Add(temp);
 
     // Add control for the "Layer height"
-    auto sizer = new wxBoxSizer(wxHORIZONTAL); 
-
-    const wxString text_value = double_to_string(layer.second.option("layer_height")->getFloat());
-
-    temp = new LayerRangeEditor(m_parent, text_value, size, [temp, layer](coordf_t layer_height) {
+    temp = new LayerRangeEditor(m_parent, 
+                                double_to_string(layer.second.option("layer_height")->getFloat()), 
+                                [layer](coordf_t layer_height) {
         wxGetApp().obj_list()->edit_layer_range(layer.first, layer_height);
-    } );
-    sizer->Add(temp);
+    }, false );
 
+    auto sizer = new wxBoxSizer(wxHORIZONTAL); 
+    sizer->Add(temp);
     m_grid_sizer->Add(sizer);
 
     return sizer;
@@ -164,25 +169,28 @@ void ObjectLayers::msw_rescale()
 
 LayerRangeEditor::LayerRangeEditor( wxWindow* parent,
                                     const wxString& value,
-                                    const wxSize& size,
-                                    std::function<void(coordf_t)> edit_fn
+                                    std::function<void(coordf_t)> edit_fn,
+                                    const bool deletable_after_change
                                     ) :
-    wxTextCtrl(parent, wxID_ANY, value, wxDefaultPosition, size, wxTE_PROCESS_ENTER)
+    wxTextCtrl(parent, wxID_ANY, value, wxDefaultPosition, 
+               wxSize(field_width * em_unit(parent), wxDefaultCoord), wxTE_PROCESS_ENTER)
 {
     this->SetFont(wxGetApp().normal_font());
     
     this->Bind(wxEVT_TEXT_ENTER, ([this, edit_fn](wxEvent& e)
     {
-        edit_fn(get_value());
         m_enter_pressed = true;
+        edit_fn(get_value());
     }), this->GetId());
 
-    this->Bind(wxEVT_KILL_FOCUS, ([this, edit_fn](wxEvent& e)
+    this->Bind(wxEVT_KILL_FOCUS, ([this, edit_fn, deletable_after_change](wxEvent& e)
     {
-        e.Skip();
-        if (!m_enter_pressed)
+        if (!deletable_after_change)
+            e.Skip();
+        if (!m_enter_pressed) {
+            m_enter_pressed = false;
             edit_fn(get_value());
-        m_enter_pressed = false;
+        }
     }), this->GetId());
 
 
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index 3aa3cb967..f34dd1314 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -18,8 +18,8 @@ class LayerRangeEditor : public wxTextCtrl
 public:
     LayerRangeEditor(   wxWindow* parent,
                         const wxString& value = wxEmptyString,
-                        const wxSize& size = wxDefaultSize,
-                        std::function<void(coordf_t val)> edit_fn = [](coordf_t) {; }
+                        std::function<void(coordf_t val)> edit_fn = [](coordf_t) {},
+                        const bool deletable_after_change = true
                         );
     ~LayerRangeEditor() {}
 
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 25df5c4fb..96d071d54 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -2265,6 +2265,9 @@ void ObjectList::add_layer_range(const t_layer_height_range& range)
             ++it;
         }
 
+        if (selected_range->first.second > next_range->first.first)
+            return; // range devision has no mean
+        
         if (selected_range->first.second == next_range->first.first)
         {
             const coordf_t delta = (next_range->first.second - next_range->first.first);
@@ -2323,6 +2326,31 @@ void ObjectList::edit_layer_range(const t_layer_height_range& range, coordf_t la
     config->set_key_value("layer_height", new ConfigOptionFloat(layer_height));
 }
 
+void ObjectList::edit_layer_range(const t_layer_height_range& range, const t_layer_height_range& new_range)
+{
+    const int obj_idx = get_selected_obj_idx();
+    if (obj_idx < 0) return;
+
+    t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
+
+    const DynamicPrintConfig config = ranges[range];
+
+    ranges.erase(range);
+    ranges[new_range] = config;
+
+    wxDataViewItem root_item = m_objects_model->GetLayerRootItem(m_objects_model->GetItemById(obj_idx));
+    m_objects_model->DeleteChildren(root_item);
+
+    if (root_item.IsOk())
+        // create Layer item(s) according to the layer_config_ranges
+        for (const auto r : ranges)
+            add_layer_item(r.first, root_item);
+
+    // To update(recreate) layers sizer call select_item for LayerRoot item expand
+    select_item(root_item);
+    Expand(root_item);
+}
+
 void ObjectList::init_objects()
 {
     m_objects = wxGetApp().model_objects();
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 5e24b9659..c970a23a0 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -277,6 +277,8 @@ public:
                          const wxDataViewItem layers_item, 
                          const int layer_idx = -1);
     void edit_layer_range(const std::pair<coordf_t, coordf_t>& range, coordf_t layer_height);
+    void edit_layer_range(const std::pair<coordf_t, coordf_t>& range, 
+                          const std::pair<coordf_t, coordf_t>& new_range);
 
     void init_objects();
     bool multiple_selection() const ;

From 567f382938b7939c4266b2ffcc3e14d91f9a80a1 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Wed, 5 Jun 2019 11:03:46 +0200
Subject: [PATCH 15/34] Implemented focusing of the last edited range

---
 src/slic3r/GUI/GUI_ObjectLayers.cpp | 73 +++++++++++++++++++++++------
 src/slic3r/GUI/GUI_ObjectLayers.hpp | 19 ++++++--
 src/slic3r/GUI/GUI_ObjectList.cpp   |  8 ++--
 3 files changed, 76 insertions(+), 24 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
index de1c95fc9..1f0511acb 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.cpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -43,28 +43,67 @@ ObjectLayers::ObjectLayers(wxWindow* parent) :
 
 wxSizer* ObjectLayers::create_layer_without_buttons(const t_layer_config_ranges::value_type& layer)
 {
+    const bool is_last_edited_range = layer.first == m_last_edited_range;
+
     // Add control for the "Min Z"
+
     auto temp = new LayerRangeEditor(m_parent, double_to_string(layer.first.first),
-                                     [layer](coordf_t min_z) {
-        wxGetApp().obj_list()->edit_layer_range(layer.first, { min_z, layer.first.second });
-    });
+                                     [layer, this](coordf_t min_z) 
+    {
+        if (fabs(min_z - layer.first.first) < EPSILON) {
+            m_selection_type = sitUndef;            
+            return false;       // LayersList would not be updated/recreated
+        }
+
+        // data for next focusing
+        m_last_edited_range = { min_z, layer.first.second };
+        m_selection_type = sitMinZ;
+
+        wxGetApp().obj_list()->edit_layer_range(layer.first, m_last_edited_range);
+        return true;            // LayersList will be updated/recreated
+    } );
+
+    if (is_last_edited_range && m_selection_type == sitMinZ) {
+        temp->SetFocus();
+        temp->SetInsertionPointEnd();
+    }
 
     m_grid_sizer->Add(temp);
 
     // Add control for the "Max Z"
+
     temp = new LayerRangeEditor(m_parent, double_to_string(layer.first.second),
-                                [layer](coordf_t max_z) {
-        wxGetApp().obj_list()->edit_layer_range(layer.first, { layer.first.first, max_z });
+                                [layer, this](coordf_t max_z)
+    {
+        if (fabs(max_z - layer.first.second) < EPSILON) {
+            m_selection_type = sitUndef;
+            return false;       // LayersList would not be updated/recreated
+        }
+
+        // data for next focusing
+        m_last_edited_range = { layer.first.first, max_z };
+        m_selection_type = sitMaxZ;
+
+        wxGetApp().obj_list()->edit_layer_range(layer.first, m_last_edited_range);
+        return true;            // LayersList will not be updated/recreated
     });
+
+    if (is_last_edited_range && m_selection_type == sitMaxZ) {
+        temp->SetFocus();
+        temp->SetInsertionPointEnd();
+    }
     
     m_grid_sizer->Add(temp);
 
     // Add control for the "Layer height"
+
     temp = new LayerRangeEditor(m_parent, 
                                 double_to_string(layer.second.option("layer_height")->getFloat()), 
-                                [layer](coordf_t layer_height) {
+                                [layer, this](coordf_t layer_height)
+    {
         wxGetApp().obj_list()->edit_layer_range(layer.first, layer_height);
-    }, false );
+        return false;           // LayersList would not be updated/recreated
+    });
 
     auto sizer = new wxBoxSizer(wxHORIZONTAL); 
     sizer->Add(temp);
@@ -169,8 +208,7 @@ void ObjectLayers::msw_rescale()
 
 LayerRangeEditor::LayerRangeEditor( wxWindow* parent,
                                     const wxString& value,
-                                    std::function<void(coordf_t)> edit_fn,
-                                    const bool deletable_after_change
+                                    std::function<bool(coordf_t)> edit_fn
                                     ) :
     wxTextCtrl(parent, wxID_ANY, value, wxDefaultPosition, 
                wxSize(field_width * em_unit(parent), wxDefaultCoord), wxTE_PROCESS_ENTER)
@@ -179,18 +217,23 @@ LayerRangeEditor::LayerRangeEditor( wxWindow* parent,
     
     this->Bind(wxEVT_TEXT_ENTER, ([this, edit_fn](wxEvent& e)
     {
-        m_enter_pressed = true;
-        edit_fn(get_value());
+        m_enter_pressed     = true;
+        // If LayersList wasn't updated/recreated, we can call wxEVT_KILL_FOCUS.Skip()
+        if ( !edit_fn(get_value()) )
+            m_call_kill_focus = true;
     }), this->GetId());
 
-    this->Bind(wxEVT_KILL_FOCUS, ([this, edit_fn, deletable_after_change](wxEvent& e)
+    this->Bind(wxEVT_KILL_FOCUS, ([this, edit_fn](wxEvent& e)
     {
-        if (!deletable_after_change)
-            e.Skip();
         if (!m_enter_pressed) {
             m_enter_pressed = false;
-            edit_fn(get_value());
+
+            // If LayersList wasn't updated/recreated, we should call e.Skip()
+            if ( !edit_fn(get_value()) )
+                e.Skip();
         }
+        else if (m_call_kill_focus)
+            e.Skip();
     }), this->GetId());
 
 
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index f34dd1314..e69a6173a 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -14,16 +14,16 @@ class ConfigOptionsGroup;
 
 class LayerRangeEditor : public wxTextCtrl
 {
-    bool                m_enter_pressed { false };
+    bool                m_enter_pressed     { false };
+    bool                m_call_kill_focus   { false };
+
 public:
     LayerRangeEditor(   wxWindow* parent,
                         const wxString& value = wxEmptyString,
-                        std::function<void(coordf_t val)> edit_fn = [](coordf_t) {},
-                        const bool deletable_after_change = true
+                        std::function<bool(coordf_t val)> edit_fn = [](coordf_t) {return false; }
                         );
     ~LayerRangeEditor() {}
 
-
 private:
     coordf_t            get_value();
 };
@@ -34,7 +34,16 @@ class ObjectLayers : public OG_Settings
     ScalableBitmap  m_bmp_add;
     ModelObject*    m_object {nullptr};
 
-    wxFlexGridSizer*            m_grid_sizer;
+    wxFlexGridSizer*                m_grid_sizer;
+    std::pair<coordf_t, coordf_t>   m_last_edited_range;
+
+    enum SelectedItemType
+    {
+        sitUndef,
+        sitMinZ,
+        sitMaxZ,
+        sitLayerHeight,
+    } m_selection_type {sitUndef};
 
 public:
     ObjectLayers(wxWindow* parent);
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 96d071d54..04423e359 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -2212,7 +2212,7 @@ void ObjectList::del_layer_range(const std::pair<coordf_t, coordf_t>& range)
     const int obj_idx = get_selected_obj_idx();
     if (obj_idx < 0) return;
 
-    t_layer_height_ranges& ranges = object(obj_idx)->layer_height_ranges;
+    t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
 
     wxDataViewItem selectable_item = GetSelection();
     int layer_idx = 0;
@@ -2221,10 +2221,10 @@ void ObjectList::del_layer_range(const std::pair<coordf_t, coordf_t>& range)
         selectable_item = m_objects_model->GetParent(selectable_item);
     else {
         // May be not a best solution #ys_FIXME
-        t_layer_height_ranges::iterator layer_selected = ranges.find(range);
-        t_layer_height_ranges::iterator it = ranges.begin();
+        t_layer_config_ranges::iterator layer_selected = ranges.find(range);
+        t_layer_config_ranges::iterator it = ranges.begin();
         while (it != layer_selected) {
-            it++;
+            ++it;
             layer_idx++;
         }
     }

From 1090105b6879b0f0212abd4259bd54e86471e60f Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Wed, 5 Jun 2019 11:50:59 +0200
Subject: [PATCH 16/34] Experiments with updating layer_config_ranges from UI 
 + Fixed OSX build

---
 src/libslic3r/Model.cpp             |  2 ++
 src/libslic3r/Print.cpp             |  6 ++++--
 src/libslic3r/PrintObject.cpp       |  5 +++--
 src/libslic3r/Slicing.cpp           | 13 +++++++++----
 src/libslic3r/Slicing.hpp           |  3 ++-
 src/slic3r/GUI/GUI_ObjectLayers.hpp | 10 +++++++---
 src/slic3r/GUI/GUI_ObjectList.hpp   | 15 +++++++++------
 src/slic3r/GUI/Selection.cpp        |  3 ++-
 8 files changed, 38 insertions(+), 19 deletions(-)

diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index 3b1bd5df2..f31ae27db 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -600,6 +600,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
     this->sla_support_points          = rhs.sla_support_points;
     this->sla_points_status           = rhs.sla_points_status;
     this->layer_height_ranges         = rhs.layer_height_ranges;
+    this->layer_config_ranges         = rhs.layer_config_ranges;    // #ys_FIXME_experiment
     this->layer_height_profile        = rhs.layer_height_profile;
     this->origin_translation          = rhs.origin_translation;
     m_bounding_box                    = rhs.m_bounding_box;
@@ -636,6 +637,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
     this->sla_support_points          = std::move(rhs.sla_support_points);
     this->sla_points_status           = std::move(rhs.sla_points_status);
     this->layer_height_ranges         = std::move(rhs.layer_height_ranges);
+    this->layer_config_ranges         = std::move(rhs.layer_config_ranges); // #ys_FIXME_experiment
     this->layer_height_profile        = std::move(rhs.layer_height_profile);
     this->origin_translation          = std::move(rhs.origin_translation);
     m_bounding_box                    = std::move(rhs.m_bounding_box);
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index f9129f15a..ed4af3995 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -874,7 +874,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
         bool support_enforcers_differ   = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER);
         if (model_parts_differ || modifiers_differ || 
             model_object.origin_translation         != model_object_new.origin_translation   ||
-            model_object.layer_height_ranges        != model_object_new.layer_height_ranges  || 
+//             model_object.layer_height_ranges        != model_object_new.layer_height_ranges  || 
+            model_object.layer_config_ranges        != model_object_new.layer_config_ranges  ||         // #ys_FIXME_experiment
             model_object.layer_height_profile       != model_object_new.layer_height_profile) {
             // The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
             auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
@@ -1227,7 +1228,8 @@ std::string Print::validate() const
             bool                                has_custom_layering = false;
             std::vector<std::vector<coordf_t>>  layer_height_profiles;
             for (const PrintObject *object : m_objects) {
-                has_custom_layering = ! object->model_object()->layer_height_ranges.empty() || ! object->model_object()->layer_height_profile.empty();
+//                 has_custom_layering = ! object->model_object()->layer_height_ranges.empty() || ! object->model_object()->layer_height_profile.empty();
+                has_custom_layering = ! object->model_object()->layer_config_ranges.empty() || ! object->model_object()->layer_height_profile.empty();      // #ys_FIXME_experiment
                 if (has_custom_layering) {
                     layer_height_profiles.assign(m_objects.size(), std::vector<coordf_t>());
                     break;
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index 660a2d939..c12861d21 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -1434,8 +1434,9 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
 //        if (this->layer_height_profile.empty())
             layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_height_ranges, model_object.volumes);
         else
-            layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_height_ranges);
-        updated = true;
+//             layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_height_ranges);
+             layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges);     // #ys_FIXME_experiment
+       updated = true;
     }
     return updated;
 }
diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp
index 3a05e9d8a..b4c78ad09 100644
--- a/src/libslic3r/Slicing.cpp
+++ b/src/libslic3r/Slicing.cpp
@@ -157,20 +157,25 @@ SlicingParameters SlicingParameters::create_from_config(
 // in the height profile and the printed object may be lifted by the raft thickness at the time of the G-code generation.
 std::vector<coordf_t> layer_height_profile_from_ranges(
 	const SlicingParameters 	&slicing_params,
-	const t_layer_height_ranges &layer_height_ranges)
+//	const t_layer_height_ranges &layer_height_ranges) 
+	const t_layer_config_ranges &layer_config_ranges)                           // #ys_FIXME_experiment
 {
     // 1) If there are any height ranges, trim one by the other to make them non-overlapping. Insert the 1st layer if fixed.
     std::vector<std::pair<t_layer_height_range,coordf_t>> ranges_non_overlapping;
-    ranges_non_overlapping.reserve(layer_height_ranges.size() * 4);
+//     ranges_non_overlapping.reserve(layer_height_ranges.size() * 4);
+    ranges_non_overlapping.reserve(layer_config_ranges.size() * 4);             // #ys_FIXME_experiment
     if (slicing_params.first_object_layer_height_fixed())
         ranges_non_overlapping.push_back(std::pair<t_layer_height_range,coordf_t>(
             t_layer_height_range(0., slicing_params.first_object_layer_height), 
             slicing_params.first_object_layer_height));
     // The height ranges are sorted lexicographically by low / high layer boundaries.
-    for (t_layer_height_ranges::const_iterator it_range = layer_height_ranges.begin(); it_range != layer_height_ranges.end(); ++ it_range) {
+//     for (t_layer_height_ranges::const_iterator it_range = layer_height_ranges.begin(); it_range != layer_height_ranges.end(); ++ it_range) {
+    for (t_layer_config_ranges::const_iterator it_range = layer_config_ranges.begin(); 
+                                               it_range != layer_config_ranges.end(); ++ it_range) { // #ys_FIXME_experiment
         coordf_t lo = it_range->first.first;
         coordf_t hi = std::min(it_range->first.second, slicing_params.object_print_z_height());
-        coordf_t height = it_range->second;
+//         coordf_t height = it_range->second;
+        coordf_t height = it_range->second.option("layer_height")->getFloat();  // #ys_FIXME_experiment
         if (! ranges_non_overlapping.empty())
             // Trim current low with the last high.
             lo = std::max(lo, ranges_non_overlapping.back().first.second);
diff --git a/src/libslic3r/Slicing.hpp b/src/libslic3r/Slicing.hpp
index c3278dc0d..ea5413e9c 100644
--- a/src/libslic3r/Slicing.hpp
+++ b/src/libslic3r/Slicing.hpp
@@ -135,7 +135,8 @@ typedef std::map<t_layer_height_range, DynamicPrintConfig> t_layer_config_ranges
 
 extern std::vector<coordf_t> layer_height_profile_from_ranges(
     const SlicingParameters     &slicing_params,
-    const t_layer_height_ranges &layer_height_ranges);
+//     const t_layer_height_ranges &layer_height_ranges);
+    const t_layer_config_ranges &layer_config_ranges);
 
 extern std::vector<coordf_t> layer_height_profile_adaptive(
     const SlicingParameters     &slicing_params,
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index e69a6173a..aa09e64a6 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -12,6 +12,10 @@ class ModelObject;
 namespace GUI {
 class ConfigOptionsGroup;
 
+typedef double                                              coordf_t;
+typedef std::pair<coordf_t, coordf_t>                       t_layer_height_range;
+typedef std::map<t_layer_height_range, DynamicPrintConfig>  t_layer_config_ranges;
+
 class LayerRangeEditor : public wxTextCtrl
 {
     bool                m_enter_pressed     { false };
@@ -34,8 +38,8 @@ class ObjectLayers : public OG_Settings
     ScalableBitmap  m_bmp_add;
     ModelObject*    m_object {nullptr};
 
-    wxFlexGridSizer*                m_grid_sizer;
-    std::pair<coordf_t, coordf_t>   m_last_edited_range;
+    wxFlexGridSizer*       m_grid_sizer;
+    t_layer_height_range   m_last_edited_range;
 
     enum SelectedItemType
     {
@@ -49,7 +53,7 @@ public:
     ObjectLayers(wxWindow* parent);
     ~ObjectLayers() {}
 
-    wxSizer*    create_layer_without_buttons(const std::map<std::pair<coordf_t, coordf_t>, DynamicPrintConfig>::value_type& layer);
+    wxSizer*    create_layer_without_buttons(const t_layer_config_ranges::value_type& layer);
     void        create_layer(int id);
     void        create_layers_list();
     void        update_layers_list();
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index c970a23a0..24c9f65b2 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -33,6 +33,9 @@ typedef std::map< std::string, std::vector< std::pair<std::string, std::string>
 
 typedef std::vector<ModelVolume*> ModelVolumePtrs;
 
+typedef double                                      coordf_t;
+typedef std::pair<coordf_t, coordf_t>               t_layer_height_range;
+
 namespace GUI {
 
 wxDECLARE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent);
@@ -271,14 +274,14 @@ public:
 
     // Remove objects/sub-object from the list
     void remove();
-    void del_layer_range(const std::pair<coordf_t, coordf_t>& range);
-    void add_layer_range(const std::pair<coordf_t, coordf_t>& range);
-    void add_layer_item (const std::pair<coordf_t, coordf_t>& range, 
+    void del_layer_range(const t_layer_height_range& range);
+    void add_layer_range(const t_layer_height_range& range);
+    void add_layer_item (const t_layer_height_range& range, 
                          const wxDataViewItem layers_item, 
                          const int layer_idx = -1);
-    void edit_layer_range(const std::pair<coordf_t, coordf_t>& range, coordf_t layer_height);
-    void edit_layer_range(const std::pair<coordf_t, coordf_t>& range, 
-                          const std::pair<coordf_t, coordf_t>& new_range);
+    void edit_layer_range(const t_layer_height_range& range, coordf_t layer_height);
+    void edit_layer_range(const t_layer_height_range& range, 
+                          const t_layer_height_range& new_range);
 
     void init_objects();
     bool multiple_selection() const ;
diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp
index ff994c32d..0f364f8a1 100644
--- a/src/slic3r/GUI/Selection.cpp
+++ b/src/slic3r/GUI/Selection.cpp
@@ -1126,7 +1126,8 @@ void Selection::copy_to_clipboard()
         dst_object->config               = src_object->config;
         dst_object->sla_support_points   = src_object->sla_support_points;
         dst_object->sla_points_status    = src_object->sla_points_status;
-        dst_object->layer_height_ranges  = src_object->layer_height_ranges;
+//         dst_object->layer_height_ranges  = src_object->layer_height_ranges;
+        dst_object->layer_config_ranges  = src_object->layer_config_ranges;     // #ys_FIXME_experiment
         dst_object->layer_height_profile = src_object->layer_height_profile;
         dst_object->origin_translation   = src_object->origin_translation;
 

From 401999b68b3e8e625356a9fc017427aa0903432f Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Wed, 5 Jun 2019 12:32:59 +0200
Subject: [PATCH 17/34] Next try to fix OSX build

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

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index aa09e64a6..0b404be4f 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -9,13 +9,13 @@ class wxBoxSizer;
 namespace Slic3r {
 class ModelObject;
 
-namespace GUI {
-class ConfigOptionsGroup;
-
 typedef double                                              coordf_t;
 typedef std::pair<coordf_t, coordf_t>                       t_layer_height_range;
 typedef std::map<t_layer_height_range, DynamicPrintConfig>  t_layer_config_ranges;
 
+namespace GUI {
+class ConfigOptionsGroup;
+
 class LayerRangeEditor : public wxTextCtrl
 {
     bool                m_enter_pressed     { false };

From 67ed89c2405a242370066993c16e26fa26fdb6c4 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Wed, 5 Jun 2019 13:52:53 +0200
Subject: [PATCH 18/34] Fixed OSX build and a bug when for part is able to add
 "layer_height" option

---
 src/slic3r/GUI/GUI_ObjectLayers.hpp | 10 +++++++---
 src/slic3r/GUI/GUI_ObjectList.cpp   | 12 +++++++++++-
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index 0b404be4f..bec2a1f49 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -4,18 +4,22 @@
 #include "GUI_ObjectSettings.hpp"
 #include "wxExtensions.hpp"
 
+#ifdef __WXOSX__
+#include "..\libslic3r\PrintConfig.hpp"
+#endif
+
 class wxBoxSizer;
 
 namespace Slic3r {
 class ModelObject;
 
+namespace GUI {
+class ConfigOptionsGroup;
+
 typedef double                                              coordf_t;
 typedef std::pair<coordf_t, coordf_t>                       t_layer_height_range;
 typedef std::map<t_layer_height_range, DynamicPrintConfig>  t_layer_config_ranges;
 
-namespace GUI {
-class ConfigOptionsGroup;
-
 class LayerRangeEditor : public wxTextCtrl
 {
     bool                m_enter_pressed     { false };
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 04423e359..b7a582062 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1035,7 +1035,17 @@ void ObjectList::get_settings_choice(const wxString& category_name)
 
 void ObjectList::get_freq_settings_choice(const wxString& bundle_name)
 {
-    const std::vector<std::string>& options = get_options_for_bundle(bundle_name);
+    std::vector<std::string> options = get_options_for_bundle(bundle_name);
+
+    /* Because of we couldn't edited layer_height for ItVolume and itLayer from settings list,
+     * correct options according to the selected item type :
+     * remove "layer_height" option
+     */
+    if (m_objects_model->GetItemType(GetSelection()) & (itVolume | itLayer) && bundle_name == _("Layers and Perimeters")) {
+        const auto layer_height_it = std::find(options.begin(), options.end(), "layer_height");
+        if (layer_height_it != options.end())
+            options.erase(layer_height_it);
+    }
 
     assert(m_config);
     auto opt_keys = m_config->keys();

From 44c05fa2099b3c0a7daa96181d07a8d61e8f6397 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Wed, 5 Jun 2019 16:47:09 +0200
Subject: [PATCH 19/34] Implemented additional settings for layers range
 (except of "extruder")

---
 src/slic3r/GUI/GUI_ObjectLayers.hpp   |  2 +-
 src/slic3r/GUI/GUI_ObjectList.cpp     | 80 +++++++++++++++++++++------
 src/slic3r/GUI/GUI_ObjectList.hpp     |  2 +
 src/slic3r/GUI/GUI_ObjectSettings.cpp | 11 ++--
 4 files changed, 72 insertions(+), 23 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index bec2a1f49..55002ff35 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -5,7 +5,7 @@
 #include "wxExtensions.hpp"
 
 #ifdef __WXOSX__
-#include "..\libslic3r\PrintConfig.hpp"
+#include "../libslic3r/PrintConfig.hpp"
 #endif
 
 class wxBoxSizer;
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index b7a582062..f68130ddd 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -360,6 +360,21 @@ DynamicPrintConfig& ObjectList::get_item_config(const wxDataViewItem& item) cons
                             (*m_objects)[obj_idx]->config;
 }
 
+const t_layer_height_range& ObjectList::get_layer_range_from_item(const wxDataViewItem layer_item, const int obj_idx) const
+{
+    ModelObject* object = (*m_objects)[obj_idx];
+    t_layer_config_ranges::iterator layer_range = object->layer_config_ranges.begin();
+    int id = m_objects_model->GetLayerIdByItem(layer_item);
+
+    // May be not a best solution #ys_FIXME
+    while (id > 0 && layer_range != object->layer_config_ranges.end()) {
+        ++layer_range;
+        id--;
+    }
+
+    return layer_range->first;
+}
+
 wxDataViewColumn* ObjectList::create_objects_list_extruder_column(int extruders_count)
 {
     wxArrayString choices;
@@ -1037,11 +1052,11 @@ void ObjectList::get_freq_settings_choice(const wxString& bundle_name)
 {
     std::vector<std::string> options = get_options_for_bundle(bundle_name);
 
-    /* Because of we couldn't edited layer_height for ItVolume and itLayer from settings list,
+    /* Because of we couldn't edited layer_height for ItVolume from settings list,
      * correct options according to the selected item type :
      * remove "layer_height" option
      */
-    if (m_objects_model->GetItemType(GetSelection()) & (itVolume | itLayer) && bundle_name == _("Layers and Perimeters")) {
+    if ((m_objects_model->GetItemType(GetSelection()) & itVolume) && bundle_name == _("Layers and Perimeters")) {
         const auto layer_height_it = std::find(options.begin(), options.end(), "layer_height");
         if (layer_height_it != options.end())
             options.erase(layer_height_it);
@@ -1833,7 +1848,7 @@ void ObjectList::layers_editing()
         t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
         
         if (ranges.empty())
-            ranges[{ 0.0f, 0.2f }] = *DynamicPrintConfig::new_from_defaults_keys({"layer_height"});// some default value
+            ranges[{ 0.0f, 0.6f }] = get_default_layer_config(obj_idx);
 
         // and create Layer item(s) according to the layer_config_ranges
         for (const auto range : ranges)
@@ -1845,6 +1860,18 @@ void ObjectList::layers_editing()
     Expand(layers_item);
 }
 
+DynamicPrintConfig ObjectList::get_default_layer_config(const int obj_idx)
+{
+    DynamicPrintConfig config;
+    coordf_t layer_height = object(obj_idx)->config.has("layer_height") ? 
+                            object(obj_idx)->config.opt_float("layer_height") : 
+                            wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_float("layer_height");
+    config.set_key_value("layer_height",new ConfigOptionFloat(layer_height));
+    config.set_key_value("extruder",    new ConfigOptionInt(0));
+
+    return config;
+}
+
 bool ObjectList::get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume)
 {
     auto obj_idx = get_selected_obj_idx();
@@ -1937,22 +1964,28 @@ void ObjectList::part_selection_changed()
                 update_and_show_manipulations = true;
             }
             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
-                obj_idx = m_objects_model->GetIdByItem(parent);
+                obj_idx = m_objects_model->GetObjectIdByItem(item);
+                
                 const ItemType type = m_objects_model->GetItemType(item);
                 if (type & itSettings) {
-                    if (m_objects_model->GetParent(parent) == wxDataViewItem(0)) {
+                    const auto parent = m_objects_model->GetParent(item);
+                    const ItemType parent_type = m_objects_model->GetItemType(parent);
+
+                    if (parent_type & itObject) {
                         og_name = _(L("Object Settings to modify"));
                         m_config = &(*m_objects)[obj_idx]->config;
                     }
-                    else {
+                    else if (parent_type & itVolume) {
                         og_name = _(L("Part Settings to modify"));
-                        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);
+                        volume_id = m_objects_model->GetVolumeIdByItem(parent);
                         m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
                     }
+                    else if (parent_type & itLayer) {
+                        og_name = _(L("Layer range Settings to modify"));
+
+                        const t_layer_height_range& layer_height_range = get_layer_range_from_item(parent, obj_idx);
+                        m_config = &(*m_objects)[obj_idx]->layer_config_ranges[layer_height_range];
+                    }
                     update_and_show_settings = true;
                 }
                 else if (type & itVolume) {
@@ -1966,12 +1999,14 @@ void ObjectList::part_selection_changed()
                     update_and_show_manipulations = true;
 
                     // fill m_config by object's values
-                    const int obj_idx_ = m_objects_model->GetObjectIdByItem(item);
-                    m_config = &(*m_objects)[obj_idx_]->config;
+                    m_config = &(*m_objects)[obj_idx]->config;
                 }
                 else if (type & (itLayerRoot|itLayer)) {
                     og_name = type & itLayerRoot ? _(L("Layers Editing")) : _(L("Layer Editing"));
                     update_and_show_layers = true;
+
+                    const t_layer_height_range& layer_height_range = get_layer_range_from_item(item, obj_idx);
+                    m_config = &(*m_objects)[obj_idx]->layer_config_ranges[layer_height_range];
                 }
             }
         }
@@ -2259,8 +2294,8 @@ void ObjectList::add_layer_range(const t_layer_height_range& range)
     
     if (selected_range->first == last_range->first)
     {
-        const t_layer_height_range new_range = { last_range->first.second, last_range->first.second + 0.2f };
-        ranges[new_range] = last_range->second;
+        const t_layer_height_range new_range = { last_range->first.second, last_range->first.second + 0.5f };
+        ranges[new_range] = get_default_layer_config(obj_idx);
         add_layer_item(new_range, layers_item);
     }
     else
@@ -2300,13 +2335,13 @@ void ObjectList::add_layer_range(const t_layer_height_range& range)
             add_layer_item(new_range, layers_item, layer_idx);
 
             new_range = { selected_range->first.second, midl_layer };
-            ranges[new_range] = selected_range->second;            
+            ranges[new_range] = get_default_layer_config(obj_idx);
             add_layer_item(new_range, layers_item, layer_idx);
         }
         else
         {
             const t_layer_height_range new_range = { selected_range->first.second, next_range->first.first };
-            ranges[new_range] = selected_range->second;
+            ranges[new_range] = get_default_layer_config(obj_idx);
             add_layer_item(new_range, layers_item, layer_idx);
         }        
     }
@@ -2322,7 +2357,16 @@ void ObjectList::add_layer_item(const t_layer_height_range& range,
                                 const int layer_idx /* = -1*/)
 {
     const std::string label = (boost::format(" %.2f-%.2f ") % range.first % range.second).str();
-    m_objects_model->AddLayersChild(layers_item, label, layer_idx);
+    const wxDataViewItem layer_item = m_objects_model->AddLayersChild(layers_item, label, layer_idx);
+
+    const int obj_idx = get_selected_obj_idx();
+    if (obj_idx < 0) return;
+
+//     auto opt_keys = object(obj_idx)->layer_config_ranges[range].keys();
+    const DynamicPrintConfig& config = object(obj_idx)->layer_config_ranges[range];
+//     if (!opt_keys.empty() && !(opt_keys.size() == 2 && opt_keys[0] == "layer_height" && opt_keys[1] == "extruder"))
+    if (config.keys().size() > 2)
+        select_item(m_objects_model->AddSettingsChild(layer_item));
 }
 
 void ObjectList::edit_layer_range(const t_layer_height_range& range, coordf_t layer_height)
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 24c9f65b2..ad7587a01 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -235,6 +235,7 @@ public:
     bool                del_subobject_from_object(const int obj_idx, const int idx, const int type);
     void                split();
     void                layers_editing();
+    DynamicPrintConfig  get_default_layer_config(const int obj_idx);
     bool                get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume);
     bool                is_splittable();
     bool                selected_instances_of_same_object();
@@ -244,6 +245,7 @@ public:
     wxBoxSizer*         get_sizer() {return  m_sizer;}
     int                 get_selected_obj_idx() const;
     DynamicPrintConfig& get_item_config(const wxDataViewItem& item) const;
+    const t_layer_height_range& get_layer_range_from_item(const wxDataViewItem layer_item, const int obj_idx) const;
 
     void                changed_object(const int obj_idx = -1) const;
     void                part_selection_changed();
diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp
index a4aa7dec2..ab2614895 100644
--- a/src/slic3r/GUI/GUI_ObjectSettings.cpp
+++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp
@@ -72,6 +72,8 @@ void ObjectSettings::update_settings_list()
     auto config         = wxGetApp().obj_list()->config();
 
     const auto item = objects_ctrl->GetSelection();
+    const bool is_layers_range_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itLayer;
+
     if (item && !objects_ctrl->multiple_selection() && 
         config && objects_model->IsSettingsItem(item))
 	{
@@ -119,7 +121,8 @@ void ObjectSettings::update_settings_list()
             }
 
             for (auto& cat : cat_options) {
-                if (cat.second.size() == 1 && cat.second[0] == "extruder")
+                if (cat.second.size() == 1 && 
+                    (cat.second[0] == "extruder" || is_layers_range_settings && cat.second[0] == "layer_height"))
                     continue;
 
                 auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), _(cat.first), config, false, extra_column);
@@ -129,14 +132,14 @@ void ObjectSettings::update_settings_list()
                 optgroup->m_on_change = [](const t_config_option_key& opt_id, const boost::any& value) {
                                         wxGetApp().obj_list()->changed_object(); };
 
-                const bool is_extriders_cat = cat.first == "Extruders";
+                const bool is_extruders_cat = cat.first == "Extruders";
                 for (auto& opt : cat.second)
                 {
-                    if (opt == "extruder")
+                    if (opt == "extruder" || is_layers_range_settings && opt == "layer_height")
                         continue;
                     Option option = optgroup->get_option(opt);
                     option.opt.width = 12;
-                    if (is_extriders_cat)
+                    if (is_extruders_cat)
                         option.opt.max = wxGetApp().extruders_cnt();
                     optgroup->append_single_option_line(option);
                 }

From 71cc0fdb535bdf1cb4c35429655ed75debf0afce Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Thu, 6 Jun 2019 14:14:29 +0200
Subject: [PATCH 20/34] Some code refactoring and improvements

---
 src/slic3r/GUI/GUI_ObjectLayers.cpp |  79 ++++++--------
 src/slic3r/GUI/GUI_ObjectLayers.hpp |   8 +-
 src/slic3r/GUI/GUI_ObjectList.cpp   | 157 +++++++++++++---------------
 src/slic3r/GUI/GUI_ObjectList.hpp   |   6 +-
 src/slic3r/GUI/Tab.cpp              |   7 +-
 src/slic3r/GUI/wxExtensions.cpp     |  61 ++++++++---
 src/slic3r/GUI/wxExtensions.hpp     |  11 +-
 7 files changed, 171 insertions(+), 158 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
index 1f0511acb..ba0012a2b 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.cpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -16,8 +16,6 @@ namespace Slic3r
 namespace GUI
 {
 
-#define field_width 8
-
 ObjectLayers::ObjectLayers(wxWindow* parent) :
     OG_Settings(parent, true)
 {
@@ -41,27 +39,27 @@ ObjectLayers::ObjectLayers(wxWindow* parent) :
     m_bmp_add       = ScalableBitmap(parent, "add_copies");
 }
 
-wxSizer* ObjectLayers::create_layer_without_buttons(const t_layer_config_ranges::value_type& layer)
+wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range) 
 {
-    const bool is_last_edited_range = layer.first == m_last_edited_range;
+    const bool is_last_edited_range = range == m_last_edited_range;
 
     // Add control for the "Min Z"
 
-    auto temp = new LayerRangeEditor(m_parent, double_to_string(layer.first.first),
-                                     [layer, this](coordf_t min_z) 
+    auto temp = new LayerRangeEditor(m_parent, double_to_string(range.first),
+        [range, this](coordf_t min_z)
     {
-        if (fabs(min_z - layer.first.first) < EPSILON) {
-            m_selection_type = sitUndef;            
+        if (fabs(min_z - range.first) < EPSILON) {
+            m_selection_type = sitUndef;
             return false;       // LayersList would not be updated/recreated
         }
 
         // data for next focusing
-        m_last_edited_range = { min_z, layer.first.second };
+        m_last_edited_range = { min_z, range.second };
         m_selection_type = sitMinZ;
 
-        wxGetApp().obj_list()->edit_layer_range(layer.first, m_last_edited_range);
+        wxGetApp().obj_list()->edit_layer_range(range, m_last_edited_range);
         return true;            // LayersList will be updated/recreated
-    } );
+    });
 
     if (is_last_edited_range && m_selection_type == sitMinZ) {
         temp->SetFocus();
@@ -72,19 +70,19 @@ wxSizer* ObjectLayers::create_layer_without_buttons(const t_layer_config_ranges:
 
     // Add control for the "Max Z"
 
-    temp = new LayerRangeEditor(m_parent, double_to_string(layer.first.second),
-                                [layer, this](coordf_t max_z)
+    temp = new LayerRangeEditor(m_parent, double_to_string(range.second),
+                                [range, this](coordf_t max_z)
     {
-        if (fabs(max_z - layer.first.second) < EPSILON) {
+        if (fabs(max_z - range.second) < EPSILON) {
             m_selection_type = sitUndef;
             return false;       // LayersList would not be updated/recreated
         }
 
         // data for next focusing
-        m_last_edited_range = { layer.first.first, max_z };
+        m_last_edited_range = { range.first, max_z };
         m_selection_type = sitMaxZ;
 
-        wxGetApp().obj_list()->edit_layer_range(layer.first, m_last_edited_range);
+        wxGetApp().obj_list()->edit_layer_range(range, m_last_edited_range);
         return true;            // LayersList will not be updated/recreated
     });
 
@@ -92,20 +90,20 @@ wxSizer* ObjectLayers::create_layer_without_buttons(const t_layer_config_ranges:
         temp->SetFocus();
         temp->SetInsertionPointEnd();
     }
-    
+
     m_grid_sizer->Add(temp);
 
     // Add control for the "Layer height"
 
-    temp = new LayerRangeEditor(m_parent, 
-                                double_to_string(layer.second.option("layer_height")->getFloat()), 
-                                [layer, this](coordf_t layer_height)
+    temp = new LayerRangeEditor(m_parent,
+                                double_to_string(m_object->layer_config_ranges[range].option("layer_height")->getFloat()),
+                                [range, this](coordf_t layer_height)
     {
-        wxGetApp().obj_list()->edit_layer_range(layer.first, layer_height);
+        wxGetApp().obj_list()->edit_layer_range(range, layer_height);
         return false;           // LayersList would not be updated/recreated
     });
 
-    auto sizer = new wxBoxSizer(wxHORIZONTAL); 
+    auto sizer = new wxBoxSizer(wxHORIZONTAL);
     sizer->Add(temp);
     m_grid_sizer->Add(sizer);
 
@@ -116,42 +114,29 @@ void ObjectLayers::create_layers_list()
 {
     for (const auto layer : m_object->layer_config_ranges)
     {
-        auto sizer = create_layer_without_buttons(layer);
+        const t_layer_height_range& range = layer.first;
+        auto sizer = create_layer(range);
 
-        wxWindow* parent = m_parent;
-        auto del_btn = new ScalableButton(parent, wxID_ANY, m_bmp_delete);
+        auto del_btn = new ScalableButton(m_parent, wxID_ANY, m_bmp_delete);
         del_btn->SetToolTip(_(L("Remove layer")));
 
-        sizer->Add(del_btn, 0, wxRIGHT | wxLEFT, em_unit(parent));
+        sizer->Add(del_btn, 0, wxRIGHT | wxLEFT, em_unit(m_parent));
 
-        del_btn->Bind(wxEVT_BUTTON, [this, layer](wxEvent &event) {
-            wxGetApp().obj_list()->del_layer_range(layer.first);
+        del_btn->Bind(wxEVT_BUTTON, [this, range](wxEvent &event) {
+            wxGetApp().obj_list()->del_layer_range(range);
         });
 
-        auto add_btn = new ScalableButton(parent, wxID_ANY, m_bmp_add);
+        auto add_btn = new ScalableButton(m_parent, wxID_ANY, m_bmp_add);
         add_btn->SetToolTip(_(L("Add layer")));
 
-        sizer->Add(add_btn, 0, wxRIGHT, em_unit(parent));
+        sizer->Add(add_btn, 0, wxRIGHT, em_unit(m_parent));
 
-        add_btn->Bind(wxEVT_BUTTON, [this, layer](wxEvent &event) {
-            wxGetApp().obj_list()->add_layer_range(layer.first);
+        add_btn->Bind(wxEVT_BUTTON, [this, range](wxEvent &event) {
+            wxGetApp().obj_list()->add_layer_range_after_current(range);
         });
     }
 }
 
-void ObjectLayers::create_layer(int id)
-{
-    t_layer_config_ranges::iterator layer_range = m_object->layer_config_ranges.begin();
-
-    // May be not a best solution #ys_FIXME
-    while (id > 0 && layer_range != m_object->layer_config_ranges.end()) {
-        ++layer_range;
-        id--;
-    }
-
-    create_layer_without_buttons(*layer_range);
-}
-
 void ObjectLayers::update_layers_list()
 {
     ObjectList* objects_ctrl   = wxGetApp().obj_list();
@@ -187,7 +172,7 @@ void ObjectLayers::update_layers_list()
     if (type & itLayerRoot)
         create_layers_list();
     else
-        create_layer(objects_ctrl->GetModel()->GetLayerIdByItem(item));
+        create_layer(objects_ctrl->GetModel()->GetLayerRangeByItem(item));
     
     m_parent->Layout();
 }
@@ -211,7 +196,7 @@ LayerRangeEditor::LayerRangeEditor( wxWindow* parent,
                                     std::function<bool(coordf_t)> edit_fn
                                     ) :
     wxTextCtrl(parent, wxID_ANY, value, wxDefaultPosition, 
-               wxSize(field_width * em_unit(parent), wxDefaultCoord), wxTE_PROCESS_ENTER)
+               wxSize(8 * em_unit(parent), wxDefaultCoord), wxTE_PROCESS_ENTER)
 {
     this->SetFont(wxGetApp().normal_font());
     
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index 55002ff35..562e04972 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -16,9 +16,8 @@ class ModelObject;
 namespace GUI {
 class ConfigOptionsGroup;
 
-typedef double                                              coordf_t;
-typedef std::pair<coordf_t, coordf_t>                       t_layer_height_range;
-typedef std::map<t_layer_height_range, DynamicPrintConfig>  t_layer_config_ranges;
+typedef double                          coordf_t;
+typedef std::pair<coordf_t, coordf_t>   t_layer_height_range;
 
 class LayerRangeEditor : public wxTextCtrl
 {
@@ -57,8 +56,7 @@ public:
     ObjectLayers(wxWindow* parent);
     ~ObjectLayers() {}
 
-    wxSizer*    create_layer_without_buttons(const t_layer_config_ranges::value_type& layer);
-    void        create_layer(int id);
+    wxSizer*    create_layer(const t_layer_height_range& range);    // without_buttons
     void        create_layers_list();
     void        update_layers_list();
 
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index f68130ddd..3060a166d 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -351,30 +351,16 @@ DynamicPrintConfig& ObjectList::get_item_config(const wxDataViewItem& item) cons
     const ItemType type = m_objects_model->GetItemType(item);
 
     const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) :
-        m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
+                        m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
 
     const int vol_idx = type & itVolume ? m_objects_model->GetVolumeIdByItem(item) : -1;
 
     assert(obj_idx >= 0 || ((type & itVolume) && vol_idx >=0));
     return type & itVolume ?(*m_objects)[obj_idx]->volumes[vol_idx]->config :
+           type & itLayer  ?(*m_objects)[obj_idx]->layer_config_ranges[m_objects_model->GetLayerRangeByItem(item)] :
                             (*m_objects)[obj_idx]->config;
 }
 
-const t_layer_height_range& ObjectList::get_layer_range_from_item(const wxDataViewItem layer_item, const int obj_idx) const
-{
-    ModelObject* object = (*m_objects)[obj_idx];
-    t_layer_config_ranges::iterator layer_range = object->layer_config_ranges.begin();
-    int id = m_objects_model->GetLayerIdByItem(layer_item);
-
-    // May be not a best solution #ys_FIXME
-    while (id > 0 && layer_range != object->layer_config_ranges.end()) {
-        ++layer_range;
-        id--;
-    }
-
-    return layer_range->first;
-}
-
 wxDataViewColumn* ObjectList::create_objects_list_extruder_column(int extruders_count)
 {
     wxArrayString choices;
@@ -457,16 +443,23 @@ void ObjectList::update_extruder_in_config(const wxDataViewItem& item)
 {
     if (m_prevent_update_extruder_in_config)
         return;
-    if (m_objects_model->GetParent(item) == wxDataViewItem(0)) {
+
+    const ItemType item_type = m_objects_model->GetItemType(item);
+    if (item_type & itObject) {
         const int obj_idx = m_objects_model->GetIdByItem(item);
         m_config = &(*m_objects)[obj_idx]->config;
     }
     else {
-        const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item));
+        const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
+        if (item_type & itVolume)
+        {
         const int volume_id = m_objects_model->GetVolumeIdByItem(item);
         if (obj_idx < 0 || volume_id < 0)
             return;
         m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
+        }
+        else if (item_type & itLayer)
+            m_config = &get_item_config(item);
     }
 
     wxVariant variant;
@@ -669,7 +662,7 @@ void ObjectList::OnContextMenu(wxDataViewEvent&)
     const wxPoint pt = get_mouse_position_in_control();
     HitTest(pt, item, col);
     if (!item)
-#ifdef __WXOSX__ // #ys_FIXME temporary workaround for OSX 
+#ifdef __WXOSX__ // temporary workaround for OSX 
         // after Yosemite OS X version, HitTest return undefined item
         item = GetSelection();
     if (item)
@@ -1668,40 +1661,52 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
     ItemType type;
 
     m_objects_model->GetItemInfo(item, type, obj_idx, idx);
-    if (type == itUndef)
+    if (type & itUndef)
         return;
 
-    if (type == itSettings)
-        del_settings_from_config();
-    else if (type == itInstanceRoot && obj_idx != -1)
+    if (type & itSettings)
+        del_settings_from_config(m_objects_model->GetParent(item));
+    else if (type & itInstanceRoot && obj_idx != -1)
         del_instances_from_object(obj_idx);
-    else if ((type & itLayerRoot) && obj_idx != -1)
+    else if (type & itLayerRoot && obj_idx != -1)
         del_layers_from_object(obj_idx);
+    else if (type & itLayer && obj_idx != -1)
+        del_layer_from_object(obj_idx, m_objects_model->GetLayerRangeByItem(item));
     else if (idx == -1)
         return;
     else if (!del_subobject_from_object(obj_idx, idx, type))
         return;
 
     // If last volume item with warning was deleted, unmark object item
-    if (type == itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0)
+    if (type & itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0)
         m_objects_model->DeleteWarningIcon(m_objects_model->GetParent(item));
 
     m_objects_model->Delete(item);
 }
 
-void ObjectList::del_settings_from_config()
+void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item)
 {
-    auto opt_keys = m_config->keys();
-    if (opt_keys.size() == 1 && opt_keys[0] == "extruder")
+    const bool is_layer_settings = m_objects_model->GetItemType(parent_item) == itLayer;
+
+    const int opt_cnt = m_config->keys().size();
+    if (opt_cnt == 1 && m_config->has("extruder") || 
+        is_layer_settings && opt_cnt == 2 && m_config->has("extruder") && m_config->has("layer_height"))
         return;
+
     int extruder = -1;
     if (m_config->has("extruder"))
         extruder = m_config->option<ConfigOptionInt>("extruder")->value;
 
+    coordf_t layer_height = 0.0;
+    if (is_layer_settings)
+        layer_height = m_config->opt_float("layer_height");
+
     m_config->clear();
 
     if (extruder >= 0)
         m_config->set_key_value("extruder", new ConfigOptionInt(extruder));
+    if (is_layer_settings)
+        m_config->set_key_value("layer_height", new ConfigOptionFloat(layer_height));
 }
 
 void ObjectList::del_instances_from_object(const int obj_idx)
@@ -1718,6 +1723,17 @@ void ObjectList::del_instances_from_object(const int obj_idx)
     changed_object(obj_idx);
 }
 
+void ObjectList::del_layer_from_object(const int obj_idx, const t_layer_height_range& layer_range)
+{
+    const auto del_range = object(obj_idx)->layer_config_ranges.find(layer_range);
+    if (del_range == object(obj_idx)->layer_config_ranges.end())
+        return;
+        
+    object(obj_idx)->layer_config_ranges.erase(del_range);
+
+    changed_object(obj_idx);
+}
+
 void ObjectList::del_layers_from_object(const int obj_idx)
 {
     object(obj_idx)->layer_config_ranges.clear();
@@ -1764,15 +1780,6 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con
         }
         object->delete_instance(idx);
     }
-    else if (type == itLayer) {
-        t_layer_config_ranges::iterator layer_range = object->layer_config_ranges.begin();
-        int id = idx;
-        while (id > 0 && layer_range != object->layer_config_ranges.end()) {
-            layer_range++;
-            id--;
-        }
-        object->layer_config_ranges.erase(layer_range);
-    }
     else
         return false;
 
@@ -1982,9 +1989,7 @@ void ObjectList::part_selection_changed()
                     }
                     else if (parent_type & itLayer) {
                         og_name = _(L("Layer range Settings to modify"));
-
-                        const t_layer_height_range& layer_height_range = get_layer_range_from_item(parent, obj_idx);
-                        m_config = &(*m_objects)[obj_idx]->layer_config_ranges[layer_height_range];
+                        m_config = &get_item_config(parent);
                     }
                     update_and_show_settings = true;
                 }
@@ -2005,8 +2010,8 @@ void ObjectList::part_selection_changed()
                     og_name = type & itLayerRoot ? _(L("Layers Editing")) : _(L("Layer Editing"));
                     update_and_show_layers = true;
 
-                    const t_layer_height_range& layer_height_range = get_layer_range_from_item(item, obj_idx);
-                    m_config = &(*m_objects)[obj_idx]->layer_config_ranges[layer_height_range];
+                    if (type & itLayer)
+                        m_config = &get_item_config(item);
                 }
             }
         }
@@ -2252,7 +2257,7 @@ void ObjectList::remove()
     }
 }
 
-void ObjectList::del_layer_range(const std::pair<coordf_t, coordf_t>& range)
+void ObjectList::del_layer_range(const t_layer_height_range& range)
 {
     const int obj_idx = get_selected_obj_idx();
     if (obj_idx < 0) return;
@@ -2260,73 +2265,58 @@ void ObjectList::del_layer_range(const std::pair<coordf_t, coordf_t>& range)
     t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
 
     wxDataViewItem selectable_item = GetSelection();
-    int layer_idx = 0;
 
     if (ranges.size() == 1)
         selectable_item = m_objects_model->GetParent(selectable_item);
-    else {
-        // May be not a best solution #ys_FIXME
-        t_layer_config_ranges::iterator layer_selected = ranges.find(range);
-        t_layer_config_ranges::iterator it = ranges.begin();
-        while (it != layer_selected) {
-            ++it;
-            layer_idx++;
-        }
-    }
 
-    wxDataViewItem layer_item = m_objects_model->GetItemByLayerId(obj_idx, layer_idx);
+    wxDataViewItem layer_item = m_objects_model->GetItemByLayerRange(obj_idx, range);
     del_subobject_item(layer_item);
 
     select_item(selectable_item);
 }
 
-void ObjectList::add_layer_range(const t_layer_height_range& range)
+void ObjectList::add_layer_range_after_current(const t_layer_height_range& current_range)
 {
     const int obj_idx = get_selected_obj_idx();
     if (obj_idx < 0) return;
 
-    wxDataViewItem layers_item = GetSelection();
+    const wxDataViewItem layers_item = GetSelection();
 
     t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
 
-    const t_layer_config_ranges::iterator selected_range = ranges.find(range);
-    const t_layer_config_ranges::iterator last_range = --ranges.end();   
+    const t_layer_height_range& last_range = (--ranges.end())->first;
     
-    if (selected_range->first == last_range->first)
+    if (current_range == last_range)
     {
-        const t_layer_height_range new_range = { last_range->first.second, last_range->first.second + 0.5f };
+        const t_layer_height_range& new_range = { last_range.second, last_range.second + 0.5f };
         ranges[new_range] = get_default_layer_config(obj_idx);
         add_layer_item(new_range, layers_item);
     }
     else
     {
-        int layer_idx = 0;
-        t_layer_config_ranges::iterator next_range = ++ranges.find(range);
+        const t_layer_height_range& next_range = (++ranges.find(current_range))->first;
 
-        // May be not a best solution #ys_FIXME
-        t_layer_config_ranges::iterator it = ranges.begin();
-        while (it != next_range && it != ranges.end()) {
-            layer_idx++;
-            ++it;
-        }
-
-        if (selected_range->first.second > next_range->first.first)
-            return; // range devision has no mean
+        if (current_range.second > next_range.first)
+            return; // range division has no sense
         
-        if (selected_range->first.second == next_range->first.first)
+        const int layer_idx = m_objects_model->GetItemIdByLayerRange(obj_idx, next_range);
+        if (layer_idx < 0)
+            return;
+
+        if (current_range.second == next_range.first)
         {
-            const coordf_t delta = (next_range->first.second - next_range->first.first);
-            if (delta < 0.05f) // next range devision has no mean 
+            const coordf_t delta = (next_range.second - next_range.first);
+            if (delta < 0.05f) // next range division has no sense 
                 return; 
 
-            const coordf_t midl_layer = next_range->first.first + 0.5f * delta;
-            // #ys_FIXME  May be it should be copied just a "layer_height" option
-            const /*coordf_t*/auto old_config = next_range->second;
-            t_layer_height_range new_range = { midl_layer, next_range->first.second };
+            const coordf_t midl_layer = next_range.first + 0.5f * delta;
+            
+            const auto old_config = ranges.at(next_range);
+            t_layer_height_range new_range = { midl_layer, next_range.second };
 
             // delete old layer
 
-            wxDataViewItem layer_item = m_objects_model->GetItemByLayerId(obj_idx, layer_idx);
+            wxDataViewItem layer_item = m_objects_model->GetItemByLayerRange(obj_idx, next_range);
             del_subobject_item(layer_item);
 
             // create new 2 layers instead of deleted one
@@ -2334,13 +2324,13 @@ void ObjectList::add_layer_range(const t_layer_height_range& range)
             ranges[new_range] = old_config;
             add_layer_item(new_range, layers_item, layer_idx);
 
-            new_range = { selected_range->first.second, midl_layer };
+            new_range = { current_range.second, midl_layer };
             ranges[new_range] = get_default_layer_config(obj_idx);
             add_layer_item(new_range, layers_item, layer_idx);
         }
         else
         {
-            const t_layer_height_range new_range = { selected_range->first.second, next_range->first.first };
+            const t_layer_height_range new_range = { current_range.second, next_range.first };
             ranges[new_range] = get_default_layer_config(obj_idx);
             add_layer_item(new_range, layers_item, layer_idx);
         }        
@@ -2356,15 +2346,12 @@ void ObjectList::add_layer_item(const t_layer_height_range& range,
                                 const wxDataViewItem layers_item, 
                                 const int layer_idx /* = -1*/)
 {
-    const std::string label = (boost::format(" %.2f-%.2f ") % range.first % range.second).str();
-    const wxDataViewItem layer_item = m_objects_model->AddLayersChild(layers_item, label, layer_idx);
+    const wxDataViewItem layer_item = m_objects_model->AddLayersChild(layers_item, range, layer_idx);
 
     const int obj_idx = get_selected_obj_idx();
     if (obj_idx < 0) return;
 
-//     auto opt_keys = object(obj_idx)->layer_config_ranges[range].keys();
     const DynamicPrintConfig& config = object(obj_idx)->layer_config_ranges[range];
-//     if (!opt_keys.empty() && !(opt_keys.size() == 2 && opt_keys[0] == "layer_height" && opt_keys[1] == "extruder"))
     if (config.keys().size() > 2)
         select_item(m_objects_model->AddSettingsChild(layer_item));
 }
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index ad7587a01..455f9f7a1 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -229,8 +229,9 @@ public:
 	void                load_generic_subobject(const std::string& type_name, const ModelVolumeType type);
     void                del_object(const int obj_idx);
     void                del_subobject_item(wxDataViewItem& item);
-    void                del_settings_from_config();
+    void                del_settings_from_config(const wxDataViewItem& parent_item);
     void                del_instances_from_object(const int obj_idx);
+    void                del_layer_from_object(const int obj_idx, const t_layer_height_range& layer_range);
     void                del_layers_from_object(const int obj_idx);
     bool                del_subobject_from_object(const int obj_idx, const int idx, const int type);
     void                split();
@@ -245,7 +246,6 @@ public:
     wxBoxSizer*         get_sizer() {return  m_sizer;}
     int                 get_selected_obj_idx() const;
     DynamicPrintConfig& get_item_config(const wxDataViewItem& item) const;
-    const t_layer_height_range& get_layer_range_from_item(const wxDataViewItem layer_item, const int obj_idx) const;
 
     void                changed_object(const int obj_idx = -1) const;
     void                part_selection_changed();
@@ -277,7 +277,7 @@ public:
     // Remove objects/sub-object from the list
     void remove();
     void del_layer_range(const t_layer_height_range& range);
-    void add_layer_range(const t_layer_height_range& range);
+    void add_layer_range_after_current(const t_layer_height_range& current_range);
     void add_layer_item (const t_layer_height_range& range, 
                          const wxDataViewItem layers_item, 
                          const int layer_idx = -1);
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index 6cd270e5b..045feb75a 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -3442,9 +3442,9 @@ void TabSLAMaterial::reload_config()
 void TabSLAMaterial::update()
 {
     if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF)
-        return; // #ys_FIXME
+        return;
     
-// #ys_FIXME
+// #ys_FIXME. Just a template for this function
 //     m_update_cnt++;
 //     ! something to update
 //     m_update_cnt--;
@@ -3542,9 +3542,8 @@ void TabSLAPrint::reload_config()
 void TabSLAPrint::update()
 {
     if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF)
-        return; // #ys_FIXME
+        return;
 
-// #ys_FIXME
      m_update_cnt++;
 
      double head_penetration = m_config->opt_float("support_head_penetration");
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index adc2e6d07..ed49c8513 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -464,12 +464,13 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
 }
 
 ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, 
-                                                 const wxString& label_range, 
+                                                 const t_layer_height_range& layer_range,
                                                  const int idx /*= -1 */, 
                                                  const wxString& extruder) :
     m_parent(parent),
     m_type(itLayer),
     m_idx(idx),
+    m_layer_range(layer_range),
     m_extruder(extruder)
 {
     const int children_cnt = parent->GetChildCount();
@@ -481,7 +482,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
         for (int i = m_idx; i < children_cnt; i++)
             parent->GetNthChild(i)->SetIdx(i + 1);
     }
-//     m_name = wxString::Format(_(L("Layer %s (mm)")), label_range);
+    const std::string label_range = (boost::format(" %.2f-%.2f ") % layer_range.first % layer_range.second).str();
     m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")";
     m_bmp = create_scaled_bitmap(nullptr, "layers_white");    // FIXME: pass window ptr
 
@@ -751,7 +752,7 @@ wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_i
 }
 
 wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item, 
-                                                   const std::string& label_range, 
+                                                   const t_layer_height_range& layer_range, 
                                                    const int index /* = -1*/)
 {
     ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
@@ -773,7 +774,7 @@ wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_
     }
 
     // Add layer node
-    ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, label_range, index);
+    ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, layer_range, index);
     if (index < 0)
         layer_root_node->Append(layer_node);
     else
@@ -1122,7 +1123,7 @@ wxDataViewItem ObjectDataViewModel::GetItemById(const int obj_idx, const int sub
     if (!item)
         return wxDataViewItem(0);
 
-    auto parent = (ObjectDataViewModelNode*)item.GetID();;
+    auto parent = (ObjectDataViewModelNode*)item.GetID();
     for (size_t i = 0; i < parent->GetChildCount(); i++)
         if (parent->GetNthChild(i)->m_idx == sub_obj_idx)
             return wxDataViewItem(parent->GetNthChild(i));
@@ -1140,6 +1141,34 @@ wxDataViewItem ObjectDataViewModel::GetItemByLayerId(int obj_idx, int layer_idx)
     return GetItemById(obj_idx, layer_idx, itLayerRoot);
 }
 
+wxDataViewItem ObjectDataViewModel::GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range)
+{
+    if (obj_idx >= m_objects.size() || obj_idx < 0) {
+        printf("Error! Out of objects range.\n");
+        return wxDataViewItem(0);
+    }
+
+    auto item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), itLayerRoot);
+    if (!item)
+        return wxDataViewItem(0);
+
+    auto parent = (ObjectDataViewModelNode*)item.GetID();
+    for (size_t i = 0; i < parent->GetChildCount(); i++)
+        if (parent->GetNthChild(i)->m_layer_range == layer_range)
+            return wxDataViewItem(parent->GetNthChild(i));
+
+    return wxDataViewItem(0);
+}
+
+int  ObjectDataViewModel::GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range)
+{
+    wxDataViewItem item = GetItemByLayerRange(obj_idx, layer_range);
+    if (!item)
+        return -1;
+
+    return GetLayerIdByItem(item);
+}
+
 int ObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) const
 {
 	wxASSERT(item.IsOk());
@@ -1182,6 +1211,16 @@ int ObjectDataViewModel::GetLayerIdByItem(const wxDataViewItem& item) const
     return GetIdByItemAndType(item, itLayer);
 }
 
+t_layer_height_range ObjectDataViewModel::GetLayerRangeByItem(const wxDataViewItem& item) const
+{
+    wxASSERT(item.IsOk());
+
+    ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
+    if (!node || node->m_type != itLayer)
+        return { 0.0f, 0.0f };
+    return node->GetLayerRange();
+}
+
 void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx)
 {
     wxASSERT(item.IsOk());
@@ -1196,9 +1235,10 @@ void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type
 
     ObjectDataViewModelNode *parent_node = node->GetParent();
     if (!parent_node) return;
-    if (type & (itInstance | itLayer))
-        parent_node = node->GetParent()->GetParent();
-    if (!parent_node || parent_node->m_type != itObject) { type = itUndef; return; }
+
+    // get top parent (Object) node
+    while (parent_node->m_type != itObject)
+        parent_node = parent_node->GetParent();
 
     auto it = find(m_objects.begin(), m_objects.end(), parent_node);
     if (it != m_objects.end())
@@ -1366,10 +1406,7 @@ wxDataViewItem ObjectDataViewModel::GetTopParent(const wxDataViewItem &item) con
 
     ObjectDataViewModelNode *parent_node = node->GetParent();
     while (parent_node->m_type != itObject)
-    {
-        node = parent_node;
-        parent_node = node->GetParent();
-    }
+        parent_node = parent_node->GetParent();
 
     return wxDataViewItem((void*)parent_node);
 }
diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp
index 775d89a3b..3f43b0882 100644
--- a/src/slic3r/GUI/wxExtensions.hpp
+++ b/src/slic3r/GUI/wxExtensions.hpp
@@ -20,6 +20,8 @@ namespace Slic3r {
 	enum class ModelVolumeType : int;
 };
 
+typedef std::pair<coordf_t, coordf_t>                       t_layer_height_range;
+
 #ifdef __WXMSW__
 void                msw_rescale_menu(wxMenu* menu);
 #else /* __WXMSW__ */
@@ -179,6 +181,7 @@ class ObjectDataViewModelNode
     wxBitmap                        m_empty_bmp;
     size_t                          m_volumes_cnt = 0;
     std::vector< std::string >      m_opt_categories;
+    t_layer_height_range            m_layer_range = { 0.0f, 0.0f };
 
     wxString				        m_name;
     wxBitmap&                       m_bmp = m_empty_bmp;
@@ -232,7 +235,7 @@ public:
     }
 
 	ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
-							const wxString& label_range,
+							const t_layer_height_range& layer_range,
                             const int idx = -1,
                             const wxString& extruder = wxEmptyString );
 
@@ -325,6 +328,7 @@ public:
     ItemType        GetType() const                 { return m_type; }
 	void			SetIdx(const int& idx);
 	int             GetIdx() const                  { return m_idx; }
+	t_layer_height_range    GetLayerRange() const   { return m_layer_range; }
 
 	// use this function only for childrens
 	void AssignAllVal(ObjectDataViewModelNode& from_node)
@@ -397,7 +401,7 @@ public:
     wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
     wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
     wxDataViewItem AddLayersChild(  const wxDataViewItem &parent_item, 
-                                    const std::string& label_range, 
+                                    const t_layer_height_range& layer_range, 
                                     const int index = -1);
 	wxDataViewItem Delete(const wxDataViewItem &item);
 	wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
@@ -410,6 +414,8 @@ public:
 	wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx);
 	wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx);
     wxDataViewItem GetItemByLayerId(int obj_idx, int layer_idx);
+    wxDataViewItem GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
+    int  GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
 	int  GetIdByItem(const wxDataViewItem& item) const;
     int  GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
     int  GetObjectIdByItem(const wxDataViewItem& item) const;
@@ -480,6 +486,7 @@ public:
     wxBitmap    GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, 
                               const bool is_marked = false);
     void        DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
+    t_layer_height_range    GetLayerRangeByItem(const wxDataViewItem& item) const;
 };
 
 // ----------------------------------------------------------------------------

From 446e37b1512e507d3f99526e0572c7aacb1c406c Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Fri, 7 Jun 2019 11:32:46 +0200
Subject: [PATCH 21/34] Implemented extruder selection for Layers

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

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 3060a166d..85195f87d 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -2346,12 +2346,18 @@ void ObjectList::add_layer_item(const t_layer_height_range& range,
                                 const wxDataViewItem layers_item, 
                                 const int layer_idx /* = -1*/)
 {
-    const wxDataViewItem layer_item = m_objects_model->AddLayersChild(layers_item, range, layer_idx);
-
     const int obj_idx = get_selected_obj_idx();
     if (obj_idx < 0) return;
 
     const DynamicPrintConfig& config = object(obj_idx)->layer_config_ranges[range];
+    if (!config.has("extruder"))
+        return;
+
+    const auto layer_item = m_objects_model->AddLayersChild(layers_item, 
+                                                            range, 
+                                                            config.opt_int("extruder"),
+                                                            layer_idx);
+
     if (config.keys().size() > 2)
         select_item(m_objects_model->AddSettingsChild(layer_item));
 }
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index ed49c8513..05cc265c3 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -752,12 +752,15 @@ wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_i
 }
 
 wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item, 
-                                                   const t_layer_height_range& layer_range, 
+                                                   const t_layer_height_range& layer_range,
+                                                   const int extruder/* = 0*/, 
                                                    const int index /* = -1*/)
 {
     ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
     if (!parent_node) return wxDataViewItem(0);
 
+    wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
+
     // get LayerRoot node
     ObjectDataViewModelNode *layer_root_node;
     wxDataViewItem layer_root_item;
@@ -774,7 +777,7 @@ wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_
     }
 
     // Add layer node
-    ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, layer_range, index);
+    ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, layer_range, index, extruder_str);
     if (index < 0)
         layer_root_node->Append(layer_node);
     else
diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp
index 3f43b0882..8ade7af07 100644
--- a/src/slic3r/GUI/wxExtensions.hpp
+++ b/src/slic3r/GUI/wxExtensions.hpp
@@ -401,7 +401,8 @@ public:
     wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
     wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
     wxDataViewItem AddLayersChild(  const wxDataViewItem &parent_item, 
-                                    const t_layer_height_range& layer_range, 
+                                    const t_layer_height_range& layer_range,
+                                    const int extruder = 0, 
                                     const int index = -1);
 	wxDataViewItem Delete(const wxDataViewItem &item);
 	wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);

From 2fa87044be0796625691702485344059b1832d9f Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 10 Jun 2019 10:48:43 +0200
Subject: [PATCH 22/34] Implemented update_object_list_by_printer_technology()

---
 src/slic3r/GUI/GUI_ObjectList.cpp | 118 +++++++++++++++++++++++++++---
 src/slic3r/GUI/GUI_ObjectList.hpp |   5 ++
 src/slic3r/GUI/Plater.cpp         |   8 +-
 3 files changed, 121 insertions(+), 10 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 85195f87d..dfdaa7171 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -1849,24 +1849,41 @@ void ObjectList::layers_editing()
     // if it doesn't exist now
     if (!layers_item.IsOk())
     {
-        // create LayerRoot item
-        layers_item = m_objects_model->AddLayersRoot(obj_item);
-
         t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
-        
+
+        // set some default value
         if (ranges.empty())
             ranges[{ 0.0f, 0.6f }] = get_default_layer_config(obj_idx);
 
-        // and create Layer item(s) according to the layer_config_ranges
-        for (const auto range : ranges)
-            add_layer_item(range.first, layers_item);
+        // create layer root item
+        layers_item = add_layer_root_item(obj_item);
     }
+    if (!layers_item.IsOk())
+        return;
 
     // select LayerRoor item and expand
     select_item(layers_item);
     Expand(layers_item);
 }
 
+wxDataViewItem ObjectList::add_layer_root_item(const wxDataViewItem obj_item)
+{
+    const int obj_idx = m_objects_model->GetIdByItem(obj_item);
+    if (obj_idx < 0 || 
+        object(obj_idx)->layer_config_ranges.empty() ||
+        printer_technology() == ptSLA)
+        return wxDataViewItem(0);
+
+    // create LayerRoot item
+    wxDataViewItem layers_item = m_objects_model->AddLayersRoot(obj_item);
+
+    // and create Layer item(s) according to the layer_config_ranges
+    for (const auto range : object(obj_idx)->layer_config_ranges)
+        add_layer_item(range.first, layers_item);
+
+    return layers_item;
+}
+
 DynamicPrintConfig ObjectList::get_default_layer_config(const int obj_idx)
 {
     DynamicPrintConfig config;
@@ -2031,7 +2048,9 @@ void ObjectList::part_selection_changed()
     if (update_and_show_settings)
         wxGetApp().obj_settings()->get_og()->set_name(" " + og_name + " ");
 
-    if (update_and_show_layers)
+    if (printer_technology() == ptSLA)
+        update_and_show_layers = false;
+    else if (update_and_show_layers)
         wxGetApp().obj_layers()->get_og()->set_name(" " + og_name + " ");
 
     Sidebar& panel = wxGetApp().sidebar();
@@ -2346,7 +2365,7 @@ void ObjectList::add_layer_item(const t_layer_height_range& range,
                                 const wxDataViewItem layers_item, 
                                 const int layer_idx /* = -1*/)
 {
-    const int obj_idx = get_selected_obj_idx();
+    const int obj_idx = m_objects_model->GetObjectIdByItem(layers_item);
     if (obj_idx < 0) return;
 
     const DynamicPrintConfig& config = object(obj_idx)->layer_config_ranges[range];
@@ -2908,6 +2927,87 @@ void ObjectList::update_settings_items()
     m_prevent_canvas_selection_update = false;
 }
 
+// Update settings item for item had it
+void ObjectList::update_settings_item_for_item(wxDataViewItem item, wxDataViewItemArray& selections)
+{
+    const wxDataViewItem& settings_item = m_objects_model->GetSettingsItem(item);
+    select_item(settings_item ? settings_item : m_objects_model->AddSettingsChild(item));
+
+    // If settings item was deleted from the list, 
+    // it's need to be deleted from selection array, if it was there
+    if (settings_item != m_objects_model->GetSettingsItem(item) &&
+        selections.Index(settings_item) != wxNOT_FOUND) {
+        selections.Remove(settings_item);
+
+        // Select item, if settings_item doesn't exist for item anymore, but was selected
+        if (selections.Index(item) == wxNOT_FOUND)
+            selections.Add(item);
+    }
+}
+
+void ObjectList::update_object_list_by_printer_technology()
+{
+    m_prevent_canvas_selection_update = true;
+    wxDataViewItemArray sel;
+    GetSelections(sel); // stash selection
+
+    wxDataViewItemArray object_items;
+    m_objects_model->GetChildren(wxDataViewItem(0), object_items);
+
+    for (auto& object_item : object_items) {
+        // Update Settings Item for object
+        update_settings_item_for_item(object_item, sel);
+
+        // Update settings for Volumes
+        wxDataViewItemArray all_object_subitems;
+        m_objects_model->GetChildren(object_item, all_object_subitems);
+        for (auto item : all_object_subitems)
+            if (m_objects_model->GetItemType(item) & itVolume)
+                // update settings for volume
+                update_settings_item_for_item(item, sel);
+
+        // Update Layers Items
+        wxDataViewItem layers_item = m_objects_model->GetLayerRootItem(object_item);
+        if (!layers_item)
+            layers_item = add_layer_root_item(object_item);
+        else if (printer_technology() == ptSLA) {
+            // If layers root item will be deleted from the list, so
+            // it's need to be deleted from selection array, if it was there
+            wxDataViewItemArray del_items;
+            bool some_layers_was_selected = false;
+            m_objects_model->GetAllChildren(layers_item, del_items);
+            for (auto& del_item:del_items)
+                if (sel.Index(del_item) != wxNOT_FOUND) {
+                    some_layers_was_selected = true;
+                    sel.Remove(del_item);
+                }
+            if (sel.Index(layers_item) != wxNOT_FOUND) {
+                some_layers_was_selected = true;
+                sel.Remove(layers_item);
+            }
+
+            // delete all "layers" items
+            m_objects_model->Delete(layers_item);
+
+            // Select object_item, if layers_item doesn't exist for item anymore, but was some of layer items was/were selected
+            if (some_layers_was_selected)
+                sel.Add(object_item);
+        }
+        else {
+            wxDataViewItemArray all_obj_layers;
+            m_objects_model->GetChildren(layers_item, all_obj_layers);
+
+            for (auto item : all_obj_layers)
+                // update settings for layer
+                update_settings_item_for_item(item, sel);
+        }
+    }
+
+    // restore selection:
+    SetSelections(sel);
+    m_prevent_canvas_selection_update = false;
+}
+
 void ObjectList::update_object_menu()
 {
     append_menu_items_add_volume(&m_menu_object);
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 455f9f7a1..29a8096d4 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -236,6 +236,9 @@ public:
     bool                del_subobject_from_object(const int obj_idx, const int idx, const int type);
     void                split();
     void                layers_editing();
+
+    wxDataViewItem      add_layer_root_item(const wxDataViewItem obj_item);
+
     DynamicPrintConfig  get_default_layer_config(const int obj_idx);
     bool                get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume);
     bool                is_splittable();
@@ -305,6 +308,8 @@ public:
     void last_volume_is_deleted(const int obj_idx);
     bool has_multi_part_objects();
     void update_settings_items();
+    void update_settings_item_for_item(wxDataViewItem item, wxDataViewItemArray& selections);
+    void update_object_list_by_printer_technology();
     void update_object_menu();
 
     void instances_to_separated_object(const int obj_idx, const std::set<int>& inst_idx);
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index cba15d7a9..8e2764bb3 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -2733,8 +2733,14 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
 
     // update plater with new config
     wxGetApp().plater()->on_config_change(wxGetApp().preset_bundle->full_config());
+    /* Settings list can be changed after printer preset changing, so
+     * update all settings items for all item had it.
+     * Furthermore, Layers editing is implemented only for FFF printers 
+     * and for SLA presets they should be deleted
+     */
     if (preset_type == Preset::TYPE_PRINTER)
-        wxGetApp().obj_list()->update_settings_items();
+//        wxGetApp().obj_list()->update_settings_items();
+        wxGetApp().obj_list()->update_object_list_by_printer_technology();
 }
 
 void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)

From 2b6e5a0a7077b2d759ced0a551ba482f6e0469dd Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 10 Jun 2019 15:22:09 +0200
Subject: [PATCH 23/34] Implemented Copy/Paste for Layers. + improved selection
 (in respect to the Layers)

---
 src/slic3r/GUI/GUI_ObjectList.cpp | 144 ++++++++++++++++++++++--------
 src/slic3r/GUI/GUI_ObjectList.hpp |  20 +++--
 src/slic3r/GUI/wxExtensions.cpp   |   3 +-
 3 files changed, 120 insertions(+), 47 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index dfdaa7171..f6dd6c591 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -581,6 +581,56 @@ void ObjectList::selection_changed()
     part_selection_changed();
 }
 
+void ObjectList::fill_layer_config_ranges_cache()
+{
+    wxDataViewItemArray sel_layers;
+    GetSelections(sel_layers);
+
+    const int obj_idx = m_objects_model->GetObjectIdByItem(sel_layers[0]);
+    if (obj_idx < 0 || (int)m_objects->size() <= obj_idx)
+        return;
+
+    const t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
+    m_layer_config_ranges_cache.clear();
+
+    for (const auto layer_item : sel_layers)
+        if (m_objects_model->GetItemType(layer_item) & itLayer) {
+            auto range = m_objects_model->GetLayerRangeByItem(layer_item);
+            auto it = ranges.find(range);
+            if (it != ranges.end())
+                m_layer_config_ranges_cache[it->first] = it->second;
+        }
+}
+
+void ObjectList::paste_layers_into_list()
+{
+    const int obj_idx = m_objects_model->GetObjectIdByItem(GetSelection());
+
+    if (obj_idx < 0 || (int)m_objects->size() <= obj_idx || 
+        m_layer_config_ranges_cache.empty() || printer_technology() == ptSLA)
+        return;
+
+    const wxDataViewItem object_item = m_objects_model->GetItemById(obj_idx);
+    wxDataViewItem layers_item = m_objects_model->GetLayerRootItem(object_item);
+    if (layers_item)
+        m_objects_model->Delete(layers_item);
+
+    t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
+
+    // and create Layer item(s) according to the layer_config_ranges
+    for (const auto range : m_layer_config_ranges_cache)
+        ranges.emplace(range);
+
+    layers_item = add_layer_root_item(object_item);
+
+    changed_object(obj_idx);
+
+    select_item(layers_item);
+#ifndef __WXOSX__
+    selection_changed();
+#endif //no __WXOSX__
+}
+
 void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes)
 {
     if ((obj_idx < 0) || ((int)m_objects->size() <= obj_idx))
@@ -737,10 +787,18 @@ void ObjectList::key_event(wxKeyEvent& event)
     }
     else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/))
         select_item_all_children();
-    else if (wxGetKeyState(wxKeyCode('C')) && wxGetKeyState(WXK_CONTROL))
-        wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY));
-    else if (wxGetKeyState(wxKeyCode('V')) && wxGetKeyState(WXK_CONTROL))
-        wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE));
+    else if (wxGetKeyState(wxKeyCode('C')) && wxGetKeyState(WXK_CONTROL)) {
+        if (m_selection_mode & smLayer)
+            fill_layer_config_ranges_cache();
+        else
+            wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY));
+    }
+    else if (wxGetKeyState(wxKeyCode('V')) && wxGetKeyState(WXK_CONTROL)) {
+        if (!m_layer_config_ranges_cache.empty())
+            paste_layers_into_list();
+        else
+            wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE));
+    }
     else
         event.Skip();
 }
@@ -2104,6 +2162,9 @@ void ObjectList::add_object_to_list(size_t obj_idx)
         Expand(item);
     }
 
+    // Add layers if it has
+    add_layer_root_item(item);
+
 #ifndef __WXOSX__ 
     selection_changed();
 #endif //__WXMSW__
@@ -2568,22 +2629,18 @@ void ObjectList::update_selections_on_canvas()
     auto add_to_selection = [this](const wxDataViewItem& item, Selection& selection, int instance_idx, bool as_single_selection)
     {
         const ItemType& type = m_objects_model->GetItemType(item);
-        if ( type == itLayerRoot || m_objects_model->GetParent(item) == wxDataViewItem(0) ) {
-            wxDataViewItem obj_item = type == itLayerRoot ? m_objects_model->GetParent(item) : item;
-            selection.add_object(m_objects_model->GetIdByItem(obj_item), as_single_selection);
-            return;
-        }
+        const int obj_idx = m_objects_model->GetObjectIdByItem(item);
 
         if (type == itVolume) {
-            const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item));
             const int vol_idx = m_objects_model->GetVolumeIdByItem(item);
             selection.add_volume(obj_idx, vol_idx, std::max(instance_idx, 0), as_single_selection);
         }
         else if (type == itInstance) {
-            const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
             const int inst_idx = m_objects_model->GetInstanceIdByItem(item);
             selection.add_instance(obj_idx, inst_idx, as_single_selection);
         }
+        else
+            selection.add_object(obj_idx, as_single_selection);
     };
 
     // stores current instance idx before to clear the selection
@@ -2654,11 +2711,13 @@ void ObjectList::select_item_all_children()
     }
     else {
         const auto item = GetSelection();
-        // Some volume(instance) is selected    =>  select all volumes(instances) inside the current object
-        if (m_objects_model->GetItemType(item) & (itVolume | itInstance))
+        const ItemType item_type = m_objects_model->GetItemType(item);
+        // Some volume/layer/instance is selected    =>  select all volumes/layers/instances inside the current object
+        if (item_type & (itVolume | itInstance | itLayer))
             m_objects_model->GetChildren(m_objects_model->GetParent(item), sels);
 
-        m_selection_mode = m_objects_model->GetItemType(item)&itVolume ? smVolume : smInstance;
+        m_selection_mode = item_type&itVolume ? smVolume : 
+                           item_type&itLayer  ? smLayer  : smInstance;
     }
 
     SetSelections(sels);
@@ -2677,8 +2736,9 @@ void ObjectList::update_selection_mode()
     }
 
     const ItemType type = m_objects_model->GetItemType(GetSelection());
-    m_selection_mode =  type&itSettings ? smUndef   :
-                        type&itVolume   ? smVolume  : smInstance;
+    m_selection_mode =  type & itSettings ? smUndef  :
+                        type & itLayer    ? smLayer  :
+                        type & itVolume   ? smVolume : smInstance;
 }
 
 // check last selected item. If is it possible to select it
@@ -2689,33 +2749,37 @@ bool ObjectList::check_last_selection(wxString& msg_str)
         
     const bool is_shift_pressed = wxGetKeyState(WXK_SHIFT);
 
-    /* We can't mix Parts and Objects/Instances.
+    /* We can't mix Volumes, Layers and Objects/Instances.
      * So, show information about it
      */
     const ItemType type = m_objects_model->GetItemType(m_last_selected_item);
 
-    // check a case of a selection of the Parts from different Objects
-    bool impossible_multipart_selection = false;
-    if (type & itVolume && m_selection_mode == smVolume)
-    {
+    // check a case of a selection of the same type items from different Objects
+    auto impossible_multi_selection = [type, this](const ItemType item_type, const SELECTION_MODE selection_mode) {
+        if (!(type & item_type && m_selection_mode & selection_mode))
+            return false;
+
         wxDataViewItemArray sels;
         GetSelections(sels);
-        for (const auto& sel: sels)
-            if (sel != m_last_selected_item && 
-                m_objects_model->GetParent(sel) != m_objects_model->GetParent(m_last_selected_item))
-            {
-                impossible_multipart_selection = true;
-                break;
-            }
-    }
+        for (const auto& sel : sels)
+            if (sel != m_last_selected_item &&
+                m_objects_model->GetTopParent(sel) != m_objects_model->GetTopParent(m_last_selected_item))
+                return true;
 
-    if (impossible_multipart_selection ||
+        return false;
+    };
+
+    if (impossible_multi_selection(itVolume, smVolume) ||
+        impossible_multi_selection(itLayer,  smLayer ) ||
         type & itSettings ||
-        type & itVolume && m_selection_mode == smInstance ||
-        !(type & itVolume) && m_selection_mode == smVolume)
+        type & itVolume   && !(m_selection_mode & smVolume  ) ||
+        type & itLayer    && !(m_selection_mode & smLayer   ) ||
+        type & itInstance && !(m_selection_mode & smInstance)
+        )
     {
         // Inform user why selection isn't complited
-        const wxString item_type = m_selection_mode == smInstance ? _(L("Object or Instance")) : _(L("Part"));
+        const wxString item_type = m_selection_mode & smInstance ? _(L("Object or Instance")) : 
+                                   m_selection_mode & smVolume   ? _(L("Part")) : _(L("Layer"));
 
         msg_str = wxString::Format( _(L("Unsupported selection")) + "\n\n" + 
                                     _(L("You started your selection with %s Item.")) + "\n" +
@@ -2752,7 +2816,7 @@ void ObjectList::fix_multiselection_conflicts()
     wxDataViewItemArray sels;
     GetSelections(sels);
 
-    if (m_selection_mode == smVolume)
+    if (m_selection_mode & (smVolume|smLayer))
     {
         // identify correct parent of the initial selected item
         const wxDataViewItem& parent = m_objects_model->GetParent(m_last_selected_item == sels.front() ? sels.back() : sels.front());
@@ -2761,8 +2825,10 @@ void ObjectList::fix_multiselection_conflicts()
         wxDataViewItemArray children; // selected volumes from current parent
         m_objects_model->GetChildren(parent, children);
 
+        const ItemType item_type = m_selection_mode & smVolume ? itVolume : itLayer;
+
         for (const auto child : children)
-            if (IsSelected(child) && m_objects_model->GetItemType(child)&itVolume)
+            if (IsSelected(child) && m_objects_model->GetItemType(child) & item_type)
                 sels.Add(child);
 
         // If some part is selected, unselect all items except of selected parts of the current object
@@ -2928,7 +2994,7 @@ void ObjectList::update_settings_items()
 }
 
 // Update settings item for item had it
-void ObjectList::update_settings_item_for_item(wxDataViewItem item, wxDataViewItemArray& selections)
+void ObjectList::update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections)
 {
     const wxDataViewItem& settings_item = m_objects_model->GetSettingsItem(item);
     select_item(settings_item ? settings_item : m_objects_model->AddSettingsChild(item));
@@ -2956,7 +3022,7 @@ void ObjectList::update_object_list_by_printer_technology()
 
     for (auto& object_item : object_items) {
         // Update Settings Item for object
-        update_settings_item_for_item(object_item, sel);
+        update_settings_item_and_selection(object_item, sel);
 
         // Update settings for Volumes
         wxDataViewItemArray all_object_subitems;
@@ -2964,7 +3030,7 @@ void ObjectList::update_object_list_by_printer_technology()
         for (auto item : all_object_subitems)
             if (m_objects_model->GetItemType(item) & itVolume)
                 // update settings for volume
-                update_settings_item_for_item(item, sel);
+                update_settings_item_and_selection(item, sel);
 
         // Update Layers Items
         wxDataViewItem layers_item = m_objects_model->GetLayerRootItem(object_item);
@@ -2999,7 +3065,7 @@ void ObjectList::update_object_list_by_printer_technology()
 
             for (auto item : all_obj_layers)
                 // update settings for layer
-                update_settings_item_for_item(item, sel);
+                update_settings_item_and_selection(item, sel);
         }
     }
 
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 29a8096d4..7c7046626 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -33,8 +33,9 @@ typedef std::map< std::string, std::vector< std::pair<std::string, std::string>
 
 typedef std::vector<ModelVolume*> ModelVolumePtrs;
 
-typedef double                                      coordf_t;
-typedef std::pair<coordf_t, coordf_t>               t_layer_height_range;
+typedef double                                              coordf_t;
+typedef std::pair<coordf_t, coordf_t>                       t_layer_height_range;
+typedef std::map<t_layer_height_range, DynamicPrintConfig>  t_layer_config_ranges;
 
 namespace GUI {
 
@@ -67,9 +68,10 @@ class ObjectList : public wxDataViewCtrl
 {
     enum SELECTION_MODE
     {
-        smUndef,
-        smVolume,
-        smInstance
+        smUndef     = 0,
+        smVolume    = 1,
+        smInstance  = 2,
+        smLayer     = 4
     } m_selection_mode {smUndef};
 
     struct dragged_item_data
@@ -130,7 +132,9 @@ class ObjectList : public wxDataViewCtrl
     DynamicPrintConfig          *m_config {nullptr};
     std::vector<ModelObject*>   *m_objects{ nullptr };
 
-    std::vector<wxBitmap*> m_bmp_vector;
+    std::vector<wxBitmap*>      m_bmp_vector;
+
+    t_layer_config_ranges       m_layer_config_ranges_cache;
 
     int			m_selected_object_id = -1;
     bool		m_prevent_list_events = false;		// We use this flag to avoid circular event handling Select() 
@@ -308,7 +312,7 @@ public:
     void last_volume_is_deleted(const int obj_idx);
     bool has_multi_part_objects();
     void update_settings_items();
-    void update_settings_item_for_item(wxDataViewItem item, wxDataViewItemArray& selections);
+    void update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections);
     void update_object_list_by_printer_technology();
     void update_object_menu();
 
@@ -319,6 +323,8 @@ public:
     void fix_through_netfabb();
     void update_item_error_icon(const int obj_idx, int vol_idx) const ;
 
+    void fill_layer_config_ranges_cache();
+    void paste_layers_into_list();
     void paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes);
     void paste_objects_into_list(const std::vector<size_t>& object_idxs);
 
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index 05cc265c3..c23caa6c8 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -1174,7 +1174,8 @@ int  ObjectDataViewModel::GetItemIdByLayerRange(const int obj_idx, const t_layer
 
 int ObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) const
 {
-	wxASSERT(item.IsOk());
+	if(!item.IsOk())
+        return -1;
 
 	ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
 	auto it = find(m_objects.begin(), m_objects.end(), node);

From 72046598a966e04caf734867b99e8b360fb05aeb Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 10 Jun 2019 15:49:41 +0200
Subject: [PATCH 24/34] Fixed OSX build

---
 src/slic3r/GUI/wxExtensions.hpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp
index 8ade7af07..1ed5770bb 100644
--- a/src/slic3r/GUI/wxExtensions.hpp
+++ b/src/slic3r/GUI/wxExtensions.hpp
@@ -20,7 +20,8 @@ namespace Slic3r {
 	enum class ModelVolumeType : int;
 };
 
-typedef std::pair<coordf_t, coordf_t>                       t_layer_height_range;
+typedef double                          coordf_t;
+typedef std::pair<coordf_t, coordf_t>   t_layer_height_range;
 
 #ifdef __WXMSW__
 void                msw_rescale_menu(wxMenu* menu);

From 16c5a87997e6ce1cea09cda8e2ca4aaf06676092 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 11 Jun 2019 09:50:58 +0200
Subject: [PATCH 25/34] Import/export of the Layers information to/from AMF

---
 src/libslic3r/Format/AMF.cpp | 57 ++++++++++++++++++++++++++++++++++--
 1 file changed, 55 insertions(+), 2 deletions(-)

diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index d26b5f3ed..ed9c8f445 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -106,6 +106,9 @@ struct AMFParserContext
                                         // amf/material/metadata
         NODE_TYPE_OBJECT,               // amf/object
                                         // amf/object/metadata
+        NODE_TYPE_LAYER_CONFIG,         // amf/object/layer_config_ranges
+        NODE_TYPE_RANGE,                // amf/object/layer_config_ranges/range
+                                        // amf/object/layer_config_ranges/range/metadata
         NODE_TYPE_MESH,                 // amf/object/mesh
         NODE_TYPE_VERTICES,             // amf/object/mesh/vertices
         NODE_TYPE_VERTEX,               // amf/object/mesh/vertices/vertex
@@ -260,7 +263,9 @@ void AMFParserContext::startElement(const char *name, const char **atts)
                 m_value[0] = get_attribute(atts, "type");
                 node_type_new = NODE_TYPE_METADATA;
             }
-        } else if (strcmp(name, "mesh") == 0) {
+        } else if (strcmp(name, "layer_config_ranges") == 0 && m_path[1] == NODE_TYPE_OBJECT)
+                node_type_new = NODE_TYPE_LAYER_CONFIG;
+        else if (strcmp(name, "mesh") == 0) {
             if (m_path[1] == NODE_TYPE_OBJECT)
                 node_type_new = NODE_TYPE_MESH;
         } else if (strcmp(name, "instance") == 0) {
@@ -317,6 +322,10 @@ void AMFParserContext::startElement(const char *name, const char **atts)
             else if (strcmp(name, "mirrorz") == 0)
                 node_type_new = NODE_TYPE_MIRRORZ;
         }
+        else if (m_path[2] == NODE_TYPE_LAYER_CONFIG && strcmp(name, "range") == 0) {
+            assert(m_object);
+            node_type_new = NODE_TYPE_RANGE;
+        }
         break;
     case 4:
         if (m_path[3] == NODE_TYPE_VERTICES) {
@@ -334,6 +343,10 @@ void AMFParserContext::startElement(const char *name, const char **atts)
             } else if (strcmp(name, "triangle") == 0)
                 node_type_new = NODE_TYPE_TRIANGLE;
         }
+        else if (m_path[3] == NODE_TYPE_RANGE && strcmp(name, "metadata") == 0) {
+            m_value[0] = get_attribute(atts, "type");
+            node_type_new = NODE_TYPE_METADATA;
+        }
         break;
     case 5:
         if (strcmp(name, "coordinates") == 0) {
@@ -569,8 +582,13 @@ void AMFParserContext::endElement(const char * /* name */)
                         config = &m_material->config;
                     else if (m_path[1] == NODE_TYPE_OBJECT && m_object)
                         config = &m_object->config;
-                } else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume)
+                }
+                else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume)
                     config = &m_volume->config;
+                else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_RANGE && m_object && !m_object->layer_config_ranges.empty()) {
+                    auto it  = --m_object->layer_config_ranges.end();
+                    config = &it->second;
+                }
                 if (config)
                     config->set_deserialize(opt_key, m_value[1]);
             } else if (m_path.size() == 3 && m_path[1] == NODE_TYPE_OBJECT && m_object && strcmp(opt_key, "layer_height_profile") == 0) {
@@ -607,6 +625,16 @@ void AMFParserContext::endElement(const char * /* name */)
                 }
                 m_object->sla_points_status = sla::PointsStatus::UserModified;
             }
+            else if (m_path.size() == 5 && m_path[1] == NODE_TYPE_OBJECT && m_path[3] == NODE_TYPE_RANGE && 
+                     m_object && strcmp(opt_key, "layer_height_ranges") == 0) {
+                // Parse object's layer_height_ranges, a semicolon separated doubles.
+                char* p = const_cast<char*>(m_value[1].c_str());
+                char* end = strchr(p, ';');
+                *end = 0;
+
+                const t_layer_height_range range = {double(atof(p)), double(atof(end + 1))};
+                m_object->layer_config_ranges[range];
+            }
             else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume) {
                 if (strcmp(opt_key, "modifier") == 0) {
                     // Is this volume a modifier volume?
@@ -905,6 +933,31 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
         }
         //FIXME Store the layer height ranges (ModelObject::layer_height_ranges)
 
+
+        // #ys_FIXME_experiment : Try to export layer config range
+        const t_layer_config_ranges& config_ranges = object->layer_config_ranges;
+        if (!config_ranges.empty())
+        {
+            // Store the layer config range as a single semicolon separated list.
+            stream << "    <layer_config_ranges>\n";
+            size_t layer_counter = 0;
+            for (auto range : config_ranges) {
+                stream << "      <range id=\"" << layer_counter << "\">\n";
+
+                stream << "        <metadata type=\"slic3r.layer_height_ranges\">";
+                stream << range.first.first << ";" << range.first.second << "</metadata>\n";
+
+                for (const std::string& key : range.second.keys())
+                    stream << "        <metadata type=\"slic3r." << key << "\">" << range.second.serialize(key) << "</metadata>\n";
+
+                stream << "      </range>\n";
+                layer_counter++;
+            }
+
+            stream << "    </layer_config_ranges>\n";
+        }
+
+
         const std::vector<sla::SupportPoint>& sla_support_points = object->sla_support_points;
         if (!sla_support_points.empty()) {
             // Store the SLA supports as a single semicolon separated list.

From f0f608f247832b9f5ca3b1cd0a3bb03d148a7fad Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 11 Jun 2019 10:11:42 +0200
Subject: [PATCH 26/34] Copy/paste Layers for OSX

---
 src/slic3r/GUI/GUI_ObjectList.cpp | 40 ++++++++++++++++++-------------
 src/slic3r/GUI/GUI_ObjectList.hpp |  3 +++
 2 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index f6dd6c591..23eb67c50 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -148,10 +148,10 @@ ObjectList::ObjectList(wxWindow* parent) :
         wxAcceleratorTable accel(6, entries);
         SetAcceleratorTable(accel);
 
-        this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY)); }, wxID_COPY);
-        this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE)); }, wxID_PASTE);
-        this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->select_item_all_children(); }, wxID_SELECTALL);
-        this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->remove(); }, wxID_DELETE);
+        this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->copy();                      }, wxID_COPY);
+        this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->paste();                     }, wxID_PASTE);
+        this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->select_item_all_children();  }, wxID_SELECTALL);
+        this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->remove();                    }, wxID_DELETE);
     }
 #else __WXOSX__
     Bind(wxEVT_CHAR, [this](wxKeyEvent& event) { key_event(event); }); // doesn't work on OSX
@@ -773,6 +773,22 @@ void ObjectList::show_context_menu()
     }
 }
 
+void ObjectList::copy()
+{
+    if (m_selection_mode & smLayer)
+        fill_layer_config_ranges_cache();
+    else
+        wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY));
+}
+
+void ObjectList::paste()
+{
+    if (!m_layer_config_ranges_cache.empty())
+        paste_layers_into_list();
+    else
+        wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE));
+}
+
 #ifndef __WXOSX__
 void ObjectList::key_event(wxKeyEvent& event)
 {
@@ -787,18 +803,10 @@ void ObjectList::key_event(wxKeyEvent& event)
     }
     else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/))
         select_item_all_children();
-    else if (wxGetKeyState(wxKeyCode('C')) && wxGetKeyState(WXK_CONTROL)) {
-        if (m_selection_mode & smLayer)
-            fill_layer_config_ranges_cache();
-        else
-            wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY));
-    }
-    else if (wxGetKeyState(wxKeyCode('V')) && wxGetKeyState(WXK_CONTROL)) {
-        if (!m_layer_config_ranges_cache.empty())
-            paste_layers_into_list();
-        else
-            wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE));
-    }
+    else if (wxGetKeyState(wxKeyCode('C')) && wxGetKeyState(WXK_CONTROL)) 
+        copy();
+    else if (wxGetKeyState(wxKeyCode('V')) && wxGetKeyState(WXK_CONTROL))
+        paste();
     else
         event.Skip();
 }
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 7c7046626..ed055a3a6 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -202,6 +202,9 @@ public:
     void                key_event(wxKeyEvent& event);
 #endif /* __WXOSX__ */
 
+    void                copy();
+    void                paste();
+
     void                get_settings_choice(const wxString& category_name);
     void                get_freq_settings_choice(const wxString& bundle_name);
     void                update_settings_item();

From 4e0eb12ef6518e0a9e964612da626c86890d5e02 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 11 Jun 2019 14:39:41 +0200
Subject: [PATCH 27/34] Import/export of the Layers information to/from 3MF

---
 src/libslic3r/Format/3mf.cpp | 181 ++++++++++++++++++++++++++++++++++-
 1 file changed, 180 insertions(+), 1 deletion(-)

diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index 38b34c462..11202e7b3 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -33,6 +33,7 @@ const std::string RELATIONSHIPS_FILE = "_rels/.rels";
 const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config";
 const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config";
 const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt";
+const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/Slic3r_PE_layer_config_ranges.txt";
 const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt";
 
 const char* MODEL_TAG = "model";
@@ -331,6 +332,7 @@ namespace Slic3r {
         typedef std::map<int, ObjectMetadata> IdToMetadataMap;
         typedef std::map<int, Geometry> IdToGeometryMap;
         typedef std::map<int, std::vector<coordf_t>> IdToLayerHeightsProfileMap;
+        typedef std::map<int, t_layer_config_ranges> IdToLayerConfigRangesMap;
         typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap;
 
         // Version of the 3mf file
@@ -347,6 +349,7 @@ namespace Slic3r {
         CurrentConfig m_curr_config;
         IdToMetadataMap m_objects_metadata;
         IdToLayerHeightsProfileMap m_layer_heights_profiles;
+        IdToLayerConfigRangesMap m_layer_config_ranges;
         IdToSlaSupportPointsMap m_sla_support_points;
         std::string m_curr_metadata_name;
         std::string m_curr_characters;
@@ -365,6 +368,7 @@ namespace Slic3r {
         bool _load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config);
         bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
         void _extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
+        void _extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
         void _extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
 
         void _extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, const std::string& archive_filename);
@@ -476,6 +480,7 @@ namespace Slic3r {
         m_curr_config.volume_id = -1;
         m_objects_metadata.clear();
         m_layer_heights_profiles.clear();
+        m_layer_config_ranges.clear();
         m_sla_support_points.clear();
         m_curr_metadata_name.clear();
         m_curr_characters.clear();
@@ -546,9 +551,14 @@ namespace Slic3r {
 
                 if (boost::algorithm::iequals(name, LAYER_HEIGHTS_PROFILE_FILE))
                 {
-                    // extract slic3r lazer heights profile file
+                    // extract slic3r layer heights profile file
                     _extract_layer_heights_profile_config_from_archive(archive, stat);
                 }
+                if (boost::algorithm::iequals(name, LAYER_CONFIG_RANGES_FILE))
+                {
+                    // extract slic3r layer config ranges file
+                    _extract_layer_config_ranges_from_archive(archive, stat);
+                }
                 else if (boost::algorithm::iequals(name, SLA_SUPPORT_POINTS_FILE))
                 {
                     // extract sla support points file
@@ -592,6 +602,11 @@ namespace Slic3r {
             if (obj_layer_heights_profile != m_layer_heights_profiles.end())
                 model_object->layer_height_profile = obj_layer_heights_profile->second;
 
+            // m_layer_config_ranges are indexed by a 1 based model object index.
+            IdToLayerConfigRangesMap::iterator obj_layer_config_ranges = m_layer_config_ranges.find(object.second + 1);
+            if (obj_layer_config_ranges != m_layer_config_ranges.end())
+                model_object->layer_config_ranges = obj_layer_config_ranges->second;
+
             // m_sla_support_points are indexed by a 1 based model object index.
             IdToSlaSupportPointsMap::iterator obj_sla_support_points = m_sla_support_points.find(object.second + 1);
             if (obj_sla_support_points != m_sla_support_points.end() && !obj_sla_support_points->second.empty()) {
@@ -769,6 +784,115 @@ namespace Slic3r {
         }
     }
 
+    void _3MF_Importer::_extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
+    {
+        if (stat.m_uncomp_size > 0)
+        {
+            std::string buffer((size_t)stat.m_uncomp_size, 0);
+            mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
+            if (res == 0) {
+                add_error("Error while reading layer config ranges data to buffer");
+                return;
+            }
+
+            if (buffer.back() == '|')
+                buffer.pop_back();
+
+            std::vector<std::string> objects;
+            boost::split(objects, buffer, boost::is_any_of("|"), boost::token_compress_off);
+
+            for (std::string& object : objects)
+            {
+                // delete all spaces
+                boost::replace_all(object, " ", "");
+
+                std::vector<std::string> object_data;
+                boost::split(object_data, object, boost::is_any_of("*"), boost::token_compress_off);
+                /* there should be at least one layer config range in the object 
+                 * object_data[0]       => object information
+                 * object_data[i>=1]    => range information
+                 */
+                if (object_data.size() < 2) {
+                    add_error("Error while reading object data");
+                    continue;
+                }
+
+                std::vector<std::string> object_data_id;
+                boost::split(object_data_id, object_data[0], boost::is_any_of("="), boost::token_compress_off);
+                if (object_data_id.size() != 2) {
+                    add_error("Error while reading object id");
+                    continue;
+                }
+
+                // get object information
+                int object_id = std::atoi(object_data_id[1].c_str());
+                if (object_id == 0) {
+                    add_error("Found invalid object id");
+                    continue;
+                }
+
+                IdToLayerConfigRangesMap::iterator object_item = m_layer_config_ranges.find(object_id);
+                if (object_item != m_layer_config_ranges.end()) {
+                    add_error("Found duplicated layer config range");
+                    continue;
+                }
+
+                t_layer_config_ranges config_ranges;
+
+                // get ranges information
+                for (size_t i = 1; i < object_data.size(); ++i)
+                {
+                    if (object_data[i].back() == '\n')
+                        object_data[i].pop_back();
+
+                    std::vector<std::string> range_data;
+                    boost::split(range_data, object_data[i], boost::is_any_of("\n"), boost::token_compress_off);
+                    /* There should be at least two options for layer config range
+                     * range_data[0]       => Z range information
+                     * range_data[i>=1]    => configuration for the range
+                     */
+                    if (range_data.size() < 3) {
+                        add_error("Found invalid layer config range");
+                        continue;
+                    }
+
+                    std::vector<std::string> z_range_str;
+                    boost::split(z_range_str, range_data[0], boost::is_any_of("="), boost::token_compress_off);
+                    if (z_range_str.size() != 2) {
+                        add_error("Error while reading layer config range");
+                        continue;
+                    }
+
+                    std::vector<std::string> z_values;
+                    boost::split(z_values, z_range_str[1], boost::is_any_of(";"), boost::token_compress_off);
+                    if (z_values.size() != 2) {
+                        add_error("Found invalid layer config range");
+                        continue;
+                    }
+
+                    // get Z range information
+                    t_layer_height_range z_range = { (coordf_t)std::atof(z_values[0].c_str()) , (coordf_t)std::atof(z_values[1].c_str()) };
+                    DynamicPrintConfig& config = config_ranges[z_range];
+
+                    // get configuration options for the range
+                    for (size_t j = 1; j < range_data.size(); ++j)
+                    {
+                        std::vector<std::string> key_val;
+                        boost::split(key_val, range_data[j], boost::is_any_of("="), boost::token_compress_off);
+                        if (key_val.size() != 2) {
+                            add_error("Error while reading config value");
+                            continue;
+                        }
+                        config.set_deserialize(key_val[0], key_val[1]);
+                    }
+                }
+
+                if (!config_ranges.empty())
+                    m_layer_config_ranges.insert(IdToLayerConfigRangesMap::value_type(object_id, config_ranges));
+            }
+        }
+    }
+
     void _3MF_Importer::_extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
     {
         if (stat.m_uncomp_size > 0)
@@ -1622,6 +1746,7 @@ namespace Slic3r {
         bool _add_mesh_to_object_stream(std::stringstream& stream, ModelObject& object, VolumeToOffsetsMap& volumes_offsets);
         bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items);
         bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model);
+        bool _add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model);
         bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model);
         bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config);
         bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data);
@@ -1682,6 +1807,16 @@ namespace Slic3r {
             return false;
         }
 
+        // Adds layer config ranges file ("Metadata/Slic3r_PE_layer_config_ranges.txt").
+        // All layer height profiles of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
+        // The index differes from the index of an object ID of an object instance of a 3MF file!
+        if (!_add_layer_config_ranges_file_to_archive(archive, model))
+        {
+            close_zip_writer(&archive);
+            boost::filesystem::remove(filename);
+            return false;
+        }
+
         // Adds sla support points file ("Metadata/Slic3r_PE_sla_support_points.txt").
         // All  sla support points of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
         // The index differes from the index of an object ID of an object instance of a 3MF file!
@@ -2012,6 +2147,50 @@ namespace Slic3r {
         return true;
     }
 
+    bool _3MF_Exporter::_add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model)
+    {
+        std::string out = "";
+        char buffer[1024];
+
+        unsigned int object_cnt = 0;
+        for (const ModelObject* object : model.objects)
+        {
+            object_cnt++;
+            const t_layer_config_ranges& ranges = object->layer_config_ranges;
+            if (!ranges.empty())
+            {
+                sprintf(buffer, "object_id=%d\n", object_cnt);
+                out += buffer;
+
+                // Store the layer config ranges.
+                for (const auto& range : ranges)
+                {
+                    // store minX and maxZ
+                    sprintf(buffer, "*z_range = %f;%f\n", range.first.first, range.first.second);
+                    out += buffer;
+
+                    // store range configuration
+                    const DynamicPrintConfig& config = range.second;
+                    for (const std::string& key : config.keys())
+                        out += " " + key + " = " + config.serialize(key) + "\n";
+                }
+                
+                out += "|";
+            }
+        }
+
+        if (!out.empty())
+        {
+            if (!mz_zip_writer_add_mem(&archive, LAYER_CONFIG_RANGES_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
+            {
+                add_error("Unable to add layer heights profile file to archive");
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     bool _3MF_Exporter::_add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model)
     {
         std::string out = "";

From 26fb68ba459d11b9bc0df5047ccda8fbd0b9419e Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Tue, 11 Jun 2019 14:54:31 +0200
Subject: [PATCH 28/34] Added missed include for the OSX build

---
 src/libslic3r/Format/3mf.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index 11202e7b3..9103232a8 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -11,6 +11,7 @@
 #include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/split.hpp>
 #include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string/replace.hpp>
 #include <boost/filesystem/operations.hpp>
 #include <boost/nowide/fstream.hpp>
 #include <boost/nowide/cstdio.hpp>

From 1694204687ca93e7bd831cf5a5598bc1acfce658 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Wed, 12 Jun 2019 16:28:25 +0200
Subject: [PATCH 29/34] Added some logic to layers editor selection

---
 src/slic3r/GUI/GUI_ObjectLayers.cpp | 126 ++++++++++++++++++----------
 src/slic3r/GUI/GUI_ObjectLayers.hpp |  26 ++++--
 src/slic3r/GUI/GUI_ObjectList.cpp   |  44 ++++++++--
 src/slic3r/GUI/GUI_ObjectList.hpp   |   4 +-
 4 files changed, 136 insertions(+), 64 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
index ba0012a2b..5f0ec259d 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.cpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -39,72 +39,83 @@ ObjectLayers::ObjectLayers(wxWindow* parent) :
     m_bmp_add       = ScalableBitmap(parent, "add_copies");
 }
 
+void ObjectLayers::select_editor(LayerRangeEditor* editor, const bool is_last_edited_range)
+{
+    if (is_last_edited_range && m_selection_type == editor->type()) {
+        editor->SetFocus();
+        editor->SetInsertionPointEnd();
+    }    
+}
+
 wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range) 
 {
     const bool is_last_edited_range = range == m_last_edited_range;
 
+    auto set_focus_fn = [range, this](const EditorType type)
+    {
+        m_last_edited_range = range;
+        m_selection_type = type;
+    };
+
     // Add control for the "Min Z"
 
-    auto temp = new LayerRangeEditor(m_parent, double_to_string(range.first),
-        [range, this](coordf_t min_z)
+    auto editor = new LayerRangeEditor(m_parent, double_to_string(range.first), etMinZ,
+                                       set_focus_fn, [range, this](coordf_t min_z, bool enter_pressed)
     {
-        if (fabs(min_z - range.first) < EPSILON) {
-            m_selection_type = sitUndef;
-            return false;       // LayersList would not be updated/recreated
+        if (fabs(min_z - range.first) < EPSILON || min_z > range.second) {
+            m_selection_type = etUndef;
+            return false;
         }
 
         // data for next focusing
-        m_last_edited_range = { min_z, range.second };
-        m_selection_type = sitMinZ;
+        const t_layer_height_range& new_range = { min_z, range.second };
+        if (enter_pressed) {
+            m_last_edited_range = new_range;
+            m_selection_type = etMinZ;
+        }
 
-        wxGetApp().obj_list()->edit_layer_range(range, m_last_edited_range);
-        return true;            // LayersList will be updated/recreated
+        return wxGetApp().obj_list()->edit_layer_range(range, new_range);
     });
 
-    if (is_last_edited_range && m_selection_type == sitMinZ) {
-        temp->SetFocus();
-        temp->SetInsertionPointEnd();
-    }
-
-    m_grid_sizer->Add(temp);
+    select_editor(editor, is_last_edited_range);
+    m_grid_sizer->Add(editor);
 
     // Add control for the "Max Z"
 
-    temp = new LayerRangeEditor(m_parent, double_to_string(range.second),
-                                [range, this](coordf_t max_z)
+    editor = new LayerRangeEditor(m_parent, double_to_string(range.second), etMaxZ,
+                                  set_focus_fn, [range, this](coordf_t max_z, bool enter_pressed)
     {
-        if (fabs(max_z - range.second) < EPSILON) {
-            m_selection_type = sitUndef;
+        if (fabs(max_z - range.second) < EPSILON || range.first > max_z) {
+            m_selection_type = etUndef;
             return false;       // LayersList would not be updated/recreated
         }
 
         // data for next focusing
-        m_last_edited_range = { range.first, max_z };
-        m_selection_type = sitMaxZ;
+        const t_layer_height_range& new_range = { range.first, max_z };
+        if (enter_pressed) {
+            m_last_edited_range = new_range;
+            m_selection_type = etMaxZ;
+        }
 
-        wxGetApp().obj_list()->edit_layer_range(range, m_last_edited_range);
-        return true;            // LayersList will not be updated/recreated
+        return wxGetApp().obj_list()->edit_layer_range(range, new_range);
     });
 
-    if (is_last_edited_range && m_selection_type == sitMaxZ) {
-        temp->SetFocus();
-        temp->SetInsertionPointEnd();
-    }
-
-    m_grid_sizer->Add(temp);
+    select_editor(editor, is_last_edited_range);
+    m_grid_sizer->Add(editor);
 
     // Add control for the "Layer height"
 
-    temp = new LayerRangeEditor(m_parent,
+    editor = new LayerRangeEditor(m_parent,
                                 double_to_string(m_object->layer_config_ranges[range].option("layer_height")->getFloat()),
-                                [range, this](coordf_t layer_height)
+                             etLayerHeight, set_focus_fn, [range, this](coordf_t layer_height, bool)
     {
-        wxGetApp().obj_list()->edit_layer_range(range, layer_height);
-        return false;           // LayersList would not be updated/recreated
+        return wxGetApp().obj_list()->edit_layer_range(range, layer_height);
     });
 
+    select_editor(editor, is_last_edited_range);
+
     auto sizer = new wxBoxSizer(wxHORIZONTAL);
-    sizer->Add(temp);
+    sizer->Add(editor);
     m_grid_sizer->Add(sizer);
 
     return sizer;
@@ -193,34 +204,61 @@ void ObjectLayers::msw_rescale()
 
 LayerRangeEditor::LayerRangeEditor( wxWindow* parent,
                                     const wxString& value,
-                                    std::function<bool(coordf_t)> edit_fn
+                                    EditorType type,
+                                    std::function<void(EditorType)> set_focus_fn,
+                                    std::function<bool(coordf_t, bool enter_pressed)>   edit_fn
                                     ) :
+    m_valid_value(value),
+    m_type(type),
     wxTextCtrl(parent, wxID_ANY, value, wxDefaultPosition, 
                wxSize(8 * em_unit(parent), wxDefaultCoord), wxTE_PROCESS_ENTER)
 {
     this->SetFont(wxGetApp().normal_font());
     
-    this->Bind(wxEVT_TEXT_ENTER, ([this, edit_fn](wxEvent& e)
+    this->Bind(wxEVT_TEXT_ENTER, [this, edit_fn](wxEvent&)
     {
         m_enter_pressed     = true;
         // If LayersList wasn't updated/recreated, we can call wxEVT_KILL_FOCUS.Skip()
-        if ( !edit_fn(get_value()) )
+        if (m_type&etLayerHeight) {
+            if (!edit_fn(get_value(), true))
+                SetValue(m_valid_value);
+            else
+                m_valid_value = double_to_string(get_value());
             m_call_kill_focus = true;
-    }), this->GetId());
+        }
+        else if (!edit_fn(get_value(), true)) {
+            SetValue(m_valid_value);
+            m_call_kill_focus = true;
+        }
+    }, this->GetId());
 
-    this->Bind(wxEVT_KILL_FOCUS, ([this, edit_fn](wxEvent& e)
+    this->Bind(wxEVT_KILL_FOCUS, [this, edit_fn](wxFocusEvent& e)
     {
         if (!m_enter_pressed) {
-            m_enter_pressed = false;
-
             // If LayersList wasn't updated/recreated, we should call e.Skip()
-            if ( !edit_fn(get_value()) )
+            if (m_type & etLayerHeight) {
+                if (!edit_fn(get_value(), false))
+                    SetValue(m_valid_value);
+                else
+                    m_valid_value = double_to_string(get_value());
                 e.Skip();
+            }
+            else if (!edit_fn(get_value(), false)) {
+                SetValue(m_valid_value);
+                e.Skip();
+            } 
         }
-        else if (m_call_kill_focus)
+        else if (m_call_kill_focus) {
+            m_call_kill_focus = false;
             e.Skip();
-    }), this->GetId());
+        }
+    }, this->GetId());
 
+    this->Bind(wxEVT_LEFT_DOWN, ([this, set_focus_fn](wxEvent& e)
+    {
+        set_focus_fn(m_type);
+        e.Skip();
+    }));
 
     this->Bind(wxEVT_CHAR, ([this](wxKeyEvent& event)
     {
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index 562e04972..9c2af20e5 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -19,18 +19,32 @@ class ConfigOptionsGroup;
 typedef double                          coordf_t;
 typedef std::pair<coordf_t, coordf_t>   t_layer_height_range;
 
+enum EditorType
+{
+    etUndef         = 0,
+    etMinZ          = 1,
+    etMaxZ          = 2,
+    etLayerHeight   = 4,
+};
+
 class LayerRangeEditor : public wxTextCtrl
 {
     bool                m_enter_pressed     { false };
     bool                m_call_kill_focus   { false };
+    wxString            m_valid_value;
+    EditorType          m_type;
 
 public:
     LayerRangeEditor(   wxWindow* parent,
                         const wxString& value = wxEmptyString,
-                        std::function<bool(coordf_t val)> edit_fn = [](coordf_t) {return false; }
+                        EditorType type = etUndef,
+                        std::function<void(EditorType)>     set_focus_fn = [](EditorType)      {;},
+                        std::function<bool(coordf_t, bool)> edit_fn      = [](coordf_t, bool) {return false; }
                         );
     ~LayerRangeEditor() {}
 
+    EditorType          type() const {return m_type;}
+
 private:
     coordf_t            get_value();
 };
@@ -43,19 +57,13 @@ class ObjectLayers : public OG_Settings
 
     wxFlexGridSizer*       m_grid_sizer;
     t_layer_height_range   m_last_edited_range;
-
-    enum SelectedItemType
-    {
-        sitUndef,
-        sitMinZ,
-        sitMaxZ,
-        sitLayerHeight,
-    } m_selection_type {sitUndef};
+    EditorType             m_selection_type {etUndef};
 
 public:
     ObjectLayers(wxWindow* parent);
     ~ObjectLayers() {}
 
+    void        select_editor(LayerRangeEditor* editor, const bool is_last_edited_range);
     wxSizer*    create_layer(const t_layer_height_range& range);    // without_buttons
     void        create_layers_list();
     void        update_layers_list();
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 23eb67c50..b1b57fcd6 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -2363,6 +2363,18 @@ void ObjectList::del_layer_range(const t_layer_height_range& range)
     select_item(selectable_item);
 }
 
+double get_min_layer_height(const int extruder_idx)
+{
+    const DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
+    return config.opt_float("min_layer_height", extruder_idx <= 0 ? 0 : extruder_idx-1);
+}
+
+double get_max_layer_height(const int extruder_idx)
+{
+    const DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
+    return config.opt_float("max_layer_height", extruder_idx <= 0 ? 0 : extruder_idx-1);
+}
+
 void ObjectList::add_layer_range_after_current(const t_layer_height_range& current_range)
 {
     const int obj_idx = get_selected_obj_idx();
@@ -2393,13 +2405,14 @@ void ObjectList::add_layer_range_after_current(const t_layer_height_range& curre
 
         if (current_range.second == next_range.first)
         {
+            const auto old_config = ranges.at(next_range);
+
             const coordf_t delta = (next_range.second - next_range.first);
-            if (delta < 0.05f) // next range division has no sense 
+            if (delta < get_min_layer_height(old_config.opt_int("extruder"))/*0.05f*/) // next range division has no sense 
                 return; 
 
             const coordf_t midl_layer = next_range.first + 0.5f * delta;
             
-            const auto old_config = ranges.at(next_range);
             t_layer_height_range new_range = { midl_layer, next_range.second };
 
             // delete old layer
@@ -2450,21 +2463,32 @@ void ObjectList::add_layer_item(const t_layer_height_range& range,
         select_item(m_objects_model->AddSettingsChild(layer_item));
 }
 
-void ObjectList::edit_layer_range(const t_layer_height_range& range, coordf_t layer_height)
+bool ObjectList::edit_layer_range(const t_layer_height_range& range, coordf_t layer_height)
 {
     const int obj_idx = get_selected_obj_idx();
-    if (obj_idx < 0) return;
+    if (obj_idx < 0) 
+        return false;
 
-    t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
+    DynamicPrintConfig* config = &object(obj_idx)->layer_config_ranges[range];
+    if (fabs(layer_height - config->opt_float("layer_height")) < EPSILON)
+        return false;
 
-    DynamicPrintConfig* config = &ranges[range];
-    config->set_key_value("layer_height", new ConfigOptionFloat(layer_height));
+    const int extruder_idx = config->opt_int("extruder");
+
+    if (layer_height >= get_min_layer_height(extruder_idx) && 
+        layer_height <= get_max_layer_height(extruder_idx)) 
+    {
+        config->set_key_value("layer_height", new ConfigOptionFloat(layer_height));
+        return true;
+    }
+
+    return false;
 }
 
-void ObjectList::edit_layer_range(const t_layer_height_range& range, const t_layer_height_range& new_range)
+bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_layer_height_range& new_range)
 {
     const int obj_idx = get_selected_obj_idx();
-    if (obj_idx < 0) return;
+    if (obj_idx < 0) return false;
 
     t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
 
@@ -2484,6 +2508,8 @@ void ObjectList::edit_layer_range(const t_layer_height_range& range, const t_lay
     // To update(recreate) layers sizer call select_item for LayerRoot item expand
     select_item(root_item);
     Expand(root_item);
+
+    return true;
 }
 
 void ObjectList::init_objects()
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index ed055a3a6..ed19edd62 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -291,8 +291,8 @@ public:
     void add_layer_item (const t_layer_height_range& range, 
                          const wxDataViewItem layers_item, 
                          const int layer_idx = -1);
-    void edit_layer_range(const t_layer_height_range& range, coordf_t layer_height);
-    void edit_layer_range(const t_layer_height_range& range, 
+    bool edit_layer_range(const t_layer_height_range& range, coordf_t layer_height);
+    bool edit_layer_range(const t_layer_height_range& range, 
                           const t_layer_height_range& new_range);
 
     void init_objects();

From c9dd5f878699e79d64ccb4059f37b8967e872270 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Thu, 13 Jun 2019 11:37:03 +0200
Subject: [PATCH 30/34] Fixed updating of data for LayerEditors selection

---
 src/slic3r/GUI/GUI_ObjectLayers.cpp | 39 ++++++++++++++++-------------
 src/slic3r/GUI/GUI_ObjectLayers.hpp |  5 +++-
 2 files changed, 25 insertions(+), 19 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
index 5f0ec259d..df0c4faeb 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.cpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -49,18 +49,27 @@ void ObjectLayers::select_editor(LayerRangeEditor* editor, const bool is_last_ed
 
 wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range) 
 {
-    const bool is_last_edited_range = range == m_last_edited_range;
+    const bool is_last_edited_range = range == m_selectable_range;
 
     auto set_focus_fn = [range, this](const EditorType type)
     {
-        m_last_edited_range = range;
+        m_selectable_range = range;
         m_selection_type = type;
     };
 
+    auto set_focus = [range, this](const t_layer_height_range& new_range, EditorType type, bool enter_pressed)
+    {
+        // change selectable range for new one, if enter was pressed or if same range was selected
+        if (enter_pressed || m_selectable_range == range)
+            m_selectable_range = new_range;
+        if (enter_pressed)
+            m_selection_type = type;
+    };
+
     // Add control for the "Min Z"
 
     auto editor = new LayerRangeEditor(m_parent, double_to_string(range.first), etMinZ,
-                                       set_focus_fn, [range, this](coordf_t min_z, bool enter_pressed)
+                                       set_focus_fn, [range, set_focus, this](coordf_t min_z, bool enter_pressed)
     {
         if (fabs(min_z - range.first) < EPSILON || min_z > range.second) {
             m_selection_type = etUndef;
@@ -69,10 +78,7 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range)
 
         // data for next focusing
         const t_layer_height_range& new_range = { min_z, range.second };
-        if (enter_pressed) {
-            m_last_edited_range = new_range;
-            m_selection_type = etMinZ;
-        }
+        set_focus(new_range, etMinZ, enter_pressed);
 
         return wxGetApp().obj_list()->edit_layer_range(range, new_range);
     });
@@ -83,7 +89,7 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range)
     // Add control for the "Max Z"
 
     editor = new LayerRangeEditor(m_parent, double_to_string(range.second), etMaxZ,
-                                  set_focus_fn, [range, this](coordf_t max_z, bool enter_pressed)
+                                  set_focus_fn, [range, set_focus, this](coordf_t max_z, bool enter_pressed)
     {
         if (fabs(max_z - range.second) < EPSILON || range.first > max_z) {
             m_selection_type = etUndef;
@@ -92,10 +98,7 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range)
 
         // data for next focusing
         const t_layer_height_range& new_range = { range.first, max_z };
-        if (enter_pressed) {
-            m_last_edited_range = new_range;
-            m_selection_type = etMaxZ;
-        }
+        set_focus(new_range, etMaxZ, enter_pressed);
 
         return wxGetApp().obj_list()->edit_layer_range(range, new_range);
     });
@@ -210,6 +213,7 @@ LayerRangeEditor::LayerRangeEditor( wxWindow* parent,
                                     ) :
     m_valid_value(value),
     m_type(type),
+    m_set_focus(set_focus_fn),
     wxTextCtrl(parent, wxID_ANY, value, wxDefaultPosition, 
                wxSize(8 * em_unit(parent), wxDefaultCoord), wxTE_PROCESS_ENTER)
 {
@@ -235,6 +239,11 @@ LayerRangeEditor::LayerRangeEditor( wxWindow* parent,
     this->Bind(wxEVT_KILL_FOCUS, [this, edit_fn](wxFocusEvent& e)
     {
         if (!m_enter_pressed) {
+            // update data for next editor selection
+            LayerRangeEditor* new_editor = dynamic_cast<LayerRangeEditor*>(e.GetWindow());
+            if (new_editor)
+                new_editor->set_focus();
+
             // If LayersList wasn't updated/recreated, we should call e.Skip()
             if (m_type & etLayerHeight) {
                 if (!edit_fn(get_value(), false))
@@ -254,12 +263,6 @@ LayerRangeEditor::LayerRangeEditor( wxWindow* parent,
         }
     }, this->GetId());
 
-    this->Bind(wxEVT_LEFT_DOWN, ([this, set_focus_fn](wxEvent& e)
-    {
-        set_focus_fn(m_type);
-        e.Skip();
-    }));
-
     this->Bind(wxEVT_CHAR, ([this](wxKeyEvent& event)
     {
         // select all text using Ctrl+A
diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp
index 9c2af20e5..e3366e03e 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.hpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp
@@ -34,6 +34,8 @@ class LayerRangeEditor : public wxTextCtrl
     wxString            m_valid_value;
     EditorType          m_type;
 
+    std::function<void(EditorType)> m_set_focus;
+
 public:
     LayerRangeEditor(   wxWindow* parent,
                         const wxString& value = wxEmptyString,
@@ -44,6 +46,7 @@ public:
     ~LayerRangeEditor() {}
 
     EditorType          type() const {return m_type;}
+    void                set_focus() const { m_set_focus(m_type);}
 
 private:
     coordf_t            get_value();
@@ -56,7 +59,7 @@ class ObjectLayers : public OG_Settings
     ModelObject*    m_object {nullptr};
 
     wxFlexGridSizer*       m_grid_sizer;
-    t_layer_height_range   m_last_edited_range;
+    t_layer_height_range   m_selectable_range;
     EditorType             m_selection_type {etUndef};
 
 public:

From e00774d2e21319ddfacbad417f7dd7309e8f2f56 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Thu, 13 Jun 2019 13:00:46 +0200
Subject: [PATCH 31/34] Workarounds for selection under OSX and GTK

---
 src/slic3r/GUI/GUI_ObjectLayers.cpp | 27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp
index df0c4faeb..12c1022ce 100644
--- a/src/slic3r/GUI/GUI_ObjectLayers.cpp
+++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp
@@ -42,8 +42,19 @@ ObjectLayers::ObjectLayers(wxWindow* parent) :
 void ObjectLayers::select_editor(LayerRangeEditor* editor, const bool is_last_edited_range)
 {
     if (is_last_edited_range && m_selection_type == editor->type()) {
+    /* Workaround! Under OSX we should use CallAfter() for SetFocus() after LayerEditors "reorganizations", 
+     * because of selected control's strange behavior: 
+     * cursor is set to the control, but blue border - doesn't.
+     * And as a result we couldn't edit this control.
+     * */
+#ifdef __WXOSX__
+        wxTheApp->CallAfter([editor]() {
+#endif
         editor->SetFocus();
         editor->SetInsertionPointEnd();
+#ifdef __WXOSX__
+        });
+#endif
     }    
 }
 
@@ -239,11 +250,15 @@ LayerRangeEditor::LayerRangeEditor( wxWindow* parent,
     this->Bind(wxEVT_KILL_FOCUS, [this, edit_fn](wxFocusEvent& e)
     {
         if (!m_enter_pressed) {
-            // update data for next editor selection
+#ifndef __WXGTK__
+            /* Update data for next editor selection.
+             * But under GTK it lucks like there is no information about selected control at e.GetWindow(),
+             * so we'll take it from wxEVT_LEFT_DOWN event
+             * */
             LayerRangeEditor* new_editor = dynamic_cast<LayerRangeEditor*>(e.GetWindow());
             if (new_editor)
                 new_editor->set_focus();
-
+#endif // not __WXGTK__
             // If LayersList wasn't updated/recreated, we should call e.Skip()
             if (m_type & etLayerHeight) {
                 if (!edit_fn(get_value(), false))
@@ -263,6 +278,14 @@ LayerRangeEditor::LayerRangeEditor( wxWindow* parent,
         }
     }, this->GetId());
 
+#ifdef __WXGTK__ // Workaround! To take information about selectable range
+    this->Bind(wxEVT_LEFT_DOWN, [this](wxEvent& e)
+    {
+        set_focus();
+        e.Skip();
+    }, this->GetId());
+#endif //__WXGTK__
+
     this->Bind(wxEVT_CHAR, ([this](wxKeyEvent& event)
     {
         // select all text using Ctrl+A

From 86e7a07dd8130462771d91540cc3daa6e0a8bc9c Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Thu, 13 Jun 2019 16:17:54 +0200
Subject: [PATCH 32/34] Fixed selection

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

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index b1b57fcd6..31396b630 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -2543,9 +2543,11 @@ void ObjectList::update_selections()
     if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) & (itSettings | itLayerRoot | itLayer))
     {
         const auto item = GetSelection();
-        if (selection.is_single_full_object() && 
-            m_objects_model->GetIdByItem(m_objects_model->GetParent(item)) == selection.get_object_idx())
-            return; 
+        if (selection.is_single_full_object()) {
+            if (m_objects_model->GetObjectIdByItem(item) == selection.get_object_idx())
+                return;
+            sels.Add(m_objects_model->GetItemById(selection.get_object_idx()));
+        }
         if (selection.is_single_volume() || selection.is_any_modifier()) {
             const auto gl_vol = selection.get_volume(*selection.get_volume_idxs().begin());
             if (m_objects_model->GetVolumeIdByItem(m_objects_model->GetParent(item)) == gl_vol->volume_idx())

From f394f84d51b8654b9008a11e773bdd04d75b979d Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 17 Jun 2019 13:09:11 +0200
Subject: [PATCH 33/34] Fixed selection after layers deleting

---
 src/slic3r/GUI/GUI_ObjectList.cpp | 28 ++++++++++++----------------
 1 file changed, 12 insertions(+), 16 deletions(-)

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 31396b630..1d7d95b56 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -2317,32 +2317,28 @@ void ObjectList::remove()
     wxDataViewItemArray sels;
     GetSelections(sels);
 
+    wxDataViewItem  parent = wxDataViewItem(0);
+
     for (auto& item : sels)
     {
         if (m_objects_model->GetParent(item) == wxDataViewItem(0))
             delete_from_model_and_list(itObject, m_objects_model->GetIdByItem(item), -1);
         else {
-//             if (sels.size() == 1)
-//                 select_item(m_objects_model->GetParent(item));
-            wxDataViewItem  parent = m_objects_model->GetParent(item);
-            if (sels.size() == 1) {
-                if (!(m_objects_model->GetItemType(item) & itLayer)) {
-                    select_item(parent);
-                    parent = wxDataViewItem(0);
-                }
-                else {
-                    wxDataViewItemArray children;
-                    if (m_objects_model->GetChildren(parent, children) == 1)
-                        parent = m_objects_model->GetTopParent(item);
-                }
+            if (m_objects_model->GetItemType(item) & itLayer) {
+                parent = m_objects_model->GetParent(item);
+                wxDataViewItemArray children;
+                if (m_objects_model->GetChildren(parent, children) == 1)
+                    parent = m_objects_model->GetTopParent(item);
             }
+            else if (sels.size() == 1)
+                select_item(m_objects_model->GetParent(item));
             
             del_subobject_item(item);
-
-            if (sels.size() == 1 && parent)
-                select_item(parent);
         }
     }
+
+    if (parent)
+        select_item(parent);
 }
 
 void ObjectList::del_layer_range(const t_layer_height_range& range)

From 5fd3cc267686c74e422a013e62bbae6aea588678 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 17 Jun 2019 13:46:56 +0200
Subject: [PATCH 34/34] Select edited layer after changing instead of "Layers"
 selection, if editing was in "Layer" mode

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

diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 1d7d95b56..5539ee29a 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -2486,6 +2486,8 @@ bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_lay
     const int obj_idx = get_selected_obj_idx();
     if (obj_idx < 0) return false;
 
+    const ItemType sel_type = m_objects_model->GetItemType(GetSelection());
+
     t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
 
     const DynamicPrintConfig config = ranges[range];
@@ -2501,8 +2503,7 @@ bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_lay
         for (const auto r : ranges)
             add_layer_item(r.first, root_item);
 
-    // To update(recreate) layers sizer call select_item for LayerRoot item expand
-    select_item(root_item);
+    select_item(sel_type&itLayer ? m_objects_model->GetItemByLayerRange(obj_idx, new_range) : root_item);
     Expand(root_item);
 
     return true;